Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, LitElement } from '@umbraco-cms/backoffice/external/lit';
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
import { UMB_WORKSPACE_VIEW_CONTEXT } from '@umbraco-cms/backoffice/workspace';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/document';

@customElement('example-hint-workspace-view')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import type { ManifestSectionView, UmbSectionViewElement } from '../extensions/index.js';
import type { ManifestSectionView } from '../extensions/index.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, nothing, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbRoute, UmbRouterSlotChangeEvent, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router';
import type { ManifestDashboard, UmbDashboardElement } from '@umbraco-cms/backoffice/dashboard';
import type { ManifestDashboard } from '@umbraco-cms/backoffice/dashboard';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UmbExtensionsManifestInitializer, createExtensionElement } from '@umbraco-cms/backoffice/extension-api';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { pathFolderName } from '@umbraco-cms/backoffice/utils';
import { UmbViewController } from '@umbraco-cms/backoffice/view';
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
import type { UmbVariantHint } from '@umbraco-cms/backoffice/hint';

@customElement('umb-section-main-views')
export class UmbSectionMainViewElement extends UmbLitElement {
Expand All @@ -31,6 +34,13 @@
@state()
private _routes: Array<UmbRoute> = [];

@state()
private _hintMap: Map<string, UmbVariantHint> = new Map();

#viewContexts = new Map<string, UmbViewController>();
#hintObservers: Array<UmbObserverController> = [];
#currentProvidedView?: UmbViewController;

constructor() {
super();

Expand All @@ -45,6 +55,46 @@
});
}

#getOrCreateViewContext(alias: string): UmbViewController {
let context = this.#viewContexts.get(alias);
if (!context) {
context = new UmbViewController(this, alias);
context.inherit();
Comment thread
nielslyngsoe marked this conversation as resolved.
this.#viewContexts.set(alias, context);
}
return context;
}

#cleanupViewContexts(viewAliases: Set<string>) {
// Remove contexts that are no longer needed
for (const [alias, context] of this.#viewContexts) {
if (!viewAliases.has(alias)) {
context.destroy();
this.#viewContexts.delete(alias);
}
}
this.#observeHints();
}

#observeHints() {
this.#hintObservers.forEach((observer) => observer.destroy());
this._hintMap = new Map();
this.#hintObservers = [...this.#viewContexts.entries()].map(([alias, context], index) =>
this.observe(
context.hints.firstHint,
(hint) => {
if (hint) {
this._hintMap.set(alias, hint);
} else {
this._hintMap.delete(alias);
}
this.requestUpdate('_hintMap');
},
'umbObserveHint_' + index,
),
);
Comment thread
nielslyngsoe marked this conversation as resolved.
}

#constructDashboardPath(manifest: ManifestDashboard) {
const dashboardName = manifest.meta.label ?? manifest.name ?? manifest.alias;
return 'dashboard/' + (manifest.meta.pathname ? manifest.meta.pathname : pathFolderName(dashboardName));
Expand All @@ -55,27 +105,55 @@
return 'view/' + (manifest.meta.pathname ? manifest.meta.pathname : pathFolderName(viewName));
}

#getViewName(view: ManifestSectionView) {
return view.meta?.label ? this.localize.string(view.meta.label) : (view.name ?? view.alias);
}

async #createRoutes() {
const viewAliases = new Set<string>();

