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

Removes collection action state #18212

Merged
merged 11 commits into from
Feb 13, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export class UmbLocalizationController<LocalizationSetType extends UmbLocalizati
/**
* Gets the host element's directionality as determined by the `dir` attribute. The return value is transformed to
* lowercase.
* @returns {string} - the directionality.
*/
dir() {
return `${this.#hostEl?.dir || umbLocalizationManager.documentDirection}`.toLowerCase();
Expand All @@ -91,6 +92,7 @@ export class UmbLocalizationController<LocalizationSetType extends UmbLocalizati
/**
* Gets the host element's language as determined by the `lang` attribute. The return value is transformed to
* lowercase.
* @returns {string} - the language code.
*/
lang() {
return `${this.#hostEl?.lang || umbLocalizationManager.documentLanguage}`.toLowerCase();
Expand Down Expand Up @@ -158,8 +160,9 @@ export class UmbLocalizationController<LocalizationSetType extends UmbLocalizati

/**
* Outputs a localized date in the specified format.
* @param dateToFormat
* @param options
* @param {Date} dateToFormat - the date to format.
* @param {Intl.DateTimeFormatOptions} options - the options to use when formatting the date.
* @returns {string}
*/
date(dateToFormat: Date | string, options?: Intl.DateTimeFormatOptions): string {
dateToFormat = new Date(dateToFormat);
Expand All @@ -168,8 +171,9 @@ export class UmbLocalizationController<LocalizationSetType extends UmbLocalizati

/**
* Outputs a localized number in the specified format.
* @param numberToFormat
* @param options
* @param {number | string} numberToFormat - the number or string to format.
* @param {Intl.NumberFormatOptions} options - the options to use when formatting the number.
* @returns {string} - the formatted number.
*/
number(numberToFormat: number | string, options?: Intl.NumberFormatOptions): string {
numberToFormat = Number(numberToFormat);
Expand All @@ -178,14 +182,16 @@ export class UmbLocalizationController<LocalizationSetType extends UmbLocalizati

/**
* Outputs a localized time in relative format.
* @param value
* @param unit
* @param options
* @param {number} value - the value to format.
* @param {Intl.RelativeTimeFormatUnit} unit - the unit of time to format.
* @param {Intl.RelativeTimeFormatOptions} options - the options to use when formatting the time.
* @returns {string} - the formatted time.
*/
relativeTime(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string {
return new Intl.RelativeTimeFormat(this.lang(), options).format(value, unit);
}

// TODO: for V.16 we should set type to be string | undefined. [NL]
/**
* Translates a string containing one or more terms. The terms should be prefixed with a `#` character.
* If the term is found in the localization set, it will be replaced with the localized term.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';

export interface UmbCollectionAction extends UmbApi {
/**
* The href location, the action will act as a link.
* @returns {undefined | Promise<string | undefined>}
*/
getHref?: () => Promise<string | undefined>;

/**
* Determine if the UI should indicate that more options will appear when interacting with this.
* @returns {undefined | Promise<boolean | undefined>}
*/
hasAddionalOptions?: () => Promise<boolean | undefined>;

/**
* The `execute` method, the action will act as a button.
* @returns {Promise<void>}
*/
execute(): Promise<void>;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,79 +1,82 @@
import type { UmbCollectionAction } from './collection-action-base.js';
import { UmbActionExecutedEvent } from '@umbraco-cms/backoffice/event';
import { html, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import type { UUIButtonState } from '@umbraco-cms/backoffice/external/uui';
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
import type { ManifestCollectionAction } from '@umbraco-cms/backoffice/collection';
import { createExtensionApi } from '@umbraco-cms/backoffice/extension-api';

const manifest: UmbExtensionManifestKind = {
type: 'kind',
alias: 'Umb.Kind.CollectionAction.Button',
matchKind: 'button',
matchType: 'collectionAction',
manifest: {
type: 'collectionAction',
kind: 'button',
elementName: 'umb-collection-action-button',
},
};
umbExtensionsRegistry.register(manifest);
import type { UUIButtonState } from '@umbraco-cms/backoffice/external/uui';

@customElement('umb-collection-action-button')
export class UmbCollectionActionButtonElement extends UmbLitElement {
@state()
private _buttonState?: UUIButtonState;
#api?: UmbCollectionAction;

private _manifest?: ManifestCollectionAction;
@property({ type: Object, attribute: false })
public get manifest() {
return this._manifest;
}
public set manifest(value: ManifestCollectionAction | undefined) {
if (!value) return;
const oldValue = this._manifest;
this._manifest = value;
if (oldValue !== this._manifest) {
if (oldValue !== value) {
this._manifest = value;
this._href = this.manifest?.meta.href;
this._additionalOptions = this.manifest?.meta.additionalOptions;
this.#createApi();
this.requestUpdate('manifest', oldValue);
}
}
private _manifest?: ManifestCollectionAction;

async #createApi() {
if (!this._manifest) throw new Error('No manifest defined');
if (!this._manifest.api) return;
this.#api = (await createExtensionApi(this, this._manifest)) as unknown as UmbCollectionAction;
this.#api = await createExtensionApi<UmbCollectionAction>(this, this._manifest);

this._href = (await this.#api?.getHref?.()) ?? this.manifest?.meta.href;
this._additionalOptions = (await this.#api?.hasAddionalOptions?.()) ?? this.manifest?.meta.additionalOptions;

Check warning on line 35 in src/Umbraco.Web.UI.Client/src/packages/core/collection/action/collection-action-button.element.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v15/dev)

❌ New issue: Complex Method

UmbCollectionActionButtonElement.createApi 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.
}

#api?: UmbCollectionAction;
@state()
private _buttonState?: UUIButtonState;

private async _onClick() {
if (!this.#api) return;
@state()
private _additionalOptions?: boolean;

this._buttonState = 'waiting';
@state()
private _href?: string;

try {
if (!this.#api) throw new Error('No api defined');
await this.#api.execute();
this._buttonState = 'success';
} catch {
this._buttonState = 'failed';
}
private async _onClick() {
// If its a link or has additional options, then we do not want to display state on the button. [NL]
if (!this._href) {
if (!this._additionalOptions) {
this._buttonState = 'waiting';
}

try {
if (!this.#api) throw new Error('No api defined');
await this.#api.execute();
if (!this._additionalOptions) {
this._buttonState = 'success';
}
} catch {
if (!this._additionalOptions) {
this._buttonState = 'failed';
}
}
}
this.dispatchEvent(new UmbActionExecutedEvent());
}

override render() {
const label = this.manifest?.meta.label ? this.localize.string(this.manifest.meta.label) : this.manifest?.name;
const label = this.manifest?.meta.label
? this.localize.string(this.manifest.meta.label)
: (this.manifest?.name ?? '');
return html`
<uui-button
id="action-button"
data-mark="collection-action:${this.manifest?.alias}"
color="default"
look="outline"
label=${ifDefined(label)}
href=${ifDefined(this.manifest?.meta.href)}
.label=${this._additionalOptions ? label + '…' : label}
.href=${this._href}
.state=${this._buttonState}
@click=${this._onClick}></uui-button>
`;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
import UmbCollectionActionButtonElement from './collection-action-button.element.js';
import { manifests as createManifests } from './create/manifests.js';
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';

export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [...createManifests];
const manifest: UmbExtensionManifestKind = {
type: 'kind',
alias: 'Umb.Kind.CollectionAction.Button',
matchKind: 'button',
matchType: 'collectionAction',
manifest: {
type: 'collectionAction',
kind: 'button',
element: UmbCollectionActionButtonElement,
},
};

export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [manifest, ...createManifests];
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { UmbCollectionAction } from '../action/collection-action-base.js';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import type { ManifestElementAndApi, ManifestWithDynamicConditions } from '@umbraco-cms/backoffice/extension-api';

/**
Expand All @@ -6,7 +8,7 @@ import type { ManifestElementAndApi, ManifestWithDynamicConditions } from '@umbr
*/
// TODO: create interface for API
export interface ManifestCollectionAction
extends ManifestElementAndApi,
extends ManifestElementAndApi<UmbControllerHostElement, UmbCollectionAction>,
ManifestWithDynamicConditions<UmbExtensionConditionConfig> {
type: 'collectionAction';
meta: MetaCollectionAction;
Expand All @@ -15,6 +17,7 @@ export interface ManifestCollectionAction
export interface MetaCollectionAction {
label: string;
href?: string;
additionalOptions?: boolean;
}

declare global {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class UmbEntityActionDefaultElement<

return html`
<uui-menu-item
label=${ifDefined(this.manifest?.meta.additionalOptions ? label + '...' : label)}
label=${ifDefined(this.manifest?.meta.additionalOptions ? label + '' : label)}
href=${ifDefined(this._href)}
@click-label=${this.#onClickLabel}
@click=${this.#onClick}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export class UmbCreateDocumentCollectionActionElement extends UmbLitElement {
if (this._allowedDocumentTypes.length !== 1) return;

const item = this._allowedDocumentTypes[0];
// TODO: Stop appending values to labels, instead we need to parse the name as a argument to the label. [NL]
const label =
(this.manifest?.meta.label
? this.localize.string(this.manifest?.meta.label)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const manifests: Array<UmbExtensionManifest> = [
weight: 100,
meta: {
label: '#user_invite',
additionalOptions: true,
},
conditions: [
{
Expand Down
Loading