Skip to content

Commit 6cb70db

Browse files
committed
wip dashboard app picker
1 parent 9202803 commit 6cb70db

File tree

10 files changed

+245
-3
lines changed

10 files changed

+245
-3
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { UmbDashboardAppDetailModel } from './types.js';
2+
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
3+
import type { UmbCollectionFilterModel, UmbCollectionRepository } from '@umbraco-cms/backoffice/collection';
4+
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
5+
6+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
7+
export interface UmbDashboardAppCollectionFilterModel extends UmbCollectionFilterModel {}
8+
9+
export class UmbDashboardAppCollectionRepository extends UmbControllerBase implements UmbCollectionRepository {
10+
async requestCollection(args: UmbDashboardAppCollectionFilterModel) {
11+
let manifests: Array<UmbDashboardAppDetailModel> = umbExtensionsRegistry
12+
.getByType('dashboardApp')
13+
.map((manifest) => {
14+
return {
15+
unique: manifest.alias,
16+
entityType: manifest.type,
17+
name: manifest.meta.headline,
18+
};
19+
});
20+
21+
const skip = args.skip || 0;
22+
const take = args.take || 100;
23+
24+
if (args.filter) {
25+
const text = args.filter.toLowerCase();
26+
manifests = manifests.filter((x) => x.name.toLowerCase().includes(text));
27+
}
28+
29+
manifests.sort((a, b) => a.name.localeCompare(b.name));
30+
31+
const total = manifests.length;
32+
const items = manifests.slice(skip, skip + take);
33+
const data = { items, total };
34+
return { data };
35+
}
36+
}
37+
38+
export { UmbDashboardAppCollectionRepository as api };
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { manifests as pickerManifests } from './picker/manifests.js';
2+
3+
export const manifests: Array<UmbExtensionManifest> = [...pickerManifests];
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const manifests: Array<UmbExtensionManifest> = [
2+
{
3+
type: 'modal',
4+
alias: 'Umb.Modal.DashboardAppPicker',
5+
name: 'Umb Dashboard App Picker Modal',
6+
js: () => import('./picker-modal.element.js'),
7+
},
8+
];
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import type { UmbDashboardAppDetailModel } from '../types.js';
2+
import type { UmbDashboardAppPickerModalValue, UmbDashboardAppPickerModalData } from './picker-modal.token.js';
3+
import { UmbDashboardAppPickerContext } from './picker.context.js';
4+
import { html, customElement, state, repeat, nothing, type PropertyValues } from '@umbraco-cms/backoffice/external/lit';
5+
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
6+
7+
@customElement('umb-dashboard-app-picker-modal')
8+
export class UmbDashboardAppPickerModalElement extends UmbModalBaseElement<
9+
UmbDashboardAppPickerModalData,
10+
UmbDashboardAppPickerModalValue
11+
> {
12+
@state()
13+
private _items: Array<UmbDashboardAppDetailModel> = [];
14+
15+
@state()
16+
private _searchQuery: string | undefined;
17+
18+
#pickerContext = new UmbDashboardAppPickerContext(this);
19+
20+
constructor() {
21+
super();
22+
this.#observeSelection();
23+
}
24+
25+
override connectedCallback(): void {
26+
super.connectedCallback();
27+
this.#pickerContext.selection.setSelectable(true);
28+
this.#pickerContext.selection.setMultiple(this.data?.multiple ?? false);
29+
this.#pickerContext.selection.setSelection(this.value?.selection ?? []);
30+
31+
this.observe(this.#pickerContext.items, (options) => {
32+
this._items = options;
33+
});
34+
}
35+
36+
protected override firstUpdated(_changedProperties: PropertyValues): void {
37+
super.firstUpdated(_changedProperties);
38+
this.#pickerContext.loadData();
39+
}
40+
41+
#observeSelection() {
42+
this.observe(
43+
this.#pickerContext.selection.selection,
44+
(selection) => {
45+
this.updateValue({ selection });
46+
},
47+
'uopObserveSelection',
48+
);
49+
}
50+
override render() {
51+
return html`<umb-body-layout headline="Select item(s)">
52+
<uui-box>${this.#renderMenu()}</uui-box>
53+
${this.#renderActions()}
54+
</umb-body-layout> `;
55+
}
56+
57+
#renderMenu() {
58+
if (this._searchQuery) {
59+
return nothing;
60+
}
61+
62+
return html`
63+
${repeat(
64+
this._items,
65+
(item) => item.unique,
66+
(item) => html`
67+
<uui-menu-item
68+
label=${this.localize.string(item.name ?? '')}
69+
selectable
70+
@selected=${() => this.#pickerContext.selection.select(item.unique)}
71+
@deselected=${() => this.#pickerContext.selection.deselect(item.unique)}
72+
?selected=${this.value.selection.includes(item.unique)}>
73+
</uui-menu-item>
74+
`,
75+
)}
76+
`;
77+
}
78+
79+
#renderActions() {
80+
return html`
81+
<div slot="actions">
82+
<uui-button label="Close" @click=${this._rejectModal}></uui-button>
83+
<uui-button label="Submit" look="primary" color="positive" @click=${this._submitModal}></uui-button>
84+
</div>
85+
`;
86+
}
87+
}
88+
89+
export { UmbDashboardAppPickerModalElement as element };
90+
91+
declare global {
92+
interface HTMLElementTagNameMap {
93+
'uop-data-configuration-type-picker-modal': UmbDashboardAppPickerModalElement;
94+
}
95+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
2+
3+
export interface UmbDashboardAppPickerModalData {
4+
multiple?: boolean;
5+
}
6+
7+
export interface UmbDashboardAppPickerModalValue {
8+
selection: Array<string | null>;
9+
}
10+
11+
export const UMB_DASHBOARD_APP_PICKER_MODAL = new UmbModalToken<
12+
UmbDashboardAppPickerModalData,
13+
UmbDashboardAppPickerModalValue
14+
>('Umb.Modal.DashboardAppPicker', {
15+
modal: {
16+
type: 'sidebar',
17+
size: 'small',
18+
},
19+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
2+
import { UmbDashboardAppPickerContext } from './picker.context';
3+
4+
export const UMB_DASHBOARD_APP_PICKER_CONTEXT = new UmbContextToken<UmbDashboardAppPickerContext>(
5+
'Umb.Modal.DashboardAppPicker',
6+
);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { UmbDashboardAppDetailModel } from '../types.js';
2+
import { UmbDashboardAppCollectionRepository } from '../collection.repository.js';
3+
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
4+
import { UmbCollectionItemPickerContext } from '@umbraco-cms/backoffice/collection';
5+
6+
export class UmbDashboardAppPickerContext extends UmbCollectionItemPickerContext {
7+
public getUnique = (item: UmbDashboardAppDetailModel) => item.unique;
8+
9+
#items = new UmbArrayState<UmbDashboardAppDetailModel>([], (x) => x.unique);
10+
public items = this.#items.asObservable();
11+
12+
#take = 100;
13+
#collectionRepository = new UmbDashboardAppCollectionRepository(this);
14+
15+
async loadData() {
16+
const { data, error } = await this.#collectionRepository.requestCollection({
17+
take: this.#take,
18+
});
19+
20+
if (error) {
21+
this.#items.setValue([]);
22+
}
23+
24+
if (data) {
25+
this.#items.setValue(data.items);
26+
}
27+
}
28+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
2+
3+
export interface UmbDashboardAppDetailModel extends UmbEntityModel {
4+
name: string;
5+
}

src/Umbraco.Web.UI.Client/src/packages/core/dashboard/default/dashboard.element.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import type { ManifestDashboardApp } from '../dashboard-app.extension.js';
2+
import { UMB_DASHBOARD_APP_PICKER_MODAL } from '../app/picker/picker-modal.token.js';
3+
import type { UmbDashboardAppDetailModel } from '../app/types.js';
24
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
3-
import { css, html, customElement, nothing, ifDefined } from '@umbraco-cms/backoffice/external/lit';
5+
import { css, html, customElement, nothing, ifDefined, state, repeat } from '@umbraco-cms/backoffice/external/lit';
46
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
57
import type { UmbExtensionElementInitializer } from '@umbraco-cms/backoffice/extension-api';
8+
import { umbOpenModal } from '@umbraco-cms/backoffice/modal';
69

710
@customElement('umb-dashboard')
811
export class UmbDashboardElement extends UmbLitElement {
@@ -14,9 +17,44 @@ export class UmbDashboardElement extends UmbLitElement {
1417
['large', 'large'],
1518
]);
1619

20+
@state()
21+
_apps: Array<UmbDashboardAppDetailModel> = [];
22+
23+
// TODO: this is just a temp value. We need to look up the item data.
24+
@state()
25+
_appUniques: Array<string> = [];
26+
27+
constructor() {
28+
super();
29+
}
30+
31+
async #openAppPicker() {
32+
const value = await umbOpenModal(this, UMB_DASHBOARD_APP_PICKER_MODAL, {
33+
data: {
34+
multiple: true,
35+
},
36+
value: {
37+
selection: this._appUniques,
38+
},
39+
}).catch(() => undefined);
40+
41+
if (value) {
42+
//this._apps = value.selection;
43+
this._appUniques = value.selection.filter((item) => item !== null) as Array<string>;
44+
}
45+
}
46+
1747
override render() {
1848
return html`
1949
<section id="content">
50+
<uui-button look="placeholder" @click=${this.#openAppPicker}>Add</uui-button>
51+
${repeat(
52+
this._appUniques,
53+
(unique) => unique,
54+
(unique) => {
55+
return html`${unique}`;
56+
},
57+
)}
2058
<umb-extension-slot
2159
type="dashboardApp"
2260
.renderMethod=${this.#extensionSlotRenderMethod}
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import type { UmbExtensionManifestKind } from '../extension-registry/registry.js';
2-
import { manifests as defaultManifests } from './default/manifests.js';
2+
import { manifests as appManifests } from './app/manifests.js';
33
import { manifests as conditionManifests } from './conditions/manifests.js';
4+
import { manifests as defaultManifests } from './default/manifests.js';
45

56
export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [
6-
...defaultManifests,
7+
...appManifests,
78
...conditionManifests,
9+
...defaultManifests,
810
];

0 commit comments

Comments
 (0)