mirror of
https://github.com/nocodb/nocodb.git
synced 2026-02-01 23:48:33 +00:00
Merge pull request #11482 from nocodb/nc-versioned-feature-toggle
This commit is contained in:
@@ -1,44 +1,51 @@
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { createSharedComposable } from '@vueuse/core'
|
||||
|
||||
import rfdc from 'rfdc'
|
||||
|
||||
const deepClone = rfdc()
|
||||
const FEATURES = [
|
||||
{
|
||||
id: 'infinite_scrolling',
|
||||
title: 'Infinite scrolling',
|
||||
description: 'Effortlessly browse large datasets with infinite scrolling.',
|
||||
enabled: true,
|
||||
version: 1,
|
||||
},
|
||||
{
|
||||
id: 'canvas_grid_view',
|
||||
title: 'Improved Grid View',
|
||||
description: 'High-performance grid view with enhanced scrolling and rendering capabilities.',
|
||||
enabled: !ncIsPlaywright(),
|
||||
version: 1,
|
||||
},
|
||||
{
|
||||
id: 'canvas_group_grid_view',
|
||||
title: 'Improved Group By',
|
||||
description: 'New and Improved groupby in grid view with enhanced scrolling and rendering capabilities.',
|
||||
enabled: !ncIsPlaywright(),
|
||||
version: 1,
|
||||
},
|
||||
{
|
||||
id: 'improved_sidebar_ui',
|
||||
title: 'Improved Sidebar',
|
||||
description: 'New and Improved sidebar for better UI experience',
|
||||
enabled: !ncIsPlaywright(),
|
||||
isEngineering: false,
|
||||
version: 2,
|
||||
},
|
||||
{
|
||||
id: 'link_to_another_record',
|
||||
title: 'Link To Another Record',
|
||||
description: 'Show linked record display value in Link fields.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
},
|
||||
|
||||
{
|
||||
id: 'model_context_protocol',
|
||||
title: 'Model Context Protocol',
|
||||
description: 'Connect NocoDB base to Claude AI, Windsurf AI, and more.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
},
|
||||
{
|
||||
@@ -46,6 +53,7 @@ const FEATURES = [
|
||||
title: 'Payment Flows',
|
||||
description: 'Enable NocoDB Payment Flows.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
isEE: true,
|
||||
},
|
||||
@@ -54,6 +62,7 @@ const FEATURES = [
|
||||
title: 'AI features',
|
||||
description: 'Unlock AI features to enhance your NocoDB experience.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
isEE: true,
|
||||
},
|
||||
@@ -62,6 +71,7 @@ const FEATURES = [
|
||||
title: 'NocoDB Scripts (Beta)',
|
||||
description: 'Enable NocoDB Scripts to automate repetitive workflow',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
isEE: true,
|
||||
},
|
||||
@@ -70,6 +80,7 @@ const FEATURES = [
|
||||
title: 'Integrations',
|
||||
description: 'Enable dynamic integrations.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
},
|
||||
{
|
||||
@@ -77,6 +88,7 @@ const FEATURES = [
|
||||
title: 'Data reflection',
|
||||
description: 'Enable data reflection.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
isEE: true,
|
||||
},
|
||||
@@ -85,6 +97,7 @@ const FEATURES = [
|
||||
title: 'OSS to Enterprise migration',
|
||||
description: 'Enable import from NocoDB OSS instance to Enterprise Edition.',
|
||||
enabled: true,
|
||||
version: 1,
|
||||
isEE: true,
|
||||
},
|
||||
{
|
||||
@@ -92,6 +105,7 @@ const FEATURES = [
|
||||
title: 'Sync',
|
||||
description: 'Enable sync feature.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
isEE: true,
|
||||
},
|
||||
@@ -100,6 +114,7 @@ const FEATURES = [
|
||||
title: 'Geodata column',
|
||||
description: 'Enable the geodata column.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
},
|
||||
{
|
||||
@@ -107,6 +122,7 @@ const FEATURES = [
|
||||
title: 'Scanner for filling data in forms',
|
||||
description: 'Enable scanner to fill data in forms.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
},
|
||||
{
|
||||
@@ -114,6 +130,7 @@ const FEATURES = [
|
||||
title: 'Extensions',
|
||||
description: 'Extensions allows you to add new features or functionalities to the NocoDB platform.',
|
||||
enabled: ncIsPlaywright(),
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
},
|
||||
{
|
||||
@@ -121,6 +138,7 @@ const FEATURES = [
|
||||
title: 'Comments in attachment carousel',
|
||||
description: 'Enable comments in attachment carousel.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
},
|
||||
{
|
||||
@@ -128,6 +146,7 @@ const FEATURES = [
|
||||
title: 'Expanded form file preview mode',
|
||||
description: 'Preview mode allows you to see attachments inline',
|
||||
enabled: true,
|
||||
version: 2,
|
||||
isEE: true,
|
||||
},
|
||||
{
|
||||
@@ -135,6 +154,7 @@ const FEATURES = [
|
||||
title: 'Expanded form discussion mode',
|
||||
description: 'Discussion mode allows you to see the comments and records audits combined in one place',
|
||||
enabled: true,
|
||||
version: 2,
|
||||
isEE: true,
|
||||
},
|
||||
{
|
||||
@@ -142,6 +162,7 @@ const FEATURES = [
|
||||
title: 'Language',
|
||||
description: 'Community/AI Translated',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEngineering: true,
|
||||
isEE: true,
|
||||
},
|
||||
@@ -150,6 +171,7 @@ const FEATURES = [
|
||||
title: 'Cross Base Link',
|
||||
description: 'Enables link creation between tables in different bases.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEE: true,
|
||||
},
|
||||
{
|
||||
@@ -157,6 +179,7 @@ const FEATURES = [
|
||||
title: 'Custom Link',
|
||||
description: 'Allows user to create custom links using existing fields.',
|
||||
enabled: false,
|
||||
version: 1,
|
||||
isEE: true,
|
||||
},
|
||||
] as const
|
||||
@@ -172,7 +195,7 @@ export type BetaFeatureType = (typeof FEATURES)[number]
|
||||
const STORAGE_KEY = 'featureToggleStates'
|
||||
|
||||
export const useBetaFeatureToggle = createSharedComposable(() => {
|
||||
const features = ref<BetaFeatureType[]>(structuredClone(FEATURES))
|
||||
const features = ref<BetaFeatureType[]>(deepClone(FEATURES))
|
||||
|
||||
const featureStates = computed(() => {
|
||||
return features.value.reduce((acc, feature) => {
|
||||
@@ -187,7 +210,13 @@ export const useBetaFeatureToggle = createSharedComposable(() => {
|
||||
|
||||
const saveFeatures = () => {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(features.value))
|
||||
const featuresToSave = features.value.map((feature) => ({
|
||||
id: feature.id,
|
||||
enabled: feature.enabled,
|
||||
version: feature.version,
|
||||
}))
|
||||
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(featuresToSave))
|
||||
window.dispatchEvent(new StorageEvent('storage', { key: STORAGE_KEY }))
|
||||
} catch (error) {
|
||||
console.error('Failed to save features:', error)
|
||||
@@ -217,15 +246,41 @@ export const useBetaFeatureToggle = createSharedComposable(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem(STORAGE_KEY)
|
||||
if (stored) {
|
||||
const parsedFeatures = JSON.parse(stored) as Partial<BetaFeatureType>[]
|
||||
features.value = FEATURES.map((defaultFeature) => ({
|
||||
...defaultFeature,
|
||||
enabled: parsedFeatures.find((f) => f.id === defaultFeature.id)?.enabled ?? defaultFeature.enabled,
|
||||
}))
|
||||
const parsedFeatures = JSON.parse(stored) as Array<{
|
||||
id: string
|
||||
enabled: boolean
|
||||
version?: number
|
||||
}>
|
||||
|
||||
features.value = FEATURES.map((defaultFeature) => {
|
||||
const storedFeature = parsedFeatures.find((f) => f.id === defaultFeature.id)
|
||||
|
||||
if (!storedFeature) {
|
||||
return { ...defaultFeature }
|
||||
}
|
||||
|
||||
const storedVersion = storedFeature.version || 1
|
||||
const currentVersion = defaultFeature.version || 1
|
||||
|
||||
if (storedVersion < currentVersion) {
|
||||
console.log(`Feature ${defaultFeature.id} updated from v${storedVersion} to v${currentVersion}`)
|
||||
return {
|
||||
...defaultFeature,
|
||||
}
|
||||
}
|
||||
return {
|
||||
...defaultFeature,
|
||||
enabled: storedFeature.enabled,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
features.value = deepClone(FEATURES)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize features:', error)
|
||||
features.value = deepClone(FEATURES)
|
||||
}
|
||||
|
||||
saveFeatures()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user