Preserve legacy personal settings in scoped editors
Why: Plugin descriptors without an explicit scope remain personal-compatible in the backend, but the editor hid them. Evidence: Frontend tests (290), production build, and check-knip pass; focused regression was red before the fix and green after. Impact: Legacy plugin settings remain visible in user and project-personal editors while shared project and system editors stay scoped. Refs: Dev feature/rdm-settings-completion P1-P2
This commit is contained in:
@@ -17,7 +17,11 @@ function readableValue(value: unknown) {
|
||||
const text = String(value)
|
||||
return optionLabels[text] || text
|
||||
}
|
||||
export function scopedSchema(schema: SettingDesc[], scope: string) { return schema.filter(desc => String(desc.scope) === scope) }
|
||||
export function scopedSchema(schema: SettingDesc[], scope: string) {
|
||||
return schema.filter(desc => !desc.scope
|
||||
? scope === 'user' || scope === 'project-personal'
|
||||
: desc.scope === scope || (scope === 'project-personal' && desc.scope === 'user'))
|
||||
}
|
||||
export function settingInputAttrs(desc: SettingDesc): { type: 'text' | 'password'; autoComplete: string } {
|
||||
return desc.secret || desc.type === 'secret' ? { type: 'password', autoComplete: 'new-password' } : { type: 'text', autoComplete: 'off' }
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export function SettingsModal() {
|
||||
const [notice, setNotice] = useState('')
|
||||
const [busy, setBusy] = useState(false)
|
||||
const schema = settings ? scopedSchema(settings.schema, 'user') : []
|
||||
const personalSchema = projectSettings ? (projectSettings.personalSchema || []).filter(desc => ['user', 'project-personal'].includes(String(desc.scope))) : []
|
||||
const personalSchema = projectSettings ? scopedSchema(projectSettings.personalSchema || [], 'project-personal') : []
|
||||
const initial = settings ? scopedDraft(settings.user, schema) : {}
|
||||
const personalInitial = projectSettings ? scopedDraft(projectSettings.personalProject || {}, personalSchema) : {}
|
||||
const dirty = JSON.stringify(draft) !== JSON.stringify(initial) || JSON.stringify(personalDraft) !== JSON.stringify(personalInitial)
|
||||
@@ -41,7 +41,7 @@ export function SettingsModal() {
|
||||
if (projectId) {
|
||||
const out = await api.getSettings(projectId)
|
||||
if (!current()) return false
|
||||
const personal = (out.personalSchema || []).filter(desc => ['user', 'project-personal'].includes(String(desc.scope)))
|
||||
const personal = scopedSchema(out.personalSchema || [], 'project-personal')
|
||||
setProjectSettings(out); setPersonalDraft(scopedDraft(out.personalProject || {}, personal))
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { SettingInput } from '../src/components/SettingsModal'
|
||||
import { scopedSchema } from '../src/components/SettingsFields'
|
||||
import { BorrowPanels } from '../src/components/BorrowPanels'
|
||||
import type { SettingDesc } from '../src/contracts'
|
||||
|
||||
@@ -10,6 +11,20 @@ const field = (type: SettingDesc['type'], options?: string[]): SettingDesc => ({
|
||||
})
|
||||
|
||||
describe('setting editors preserve types and readable values', () => {
|
||||
it('keeps legacy personal plugin settings visible only in personal scopes', () => {
|
||||
const schema: SettingDesc[] = [
|
||||
{ ...field('string'), key: 'plugin.legacy', scope: undefined },
|
||||
{ ...field('string'), key: 'plugin.user', scope: 'user' },
|
||||
{ ...field('string'), key: 'plugin.project-personal', scope: 'project-personal' },
|
||||
{ ...field('string'), key: 'plugin.project', scope: 'project' },
|
||||
{ ...field('string'), key: 'plugin.system', scope: 'system' },
|
||||
]
|
||||
const keys = (scope: string) => scopedSchema(schema, scope).map(desc => desc.key)
|
||||
expect(keys('user')).toEqual(['plugin.legacy', 'plugin.user'])
|
||||
expect(keys('project-personal')).toEqual(['plugin.legacy', 'plugin.user', 'plugin.project-personal'])
|
||||
expect(keys('project')).toEqual(['plugin.project'])
|
||||
expect(keys('system')).toEqual(['plugin.system'])
|
||||
})
|
||||
it('uses a number input for numeric values rather than submitting arbitrary strings', () => {
|
||||
expect(renderToStaticMarkup(<SettingInput desc={field('number')} value={12} onChange={() => {}} />)).toContain('type="number"')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user