Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Update layout set list when adding a new subform #14254

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe('WebSocketSyncWrapper', () => {
const queryClientMock = createQueryClientMock();
const invalidator = SyncSuccessQueriesInvalidator.getInstance(queryClientMock, org, app);

invalidator.invalidateQueryByFileLocation = jest.fn();
invalidator.invalidateQueriesByFileLocation = jest.fn();
const mockOnWSMessageReceived = jest
.fn()
.mockImplementation((callback: Function) => callback(syncSuccessMock));
Expand All @@ -80,7 +80,7 @@ describe('WebSocketSyncWrapper', () => {

renderWebSocketSyncWrapper();
await waitFor(() => {
expect(invalidator.invalidateQueryByFileLocation).toHaveBeenCalledWith(
expect(invalidator.invalidateQueriesByFileLocation).toHaveBeenCalledWith(
syncSuccessMock.source.name,
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ export const WebSocketSyncWrapper = ({

const isSuccessMessage = 'source' in message;
if (isSuccessMessage) {
// Please extend the "fileNameCacheKeyMap" inside the "SyncSuccessQueriesInvalidator" class. Do not add query-client invalidation directly here.
invalidator.invalidateQueryByFileLocation(message.source.name);
// Please extend the "fileNameCacheKeysMap" inside the "SyncSuccessQueriesInvalidator" class. Do not add query-client invalidation directly here.
invalidator.invalidateQueriesByFileLocation(message.source.name);
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const useAddLayoutSetMutation = (org: string, app: string) => {
// when process-editor renders the tasks and 'adds' them on first mount, when they already exists.
if (isLayoutSets(layoutSets)) {
queryClient.setQueryData([QueryKey.LayoutSets, org, app], layoutSets);
queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSetsExtended, org, app] });
}
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const useDeleteLayoutSetMutation = (org: string, app: string) => {
deleteLayoutSet(org, app, layoutSetIdToUpdate),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSets, org, app] });
queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSetsExtended, org, app] });
queryClient.invalidateQueries({ queryKey: [QueryKey.AppMetadataModelIds, org, app] });
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const useUpdateLayoutSetIdMutation = (org: string, app: string) => {
}) => updateLayoutSetId(org, app, layoutSetIdToUpdate, newLayoutSetId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSets, org, app] });
queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSetsExtended, org, app] });
},
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('useUpdateProcessDataTypeMutation', () => {

await renderHook({ queryClient });

expect(invalidateQueriesSpy).toHaveBeenCalledTimes(2);
expect(invalidateQueriesSpy).toHaveBeenCalledTimes(3);
expect(invalidateQueriesSpy).toHaveBeenCalledWith({
queryKey: [QueryKey.AppMetadataModelIds, org, app],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const useUpdateProcessDataTypesMutation = (org: string, app: string) => {
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: [QueryKey.AppMetadataModelIds, org, app] });
await queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSets, org, app] });
await queryClient.invalidateQueries({ queryKey: [QueryKey.LayoutSetsExtended, org, app] });
},
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ describe('SyncSuccessQueriesInvalidator', () => {
jest.clearAllMocks();
});