const dashboardRoutes = this._dashboards?.map((manifest) => {
viewAliases.add(manifest.alias);
const context = this.#getOrCreateViewContext(manifest.alias);
context.setTitle(this.#getDashboardName(manifest));
return {
path: this.#constructDashboardPath(manifest),
component: () => createExtensionElement(manifest),
setup: (component: UmbDashboardElement) => {
component.manifest = manifest;
setup: (component?: any) => {
if (this.#currentProvidedView !== context) {
this.#currentProvidedView?.unprovide();
}
if (component) {
this.#currentProvidedView = context;
context.provideAt(component);
component.manifest = manifest;
}
},
} as UmbRoute;
});

const viewRoutes = this._views?.map((manifest) => {
viewAliases.add(manifest.alias);
const context = this.#getOrCreateViewContext(manifest.alias);
context.setTitle(this.#getViewName(manifest));
return {
path: this.#constructViewPath(manifest),
component: () => createExtensionElement(manifest),
setup: (component: UmbSectionViewElement) => {
component.manifest = manifest;
setup: async (component?: any) => {
if (this.#currentProvidedView !== context) {
this.#currentProvidedView?.unprovide();
}
if (component) {
this.#currentProvidedView = context;
context.provideAt(component);
component.manifest = manifest;
}
},
} as UmbRoute;
});

this.#cleanupViewContexts(viewAliases);

Check warning on line 156 in src/Umbraco.Web.UI.Client/src/packages/core/section/section-main-views/section-main-views.element.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ New issue: Complex Method

UmbSectionMainViewElement.createRoutes has a cyclomatic complexity of 10, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
const routes = [...dashboardRoutes, ...viewRoutes];
if (routes.length > 0) {
this._defaultView = routes[0].path;
Expand Down Expand Up @@ -122,16 +200,23 @@
<uui-tab-group slot="header" id="dashboards">
${this._dashboards.map((dashboard) => {
const dashboardPath = this.#constructDashboardPath(dashboard);
const dashboardName = this.#getDashboardName(dashboard);
const hint = this._hintMap.get(dashboard.alias);
// If this path matches, or if this is the default view and the active path is empty.
const isActive =
this._activePath === dashboardPath || (this._defaultView === dashboardPath && this._activePath === '');
return html`
<uui-tab
href="${this._routerPath}/${dashboardPath}"
label="${this.#getDashboardName(dashboard)}"
?active="${isActive}"
>${this.#getDashboardName(dashboard)}</uui-tab
>
<uui-tab href="${this._routerPath}/${dashboardPath}" label=${dashboardName} ?active="${isActive}">
${dashboardName}
${hint /*&& !isActive*/
Comment thread
nielslyngsoe marked this conversation as resolved.
Outdated
? html`<umb-badge
slot="extra"
.color=${hint.color ?? 'default'}
?attention=${hint.color === 'invalid'}
>${hint.text}</umb-badge
>`
: nothing}
Comment thread
nielslyngsoe marked this conversation as resolved.
</uui-tab>
`;
})}
</uui-tab-group>
Expand All @@ -145,14 +230,22 @@
? html`
<uui-tab-group slot="navigation" id="views">
${this._views.map((view) => {
const viewName = view.meta.label ? this.localize.string(view.meta.label) : (view.name ?? view.alias);
const viewName = this.#getViewName(view);
const viewPath = this.#constructViewPath(view);
const hint = this._hintMap.get(view.alias);
// If this path matches, or if this is the default view and the active path is empty.
const isActive =
this._activePath === viewPath || (this._defaultView === viewPath && this._activePath === '');
return html`
<uui-tab href="${this._routerPath}/${viewPath}" label="${viewName}" ?active="${isActive}">
<umb-icon slot="icon" name=${view.meta.icon}></umb-icon>
<div slot="icon">
<umb-icon name=${view.meta.icon}></umb-icon>
${hint && !isActive
? html`<umb-badge .color=${hint.color ?? 'default'} ?attention=${hint.color === 'invalid'}
>${hint.text}</umb-badge
>`
: nothing}
</div>
${viewName}
</uui-tab>
`;
Expand All @@ -179,6 +272,15 @@
#views uui-tab:first-child {
border-left: 1px solid var(--uui-color-divider-standalone);
}

div[slot='icon'] {
position: relative;
}

umb-badge {
top: var(--uui-size-2);
right: calc(var(--uui-size-2) * -1);
}
`,
];
}
Expand Down
Loading