From 403560d58cecdbe261f704ccba1f9012c1328cb3 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 1 Feb 2024 08:25:35 +0100 Subject: [PATCH] setup mocks + request handlers for languages --- .../src/mocks/browser-handlers.ts | 2 +- .../src/mocks/data/data-type/data-type.db.ts | 14 +-- .../src/mocks/data/language/language.data.ts | 19 +++ .../src/mocks/data/language/language.db.ts | 48 ++++++++ .../src/mocks/data/languages.data.ts | 115 ------------------ .../mocks/data/utils/culture/culture-base.ts | 26 ++++ .../utils/culture/culture-detail.manager.ts | 46 +++++++ .../utils/culture/culture-item.manager.ts | 16 +++ .../src/mocks/handlers/language.handlers.ts | 78 ------------ .../handlers/language/detail.handlers.ts | 45 +++++++ .../src/mocks/handlers/language/index.ts | 4 + .../mocks/handlers/language/item.handlers.ts | 13 ++ .../src/mocks/handlers/language/slug.ts | 1 + 13 files changed, 226 insertions(+), 201 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/data/language/language.data.ts create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/data/language/language.db.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/mocks/data/languages.data.ts create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-base.ts create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-detail.manager.ts create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-item.manager.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/mocks/handlers/language.handlers.ts create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/handlers/language/detail.handlers.ts create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/handlers/language/index.ts create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/handlers/language/item.handlers.ts create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/handlers/language/slug.ts diff --git a/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts index a97dbf3b08..aebb7a35f1 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts @@ -8,7 +8,7 @@ import { handlers as documentTypeHandlers } from './handlers/document-type/index import { handlers as examineManagementHandlers } from './handlers/examine-management.handlers.js'; import { handlers as healthCheckHandlers } from './handlers/health-check.handlers.js'; import { handlers as installHandlers } from './handlers/install.handlers.js'; -import { handlers as languageHandlers } from './handlers/language.handlers.js'; +import { handlers as languageHandlers } from './handlers/language/index.js'; import { handlers as logViewerHandlers } from './handlers/log-viewer.handlers.js'; import { handlers as mediaHandlers } from './handlers/media/index.js'; import { handlers as mediaTypeHandlers } from './handlers/media-type/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.db.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.db.ts index 9a9170ce05..ba3613161d 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.db.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.db.ts @@ -16,16 +16,16 @@ import type { class UmbDataTypeMockDB extends UmbEntityMockDbBase { tree = new UmbMockEntityTreeManager(this, folderTreeItemMapper); - folder = new UmbMockEntityFolderManager(this, createMockDataTypeFolderMapper); - item = new UmbMockEntityItemManager(this, dataTypeItemMapper); - detail = new UmbMockEntityDetailManager(this, createMockDataTypeMapper, dataTypeDetailMapper); + folder = new UmbMockEntityFolderManager(this, createFolderMockMapper); + item = new UmbMockEntityItemManager(this, itemResponseMapper); + detail = new UmbMockEntityDetailManager(this, createDetailMockMapper, detailResponseMapper); constructor(data: Array) { super(data); } } -const createMockDataTypeFolderMapper = (request: CreateFolderRequestModel): UmbMockDataTypeModel => { +const createFolderMockMapper = (request: CreateFolderRequestModel): UmbMockDataTypeModel => { return { name: request.name, id: request.id ? request.id : UmbId.new(), @@ -37,7 +37,7 @@ const createMockDataTypeFolderMapper = (request: CreateFolderRequestModel): UmbM }; }; -const createMockDataTypeMapper = (request: CreateDataTypeRequestModel): UmbMockDataTypeModel => { +const createDetailMockMapper = (request: CreateDataTypeRequestModel): UmbMockDataTypeModel => { return { id: request.id ? request.id : UmbId.new(), parentId: request.parentId, @@ -50,7 +50,7 @@ const createMockDataTypeMapper = (request: CreateDataTypeRequestModel): UmbMockD }; }; -const dataTypeDetailMapper = (item: UmbMockDataTypeModel): DataTypeResponseModel => { +const detailResponseMapper = (item: UmbMockDataTypeModel): DataTypeResponseModel => { return { id: item.id, parentId: item.parentId, @@ -61,7 +61,7 @@ const dataTypeDetailMapper = (item: UmbMockDataTypeModel): DataTypeResponseModel }; }; -const dataTypeItemMapper = (item: UmbMockDataTypeModel): DataTypeItemResponseModel => { +const itemResponseMapper = (item: UmbMockDataTypeModel): DataTypeItemResponseModel => { return { id: item.id, name: item.name, diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/language/language.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/language/language.data.ts new file mode 100644 index 0000000000..0be6f521ac --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/language/language.data.ts @@ -0,0 +1,19 @@ +import type { LanguageItemResponseModel, LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api'; + +export type UmbMockLanguageModel = LanguageResponseModel & LanguageItemResponseModel; + +export const data: Array = [ + { + name: 'English', + isoCode: 'en', + isDefault: true, + isMandatory: true, + }, + { + name: 'Danish', + isoCode: 'da', + isDefault: false, + isMandatory: false, + fallbackIsoCode: 'en', + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/language/language.db.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/language/language.db.ts new file mode 100644 index 0000000000..07f3026c1f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/language/language.db.ts @@ -0,0 +1,48 @@ +import { UmbMockCultureItemManager } from '../utils/culture/culture-item.manager.js'; +import { UmbCultureMockDbBase } from '../utils/culture/culture-base.js'; +import { UmbMockCultureDetailManager } from '../utils/culture/culture-detail.manager.js'; +import type { UmbMockLanguageModel } from './language.data.js'; +import { data } from './language.data.js'; +import type { + CreateLanguageRequestModel, + LanguageItemResponseModel, + LanguageResponseModel, +} from '@umbraco-cms/backoffice/backend-api'; + +class UmbLanguageMockDB extends UmbCultureMockDbBase { + item = new UmbMockCultureItemManager(this, itemResponseMapper); + detail = new UmbMockCultureDetailManager(this, createDetailMockMapper, detailResponseMapper); + + constructor(data: Array) { + super(data); + } +} + +const createDetailMockMapper = (request: CreateLanguageRequestModel): UmbMockLanguageModel => { + return { + fallbackIsoCode: request.fallbackIsoCode, + isDefault: request.isDefault, + isMandatory: request.isMandatory, + isoCode: request.isoCode, + name: request.name, + }; +}; + +const detailResponseMapper = (item: UmbMockLanguageModel): LanguageResponseModel => { + return { + fallbackIsoCode: item.fallbackIsoCode, + isDefault: item.isDefault, + isMandatory: item.isMandatory, + isoCode: item.isoCode, + name: item.name, + }; +}; + +const itemResponseMapper = (item: UmbMockLanguageModel): LanguageItemResponseModel => { + return { + isoCode: item.isoCode, + name: item.name, + }; +}; + +export const umbLanguageMockDb = new UmbLanguageMockDB(data); diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/languages.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/languages.data.ts deleted file mode 100644 index c24f636a8a..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/languages.data.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { UmbMockDBBase } from './utils/mock-db-base.js'; -import type { LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api'; - -// Temp mocked database -class UmbLanguagesData extends UmbMockDBBase { - constructor(data: LanguageResponseModel[]) { - super(data); - } - - // skip can be number or null - getAll(skip = 0, take = this.data.length): Array { - return this.data.slice(skip, take); - } - - getByKey(isoCode: string) { - return this.data.find((item) => item.isoCode === isoCode); - } - - getItems(isoCodes: Array) { - return this.data.filter((item) => isoCodes.indexOf(item.isoCode || '') !== -1); - } - - insert(language: LanguageResponseModel) { - const foundIndex = this.data.findIndex((item) => item.isoCode === language.isoCode); - - if (foundIndex !== -1) { - throw new Error('Language with same iso code already exists'); - } - - this.data.push(language); - } - - // TODO: this should and can only take a single save item. - save(isoCode: string, saveItems: Array) { - saveItems.forEach((saveItem) => { - const foundIndex = this.data.findIndex((item) => item.isoCode === isoCode); - if (foundIndex !== -1) { - // update - this.data[foundIndex] = saveItem; - this.updateData(saveItem); - } else { - // Set all other languages to not default - if (saveItem.isDefault) { - this.data.forEach((item) => { - if (saveItem !== item) { - item.isDefault = false; - } - }); - } - this.data.push(saveItem); - } - }); - - return this.data; - } - - delete(isoCodes: Array) { - isoCodes.forEach((isoCode) => { - const foundIndex = this.data.findIndex((item) => item.isoCode === isoCode); - if (foundIndex !== -1) { - this.data.splice(foundIndex, 1); - } - }); - - return isoCodes; - } - - updateData(updateItem: LanguageResponseModel) { - const itemIndex = this.data.findIndex((item) => item.isoCode === updateItem.isoCode); - const item = this.data[itemIndex]; - if (!item) return; - - const itemKeys = Object.keys(item); - const newItem = {}; - - // Set all other languages to not default - if (updateItem.isDefault) { - this.data.forEach((item) => { - if (updateItem !== item) { - item.isDefault = false; - } - }); - } - - for (const [key] of Object.entries(updateItem)) { - if (itemKeys.indexOf(key) !== -1) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - newItem[key] = updateItem[key]; - } - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - this.data[itemIndex] = newItem; - } -} - -export const MockData: Array = [ - { - name: 'English', - isoCode: 'en', - isDefault: true, - isMandatory: true, - }, - { - name: 'Danish', - isoCode: 'da', - isDefault: false, - isMandatory: false, - fallbackIsoCode: 'en', - }, -]; - -export const umbLanguagesData = new UmbLanguagesData(MockData); diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-base.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-base.ts new file mode 100644 index 0000000000..0a684f0124 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-base.ts @@ -0,0 +1,26 @@ +import { UmbMockDBBase } from '../mock-db-base.js'; + +export abstract class UmbCultureMockDbBase< + MockItemType extends { isoCode: string }, +> extends UmbMockDBBase { + constructor(data: Array) { + super(data); + } + + create(item: MockItemType) { + this.data.push(item); + } + + read(isoCode: string) { + return this.data.find((item) => item.isoCode === isoCode); + } + + update(isoCode: string, updatedItem: MockItemType) { + const itemIndex = this.data.findIndex((item) => item.isoCode === isoCode); + this.data[itemIndex] = updatedItem; + } + + delete(isoCode: string) { + this.data = this.data.filter((item) => item.isoCode !== isoCode); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-detail.manager.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-detail.manager.ts new file mode 100644 index 0000000000..8f08651454 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-detail.manager.ts @@ -0,0 +1,46 @@ +import type { UmbCultureMockDbBase } from './culture-base.js'; + +export class UmbMockCultureDetailManager { + #db: UmbCultureMockDbBase; + #createMockItemMapper: (request: any) => MockType; + #readResponseMapper: (mockItem: MockType) => any; + + constructor( + db: UmbCultureMockDbBase, + createMockItemMapper: (request: any) => MockType, + readResponseMapper: (mockItem: MockType) => any, + ) { + this.#db = db; + this.#createMockItemMapper = createMockItemMapper; + this.#readResponseMapper = readResponseMapper; + } + + create(request: any) { + const mockItem = this.#createMockItemMapper(request); + // create mock item in mock db + this.#db.create(mockItem); + return mockItem.isoCode; + } + + read(id: string) { + const item = this.#db.read(id); + if (!item) throw new Error('Item not found'); + const mappedItem = this.#readResponseMapper(item); + return mappedItem; + } + + update(isoCode: string, item: any) { + const mockItem = this.#db.read(isoCode); + + const updatedMockItem = { + ...mockItem, + ...item, + } as unknown as MockType; + + this.#db.update(isoCode, updatedMockItem); + } + + delete(isoCode: string) { + this.#db.delete(isoCode); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-item.manager.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-item.manager.ts new file mode 100644 index 0000000000..640ce1348d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/utils/culture/culture-item.manager.ts @@ -0,0 +1,16 @@ +import type { UmbMockDBBase } from '../mock-db-base.js'; + +export class UmbMockCultureItemManager { + #db: UmbMockDBBase; + #itemReadMapper: (item: T) => any; + + constructor(db: UmbMockDBBase, itemReadMapper: (item: T) => any) { + this.#db = db; + this.#itemReadMapper = itemReadMapper; + } + + getItems(isoCodes: Array) { + const items = this.#db.getAll().filter((item) => isoCodes.includes(item.isoCode)); + return items.map((item) => this.#itemReadMapper(item)); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/language.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/language.handlers.ts deleted file mode 100644 index 61101d41de..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/language.handlers.ts +++ /dev/null @@ -1,78 +0,0 @@ -const { rest } = window.MockServiceWorker; -import { umbLanguagesData } from '../data/languages.data.js'; -import type { LanguageResponseModel, ProblemDetails } from '@umbraco-cms/backoffice/backend-api'; -import { umbracoPath } from '@umbraco-cms/backoffice/utils'; - -// TODO: add schema -export const handlers = [ - rest.get(umbracoPath('/language/item'), (req, res, ctx) => { - const isoCodes = req.url.searchParams.getAll('isoCode'); - if (!isoCodes) return; - const items = umbLanguagesData.getItems(isoCodes); - return res(ctx.status(200), ctx.json(items)); - }), - - rest.get(umbracoPath('/language'), (req, res, ctx) => { - const skip = req.url.searchParams.get('skip'); - const skipNumber = skip ? Number.parseInt(skip) : undefined; - const take = req.url.searchParams.get('take'); - const takeNumber = take ? Number.parseInt(take) : undefined; - - const items = umbLanguagesData.getAll(skipNumber, takeNumber); - - const response = { - total: items.length, - items, - }; - - return res(ctx.status(200), ctx.json(response)); - }), - - rest.get(umbracoPath('/language/:id'), (req, res, ctx) => { - const id = req.params.id as string; - - if (!id) return; - - const item = umbLanguagesData.getByKey(id); - return res(ctx.status(200), ctx.json(item)); - }), - - rest.post(umbracoPath('/language'), async (req, res, ctx) => { - const data = await req.json(); - - if (!data) return; - - try { - umbLanguagesData.insert(data); - return res(ctx.status(201)); - } catch (error) { - return res( - ctx.status(400), - ctx.json({ - status: 400, - type: 'validation', - detail: 'Something went wrong', - errors: { - isoCode: ['Language with same iso code already exists'], - }, - }), - ); - } - }), - - rest.put(umbracoPath('/language/:id'), async (req, res, ctx) => { - const id = req.params.id as string; - if (!id) return; - const data = await req.json(); - - if (!data) return; - - umbLanguagesData.save(id, [data]); - - return res(ctx.status(200)); - }), - - rest.delete(umbracoPath('/language/:id'), async (req, res, ctx) => { - return res(ctx.status(200)); - }), -]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/detail.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/detail.handlers.ts new file mode 100644 index 0000000000..7d523064f2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/detail.handlers.ts @@ -0,0 +1,45 @@ +const { rest } = window.MockServiceWorker; +import { umbLanguageMockDb } from '../../data/language/language.db.js'; +import { UMB_SLUG } from './slug.js'; +import type { CreateLanguageRequestModel, UpdateLanguageRequestModel } from '@umbraco-cms/backoffice/backend-api'; +import { umbracoPath } from '@umbraco-cms/backoffice/utils'; + +export const detailHandlers = [ + rest.post(umbracoPath(`${UMB_SLUG}`), async (req, res, ctx) => { + const requestBody = (await req.json()) as CreateLanguageRequestModel; + if (!requestBody) return res(ctx.status(400, 'no body found')); + + const id = umbLanguageMockDb.detail.create(requestBody); + + return res( + ctx.status(201), + ctx.set({ + Location: req.url.href + '/' + id, + 'Umb-Generated-Resource': id, + }), + ); + }), + + rest.get(umbracoPath(`${UMB_SLUG}/:id`), (req, res, ctx) => { + const id = req.params.id as string; + if (!id) return res(ctx.status(400)); + const response = umbLanguageMockDb.detail.read(id); + return res(ctx.status(200), ctx.json(response)); + }), + + rest.put(umbracoPath(`${UMB_SLUG}/:id`), async (req, res, ctx) => { + const id = req.params.id as string; + if (!id) return res(ctx.status(400)); + const requestBody = (await req.json()) as UpdateLanguageRequestModel; + if (!requestBody) return res(ctx.status(400, 'no body found')); + umbLanguageMockDb.detail.update(id, requestBody); + return res(ctx.status(200)); + }), + + rest.delete(umbracoPath(`${UMB_SLUG}/:id`), (req, res, ctx) => { + const id = req.params.id as string; + if (!id) return res(ctx.status(400)); + umbLanguageMockDb.detail.delete(id); + return res(ctx.status(200)); + }), +]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/index.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/index.ts new file mode 100644 index 0000000000..8432caafdd --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/index.ts @@ -0,0 +1,4 @@ +import { detailHandlers } from './detail.handlers.js'; +import { itemHandlers } from './item.handlers.js'; + +export const handlers = [...itemHandlers, ...detailHandlers]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/item.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/item.handlers.ts new file mode 100644 index 0000000000..b196c2b8e6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/item.handlers.ts @@ -0,0 +1,13 @@ +const { rest } = window.MockServiceWorker; +import { umbLanguageMockDb } from '../../data/language/language.db.js'; +import { UMB_SLUG } from './slug.js'; +import { umbracoPath } from '@umbraco-cms/backoffice/utils'; + +export const itemHandlers = [ + rest.get(umbracoPath(`${UMB_SLUG}/item`), (req, res, ctx) => { + const isoCodes = req.url.searchParams.getAll('id'); + if (!isoCodes) return; + const items = umbLanguageMockDb.item.getItems(isoCodes); + return res(ctx.status(200), ctx.json(items)); + }), +]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/slug.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/slug.ts new file mode 100644 index 0000000000..e26b585ad7 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/language/slug.ts @@ -0,0 +1 @@ +export const UMB_SLUG = '/data-type';