Skip to content

Commit

Permalink
Bugfix: Redirect when server file is renamed (#17663)
Browse files Browse the repository at this point in the history
* make args protected + type generic

* add rename event

* get new name and unique from modal

* dispatch event when file is renamed

* get unique from entity context

* poc redirect after rename

* move logic to controller

* dont render code editor if content is undefined

* remove unused styling

* set unique after create

* use replace state

* set additionalOptions for rename action

* Update workspace-redirect.controller.ts

* add focus to name input

* add rename redirect controller

* clean up

* split render methods

* Update script-workspace.context.ts

* implement EntityDetailWorkspaceBase for stylesheets

* remove unused

* don't render code editor if there is no content

* add rename redirect controller

---------

Co-authored-by: Niels Lyngsø <nsl@umbraco.dk>
  • Loading branch information
madsrasmussen and nielslyngsoe authored Nov 29, 2024
1 parent bce58a5 commit c4b0bde
Show file tree
Hide file tree
Showing 19 changed files with 277 additions and 209 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface UmbEntityActionEventArgs extends UmbEntityModel {}

export class UmbEntityActionEvent extends UmbControllerEvent {
#args: UmbEntityActionEventArgs;
export class UmbEntityActionEvent<
ArgsType extends UmbEntityActionEventArgs = UmbEntityActionEventArgs,
> extends UmbControllerEvent {
protected _args: ArgsType;

public constructor(type: string, args: UmbEntityActionEventArgs) {
public constructor(type: string, args: ArgsType) {
super(type);
this.#args = args;
this._args = args;
}

getEntityType(): string {
return this.#args.entityType;
return this._args.entityType;
}

getUnique(): string | null {
return this.#args.unique;
return this._args.unique;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './server-file-renamed.entity-event.js';
export type * from './types.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { UmbServerFileRenamedEventArgs } from './types.js';
import { UmbEntityActionEvent } from '@umbraco-cms/backoffice/entity-action';

export class UmbServerFileRenamedEntityEvent extends UmbEntityActionEvent<UmbServerFileRenamedEventArgs> {
static readonly TYPE = 'server-file-renamed';

constructor(args: UmbServerFileRenamedEventArgs) {
super(UmbServerFileRenamedEntityEvent.TYPE, args);
}

getNewUnique(): string {
return this._args.newUnique;
}

getNewName(): string {
return this._args.newName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { UmbEntityActionEventArgs } from '@umbraco-cms/backoffice/entity-action';

export interface UmbServerFileRenamedEventArgs extends UmbEntityActionEventArgs {
newUnique: string;
newName: string;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type * from './types.js';
export * from './rename-server-file.action.js';
export * from './rename-server-file-repository-base.js';
export * from './event/index.js';
export * from './workspace-redirect/index.js';
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { UmbExtensionApiInitializer } from '@umbraco-cms/backoffice/extension-api';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbItemRepository } from '@umbraco-cms/backoffice/repository';
import { umbFocus } from '@umbraco-cms/backoffice/lit-element';

@customElement('umb-rename-modal')
export class UmbRenameModalElement extends UmbModalBaseElement<UmbRenameModalData, UmbRenameServerFileModalValue> {
Expand Down Expand Up @@ -81,6 +82,11 @@ export class UmbRenameModalElement extends UmbModalBaseElement<UmbRenameModalDat
const { data } = await this.#renameRepository.rename(this.data.unique, name);

if (data) {
this.value = {
name: data.name,
unique: data.unique,
};

this._submitModal();
} else {
this._rejectModal();
Expand All @@ -102,7 +108,8 @@ export class UmbRenameModalElement extends UmbModalBaseElement<UmbRenameModalDat
value=${this._name}
placeholder="Enter new name..."
required
required-message="Name is required"></uui-input>
required-message="Name is required"
${umbFocus()}></uui-input>
</uui-form-layout-item>
</form>
</uui-form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ export interface UmbRenameModalData {
unique: string;
}

// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface UmbRenameServerFileModalValue {}
export interface UmbRenameServerFileModalValue {
unique: string;
name: string;
}

export const UMB_RENAME_SERVER_FILE_MODAL = new UmbModalToken<UmbRenameModalData, UmbRenameServerFileModalValue>(
UMB_RENAME_SERVER_FILE_MODAL_ALIAS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const manifest: UmbExtensionManifestKind = {
meta: {
icon: 'icon-edit',
label: '#actions_rename',
additionalOptions: true,
renameRepositoryAlias: '',
itemRepositoryAlias: '',
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { UMB_RENAME_SERVER_FILE_MODAL } from './modal/rename-server-file-modal.token.js';
import type { MetaEntityActionRenameServerFileKind } from './types.js';
import { UmbServerFileRenamedEntityEvent } from './event/index.js';
import { UmbEntityActionBase, UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice/entity-action';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
Expand All @@ -17,15 +18,29 @@ export class UmbRenameEntityAction extends UmbEntityActionBase<MetaEntityActionR
},
});

await modalContext.onSubmit();
try {
const res = await modalContext.onSubmit();

const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT);
const event = new UmbRequestReloadStructureForEntityEvent({
unique: this.args.unique,
entityType: this.args.entityType,
});
const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT);
const event = new UmbRequestReloadStructureForEntityEvent({
unique: this.args.unique,
entityType: this.args.entityType,
});

actionEventContext.dispatchEvent(event);

const event2 = new UmbServerFileRenamedEntityEvent({
unique: this.args.unique,
entityType: this.args.entityType,
newName: res.name,
newUnique: res.unique,
});

actionEventContext.dispatchEvent(event);
actionEventContext.dispatchEvent(event2);
} catch (error) {
// TODO: Handle error
console.log(error);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './workspace-redirect.controller.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { UmbServerFileRenamedEntityEvent } from '../event/index.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbRouterSlotElement } from '@umbraco-cms/backoffice/router';
import { ensurePathEndsWithSlash, umbUrlPatternToString } from '@umbraco-cms/backoffice/utils';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
import type { UmbSubmittableWorkspaceContextBase } from '@umbraco-cms/backoffice/workspace';

export const UmbServerFileRenameWorkspaceRedirectControllerAlias = Symbol(
'ServerFileRenameWorkspaceRedirectControllerAlias',
);

export class UmbServerFileRenameWorkspaceRedirectController extends UmbControllerBase {
#actionEventContext?: typeof UMB_ACTION_EVENT_CONTEXT.TYPE;
#workspaceContext: UmbSubmittableWorkspaceContextBase<unknown>;
#router: UmbRouterSlotElement;

constructor(
host: UmbControllerHost,
workspaceContext: UmbSubmittableWorkspaceContextBase<unknown>,
router: UmbRouterSlotElement,
) {
super(host, UmbServerFileRenameWorkspaceRedirectControllerAlias);

this.#workspaceContext = workspaceContext;
this.#router = router;

this.consumeContext(UMB_ACTION_EVENT_CONTEXT, (context) => {
this.#actionEventContext = context;

if (this.#actionEventContext) {
this.#actionEventContext.removeEventListener(UmbServerFileRenamedEntityEvent.TYPE, this.#onFileRenamed);
this.#actionEventContext.addEventListener(UmbServerFileRenamedEntityEvent.TYPE, this.#onFileRenamed);
}
});
}

#onFileRenamed = ((event: UmbServerFileRenamedEntityEvent) => {
if (!this.#router) throw new Error('Router is required for this controller.');

// Don't redirect if the event is not for the current entity
const currentUnique = this.#workspaceContext.getUnique();
const eventUnique = event.getUnique();
if (currentUnique !== eventUnique) return;

const newUnique = event.getNewUnique();
if (!newUnique) throw new Error('New unique is required for this event.');

const routerPath = this.#router.absoluteRouterPath;
if (!routerPath) throw new Error('Router path is required for this controller.');

const newPath: string = umbUrlPatternToString(ensurePathEndsWithSlash(routerPath) + 'edit/:unique', {
unique: newUnique,
});

this.destroy();
window.history.replaceState(null, '', newPath);
}) as EventListener;

public override destroy(): void {
super.destroy();
this.#actionEventContext?.removeEventListener(UmbServerFileRenamedEntityEvent.TYPE, this.#onFileRenamed);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
* @returns { string | undefined } The unique identifier
*/
getUnique(): UmbEntityUnique | undefined {
return this.getData()?.unique;
return this.#entityContext.getUnique();
}

setUnique(unique: string) {
Expand Down Expand Up @@ -242,6 +242,7 @@ export abstract class UmbEntityDetailWorkspaceContextBase<
throw error?.message ?? 'Repository did not return data after create.';
}

this.#entityContext.setUnique(data.unique);
this._data.setPersisted(data);
this._data.setCurrent(data);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getQuerySnippet } from '../../utils/index.js';
import type { UmbTemplatingInsertMenuElement } from '../../local-components/insert-menu/index.js';
import { UMB_PARTIAL_VIEW_WORKSPACE_CONTEXT } from './partial-view-workspace.context-token.js';
import { css, customElement, html, query, state } from '@umbraco-cms/backoffice/external/lit';
import { css, customElement, html, nothing, query, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement, umbFocus } from '@umbraco-cms/backoffice/lit-element';
import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import { UMB_TEMPLATE_QUERY_BUILDER_MODAL } from '@umbraco-cms/backoffice/template';
Expand Down Expand Up @@ -107,6 +107,10 @@ export class UmbPartialViewWorkspaceEditorElement extends UmbLitElement {
}

#renderCodeEditor() {
if (this._content === undefined) {
return nothing;
}

return html`
<umb-code-editor
id="content"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
import { PartialViewService } from '@umbraco-cms/backoffice/external/backend-api';
import type { IRoutingInfo, PageComponent } from '@umbraco-cms/backoffice/router';
import { UmbServerFileRenameWorkspaceRedirectController } from '@umbraco-cms/backoffice/server-file-system';

export interface UmbPartialViewWorkspaceContextCreateArgs
extends UmbEntityDetailWorkspaceContextCreateArgs<UmbPartialViewDetailModel> {
Expand Down Expand Up @@ -73,6 +74,12 @@ export class UmbPartialViewWorkspaceContext
setup: (component: PageComponent, info: IRoutingInfo) => {
const unique = info.match.params.unique;
this.load(unique);

new UmbServerFileRenameWorkspaceRedirectController(
this,
this,
this.getHostElement().shadowRoot!.querySelector('umb-router-slot')!,
);
},
},
]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UMB_SCRIPT_WORKSPACE_CONTEXT } from './script-workspace.context-token.js';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement, umbFocus } from '@umbraco-cms/backoffice/lit-element';
import type { UmbCodeEditorElement } from '@umbraco-cms/backoffice/code-editor';
import type { UUIInputElement } from '@umbraco-cms/backoffice/external/uui';
Expand All @@ -24,18 +24,9 @@ export class UmbScriptWorkspaceEditorElement extends UmbLitElement {

this.consumeContext(UMB_SCRIPT_WORKSPACE_CONTEXT, (context) => {
this.#context = context;

this.observe(this.#context.name, (name) => {
this._name = name;
});

this.observe(this.#context.content, (content) => {
this._content = content;
});

this.observe(this.#context.isNew, (isNew) => {
this._isNew = isNew;
});
this.observe(this.#context.name, (name) => (this._name = name));
this.observe(this.#context.content, (content) => (this._content = content));
this.observe(this.#context.isNew, (isNew) => (this._isNew = isNew));
});
}

Expand All @@ -54,26 +45,41 @@ export class UmbScriptWorkspaceEditorElement extends UmbLitElement {
override render() {
return html`
<umb-entity-detail-workspace-editor>
<div id="workspace-header" slot="header">
<uui-input
placeholder=${this.localize.term('placeholders_entername')}
.value=${this._name}
@input=${this.#onNameInput}
label=${this.localize.term('placeholders_entername')}
?readonly=${this._isNew === false}
${umbFocus()}>
</uui-input>
</div>
<uui-box>
<!-- the div below in the header is to make the box display nicely with code editor -->
<div slot="header"></div>
${this.#renderCodeEditor()}
</uui-box>
${this.#renderHeader()} ${this.#renderBody()}
</umb-entity-detail-workspace-editor>
`;
}

#renderHeader() {
return html`
<div id="workspace-header" slot="header">
<uui-input
placeholder=${this.localize.term('placeholders_entername')}
.value=${this._name}
@input=${this.#onNameInput}
label=${this.localize.term('placeholders_entername')}
?readonly=${this._isNew === false}
${umbFocus()}>
</uui-input>
</div>
`;
}

#renderBody() {
return html`
<uui-box>
<!-- the div below in the header is to make the box display nicely with code editor -->
<div slot="header"></div>
${this.#renderCodeEditor()}
</uui-box>
`;
}

#renderCodeEditor() {
if (this._content === undefined) {
return nothing;
}

return html`
<umb-code-editor
id="content"
Expand All @@ -85,11 +91,6 @@ export class UmbScriptWorkspaceEditorElement extends UmbLitElement {

static override styles = [
css`
:host {
display: block;
width: 100%;
}
umb-code-editor {
--editor-height: calc(100dvh - 260px);
}
Expand Down
Loading

0 comments on commit c4b0bde

Please sign in to comment.