Skip to content
This repository was archived by the owner on Nov 6, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type { ConditionTypes } from '../conditions/types.js';
import type { UmbAction } from '../../action/action.interface.js';
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
import type { ManifestElementAndApi, ManifestWithDynamicConditions } from '@umbraco-cms/backoffice/extension-api';
import type { UUIInterfaceColor, UUIInterfaceLook } from '@umbraco-cms/backoffice/external/uui';

export interface UmbCurrentUserActionArgs<MetaArgsType> {
meta: MetaArgsType;
}

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

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

export interface ManifestCurrentUserAction<MetaType extends MetaCurrentUserAction = MetaCurrentUserAction>
extends ManifestElementAndApi<UmbControllerHostElement, UmbCurrentUserAction<MetaType>>,
ManifestWithDynamicConditions<ConditionTypes> {
type: 'currentUserAction';
meta: MetaType;
}

export interface MetaCurrentUserAction {}

export interface ManifestCurrentUserActionDefaultKind<
MetaType extends MetaCurrentUserActionDefaultKind = MetaCurrentUserActionDefaultKind,
> extends ManifestCurrentUserAction<MetaType> {
type: 'currentUserAction';
kind: 'default';
}

export interface MetaCurrentUserActionDefaultKind extends MetaCurrentUserAction {
/**
* An icon to represent the action to be performed
*
* @examples [
* "icon-box",
* "icon-grid"
* ]
*/
icon?: string;

/**
* The friendly name of the action to perform
*
* @examples [
* "Create",
* "Create Content Template"
* ]
*/
label: string;

/**
* The look of the button
* @default primary
*/
look?: UUIInterfaceLook;

/**
* The color of the button
* @default default
*/
color?: UUIInterfaceColor;
}
4 changes: 4 additions & 0 deletions src/packages/core/extension-registry/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { ManifestAuthProvider } from './auth-provider.model.js';
import type { ManifestBlockEditorCustomView } from './block-editor-custom-view.model.js';
import type { ManifestCollection } from './collection.models.js';
import type { ManifestCollectionView } from './collection-view.model.js';
import type { ManifestCurrentUserAction, ManifestCurrentUserActionDefaultKind } from './current-user-action.model.js';
import type { ManifestDashboard } from './dashboard.model.js';
import type { ManifestDashboardCollection } from './dashboard-collection.model.js';
import type {
Expand Down Expand Up @@ -72,6 +73,7 @@ export type * from './block-editor-custom-view.model.js';
export type * from './collection.models.js';
export type * from './collection-action.model.js';
export type * from './collection-view.model.js';
export type * from './current-user-action.model.js';
export type * from './dashboard-collection.model.js';
export type * from './dashboard.model.js';
export type * from './dynamic-root.model.js';
Expand Down Expand Up @@ -143,6 +145,8 @@ export type ManifestTypes =
| ManifestCollection
| ManifestCollectionView
| ManifestCollectionAction
| ManifestCurrentUserAction
| ManifestCurrentUserActionDefaultKind
| ManifestCondition
| ManifestDashboard
| ManifestDashboardCollection
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { html, customElement, ifDefined, state, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type {
ManifestCurrentUserActionDefaultKind,
MetaCurrentUserActionDefaultKind,
UmbCurrentUserAction,
} from '@umbraco-cms/backoffice/extension-registry';
import { UmbActionExecutedEvent } from '@umbraco-cms/backoffice/event';

@customElement('umb-current-user-app-button')
export class UmbCurrentUserAppButtonElement<
MetaType extends MetaCurrentUserActionDefaultKind = MetaCurrentUserActionDefaultKind,
ApiType extends UmbCurrentUserAction<MetaType> = UmbCurrentUserAction<MetaType>,
> extends UmbLitElement {
#api?: ApiType;

@state()
_href?: string;

@property({ attribute: false })
public manifest?: ManifestCurrentUserActionDefaultKind<MetaType>;

public set api(api: ApiType | undefined) {
this.#api = api;

this.#api?.getHref?.().then((href) => {
this._href = href;
});
}

async #onClick(event: Event) {
if (!this._href) {
event.stopPropagation();
await this.#api?.execute();
}
this.dispatchEvent(new UmbActionExecutedEvent());
}

get label(): string | undefined {
return this.manifest?.meta.label ? this.localize.string(this.manifest.meta.label) : undefined;
}

render() {
return html`
<uui-button
@click=${this.#onClick}
look="${this.manifest?.meta.look ?? 'primary'}"
color="${this.manifest?.meta.color ?? 'default'}"
label="${ifDefined(this.label)}"
href="${ifDefined(this._href)}">
${this.manifest?.meta.icon ? html`<uui-icon name="${this.manifest.meta.icon}"></uui-icon>` : ''} ${this.label}
</uui-button>
`;
}

static styles = [UmbTextStyles];
}

export default UmbCurrentUserAppButtonElement;

declare global {
interface HTMLElementTagNameMap {
'umb-current-user-app-button': UmbCurrentUserAppButtonElement;
}
}
13 changes: 13 additions & 0 deletions src/packages/user/current-user/action/default.kind.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry';

export const manifest: UmbBackofficeManifestKind = {
type: 'kind',
alias: 'Umb.Kind.CurrentUserAction.Default',
matchKind: 'default',
matchType: 'currentUserAction',
manifest: {
type: 'currentUserAction',
kind: 'default',
elementName: 'umb-current-user-app-button',
},
};
1 change: 1 addition & 0 deletions src/packages/user/current-user/action/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './current-user-app-button.element.js';
1 change: 1 addition & 0 deletions src/packages/user/current-user/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './action/index.js';
export * from './components/index.js';
export * from './history/current-user-history.store.js';
export * from './utils/index.js';
Expand Down
2 changes: 2 additions & 0 deletions src/packages/user/current-user/manifests.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { manifest as actionDefaultKindManifest } from './action/default.kind.js';
import { manifests as modalManifests } from './modals/manifests.js';
import { manifests as externalLoginProviderManifests } from './external-login/manifests.js';
import { manifests as historyManifests } from './history/manifests.js';
Expand Down Expand Up @@ -29,6 +30,7 @@ export const headerApps: Array<ManifestTypes> = [
];

export const manifests = [
actionDefaultKindManifest,
...externalLoginProviderManifests,
...headerApps,
...historyManifests,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { html, customElement, state, css } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_CHANGE_PASSWORD_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UMB_CURRENT_USER_CONTEXT, type UmbCurrentUserModel } from '@umbraco-cms/backoffice/current-user';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';

@customElement('umb-current-user-profile-user-profile-app')
export class UmbCurrentUserProfileUserProfileAppElement extends UmbLitElement {
Expand Down Expand Up @@ -59,9 +60,22 @@ export class UmbCurrentUserProfileUserProfileAppElement extends UmbLitElement {
<uui-button look="primary" label=${this.localize.term('general_changePassword')} @click=${this.#changePassword}>
${this.localize.term('general_changePassword')}
</uui-button>
<umb-extension-with-api-slot id="actions" type="currentUserAction"></umb-extension-with-api-slot>
</uui-box>
`;
}

static styles = [
UmbTextStyles,
css`
#actions {
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: var(--uui-size-space-2);
}
`,
];
}

export default UmbCurrentUserProfileUserProfileAppElement;
Expand Down