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

Addon API: Improve the updateStatus API #24007

Merged
merged 1 commit into from
Aug 31, 2023
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
23 changes: 20 additions & 3 deletions code/lib/manager-api/src/modules/stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,10 @@ export interface SubAPI {
* @param {StatusUpdate} update - An object containing the updated status information.
* @returns {Promise<void>} A promise that resolves when the status has been updated.
*/
experimental_updateStatus: (addonId: string, update: API_StatusUpdate) => Promise<void>;
experimental_updateStatus: (
addonId: string,
update: API_StatusUpdate | ((state: API_StatusState) => API_StatusUpdate)
) => Promise<void>;
/**
* Updates the filtering of the index.
*
Expand Down Expand Up @@ -581,13 +584,27 @@ export const init: ModuleFn<SubAPI, SubState> = ({
},

/* EXPERIMENTAL APIs */
experimental_updateStatus: async (id, update) => {
experimental_updateStatus: async (id, input) => {
const { status, internal_index: index } = store.getState();
const newStatus = { ...status };

const update = typeof input === 'function' ? input(status) : input;

if (Object.keys(update).length === 0) {
return;
}

Object.entries(update).forEach(([storyId, value]) => {
newStatus[storyId] = { ...(newStatus[storyId] || {}) };
newStatus[storyId][id] = value;
if (value === null) {
delete newStatus[storyId][id];
} else {
newStatus[storyId][id] = value;
}

if (Object.keys(newStatus[storyId]).length === 0) {
delete newStatus[storyId];
}
});

await store.setState({ status: newStatus }, { persistence: 'session' });
Expand Down
84 changes: 84 additions & 0 deletions code/lib/manager-api/src/tests/stories.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1273,6 +1273,90 @@ describe('stories API', () => {
}
`);
});
it('delete when value is null', async () => {
const moduleArgs = createMockModuleArgs({});
const { api } = initStories(moduleArgs as unknown as ModuleArgs);
const { store } = moduleArgs;

await api.setIndex({ v: 4, entries: mockEntries });

await expect(
api.experimental_updateStatus('a-addon-id', {
'a-story-id': {
status: 'pending',
title: 'an addon title',
description: 'an addon description',
},
'another-story-id': { status: 'success', title: 'a addon title', description: '' },
})
).resolves.not.toThrow();

// do a second update, this time with null
await expect(
api.experimental_updateStatus('a-addon-id', {
'a-story-id': null,
'another-story-id': { status: 'success', title: 'a addon title', description: '' },
})
).resolves.not.toThrow();

expect(store.getState().status).toMatchInlineSnapshot(`
Object {
"another-story-id": Object {
"a-addon-id": Object {
"description": "",
"status": "success",
"title": "a addon title",
},
},
}
`);
});
it('updates with a function', async () => {
const moduleArgs = createMockModuleArgs({});
const { api } = initStories(moduleArgs as unknown as ModuleArgs);
const { store } = moduleArgs;

await api.setIndex({ v: 4, entries: mockEntries });

// setup initial state
await expect(
api.experimental_updateStatus('a-addon-id', () => ({
'a-story-id': {
status: 'pending',
title: 'an addon title',
description: 'an addon description',
},
'another-story-id': { status: 'success', title: 'a addon title', description: '' },
}))
).resolves.not.toThrow();

// use existing state in function
await expect(
api.experimental_updateStatus('a-addon-id', (current) => {
return Object.fromEntries(
Object.entries(current).map(([k, v]) => [k, { ...v['a-addon-id'], status: 'success' }])
);
})
).resolves.not.toThrow();
expect(store.getState().status).toMatchInlineSnapshot(`
Object {
"a-story-id": Object {
"a-addon-id": Object {
"description": "an addon description",
"status": "success",
"title": "an addon title",
},
},
"another-story-id": Object {
"a-addon-id": Object {
"description": "",
"status": "success",
"title": "a addon title",
},
},
}
`);
});
});
describe('experimental_setFilter', () => {
it('is included in the initial state', async () => {
Expand Down
2 changes: 1 addition & 1 deletion code/lib/types/src/modules/api-stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,5 +186,5 @@ export type API_StatusState = Record<StoryId, Record<string, API_StatusObject>>;
export type API_StatusUpdate = Record<StoryId, API_StatusObject>;

export type API_FilterFunction = (
item: API_PreparedIndexEntry & { status: Record<string, API_StatusObject> }
item: API_PreparedIndexEntry & { status: Record<string, API_StatusObject | null> }
) => boolean;
Loading