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

Feature/dictionary update #890

Merged
merged 18 commits into from
Oct 5, 2023
Merged
50 changes: 27 additions & 23 deletions src/mocks/handlers/dictionary.handlers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const { rest } = window.MockServiceWorker;
import { umbDictionaryData } from '../data/dictionary.data.js';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
import {
ImportDictionaryRequestModel,
DictionaryOverviewResponseModel,
Expand Down Expand Up @@ -48,15 +49,15 @@ const overviewData: Array<DictionaryOverviewResponseModel> = [

// TODO: add schema
export const handlers = [
rest.get('/umbraco/management/api/v1/dictionary/:id', (req, res, ctx) => {
rest.get(umbracoPath('/dictionary/:id'), (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;

const dictionary = umbDictionaryData.getById(id);
return res(ctx.status(200), ctx.json(dictionary));
}),

rest.get('/umbraco/management/api/v1/dictionary', (req, res, ctx) => {
rest.get(umbracoPath('/dictionary'), (req, res, ctx) => {
const skip = req.url.searchParams.get('skip');
const take = req.url.searchParams.get('take');
if (!skip || !take) return;
Expand All @@ -74,25 +75,16 @@ export const handlers = [
return res(ctx.status(200), ctx.json(response));
}),

rest.post('/umbraco/management/api/v1/dictionary', async (req, res, ctx) => {
rest.post(umbracoPath('/dictionary'), async (req, res, ctx) => {
const data = await req.json();

if (!data) return;

data.icon = 'umb:book-alt';
data.hasChildren = false;
data.type = 'dictionary-item';
data.translations = [
{
isoCode: 'en-US',
translation: '',
},
{
isoCode: 'fr',
translation: '',
},
];

const value = umbDictionaryData.save(data.id, data);

const value = umbDictionaryData.insert(data);

const createdResult = {
value,
Expand All @@ -102,7 +94,7 @@ export const handlers = [
return res(ctx.status(200), ctx.json(createdResult));
}),

rest.patch('/umbraco/management/api/v1/dictionary/:id', async (req, res, ctx) => {
rest.patch(umbracoPath('/dictionary/:id'), async (req, res, ctx) => {
const data = await req.json();
if (!data) return;

Expand All @@ -115,7 +107,19 @@ export const handlers = [
return res(ctx.status(200), ctx.json(saved));
}),

rest.get('/umbraco/management/api/v1/tree/dictionary/root', (req, res, ctx) => {
rest.put(umbracoPath('/dictionary/:id'), async (req, res, ctx) => {
const data = await req.json();
if (!data) return;

const id = req.params.id as string;
if (!id) return;

const saved = umbDictionaryData.save(id, data);

return res(ctx.status(200), ctx.json(saved));
}),

rest.get(umbracoPath('/tree/dictionary/root'), (req, res, ctx) => {
const items = umbDictionaryData.getTreeRoot();
const response = {
total: items.length,
Expand All @@ -124,7 +128,7 @@ export const handlers = [
return res(ctx.status(200), ctx.json(response));
}),

rest.get('/umbraco/management/api/v1/tree/dictionary/children', (req, res, ctx) => {
rest.get(umbracoPath('/tree/dictionary/children'), (req, res, ctx) => {
const parentId = req.url.searchParams.get('parentId');
if (!parentId) return;

Expand All @@ -138,7 +142,7 @@ export const handlers = [
return res(ctx.status(200), ctx.json(response));
}),

rest.get('/umbraco/management/api/v1/tree/dictionary/item', (req, res, ctx) => {
rest.get(umbracoPath('/tree/dictionary/item'), (req, res, ctx) => {
const ids = req.url.searchParams.getAll('id');
if (!ids) return;

Expand All @@ -147,7 +151,7 @@ export const handlers = [
return res(ctx.status(200), ctx.json(items));
}),

rest.delete('/umbraco/management/api/v1/dictionary/:id', (req, res, ctx) => {
rest.delete(umbracoPath('/dictionary/:id'), (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;

Expand All @@ -157,7 +161,7 @@ export const handlers = [
}),

// TODO => handle properly, querystring breaks handler
rest.get('/umbraco/management/api/v1/dictionary/:id/export', (req, res, ctx) => {
rest.get(umbracoPath('/dictionary/:id/export'), (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;

Expand All @@ -170,13 +174,13 @@ export const handlers = [
return res(ctx.status(200));
}),

rest.post('/umbraco/management/api/v1/dictionary/upload', async (req, res, ctx) => {
rest.post(umbracoPath('/dictionary/upload'), async (req, res, ctx) => {
if (!req.arrayBuffer()) return;

return res(ctx.status(200), ctx.json(uploadResponse));
}),

rest.post('/umbraco/management/api/v1/dictionary/import', async (req, res, ctx) => {
rest.post(umbracoPath('/dictionary/import'), async (req, res, ctx) => {
const file = req.url.searchParams.get('file');

if (!file || !importResponse.id) return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import { UmbDictionaryRepository } from '../../dictionary/repository/dictionary.repository.js';
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, state, when } from '@umbraco-cms/backoffice/external/lit';
import { UmbTableConfig, UmbTableColumn, UmbTableItem } from '@umbraco-cms/backoffice/components';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { DictionaryOverviewResponseModel, LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api';
import {
UmbModalManagerContext,
UMB_MODAL_MANAGER_CONTEXT_TOKEN,
UMB_CREATE_DICTIONARY_MODAL,
} from '@umbraco-cms/backoffice/modal';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';

@customElement('umb-dashboard-translation-dictionary')
export class UmbDashboardTranslationDictionaryElement extends UmbLitElement {
Expand All @@ -25,8 +19,6 @@ export class UmbDashboardTranslationDictionaryElement extends UmbLitElement {

#repo!: UmbDictionaryRepository;

#modalContext!: UmbModalManagerContext;

#tableItems: Array<UmbTableItem> = [];

#tableColumns: Array<UmbTableColumn> = [];
Expand All @@ -35,10 +27,6 @@ export class UmbDashboardTranslationDictionaryElement extends UmbLitElement {

constructor() {
super();

new UmbContextConsumerController(this, UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => {
this.#modalContext = instance;
});
}

async connectedCallback() {
Expand Down Expand Up @@ -66,7 +54,7 @@ export class UmbDashboardTranslationDictionaryElement extends UmbLitElement {
#setTableColumns() {
this.#tableColumns = [
{
name: 'Name',
name: this.localize.term('general_name'),
alias: 'name',
},
];
Expand All @@ -92,7 +80,7 @@ export class UmbDashboardTranslationDictionaryElement extends UmbLitElement {
columnAlias: 'name',
value: html`<a
style="font-weight:bold"
href="/section/dictionary/workspace/dictionary-item/edit/${dictionary.id}">
href="section/dictionary/workspace/dictionary-item/edit/${dictionary.id}">
${dictionary.name}</a
> `,
},
Expand All @@ -107,11 +95,11 @@ export class UmbDashboardTranslationDictionaryElement extends UmbLitElement {
value: dictionary.translatedIsoCodes?.includes(l.isoCode)
? html`<uui-icon
name="check"
title="Translation exists for ${l.name}"
title="${this.localize.term('visuallyHiddenTexts_hasTranslation')} (${l.name})"
style="color:var(--uui-color-positive-standalone);display:inline-block"></uui-icon>`
: html`<uui-icon
name="alert"
title="Translation does not exist for ${l.name}"
title="${this.localize.term('visuallyHiddenTexts_noTranslation')} (${l.name})"
style="color:var(--uui-color-danger-standalone);display:inline-block"></uui-icon>`,
});
});
Expand All @@ -123,41 +111,27 @@ export class UmbDashboardTranslationDictionaryElement extends UmbLitElement {
}

#filter(e: { target: HTMLInputElement }) {
this._tableItemsFiltered = e.target.value
? this.#tableItems.filter((t) => t.id.includes(e.target.value))
const searchValue = e.target.value.toLocaleLowerCase();
this._tableItemsFiltered = searchValue
? this.#tableItems.filter((t) => t.id.toLocaleLowerCase().includes(searchValue))
: this.#tableItems;
}

async #create() {
// TODO: what to do if modal service is not available?
if (!this.#modalContext) return;
if (!this.#repo) return;

const modalContext = this.#modalContext?.open(UMB_CREATE_DICTIONARY_MODAL, { parentId: null });

const { name, parentId } = await modalContext.onSubmit();
if (!name || parentId === undefined) return;

const { data: url } = await this.#repo.create({ name, parentId });

if (!url) return;
//TODO: Why do we need to extract the id like this?
const id = url.substring(url.lastIndexOf('/') + 1);

history.pushState({}, '', `/section/dictionary/workspace/dictionary-item/edit/${id}`);
}

render() {
return html`
<umb-body-layout header-transparent>
<div id="header" slot="header">
<uui-button type="button" look="outline" label="Create dictionary item" @click=${this.#create}
>Create dictionary item</uui-button
>
<uui-button
type="button"
look="outline"
label=${this.localize.term('dictionary_createNew')}
href="section/dictionary/workspace/dictionary-item/create/null">
${this.localize.term('dictionary_createNew')}
</uui-button>
<uui-input
@keyup="${this.#filter}"
placeholder="Type to filter..."
label="Type to filter dictionary"
placeholder=${this.localize.term('placeholders_filter')}
label=${this.localize.term('placeholders_filter')}
id="searchbar">
<div slot="prepend">
<uui-icon name="search" id="searchbar_icon"></uui-icon>
Expand All @@ -166,11 +140,12 @@ export class UmbDashboardTranslationDictionaryElement extends UmbLitElement {
</div>
${when(
this._tableItemsFiltered.length,
() => html` <umb-table
.config=${this._tableConfig}
.columns=${this.#tableColumns}
.items=${this._tableItemsFiltered}></umb-table>`,
() => html`<umb-empty-state>There were no dictionary items found.</umb-empty-state>`
() =>
html` <umb-table
.config=${this._tableConfig}
.columns=${this.#tableColumns}
.items=${this._tableItemsFiltered}></umb-table>`,
() => html`<umb-empty-state>${this.localize.term('emptyStates_emptyDictionaryTree')}</umb-empty-state>`,
)}
</umb-body-layout>
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export class UmbDictionaryDetailServerDataSource
// TODO => parentId will be a guid param once #13786 is merged and API regenerated
return await tryExecuteAndNotify(
this.#host,
DictionaryResource.postDictionaryImport({ requestBody: { temporaryFileId, parentId } })
DictionaryResource.postDictionaryImport({ requestBody: { temporaryFileId, parentId } }),
);
}

Expand All @@ -129,7 +129,7 @@ export class UmbDictionaryDetailServerDataSource
this.#host,
DictionaryResource.postDictionaryImport({
requestBody: formData,
})
}),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@ export class UmbDictionaryWorkspaceEditorElement extends UmbLitElement {
return html`
<umb-workspace-editor alias="Umb.Workspace.Dictionary">
<div id="header" slot="header">
<uui-button href="/section/dictionary/dashboard" label="Back to list" compact>
<uui-button href="section/dictionary/dashboard" label=${this.localize.term('general_backToOverview')} compact>
<uui-icon name="umb:arrow-left"></uui-icon>
</uui-button>
<uui-input .value=${this._name} @input="${this.#handleInput}" label="Dictionary name"></uui-input>
<uui-input
.value=${this._name ?? ''}
@input="${this.#handleInput}"
label="${this.localize.term('general_dictionary')} ${this.localize.term('general_name')}"></uui-input>
</div>
</umb-workspace-editor>
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,27 @@ export class UmbDictionaryWorkspaceContext
async save() {
if (!this.#data.value) return;
if (!this.#data.value.id) return;
await this.repository.save(this.#data.value.id, this.#data.value);
this.setIsNew(false);

if (this.getIsNew()) {
await this.repository.create(this.#data.value);
this.setIsNew(false);
} else {
await this.repository.save(this.#data.value.id, this.#data.value);
}

const data = this.getData();
if (data) this.saveComplete(data);
}

public destroy(): void {
this.#data.complete();
}
}


export const UMB_DICTIONARY_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbDictionaryWorkspaceContext>(
export const UMB_DICTIONARY_WORKSPACE_CONTEXT = new UmbContextToken<
UmbSaveableWorkspaceContextInterface,
UmbDictionaryWorkspaceContext
>(
'UmbWorkspaceContext',
(context): context is UmbDictionaryWorkspaceContext => context.getEntityType?.() === 'dictionary-item'
(context): context is UmbDictionaryWorkspaceContext => context.getEntityType?.() === 'dictionary-item',
);
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { UmbDictionaryWorkspaceContext } from './dictionary-workspace.context.js';
import { UmbDictionaryWorkspaceEditorElement } from './dictionary-workspace-editor.element.js';
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
Expand All @@ -20,6 +20,14 @@ export class UmbWorkspaceDictionaryElement extends UmbLitElement {
this.#workspaceContext.load(id);
},
},
{
path: 'create/:parentId',
component: () => this.#element,
setup: (_component, info) => {
const parentId = info.match.params.parentId === 'null' ? null : info.match.params.parentId;
this.#workspaceContext.create(parentId);
},
},
];

render() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { UMB_DICTIONARY_WORKSPACE_CONTEXT } from '../../dictionary-workspace.context.js';
import { UmbDictionaryRepository } from '../../../repository/dictionary.repository.js';
import { UUITextareaElement, UUITextareaEvent } from '@umbraco-cms/backoffice/external/uui';
import { css, html, customElement, state, repeat, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement, state, repeat, ifDefined, unsafeHTML } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
import { DictionaryItemResponseModel, LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api';
@customElement('umb-workspace-view-dictionary-editor')
Expand Down Expand Up @@ -62,12 +62,11 @@ export class UmbWorkspaceViewDictionaryEditorElement extends UmbLitElement {
render() {
return html`
<uui-box>
<p>Edit the different language versions for the dictionary item '<em>${this._dictionary?.name}</em>' below.</p>

${unsafeHTML(this.localize.term('dictionaryItem_description', this._dictionary?.name || 'unnamed'))}
loivsen marked this conversation as resolved.
Show resolved Hide resolved
${repeat(
this._languages,
(item) => item.isoCode,
(item) => this.#renderTranslation(item)
(item) => this.#renderTranslation(item),
)}
</uui-box>
`;
Expand Down
Loading