diff --git a/backend/src/web-server/controllers/history-query.controller.spec.ts b/backend/src/web-server/controllers/history-query.controller.spec.ts index e8c49fc472..9529e1c43a 100644 --- a/backend/src/web-server/controllers/history-query.controller.spec.ts +++ b/backend/src/web-server/controllers/history-query.controller.spec.ts @@ -934,20 +934,23 @@ describe('History query controller', () => { expect(ctx.ok).toHaveBeenCalled(); expect(ctx.body).toEqual('csv content'); - expect(csv.unparse).toHaveBeenCalledWith([ - { - name: 'name', - enabled: true, - settings_field: 'value' - }, - { - name: 'item2', - enabled: true, - settings_objectArray: '[]', - settings_objectSettings: '{}', - settings_objectValue: 1 - } - ]); + expect(csv.unparse).toHaveBeenCalledWith( + [ + { + name: 'name', + enabled: true, + settings_field: 'value' + }, + { + name: 'item2', + enabled: true, + settings_objectArray: '[]', + settings_objectSettings: '{}', + settings_objectValue: 1 + } + ], + { columns: ['name', 'enabled', 'settings_field', 'settings_objectSettings', 'settings_objectArray', 'settings_objectValue'] } + ); }); it('checkImportSouthItems() should check import of items in a csv file with new history', async () => { diff --git a/backend/src/web-server/controllers/history-query.controller.ts b/backend/src/web-server/controllers/history-query.controller.ts index fb4d9176c2..80c3980f7c 100644 --- a/backend/src/web-server/controllers/history-query.controller.ts +++ b/backend/src/web-server/controllers/history-query.controller.ts @@ -326,11 +326,14 @@ export default class HistoryQueryController extends AbstractController { } async exportSouthItems(ctx: KoaContext): Promise { + const columns: Set = new Set(['name', 'enabled']); + const southItems = ctx.app.repositoryService.historyQueryItemRepository.getHistoryItems(ctx.params.historyQueryId).map(item => { const flattenedItem: Record = { ...item }; for (const [itemSettingsKey, itemSettingsValue] of Object.entries(item.settings)) { + columns.add(`settings_${itemSettingsKey}`); if (typeof itemSettingsValue === 'object') { flattenedItem[`settings_${itemSettingsKey}`] = JSON.stringify(itemSettingsValue); } else { @@ -343,7 +346,7 @@ export default class HistoryQueryController extends AbstractController { delete flattenedItem.connectorId; return flattenedItem; }); - ctx.body = csv.unparse(southItems); + ctx.body = csv.unparse(southItems, { columns: Array.from(columns) }); ctx.set('Content-disposition', 'attachment; filename=items.csv'); ctx.set('Content-Type', 'application/force-download'); ctx.ok(); @@ -356,9 +359,6 @@ export default class HistoryQueryController extends AbstractController { } const file = ctx.request.file; - // if (file.mimetype !== 'text/csv') { - // return ctx.badRequest(); - // } const existingItems: Array = ctx.params.historyQueryId === 'create' @@ -388,7 +388,7 @@ export default class HistoryQueryController extends AbstractController { if (!manifestSettings) { throw new Error(`Settings "${settingsKey}" not accepted in manifest`); } - if (manifestSettings.type === 'OibArray' || manifestSettings.type === 'OibFormGroup') { + if ((manifestSettings.type === 'OibArray' || manifestSettings.type === 'OibFormGroup') && value) { item.settings[settingsKey] = JSON.parse(value as string); } else { item.settings[settingsKey] = value; diff --git a/backend/src/web-server/controllers/south-connector.controller.spec.ts b/backend/src/web-server/controllers/south-connector.controller.spec.ts index 5b09dce647..04642eb730 100644 --- a/backend/src/web-server/controllers/south-connector.controller.spec.ts +++ b/backend/src/web-server/controllers/south-connector.controller.spec.ts @@ -810,22 +810,35 @@ describe('South connector controller', () => { expect(ctx.ok).toHaveBeenCalled(); expect(ctx.body).toEqual('csv content'); - expect(csv.unparse).toHaveBeenCalledWith([ - { - name: 'name', - enabled: true, - scanMode: 'scanMode', - settings_regex: '.*' - }, + expect(csv.unparse).toHaveBeenCalledWith( + [ + { + name: 'name', + enabled: true, + scanMode: 'scanMode', + settings_regex: '.*' + }, + { + name: 'item2', + enabled: true, + scanMode: '', + settings_objectArray: '[]', + settings_objectSettings: '{}', + settings_objectValue: 1 + } + ], { - name: 'item2', - enabled: true, - scanMode: '', - settings_objectArray: '[]', - settings_objectSettings: '{}', - settings_objectValue: 1 + columns: [ + 'name', + 'enabled', + 'scanMode', + 'settings_regex', + 'settings_objectSettings', + 'settings_objectArray', + 'settings_objectValue' + ] } - ]); + ); }); it('checkImportSouthItems() should check import of items in a csv file with new south', async () => { diff --git a/backend/src/web-server/controllers/south-connector.controller.ts b/backend/src/web-server/controllers/south-connector.controller.ts index 75897918ed..d23aa7d121 100644 --- a/backend/src/web-server/controllers/south-connector.controller.ts +++ b/backend/src/web-server/controllers/south-connector.controller.ts @@ -267,12 +267,14 @@ export default class SouthConnectorController { async exportSouthItems(ctx: KoaContext): Promise { const scanModes = ctx.app.repositoryService.scanModeRepository.getScanModes(); + const columns: Set = new Set(['name', 'enabled', 'scanMode']); const southItems = ctx.app.repositoryService.southItemRepository.getSouthItems(ctx.params.southId).map(item => { const flattenedItem: Record = { ...item }; flattenedItem.scanMode = scanModes.find(scanMode => scanMode.id === flattenedItem.scanModeId)?.name ?? ''; for (const [itemSettingsKey, itemSettingsValue] of Object.entries(item.settings)) { + columns.add(`settings_${itemSettingsKey}`); if (typeof itemSettingsValue === 'object') { flattenedItem[`settings_${itemSettingsKey}`] = JSON.stringify(itemSettingsValue); } else { @@ -285,7 +287,7 @@ export default class SouthConnectorController { delete flattenedItem.connectorId; return flattenedItem; }); - ctx.body = csv.unparse(southItems); + ctx.body = csv.unparse(southItems, { columns: Array.from(columns) }); ctx.set('Content-disposition', 'attachment; filename=items.csv'); ctx.set('Content-Type', 'application/force-download'); ctx.ok(); @@ -305,9 +307,6 @@ export default class SouthConnectorController { return ctx.throw(400, 'Could not parse item ids to delete array'); } - // if (file.mimetype !== 'text/csv') { - // return ctx.badRequest('Bad type of file'); - // } const scanModes = ctx.app.repositoryService.scanModeRepository.getScanModes(); const existingItems: Array = @@ -340,7 +339,8 @@ export default class SouthConnectorController { if (!manifestSettings) { throw new Error(`Settings "${settingsKey}" not accepted in manifest`); } - if (manifestSettings.type === 'OibArray' || manifestSettings.type === 'OibFormGroup') { + + if ((manifestSettings.type === 'OibArray' || manifestSettings.type === 'OibFormGroup') && value) { item.settings[settingsKey] = JSON.parse(value as string); } else { item.settings[settingsKey] = value; diff --git a/backend/src/web-server/controllers/validators/joi.validator.ts b/backend/src/web-server/controllers/validators/joi.validator.ts index 801bc44151..082473f112 100644 --- a/backend/src/web-server/controllers/validators/joi.validator.ts +++ b/backend/src/web-server/controllers/validators/joi.validator.ts @@ -177,6 +177,7 @@ export default class JoiValidator { break; } }); + schema = this.handleConditionalDisplay(formControl, schema) as Joi.ObjectSchema; return { [formControl.key]: schema };