Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add ability to set default theme for UI #2062

Merged
merged 4 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

# ui:
# enabled: true
# default_theme: system

# cors:
# enabled: false
Expand Down
5 changes: 4 additions & 1 deletion config/flipt.schema.cue
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,10 @@ import "strings"
}
}

#ui: enabled?: bool | *true
#ui: {
enabled?: bool | *true
default_theme?: "light" | "dark" | *"system"
}

#audit: {
sinks?: {
Expand Down
15 changes: 9 additions & 6 deletions config/flipt.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@
"properties": {
"domain": { "type": "string" },
"secure": { "type": "boolean" },
"token_lifetime": {"type": "string"},
"state_lifetime": {"type": "string"},
"token_lifetime": { "type": "string" },
"state_lifetime": { "type": "string" },
"csrf": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -436,10 +436,7 @@
"type": "integer"
},
"conn_max_lifetime": {
"oneOf": [
{"type": "integer"},
{"type": "string"}
]
"oneOf": [{ "type": "integer" }, { "type": "string" }]
},
"prepared_statements_enabled": {
"type": "boolean"
Expand Down Expand Up @@ -637,6 +634,12 @@
"type": "boolean",
"default": true,
"deprecated": true
},
"default_theme": {
"type": "string",
Jamess-Lucass marked this conversation as resolved.
Show resolved Hide resolved
"enum": ["light", "dark", "system"],
"default": "system",
"deprecated": false
}
},
"title": "UI"
Expand Down
1 change: 1 addition & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,7 @@ github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0ua
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
Expand Down
3 changes: 2 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,8 @@ func DefaultConfig() *Config {
},

UI: UIConfig{
Enabled: true,
Enabled: true,
DefaultTheme: SystemUITheme,
},

Cors: CorsConfig{
Expand Down
14 changes: 12 additions & 2 deletions internal/config/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,28 @@ package config

import "github.com/spf13/viper"

type UITheme string

const (
SystemUITheme = UITheme("system")
DarkUITheme = UITheme("dark")
LightUITheme = UITheme("light")
)

// cheers up the unparam linter
var _ defaulter = (*UIConfig)(nil)

// UIConfig contains fields, which control the behaviour
// of Flipt's user interface.
type UIConfig struct {
Enabled bool `json:"enabled" mapstructure:"enabled"`
Enabled bool `json:"enabled" mapstructure:"enabled"`
DefaultTheme UITheme `json:"defaultTheme" mapstructure:"default_theme"`
}

func (c *UIConfig) setDefaults(v *viper.Viper) error {
v.SetDefault("ui", map[string]any{
"enabled": true,
"enabled": true,
"default_theme": SystemUITheme,
})

return nil
Expand Down
4 changes: 4 additions & 0 deletions ui/src/app/meta/metaSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { getConfig, getInfo } from '~/data/api';
import { IConfig, IInfo, StorageType } from '~/types/Meta';
import { Theme } from '~/types/Preferences';

interface IMetaSlice {
info: IInfo;
Expand All @@ -23,6 +24,9 @@ const initialState: IMetaSlice = {
storage: {
type: StorageType.DATABASE,
readOnly: false
},
ui: {
defaultTheme: Theme.SYSTEM
}
}
};
Expand Down
4 changes: 1 addition & 3 deletions ui/src/app/preferences/Preferences.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Switch } from '@headlessui/react';
import { Formik } from 'formik';
import nightwind from 'nightwind/helper';
import { useDispatch, useSelector } from 'react-redux';
import Select from '~/components/forms/Select';
import { Theme, Timezone } from '~/types/Preferences';
Expand Down Expand Up @@ -45,15 +44,14 @@ export default function Preferences() {
<Select
id="location"
name="location"
value={theme || Theme.LIGHT}
value={theme || Theme.SYSTEM}
options={[
{ value: Theme.LIGHT, label: 'Light' },
{ value: Theme.DARK, label: 'Dark' },
{ value: Theme.SYSTEM, label: 'System' }
]}
onChange={(e) => {
dispatch(themeChanged(e.target.value as Theme));
nightwind.enable(Theme.DARK === (e.target.value as Theme));
}}
/>
</div>
Expand Down
17 changes: 16 additions & 1 deletion ui/src/app/preferences/preferencesSlice.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
import { createSlice } from '@reduxjs/toolkit';
import { RootState } from '~/store';

Check warning on line 3 in ui/src/app/preferences/preferencesSlice.ts

View workflow job for this annotation

GitHub Actions / Lint UI

Insert `fetchConfigAsync·}·from·'~/app/meta/metaSlice';⏎import·{·`
import { Theme, Timezone } from '~/types/Preferences';

Check warning on line 4 in ui/src/app/preferences/preferencesSlice.ts

View workflow job for this annotation

GitHub Actions / Lint UI

Delete `';⏎import·{·fetchConfigAsync·}·from·'~/app/meta/metaSlice`
import { fetchConfigAsync } from '~/app/meta/metaSlice';

export const preferencesKey = 'preferences';

interface IPreferencesState {
theme: Theme;
timezone: Timezone;
}

const initialState: IPreferencesState = {
theme: Theme.LIGHT,
theme: Theme.SYSTEM,
timezone: Timezone.LOCAL
};

Expand All @@ -23,6 +26,18 @@
timezoneChanged: (state, action) => {
state.timezone = action.payload;
}
},
extraReducers(builder) {
builder.addCase(fetchConfigAsync.fulfilled, (state, action) => {
const currentPreference = JSON.parse(
localStorage.getItem(preferencesKey) || '{}'
) as IPreferencesState;

// If there isn't currently a set theme, set to the default theme
if (!currentPreference.theme) {
state.theme = action.payload.ui.defaultTheme;
}
});
}
});

Expand Down
6 changes: 4 additions & 2 deletions ui/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import {

import { metaSlice } from './app/meta/metaSlice';
import { namespacesSlice } from './app/namespaces/namespacesSlice';
import { preferencesSlice } from './app/preferences/preferencesSlice';
import {
preferencesKey,
preferencesSlice
} from './app/preferences/preferencesSlice';
import { LoadingStatus } from './types/Meta';

const listenerMiddleware = createListenerMiddleware();

const preferencesKey = 'preferences';
const namespaceKey = 'namespace';

listenerMiddleware.startListening({
Expand Down
7 changes: 7 additions & 0 deletions ui/src/types/Meta.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Theme } from './Preferences';

export interface IInfo {
version: string;
latestVersion?: string;
Expand All @@ -14,8 +16,13 @@ export interface IStorage {
readOnly?: boolean;
}

export interface IUI {
defaultTheme: Theme;
}

export interface IConfig {
storage: IStorage;
ui: IUI;
}

export enum StorageType {
Expand Down
Loading