From 956cd2d0038d7317cf2b9627a6e9161ddf8456e5 Mon Sep 17 00:00:00 2001 From: Takeno-hito <18237819+Takeno-hito@users.noreply.github.com> Date: Sat, 13 Jul 2024 15:59:50 +0900 Subject: [PATCH 01/10] feat: mdiCodeBraces --- src/assets/mdi.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/assets/mdi.ts b/src/assets/mdi.ts index c7dd5a045..0f78bb058 100644 --- a/src/assets/mdi.ts +++ b/src/assets/mdi.ts @@ -79,7 +79,8 @@ import { mdiCrown, mdiFormatTitle, mdiCloseCircle, - mdiNotebook + mdiNotebook, + mdiCodeBraces } from '@mdi/js' interface MdiIconsMapping { @@ -167,7 +168,8 @@ const mdi: MdiIconsMapping = { 'music-note': mdiMusicNote, stop: mdiStop, crown: mdiCrown, - 'format-title': mdiFormatTitle + 'format-title': mdiFormatTitle, + 'code-braces': mdiCodeBraces } export default mdi From 03278a2fce119874f296557645b858a8ca1ef31b Mon Sep 17 00:00:00 2001 From: Takeno-hito <18237819+Takeno-hito@users.noreply.github.com> Date: Sat, 13 Jul 2024 16:01:18 +0900 Subject: [PATCH 02/10] =?UTF-8?q?featureFlagSetting=20=E3=81=AE=20store=20?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/app/featureFlagSettings.ts | 110 +++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/store/app/featureFlagSettings.ts diff --git a/src/store/app/featureFlagSettings.ts b/src/store/app/featureFlagSettings.ts new file mode 100644 index 000000000..904ed9602 --- /dev/null +++ b/src/store/app/featureFlagSettings.ts @@ -0,0 +1,110 @@ +import { defineStore, acceptHMRUpdate } from 'pinia' +import { computed, toRefs } from 'vue' +import { replacePrefix } from '/@/lib/basic/string' +import { convertToRefsStore } from '/@/store/utils/convertToRefsStore' +import useIndexedDbValue from '/@/composables/utils/useIndexedDbValue' +import { channelTreeMitt } from '/@/store/domain/channelTree' +import { getVuexData } from '/@/store/utils/migrateFromVuex' +import { isObjectAndHasKey } from '/@/lib/basic/object' +import { promisifyRequest } from 'idb-keyval' +import type {Union} from "ts-pattern/dist/types/helpers"; + +type FeatureFlagKey = 'test1' | 'test2' + +type State = { + status: Map + enabled: true +} + +type FeatureFlagDescription = { + title: string + description: string + defaultValue: boolean + endAt: Date // 最大一ヶ月先を指定し、それ以上先は指定しない +} + +export type FeatureFlag = FeatureFlagDescription & { enabled: boolean } + +const featureFlagDescriptions: Record = { + test1: { + title: 'フラグテスト 1', + description: 'test1', + defaultValue: true, + endAt: new Date('2024-07-31') + }, + test2: { + title: 'フラグテスト 2', + description: 'test2', + defaultValue: false, + endAt: new Date('2020-01-31') + } +} + + +const useFlagSettingsPinia = defineStore('app/featureFlagSettings', () => { + const initialValue: State = { + status: new Map(), + enabled: true, + } + + const [state, restoring, restoringPromise] = useIndexedDbValue( + 'store/app/featureFlagSettings', + 1, + { + // migrate from vuex + 1: async getStore => { + const vuexStore = await getVuexData() + if (!vuexStore) return + if (!isObjectAndHasKey(vuexStore, 'app')) return + if (!isObjectAndHasKey(vuexStore.app, 'featureFlagSettings')) return + const addReq = getStore().add(vuexStore.app.featureFlagSettings, 'key') + await promisifyRequest(addReq) + } + }, + initialValue + ) + + const isFlagEnabled = (flag: FeatureFlagKey): boolean => { + const featureFlag = featureFlagDescriptions[flag] + if (featureFlag.endAt < new Date()) { + return false + } + return state.status.get(flag) ?? featureFlag.defaultValue + } + + const FeatureFlags = computed(() => { + const res: Map = new Map() + Object.entries(featureFlagDescriptions).forEach(([flag, featureFlag]) => { + res.set(flag as FeatureFlagKey, { + title: featureFlag.title, + description: featureFlag.description, + defaultValue: featureFlag.defaultValue, + endAt: featureFlag.endAt, + enabled: isFlagEnabled(flag as FeatureFlagKey) + }) + }) + return res + }) + + const updateFeatureFlagStatus = async ( + flag: FeatureFlagKey, + enabled: boolean + ) => { + await restoringPromise.value + state.status.set(flag, enabled) + } + + return { + ...toRefs(state), + updateFeatureFlagStatus, + FeatureFlags, + } +}) + +export const useFeatureFlagSettings = convertToRefsStore(useFlagSettingsPinia) + +if (import.meta.hot) { + import.meta.hot.accept( + acceptHMRUpdate(useFlagSettingsPinia, import.meta.hot) + ) +} From 0462f738ad6ffc3fd3818952fce4c9c8d06a1bbc Mon Sep 17 00:00:00 2001 From: Takeno-hito <18237819+Takeno-hito@users.noreply.github.com> Date: Sat, 13 Jul 2024 16:01:34 +0900 Subject: [PATCH 03/10] feat: featureFlagTab --- .../Settings/FeatureFlagTab/FeatureFlag.vue | 48 +++++++++++++++++++ .../Settings/composables/useNavigation.ts | 8 +++- src/router/settings.ts | 7 ++- src/views/Settings/FeatureFlagTab.vue | 29 +++++++++++ 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 src/components/Settings/FeatureFlagTab/FeatureFlag.vue create mode 100644 src/views/Settings/FeatureFlagTab.vue diff --git a/src/components/Settings/FeatureFlagTab/FeatureFlag.vue b/src/components/Settings/FeatureFlagTab/FeatureFlag.vue new file mode 100644 index 000000000..4ecd8f079 --- /dev/null +++ b/src/components/Settings/FeatureFlagTab/FeatureFlag.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/components/Settings/composables/useNavigation.ts b/src/components/Settings/composables/useNavigation.ts index 3957e6385..2a308eb1c 100644 --- a/src/components/Settings/composables/useNavigation.ts +++ b/src/components/Settings/composables/useNavigation.ts @@ -20,7 +20,8 @@ export const navigationRouteNameTitleMap: Record = { settingsBrowser: 'ブラウザ', settingsQall: '通話 (Qall)', settingsStamp: 'スタンプ', - settingsTheme: 'テーマ' + settingsTheme: 'テーマ', + settingsFeatureFlag: '実験的機能' } export const navigations: { @@ -60,6 +61,11 @@ export const navigations: { routeName: 'settingsTheme', iconName: 'brightness-6', iconMdi: true + }, + { + routeName: 'settingsFeatureFlag', + iconName: 'code-braces', + iconMdi: true } ] diff --git a/src/router/settings.ts b/src/router/settings.ts index 23eecff27..cb4279e55 100644 --- a/src/router/settings.ts +++ b/src/router/settings.ts @@ -9,6 +9,7 @@ export type SettingsRouteName = | 'settingsQall' | 'settingsStamp' | 'settingsTheme' + | 'settingsFeatureFlag' export const isSettingsRouteName = ( name: string @@ -33,6 +34,8 @@ const pathByRouteName = (routeName: SettingsRouteName) => { return 'stamp' case 'settingsTheme': return 'theme' + case 'settingsFeatureFlag': + return 'feature-flag' } } @@ -42,6 +45,7 @@ const Browser = () => import('/@/views/Settings/BrowserTab.vue') const Qall = () => import('/@/views/Settings/QallTab.vue') const Stamp = () => import('/@/views/Settings/StampTab.vue') const Theme = () => import('/@/views/Settings/ThemeTab.vue') +const FeatureFlag = () => import('/@/views/Settings/FeatureFlagTab.vue') const createRoute = (name: SettingsRouteName, component: Component) => ({ name, @@ -55,7 +59,8 @@ export const settingsRoutes: RouteRecordRaw[] = [ createRoute('settingsBrowser', Browser), createRoute('settingsQall', Qall), createRoute('settingsStamp', Stamp), - createRoute('settingsTheme', Theme) + createRoute('settingsTheme', Theme), + createRoute('settingsFeatureFlag', FeatureFlag) ] export const defaultSettingsName: SettingsRouteName = 'settingsProfile' diff --git a/src/views/Settings/FeatureFlagTab.vue b/src/views/Settings/FeatureFlagTab.vue new file mode 100644 index 000000000..100fce0cb --- /dev/null +++ b/src/views/Settings/FeatureFlagTab.vue @@ -0,0 +1,29 @@ + + + + + From d63ac6b4abd97ded578e8d0dd7c8f38cf815d60d Mon Sep 17 00:00:00 2001 From: Takeno-hito <18237819+Takeno-hito@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:36:08 +0900 Subject: [PATCH 04/10] =?UTF-8?q?feat:=20=E8=AA=AD=E8=BE=BC=E4=B8=AD?= =?UTF-8?q?=E3=81=AF=20loading=20=E3=82=92=E8=A1=A8=E7=A4=BA=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/app/featureFlagSettings.ts | 1 + src/views/Settings/FeatureFlagTab.vue | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/store/app/featureFlagSettings.ts b/src/store/app/featureFlagSettings.ts index 904ed9602..4faafdd7a 100644 --- a/src/store/app/featureFlagSettings.ts +++ b/src/store/app/featureFlagSettings.ts @@ -98,6 +98,7 @@ const useFlagSettingsPinia = defineStore('app/featureFlagSettings', () => { ...toRefs(state), updateFeatureFlagStatus, FeatureFlags, + restoring } }) diff --git a/src/views/Settings/FeatureFlagTab.vue b/src/views/Settings/FeatureFlagTab.vue index 100fce0cb..6106a4895 100644 --- a/src/views/Settings/FeatureFlagTab.vue +++ b/src/views/Settings/FeatureFlagTab.vue @@ -1,6 +1,7 @@ From 61599d1ff1c818fde5be8b1cc0ab765bcbc1654e Mon Sep 17 00:00:00 2001 From: Takeno-hito <18237819+Takeno-hito@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:37:18 +0900 Subject: [PATCH 05/10] fmt: fix by prettier --- .../Settings/FeatureFlagTab/FeatureFlag.vue | 2 +- src/store/app/featureFlagSettings.ts | 13 ++++++------- src/views/Settings/FeatureFlagTab.vue | 1 - 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/components/Settings/FeatureFlagTab/FeatureFlag.vue b/src/components/Settings/FeatureFlagTab/FeatureFlag.vue index 4ecd8f079..3505172a0 100644 --- a/src/components/Settings/FeatureFlagTab/FeatureFlag.vue +++ b/src/components/Settings/FeatureFlagTab/FeatureFlag.vue @@ -9,7 +9,7 @@

- +
diff --git a/src/store/app/featureFlagSettings.ts b/src/store/app/featureFlagSettings.ts index 4faafdd7a..f74ec6acf 100644 --- a/src/store/app/featureFlagSettings.ts +++ b/src/store/app/featureFlagSettings.ts @@ -7,7 +7,7 @@ import { channelTreeMitt } from '/@/store/domain/channelTree' import { getVuexData } from '/@/store/utils/migrateFromVuex' import { isObjectAndHasKey } from '/@/lib/basic/object' import { promisifyRequest } from 'idb-keyval' -import type {Union} from "ts-pattern/dist/types/helpers"; +import type { Union } from 'ts-pattern/dist/types/helpers' type FeatureFlagKey = 'test1' | 'test2' @@ -25,7 +25,10 @@ type FeatureFlagDescription = { export type FeatureFlag = FeatureFlagDescription & { enabled: boolean } -const featureFlagDescriptions: Record = { +export const featureFlagDescriptions: Record< + FeatureFlagKey, + FeatureFlagDescription +> = { test1: { title: 'フラグテスト 1', description: 'test1', @@ -40,7 +43,6 @@ const featureFlagDescriptions: Record = } } - const useFlagSettingsPinia = defineStore('app/featureFlagSettings', () => { const initialValue: State = { status: new Map(), @@ -95,7 +97,6 @@ const useFlagSettingsPinia = defineStore('app/featureFlagSettings', () => { } return { - ...toRefs(state), updateFeatureFlagStatus, FeatureFlags, restoring @@ -105,7 +106,5 @@ const useFlagSettingsPinia = defineStore('app/featureFlagSettings', () => { export const useFeatureFlagSettings = convertToRefsStore(useFlagSettingsPinia) if (import.meta.hot) { - import.meta.hot.accept( - acceptHMRUpdate(useFlagSettingsPinia, import.meta.hot) - ) + import.meta.hot.accept(acceptHMRUpdate(useFlagSettingsPinia, import.meta.hot)) } diff --git a/src/views/Settings/FeatureFlagTab.vue b/src/views/Settings/FeatureFlagTab.vue index 6106a4895..8fb1cce07 100644 --- a/src/views/Settings/FeatureFlagTab.vue +++ b/src/views/Settings/FeatureFlagTab.vue @@ -22,7 +22,6 @@ import { useFeatureFlagSettings } from '/@/store/app/featureFlagSettings' import FeatureFlag from '/@/components/Settings/FeatureFlagTab/FeatureFlag.vue' const state = useFeatureFlagSettings() -