mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
handles references mapping with new associations
This commit is contained in:
parent
2a85e4eab1
commit
2c38b85368
5 changed files with 138 additions and 69 deletions
|
|
@ -782,29 +782,17 @@ const EditorComponent = (props) => {
|
||||||
let dataQueries = JSON.parse(JSON.stringify(useDataQueriesStore.getState().dataQueries));
|
let dataQueries = JSON.parse(JSON.stringify(useDataQueriesStore.getState().dataQueries));
|
||||||
let allEvents = JSON.parse(JSON.stringify(useAppDataStore.getState().events));
|
let allEvents = JSON.parse(JSON.stringify(useAppDataStore.getState().events));
|
||||||
|
|
||||||
const entityReferencesInComponentDefinitions = findAllEntityReferences(currentComponents, [])
|
const entityReferencesInComponentDefinitions = findAllEntityReferences(currentComponents, [])?.filter(
|
||||||
?.map((entity) => {
|
(entity) => entity && isValidUUID(entity)
|
||||||
if (entity && isValidUUID(entity)) {
|
);
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
?.filter((e) => e !== undefined);
|
|
||||||
|
|
||||||
const entityReferencesInQueryoOptions = findAllEntityReferences(dataQueries, [])
|
const entityReferencesInQueryoOptions = findAllEntityReferences(dataQueries, [])?.filter(
|
||||||
?.map((entity) => {
|
(entity) => entity && isValidUUID(entity)
|
||||||
if (entity && isValidUUID(entity)) {
|
);
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
?.filter((e) => e !== undefined);
|
|
||||||
|
|
||||||
const entityReferencesInEvents = findAllEntityReferences(allEvents, [])
|
const entityReferencesInEvents = findAllEntityReferences(allEvents, [])?.filter(
|
||||||
?.map((entity) => {
|
(entity) => entity && isValidUUID(entity)
|
||||||
if (entity && isValidUUID(entity)) {
|
);
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
?.filter((e) => e !== undefined);
|
|
||||||
|
|
||||||
const manager = useResolveStore.getState().referenceMapper;
|
const manager = useResolveStore.getState().referenceMapper;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,29 +214,17 @@ class ViewerComponent extends React.Component {
|
||||||
let allDataQueries = this.state.dataQueries || [];
|
let allDataQueries = this.state.dataQueries || [];
|
||||||
let newComponentDefinition = JSON.parse(JSON.stringify(components));
|
let newComponentDefinition = JSON.parse(JSON.stringify(components));
|
||||||
|
|
||||||
const entityReferencesInComponentDefinitions = findAllEntityReferences(newComponentDefinition, [])
|
const entityReferencesInComponentDefinitions = findAllEntityReferences(newComponentDefinition, [])?.filter(
|
||||||
?.map((entity) => {
|
(entity) => entity && isValidUUID(entity)
|
||||||
if (entity && isValidUUID(entity)) {
|
);
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
?.filter((e) => e !== undefined);
|
|
||||||
|
|
||||||
const entityReferencesInQueryoOptions = findAllEntityReferences(allDataQueries, [])
|
const entityReferencesInQueryoOptions = findAllEntityReferences(allDataQueries, [])?.filter(
|
||||||
?.map((entity) => {
|
(entity) => entity && isValidUUID(entity)
|
||||||
if (entity && isValidUUID(entity)) {
|
);
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
?.filter((e) => e !== undefined);
|
|
||||||
|
|
||||||
const entityReferencesInEvents = findAllEntityReferences(allEvents, [])
|
const entityReferencesInEvents = findAllEntityReferences(allEvents, [])?.filter(
|
||||||
?.map((entity) => {
|
(entity) => entity && isValidUUID(entity)
|
||||||
if (entity && isValidUUID(entity)) {
|
);
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
?.filter((e) => e !== undefined);
|
|
||||||
|
|
||||||
const manager = useResolveStore.getState().referenceMapper;
|
const manager = useResolveStore.getState().referenceMapper;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,13 +111,9 @@ export const useAppDataStore = create(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const entityReferencesInEvents = findAllEntityReferences(updatedEvents, [])
|
const entityReferencesInEvents = findAllEntityReferences(updatedEvents, [])?.filter(
|
||||||
?.map((entity) => {
|
(entity) => entity && isValidUUID(entity)
|
||||||
if (entity && isValidUUID(entity)) {
|
);
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
?.filter((e) => e !== undefined);
|
|
||||||
const manager = useResolveStore.getState().referenceMapper;
|
const manager = useResolveStore.getState().referenceMapper;
|
||||||
let newEvents = JSON.parse(JSON.stringify(updatedEvents));
|
let newEvents = JSON.parse(JSON.stringify(updatedEvents));
|
||||||
|
|
||||||
|
|
|
||||||
53
server/src/helpers/import_export.helpers.ts
Normal file
53
server/src/helpers/import_export.helpers.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
export function updateEntityReferences(node, resourceMapping: Record<string, string> = {}) {
|
||||||
|
if (typeof node === 'object') {
|
||||||
|
for (const key in node) {
|
||||||
|
let value = node[key];
|
||||||
|
if (typeof value === 'string' && value.includes('{{') && value.includes('}}')) {
|
||||||
|
const referenceExists = value;
|
||||||
|
|
||||||
|
if (referenceExists) {
|
||||||
|
const ref = value.replace('{{', '').replace('}}', '');
|
||||||
|
|
||||||
|
const entityName = ref.split('.')[1];
|
||||||
|
|
||||||
|
if (resourceMapping[entityName]) {
|
||||||
|
const newValue = value.replace(entityName, resourceMapping[entityName]);
|
||||||
|
|
||||||
|
node[key] = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (typeof value === 'object') {
|
||||||
|
value = updateEntityReferences(value, resourceMapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findAllEntityReferences(node, allRefs): [] {
|
||||||
|
if (typeof node === 'object') {
|
||||||
|
for (const key in node) {
|
||||||
|
const value = node[key];
|
||||||
|
if (typeof value === 'string' && value.includes('{{') && value.includes('}}')) {
|
||||||
|
const referenceExists = value;
|
||||||
|
|
||||||
|
if (referenceExists) {
|
||||||
|
const ref = value.replace('{{', '').replace('}}', '');
|
||||||
|
|
||||||
|
const entityName = ref.split('.')[1];
|
||||||
|
|
||||||
|
allRefs.push(entityName);
|
||||||
|
}
|
||||||
|
} else if (typeof value === 'object') {
|
||||||
|
findAllEntityReferences(value, allRefs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allRefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isValidUUID(uuid) {
|
||||||
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
||||||
|
return uuidRegex.test(uuid);
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,7 @@ import { Component } from 'src/entities/component.entity';
|
||||||
import { Layout } from 'src/entities/layout.entity';
|
import { Layout } from 'src/entities/layout.entity';
|
||||||
import { EventHandler, Target } from 'src/entities/event_handler.entity';
|
import { EventHandler, Target } from 'src/entities/event_handler.entity';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import { findAllEntityReferences, isValidUUID, updateEntityReferences } from 'src/helpers/import_export.helpers';
|
||||||
|
|
||||||
interface AppResourceMappings {
|
interface AppResourceMappings {
|
||||||
defaultDataSourceIdMapping: Record<string, string>;
|
defaultDataSourceIdMapping: Record<string, string>;
|
||||||
|
|
@ -237,21 +238,20 @@ export class AppImportExportService {
|
||||||
? true
|
? true
|
||||||
: isTooljetVersionWithNormalizedAppDefinitionSchem(importedAppTooljetVersion);
|
: isTooljetVersionWithNormalizedAppDefinitionSchem(importedAppTooljetVersion);
|
||||||
|
|
||||||
const shouldUpdateForGridCompatibility = !cloning;
|
|
||||||
|
|
||||||
const importedApp = await this.createImportedAppForUser(this.entityManager, schemaUnifiedAppParams, user);
|
const importedApp = await this.createImportedAppForUser(this.entityManager, schemaUnifiedAppParams, user);
|
||||||
|
|
||||||
await this.setupImportedAppAssociations(
|
const resourceMapping = await this.setupImportedAppAssociations(
|
||||||
this.entityManager,
|
this.entityManager,
|
||||||
importedApp,
|
importedApp,
|
||||||
schemaUnifiedAppParams,
|
schemaUnifiedAppParams,
|
||||||
user,
|
user,
|
||||||
externalResourceMappings,
|
externalResourceMappings,
|
||||||
isNormalizedAppDefinitionSchema,
|
isNormalizedAppDefinitionSchema,
|
||||||
shouldUpdateForGridCompatibility,
|
|
||||||
tooljetVersion
|
tooljetVersion
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.createAdminGroupPermissions(this.entityManager, importedApp);
|
await this.createAdminGroupPermissions(this.entityManager, importedApp);
|
||||||
|
await this.updateEntityReferencesForImportedApp(this.entityManager, resourceMapping);
|
||||||
|
|
||||||
// NOTE: App slug updation callback doesn't work while wrapped in transaction
|
// NOTE: App slug updation callback doesn't work while wrapped in transaction
|
||||||
// hence updating slug explicitly
|
// hence updating slug explicitly
|
||||||
|
|
@ -262,6 +262,64 @@ export class AppImportExportService {
|
||||||
return importedApp;
|
return importedApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateEntityReferencesForImportedApp(manager: EntityManager, resourceMapping: AppResourceMappings) {
|
||||||
|
const mappings = { ...resourceMapping.componentsMapping, ...resourceMapping.dataQueryMapping };
|
||||||
|
const newComponentIds = Object.values(resourceMapping.componentsMapping);
|
||||||
|
const newQueriesIds = Object.values(resourceMapping.dataQueryMapping);
|
||||||
|
|
||||||
|
if (newComponentIds.length > 0) {
|
||||||
|
const components = await manager
|
||||||
|
.createQueryBuilder(Component, 'components')
|
||||||
|
.where('components.id IN(:...componentIds)', { componentIds: newComponentIds })
|
||||||
|
.select([
|
||||||
|
'components.id',
|
||||||
|
'components.properties',
|
||||||
|
'components.styles',
|
||||||
|
'components.general',
|
||||||
|
'components.validation',
|
||||||
|
'components.generalStyles',
|
||||||
|
'components.displayPreferences',
|
||||||
|
])
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
const toUpdateComponents = components.filter((component) => {
|
||||||
|
const entityReferencesInComponentDefinitions = findAllEntityReferences(component, []).filter(
|
||||||
|
(entity) => entity && isValidUUID(entity)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entityReferencesInComponentDefinitions.length > 0) {
|
||||||
|
return updateEntityReferences(component, mappings);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isEmpty(toUpdateComponents)) {
|
||||||
|
await manager.save(toUpdateComponents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newQueriesIds.length > 0) {
|
||||||
|
const dataQueries = await manager
|
||||||
|
.createQueryBuilder(DataQuery, 'dataQueries')
|
||||||
|
.where('dataQueries.id IN(:...dataQueryIds)', { dataQueryIds: newQueriesIds })
|
||||||
|
.select(['dataQueries.id', 'dataQueries.options'])
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
const toUpdateDataQueries = dataQueries.filter((dataQuery) => {
|
||||||
|
const entityReferencesInQueryOptions = findAllEntityReferences(dataQuery, []).filter(
|
||||||
|
(entity) => entity && isValidUUID(entity)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entityReferencesInQueryOptions.length > 0) {
|
||||||
|
return updateEntityReferences(dataQuery, mappings);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isEmpty(toUpdateDataQueries)) {
|
||||||
|
await manager.save(toUpdateDataQueries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async createImportedAppForUser(manager: EntityManager, appParams: any, user: User): Promise<App> {
|
async createImportedAppForUser(manager: EntityManager, appParams: any, user: User): Promise<App> {
|
||||||
return await catchDbException(async () => {
|
return await catchDbException(async () => {
|
||||||
const importedApp = manager.create(App, {
|
const importedApp = manager.create(App, {
|
||||||
|
|
@ -328,7 +386,6 @@ export class AppImportExportService {
|
||||||
user: User,
|
user: User,
|
||||||
externalResourceMappings: Record<string, unknown>,
|
externalResourceMappings: Record<string, unknown>,
|
||||||
isNormalizedAppDefinitionSchema: boolean,
|
isNormalizedAppDefinitionSchema: boolean,
|
||||||
shouldUpdateForGridCompatibility: boolean,
|
|
||||||
tooljetVersion: string
|
tooljetVersion: string
|
||||||
) {
|
) {
|
||||||
// Old version without app version
|
// Old version without app version
|
||||||
|
|
@ -393,7 +450,6 @@ export class AppImportExportService {
|
||||||
importingPages,
|
importingPages,
|
||||||
importingComponents,
|
importingComponents,
|
||||||
importingEvents,
|
importingEvents,
|
||||||
shouldUpdateForGridCompatibility,
|
|
||||||
tooljetVersion
|
tooljetVersion
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -599,7 +655,6 @@ export class AppImportExportService {
|
||||||
importingPages: Page[],
|
importingPages: Page[],
|
||||||
importingComponents: Component[],
|
importingComponents: Component[],
|
||||||
importingEvents: EventHandler[],
|
importingEvents: EventHandler[],
|
||||||
shouldUpdateForGridCompatibility: boolean,
|
|
||||||
tooljetVersion: string
|
tooljetVersion: string
|
||||||
): Promise<AppResourceMappings> {
|
): Promise<AppResourceMappings> {
|
||||||
appResourceMappings = { ...appResourceMappings };
|
appResourceMappings = { ...appResourceMappings };
|
||||||
|
|
@ -894,18 +949,6 @@ export class AppImportExportService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const appVersionIds = Object.values(appResourceMappings.appVersionMapping);
|
|
||||||
|
|
||||||
// for (const appVersionId of appVersionIds) {
|
|
||||||
// await this.updateEventActionsForNewVersionWithNewMappingIds(
|
|
||||||
// manager,
|
|
||||||
// appVersionId,
|
|
||||||
// appResourceMappings.dataQueryMapping,
|
|
||||||
// appResourceMappings.componentsMapping,
|
|
||||||
// appResourceMappings.pagesMapping
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
return appResourceMappings;
|
return appResourceMappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1656,9 +1699,10 @@ export class AppImportExportService {
|
||||||
.createQueryBuilder(EventHandler, 'event')
|
.createQueryBuilder(EventHandler, 'event')
|
||||||
.where('event.appVersionId = :versionId', { versionId })
|
.where('event.appVersionId = :versionId', { versionId })
|
||||||
.getMany();
|
.getMany();
|
||||||
|
const mappings = { ...oldDataQueryToNewMapping, ...oldComponentToNewComponentMapping } as Record<string, string>;
|
||||||
|
|
||||||
for (const event of allEvents) {
|
for (const event of allEvents) {
|
||||||
const eventDefinition = event.event;
|
const eventDefinition = updateEntityReferences(event.event, mappings);
|
||||||
|
|
||||||
if (eventDefinition?.actionId === 'run-query' && oldDataQueryToNewMapping[eventDefinition.queryId]) {
|
if (eventDefinition?.actionId === 'run-query' && oldDataQueryToNewMapping[eventDefinition.queryId]) {
|
||||||
eventDefinition.queryId = oldDataQueryToNewMapping[eventDefinition.queryId];
|
eventDefinition.queryId = oldDataQueryToNewMapping[eventDefinition.queryId];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue