V3 project migration (#1652)

* migrate settings

* migrate viewsettings

* migrate url preset

* migrate project data

* migrate custom fields

* migrate automations

* migrate rundown

* lint

* return custom field translation table

* check regex

* new url type

* refactor

* migrate old OSC subscriptions

* migrate old http subscriptions

* update comments

* migrate the whole db

* remove automation logging unlis there is an error

* return a new object

* refactor: copy currup is only used in one place

* make a copy of original migrated file

* refactor: ensure image flder is part of project service init

* add entrys to groups

* small cleanup

* just drop incorrect custom fields in the default data parser
This commit is contained in:
Alex Christoffer Rasmussen
2025-08-07 15:48:58 +02:00
committed by GitHub
parent 35347e8d63
commit 9ebb3decdb
12 changed files with 993 additions and 87 deletions
@@ -14,7 +14,7 @@ describe('parseCustomFields()', () => {
const errorEmitter = vi.fn();
// @ts-expect-error -- data is external, we check bad types
const customFields = {
1: { label: 'test', type: 'text', colour: 'red' }, // ok
test: { label: 'test', type: 'text', colour: 'red' }, // ok
2: { label: 'test', type: 'text' }, // duplicate label
3: { label: '', type: 'text' }, // missing colour
4: { type: 'text', colour: '' }, // missing label
@@ -88,9 +88,10 @@ describe('sanitiseCustomFields()', () => {
expect(sanitationResult).toStrictEqual(expectedCustomFields);
});
it('enforce name cohesion', () => {
it('drop incorrect name/key pairs', () => {
const customFields: CustomFields = {
test: { label: 'NewName', type: 'text', colour: 'red' },
NewName: { label: 'NewName', type: 'text', colour: 'red' },
willBeGone: { label: 'BadName', type: 'text', colour: 'red' },
};
const expectedCustomFields: CustomFields = {
NewName: { label: 'NewName', type: 'text', colour: 'red' },
@@ -23,40 +23,29 @@ export function parseCustomFields(data: Partial<DatabaseModel>, emitError?: Erro
export function sanitiseCustomFields(data: object): CustomFields {
const newCustomFields: CustomFields = {};
for (const [_originalKey, field] of Object.entries(data)) {
if (!isValidField(field)) {
continue;
for (const [key, field] of Object.entries(data)) {
if (isValidField(field, key)) {
newCustomFields[key] = {
type: field.type,
colour: field.colour,
label: field.label,
};
}
if (!checkRegex.isAlphanumericWithSpace(field.label)) {
continue;
}
// the key is always made from the label
const key = customFieldLabelToKey(field.label);
if (key in newCustomFields) {
continue;
}
newCustomFields[key] = {
type: field.type,
colour: field.colour,
label: field.label,
};
}
function isValidField(data: unknown): data is CustomField {
function isValidField(data: unknown, key: string): data is CustomField {
return (
typeof data === 'object' &&
data !== null &&
'label' in data &&
typeof data.label === 'string' &&
data.label !== '' &&
'colour' in data &&
typeof data.colour === 'string' &&
'type' in data &&
(data.type === 'text' || data.type === 'image')
(data.type === 'text' || data.type === 'image') &&
checkRegex.isAlphanumericWithSpace(data.label) &&
key === customFieldLabelToKey(data.label)
);
}