Skip to content

Commit

Permalink
✨ feat(menu): show entities menu as sub menu
Browse files Browse the repository at this point in the history
  • Loading branch information
thrownullexception committed Oct 10, 2023
1 parent 5b44744 commit 7f85365
Show file tree
Hide file tree
Showing 24 changed files with 308 additions and 177 deletions.
5 changes: 4 additions & 1 deletion src/__tests__/_/forCodeCoverage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import { FOR_CODE_COV as $38 } from "shared/types/dashboard/types";
import { FOR_CODE_COV as $39 } from "shared/types/dashboard/base";
import { FOR_CODE_COV as $40 } from "frontend/design-system/layouts/types";
import { FOR_CODE_COV as $41 } from "frontend/design-system/components/Form/_types";
import { FOR_CODE_COV as $42 } from "backend/menu/types";

import { noop } from "shared/lib/noop";

noop(
Expand Down Expand Up @@ -80,7 +82,8 @@ noop(
$38,
$39,
$40,
$41
$41,
$42
);

describe("Code coverage ignores plain types file", () => {
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/api/_test-utils/_app-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { createConfigDomainPersistenceService } from "backend/lib/config-persist
const TEST_APP_CONFIG: Partial<Record<string, unknown>> = {
disabled_entities: ["disabled-entity-1", "disabled-entity-2"],
"entity_diction__base-model": {
singular: "Base Model",
plural: "Base Models",
singular: "Base Model Singular",
plural: "Base Model Plural",
},
system_settings: {
forceIntrospection: false,
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/api/config/[key]/[entity].spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ describe("/api/config/[key]/[entity]", () => {

expect(res._getStatusCode()).toBe(200);
expect(res._getJSONData()).toEqual({
singular: "Base Model",
plural: "Base Models",
singular: "Base Model Singular",
plural: "Base Model Plural",
});
});

Expand Down
118 changes: 105 additions & 13 deletions src/__tests__/api/menu/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import {
setupAppConfigTestData,
} from "__tests__/api/_test-utils";

describe.skip("/api/menu", () => {
describe("/api/menu", () => {
beforeAll(async () => {
await setupAllTestData(["schema", "app-config"]);
});

it("should list all entities not disabled", async () => {
it("should render the menu with non disabled menus", async () => {
const { req, res } = createAuthenticatedMocks({
method: "GET",
});
Expand All @@ -20,16 +20,63 @@ describe.skip("/api/menu", () => {
expect(res._getJSONData()).toMatchInlineSnapshot(`
[
{
"label": "base-model",
"value": "base-model",
"icon": "Home",
"link": "home",
"title": "Home",
"type": "system",
},
{
"label": "secondary-model",
"value": "secondary-model",
"children": [
{
"icon": "File",
"link": "base-model",
"title": "Base Model Plural",
"type": "entities",
},
{
"icon": "File",
"link": "secondary-model",
"title": "Secondary Model",
"type": "entities",
},
{
"icon": "File",
"link": "tests",
"title": "Tests",
"type": "entities",
},
],
"icon": "File",
"link": "home",
"title": "Entities",
"type": "system",
},
{
"label": "tests",
"value": "tests",
"icon": "Zap",
"link": "actions",
"title": "Actions",
"type": "system",
},
{
"children": [],
"icon": "Settings",
"link": "settings",
"title": "Settings",
"type": "system",
},
{
"children": [],
"icon": "Users",
"link": "users",
"title": "Users",
"type": "system",
},
{
"children": [],
"icon": "Shield",
"link": "roles",
"title": "Roles",
"type": "system",
},
]
`);
Expand All @@ -51,16 +98,61 @@ describe.skip("/api/menu", () => {
expect(res._getJSONData()).toMatchInlineSnapshot(`
[
{
"label": "secondary-model",
"value": "secondary-model",
"icon": "Home",
"link": "home",
"title": "Home",
"type": "system",
},
{
"children": [
{
"icon": "File",
"link": "secondary-model",
"title": "Secondary Model",
"type": "entities",
},
{
"icon": "File",
"link": "base-model",
"title": "Base Model Plural",
"type": "entities",
},
],
"icon": "File",
"link": "home",
"title": "Entities",
"type": "system",
},
{
"icon": "Zap",
"link": "actions",
"title": "Actions",
"type": "system",
},
{
"children": [],
"icon": "Settings",
"link": "settings",
"title": "Settings",
"type": "system",
},
{
"children": [],
"icon": "Users",
"link": "users",
"title": "Users",
"type": "system",
},
{
"label": "base-model",
"value": "base-model",
"children": [],
"icon": "Shield",
"link": "roles",
"title": "Roles",
"type": "system",
},
]
`);
});
});

// :test piService.filterPermitte
// TODO test isMenuItemAllowed
42 changes: 33 additions & 9 deletions src/backend/configuration/configuration.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,37 @@ export class ConfigurationApiService implements IApplicationService {
);
}

async showMultipleConfigForEntities<T>(
key: AppConfigurationKeys,
entities: string[]
): Promise<Record<string, T>> {
const allKeys = entities.map((entity) =>
this._appConfigPersistenceService.mergeKeyWithSecondaryKey(key, entity)
);

const values = await this._appConfigPersistenceService.getAllItemsIn(
allKeys
);

return Object.fromEntries(
entities.map((entity) => [
entity,
(values[
this._appConfigPersistenceService.mergeKeyWithSecondaryKey(
key,
entity
)
] as T) || (CONFIGURATION_KEYS[key].defaultValue as T),
])
);
}

async show<T>(key: AppConfigurationKeys, entity?: string): Promise<T> {
this.checkConfigKeyEntityRequirement(key, entity);
const value =
await this._appConfigPersistenceService.getItemWithMaybeSecondaryKey(
key,
entity
);

const value = await this._appConfigPersistenceService.getItem(
this._appConfigPersistenceService.mergeKeyWithSecondaryKey(key, entity)
);

if (value) {
return value as T;
Expand All @@ -58,10 +82,10 @@ export class ConfigurationApiService implements IApplicationService {
entity?: string
): Promise<void> {
this.checkConfigKeyEntityRequirement(key, entity);
await this._appConfigPersistenceService.upsertItemWithMaybeSecondaryKey(
key,
value,
entity

return await this._appConfigPersistenceService.upsertItem(
this._appConfigPersistenceService.mergeKeyWithSecondaryKey(key, entity),
value
);
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/backend/dashboard-widgets/dashboard-widgets.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,9 @@ return [actual[0], relative[0]];
return await this.generateDefaultDashboardWidgets(dashboardId);
}

const widgets =
(await this._dashboardWidgetsPersistenceService.getAllItemsIn(
widgetList
)) as IWidgetConfig[];
const widgets = Object.values(
await this._dashboardWidgetsPersistenceService.getAllItemsIn(widgetList)
);

return sortByListOrder(widgetList, widgets);
}
Expand Down
2 changes: 1 addition & 1 deletion src/backend/entities/entities.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export class EntitiesApiService implements IApplicationService {
).includes(entity);
}

async getAllEntities(): Promise<{ value: string; label: string }[]> {
async getAllEntities(): Promise<ILabelValue[]> {
return (await this._schemasApiService.getDBSchema()).map(({ name }) => ({
value: name,
label: name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ export abstract class AbstractConfigDataPersistenceService<T> {
this._configApiService = configApiService;
}

private mergeKeyWithSecondaryKey(key: string, secondaryKey: string) {
public mergeKeyWithSecondaryKey(key: string, secondaryKey: string) {
if (!secondaryKey) {
return key;
}
return `${key}__${secondaryKey}`;
}

Expand All @@ -30,17 +33,7 @@ export abstract class AbstractConfigDataPersistenceService<T> {
throw new NotFoundError(`${key} not found for '${this._configDomain}'`);
}

public async getItemWithMaybeSecondaryKey(
key: string,
secondaryKey?: string
): Promise<T | undefined> {
if (!secondaryKey) {
return await this.getItem(key);
}
return await this.getItem(this.mergeKeyWithSecondaryKey(key, secondaryKey));
}

public abstract getAllItemsIn(itemIds: string[]): Promise<T[]>;
public abstract getAllItemsIn(itemIds: string[]): Promise<Record<string, T>>;

public abstract getAllAsKeyValuePair(): Promise<Record<string, T>>;

Expand All @@ -60,20 +53,6 @@ export abstract class AbstractConfigDataPersistenceService<T> {
await this.persistItem(key, data);
}

public async upsertItemWithMaybeSecondaryKey(
key: string,
value: T,
secondaryKey?: string
): Promise<void> {
if (!secondaryKey) {
return await this.upsertItem(key, value);
}
return await this.upsertItem(
this.mergeKeyWithSecondaryKey(key, secondaryKey),
value
);
}

public abstract removeItem(key: string): Promise<void>;

public async resetState(keyField: keyof T, data: T[]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ export class DatabaseConfigDataPersistenceAdaptor<
.where("domain", "=", this._configDomain)
.from(CONFIG_TABLE_NAME);

return items.map(({ value }) => JSON.parse(value));
return Object.fromEntries(
items.map(({ key, value }) => [key, JSON.parse(value)])
);
}

async getItem(key: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ export class JsonFileConfigDataPersistenceAdaptor<
async getAllItemsIn(itemIds: string[]) {
const allIndexedItems = await this.getDomainData();

return itemIds.map((itemId) => allIndexedItems[itemId]);
return Object.fromEntries(
itemIds.map((itemId) => [itemId, allIndexedItems[itemId]])
);
}

async getItem(key: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ export class MemoryConfigDataPersistenceAdaptor<
this._configDomain
);

return itemIds.map((itemId) => allItems[itemId]);
return Object.fromEntries(
itemIds.map((itemId) => [itemId, allItems[itemId]])
);
}

async getItem(key: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ export class RedisConfigDataPersistenceAdaptor<
await this.getRedisInstance()
).hmGet(this.wrapWithConfigDomain(), itemIds);

return Object.values(allData).map((value) => JSON.parse(value));
return Object.fromEntries(
allData.map((value, index) => [itemIds[index], JSON.parse(value)])
);
}

async getItem(key: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ describe.each(PERSITENT_ADAPTORS)(
});

it("should getAllItemsIn", async () => {
expect(await adaptor.getAllItemsIn(["id-2", "id-3"])).toEqual([
{ age: 2, id: "id-2", name: "Second Item" },
{ age: 3, id: "id-3", name: "Third Item" },
]);
expect(await adaptor.getAllItemsIn(["id-2", "id-3"])).toEqual({
"id-2": { age: 2, id: "id-2", name: "Second Item" },
"id-3": { age: 3, id: "id-3", name: "Third Item" },
});
});
}
);
Loading

0 comments on commit 7f85365

Please sign in to comment.