it('should invalidate query cache only once when invalidateQueryByFileLocation is called', async () => {
it('should invalidate query cache only once when invalidateQueriesByFileLocation is called', async () => {
const queriesInvalidator = SyncSuccessQueriesInvalidator.getInstance(queryClientMock, org, app);

const fileName = 'applicationmetadata.json';
queriesInvalidator.invalidateQueryByFileLocation(fileName);
queriesInvalidator.invalidateQueryByFileLocation(fileName);
queriesInvalidator.invalidateQueriesByFileLocation(fileName);
queriesInvalidator.invalidateQueriesByFileLocation(fileName);
await waitFor(() =>
expect(queryClientMock.invalidateQueries).toHaveBeenCalledWith({
queryKey: [QueryKey.AppMetadata, org, app],
Expand All @@ -33,22 +33,22 @@ describe('SyncSuccessQueriesInvalidator', () => {
expect(queryClientMock.invalidateQueries).toHaveBeenCalledTimes(1);
});

it('should not invalidate query cache when invalidateQueryByFileLocation is called with an unknown file name', async () => {
it('should not invalidate query cache when invalidateQueriesByFileLocation is called with an unknown file name', async () => {
const queriesInvalidator = SyncSuccessQueriesInvalidator.getInstance(queryClientMock, org, app);

const fileName = 'unknown.json';
queriesInvalidator.invalidateQueryByFileLocation(fileName);
queriesInvalidator.invalidateQueriesByFileLocation(fileName);

await new Promise((resolve) => setTimeout(resolve, 501));
expect(queryClientMock.invalidateQueries).not.toHaveBeenCalled();
});

it('should invalidate query cache with layoutSetName identifier when invalidateQueryByFileLocation is called and layoutSetName has been set', async () => {
it('should invalidate query cache with layoutSetName identifier when invalidateQueriesByFileLocation is called and layoutSetName has been set', async () => {
const queriesInvalidator = SyncSuccessQueriesInvalidator.getInstance(queryClientMock, org, app);
queriesInvalidator.layoutSetName = selectedLayoutSet;

const fileName = 'Settings.json';
queriesInvalidator.invalidateQueryByFileLocation(fileName);
queriesInvalidator.invalidateQueriesByFileLocation(fileName);

await waitFor(() => {
expect(queryClientMock.invalidateQueries).toHaveBeenCalledWith({
Expand All @@ -58,12 +58,12 @@ describe('SyncSuccessQueriesInvalidator', () => {
expect(queryClientMock.invalidateQueries).toHaveBeenCalledTimes(1);
});

it('should invalidate layouts query cache with layoutSetName identifier when invalidateQueryByFileLocation is called and layoutSetName has been set', async () => {
it('should invalidate layouts query cache with layoutSetName identifier when invalidateQueriesByFileLocation is called and layoutSetName has been set', async () => {
const queriesInvalidator = SyncSuccessQueriesInvalidator.getInstance(queryClientMock, org, app);
queriesInvalidator.layoutSetName = selectedLayoutSet;

const folderName = 'layouts';
queriesInvalidator.invalidateQueryByFileLocation(folderName);
queriesInvalidator.invalidateQueriesByFileLocation(folderName);

await waitFor(() =>
expect(queryClientMock.invalidateQueries).toHaveBeenCalledWith({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@ export class SyncSuccessQueriesInvalidator extends Queue {
private _queryClient: QueryClient;

// Maps file names to their cache keys for invalidation upon sync success - can be extended to include more files
private readonly fileNameCacheKeyMap: Record<string, Array<QueryKey | string>> = {
'applicationmetadata.json': [QueryKey.AppMetadata, '[org]', '[app]'],
'layout-sets.json': [QueryKey.LayoutSets, '[org]', '[app]'],
'policy.xml': [QueryKey.AppPolicy, '[org]', '[app]'],
'Settings.json': [QueryKey.FormLayoutSettings, '[org]', '[app]', '[layoutSetName]'],
private readonly fileNameCacheKeysMap: Record<string, Array<Array<QueryKey | string>>> = {
JamalAlabdullah marked this conversation as resolved.
Show resolved Hide resolved
'applicationmetadata.json': [[QueryKey.AppMetadata, '[org]', '[app]']],
'layout-sets.json': [
[QueryKey.LayoutSets, '[org]', '[app]'],
[QueryKey.LayoutSetsExtended, '[org]', '[app]'],
],
'policy.xml': [[QueryKey.AppPolicy, '[org]', '[app]']],
'Settings.json': [[QueryKey.FormLayoutSettings, '[org]', '[app]', '[layoutSetName]']],
};

// Maps folder names to their cache keys for invalidation upon sync success - can be extended to include more folders
private readonly folderNameCacheKeyMap: Record<string, Array<QueryKey | string>> = {
layouts: [QueryKey.FormLayouts, '[org]', '[app]'],
private readonly folderNameCacheKeysMap: Record<string, Array<Array<QueryKey | string>>> = {
layouts: [[QueryKey.FormLayouts, '[org]', '[app]']],
};

public set layoutSetName(layoutSetName: string) {
Expand Down Expand Up @@ -67,32 +70,36 @@ export class SyncSuccessQueriesInvalidator extends Queue {
SyncSuccessQueriesInvalidator.instance = null;
}

public invalidateQueryByFileLocation(fileOrFolderName: string): void {
const cacheKey = this.getCacheKeyByFileLocation(fileOrFolderName);
if (!cacheKey) return;
public invalidateQueriesByFileLocation(fileOrFolderName: string): void {
const cacheKeys = this.getCacheKeysByFileLocation(fileOrFolderName);
if (!cacheKeys) return;

this.addTaskToQueue({
id: fileOrFolderName,
callback: () => {
this._queryClient.invalidateQueries({ queryKey: cacheKey });
cacheKeys.forEach((cacheKey) => {
this._queryClient.invalidateQueries({ queryKey: cacheKey });
});
},
});
}

private getCacheKeyByFileLocation(fileOrFolderName: string): string[] {
const cacheKey =
this.fileNameCacheKeyMap[fileOrFolderName] || this.folderNameCacheKeyMap[fileOrFolderName];
if (!cacheKey) return undefined;
private getCacheKeysByFileLocation(fileOrFolderName: string): Array<string[]> {
const cacheKeys =
this.fileNameCacheKeysMap[fileOrFolderName] || this.folderNameCacheKeysMap[fileOrFolderName];
if (!cacheKeys) return undefined;

return this.replaceCacheKeyPlaceholders(cacheKey);
return this.replaceCacheKeysPlaceholders(cacheKeys);
}

private replaceCacheKeyPlaceholders(cacheKey: string[]): string[] {
return cacheKey.map((key) =>
key
.replace('[org]', this._org)
.replace('[app]', this._app)
.replace('[layoutSetName]', this._layoutSetName),
private replaceCacheKeysPlaceholders(cacheKeys: Array<string[]>): Array<string[]> {
return cacheKeys.map((cacheKey) =>
cacheKey.map((key) =>
key
.replace('[org]', this._org)
.replace('[app]', this._app)
.replace('[layoutSetName]', this._layoutSetName),
),
);
}
}
Loading