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

fix(edit-content): Reset UI state when navigating between portlets #31410

Merged
merged 6 commits into from
Feb 20, 2025
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
643 changes: 643 additions & 0 deletions .cursor/rules/dotcms-angular-rules.mdc

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions .cursor/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"workspaceIndexing": {
"ignorePatterns": [
"**/node_modules/**",
"**/dist/**",
"**/.nx/**",
"**/*.timestamp-*",
"**/.vite/**"
]
}
}
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,3 @@ dotCMS/dependencies.gradle
.cursorrules
.cursorignore
**/vite.config.mts.timestamp-*
.cursor/
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { DotCustomEventHandlerService } from '@dotcms/app/api/services/dot-custo
import { DotMenuService } from '@dotcms/app/api/services/dot-menu.service';
import { DotContentTypeService, DotIframeService, DotRouterService } from '@dotcms/data-access';
import { DotcmsEventsService, LoggerService, SiteService } from '@dotcms/dotcms-js';
import { UI_STORAGE_KEY } from '@dotcms/dotcms-models';
import { DotLoadingIndicatorService } from '@dotcms/utils';

@Component({
Expand Down Expand Up @@ -63,6 +64,12 @@ export class IframePortletLegacyComponent implements OnInit, OnDestroy {
});

this.subscribeToAIGeneration();

// Workaroud to remove edit-content ui state
this.#initContentEditSessionStorage();
}
#initContentEditSessionStorage() {
sessionStorage.removeItem(UI_STORAGE_KEY);
}

ngOnDestroy(): void {
Expand Down
117 changes: 58 additions & 59 deletions core-web/libs/dotcms-models/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,81 +1,80 @@
export * from './lib/content-type-view.model';
export * from './lib/dot-action-bulk-request-options.model';
export * from './lib/dot-action-bulk-result.model';
export * from './lib/dot-action-menu-item.model';
export * from './lib/dot-ai.model';
export * from './lib/dot-ajax-action-response';
export * from './lib/dot-alert-confirm.model';
export * from './lib/dot-apps.model';
export * from './lib/dot-asset-create-options.model';
export * from './lib/dot-block-editor.model';
export * from './lib/dot-bundle';
export * from './lib/dot-categories.model';
export * from './lib/dot-container.model';
export * from './lib/dot-content-analytics.model';
export * from './lib/dot-content-compare.model';
export * from './lib/dot-content-state.model';
export * from './lib/dot-content-types.model';
export * from './lib/dot-contentlet.model';
export * from './lib/dot-tree-node.model';
export * from './lib/dot-block-editor.model';
export * from './lib/dot-push-publish-dialog-data.model';
export * from './lib/dot-temp-file.model';
export * from './lib/dot-workflow-action.model';
export * from './lib/dot-workflow.model';
export * from './lib/dot-asset-create-options.model';
export * from './lib/dot-file-metadata.model';
export * from './lib/dot-contentlets-events.model';
export * from './lib/dot-current-user';
export * from './lib/dot-device.model';
export * from './lib/dot-dialog.model';
export * from './lib/dot-dynamic-field-component.model';
export * from './lib/dot-edit-content.model';
export * from './lib/dot-edit-page-view-as.model';
export * from './lib/dot-environment.model';
export * from './lib/dot-es-content.model';
export * from './lib/dot-event';
export * from './lib/dot-experiments-constants';
export * from './lib/dot-experiments.model';
export * from './lib/dot-field-variable.model';
export * from './lib/dot-file-metadata.model';
export * from './lib/dot-function-info.model';
export * from './lib/dot-global-message.model';
export * from './lib/dot-http-error-response.model';
export * from './lib/dot-http-request-options.model';
export * from './lib/dot-login.model';
export * from './lib/dot-license.model';
export * from './lib/dot-dynamic-field-component.model';
export * from './lib/dot-iframe-edit-event.model';
export * from './lib/dot-persona.model';
export * from './lib/dot-action-bulk-request-options.model';
export * from './lib/dot-action-bulk-result.model';
export * from './lib/dot-page-mode.enum';
export * from './lib/dot-page.model';
export * from './lib/dot-layout.model';
export * from './lib/dot-container.model';
export * from './lib/dot-device.model';
export * from './lib/dot-language.model';
export * from './lib/dot-layout-body.model';
export * from './lib/dot-layout-sidebar.model';
export * from './lib/dot-layout-row.model';
export * from './lib/dot-layout-column.model';
export * from './lib/dot-layout-row.model';
export * from './lib/dot-layout-sidebar.model';
export * from './lib/dot-layout.model';
export * from './lib/dot-license.model';
export * from './lib/dot-locale-options.model';
export * from './lib/dot-login.model';
export * from './lib/dot-message-severity.model';
export * from './lib/dot-message-type.model';
export * from './lib/dot-message.model';
export * from './lib/dot-page-container.model';
export * from './lib/dot-template.model';
export * from './lib/dot-site.model';
export * from './lib/dot-page-content.model';
export * from './lib/dot-page-mode.enum';
export * from './lib/dot-page-render.model';
export * from './lib/dot-page-tool.model';
export * from './lib/dot-page.model';
export * from './lib/dot-persona.model';
export * from './lib/dot-personalize.model';
export * from './lib/dot-push-publish-data.model';
export * from './lib/dot-push-publish-dialog-data.model';
export * from './lib/dot-rendered-page-state.model';
export * from './lib/dot-rendered-page.model';
export * from './lib/dot-current-user';
export * from './lib/dot-bundle';
export * from './lib/dot-ajax-action-response';
export * from './lib/dot-alert-confirm.model';
export * from './lib/dot-apps.model';
export * from './lib/content-type-view.model';
export * from './lib/structure-type.model';
export * from './lib/structure-type-view.model';
export * from './lib/dot-role.model';
export * from './lib/dot-site.model';
export * from './lib/dot-tag.model';
export * from './lib/dot-temp-file.model';
export * from './lib/dot-template.model';
export * from './lib/dot-theme.model';
export * from './lib/dot-edit-page-view-as.model';
export * from './lib/dot-environment.model';
export * from './lib/dot-locale-options.model';
export * from './lib/dot-tree-node.model';
export * from './lib/dot-vanity-url.model';
export * from './lib/dot-what-changed.model';
export * from './lib/dot-wizard.model';
export * from './lib/dot-es-content.model';
export * from './lib/dot-event';
export * from './lib/dot-page-render.model';
export * from './lib/dot-rendered-page-state.model';
export * from './lib/dot-personalize.model';
export * from './lib/dot-push-publish-data.model';
export * from './lib/dot-field-variable.model';
export * from './lib/dot-field-variable.model';
export * from './lib/dot-experiments-constants';
export * from './lib/dot-experiments.model';
export * from './lib/shared-models';
export * from './lib/dot-page-tool.model';
export * from './lib/navigation';
export * from './lib/dot-contentlets-events.model';
export * from './lib/dot-workflow-action.model';
export * from './lib/dot-workflow.model';
export * from './lib/meta-tags-model';
export * from './lib/navigation';
export * from './lib/page-model-change-event';
export * from './lib/page-model-change-event.type';
export * from './lib/dot-page-content.model';
export * from './lib/dot-message.model';
export * from './lib/dot-message-severity.model';
export * from './lib/dot-message-type.model';
export * from './lib/dot-dialog.model';
export * from './lib/dot-content-compare.model';
export * from './lib/dot-action-menu-item.model';
export * from './lib/dot-vanity-url.model';
export * from './lib/dot-categories.model';
export * from './lib/dot-ai.model';
export * from './lib/dot-content-analytics.model';
export * from './lib/shared-models';
export * from './lib/structure-type-view.model';
export * from './lib/structure-type.model';
1 change: 1 addition & 0 deletions core-web/libs/edit-content/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './lib/edit-content.routes';
export * from './lib/fields/dot-edit-content-binary-field/dot-edit-content-binary-field.component';
export * from './lib/utils/functions.util';
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { MockComponent } from 'ng-mocks';
import { of } from 'rxjs';

import { fakeAsync, tick } from '@angular/core/testing';
import { ActivatedRoute, Router } from '@angular/router';

import { MessageService } from 'primeng/api';
Expand All @@ -24,6 +25,7 @@ import {
DotWorkflowsActionsService,
DotWorkflowService
} from '@dotcms/data-access';
import { MOCK_SINGLE_WORKFLOW_ACTIONS } from '@dotcms/utils-testing';

import { DotEditContentSidebarInformationComponent } from './components/dot-edit-content-sidebar-information/dot-edit-content-sidebar-information.component';
import { DotEditContentSidebarWorkflowComponent } from './components/dot-edit-content-sidebar-workflow/dot-edit-content-sidebar-workflow.component';
Expand All @@ -33,7 +35,7 @@ import { DotEditContentService } from '../../services/dot-edit-content.service';
import { DotEditContentStore } from '../../store/edit-content.store';
import { MOCK_WORKFLOW_STATUS } from '../../utils/edit-content.mock';
import * as utils from '../../utils/functions.util';
import { MockResizeObserver } from '../../utils/mocks';
import { CONTENT_TYPE_MOCK, MockResizeObserver } from '../../utils/mocks';

describe('DotEditContentSidebarComponent', () => {
let spectator: Spectator<DotEditContentSidebarComponent>;
Expand Down Expand Up @@ -134,20 +136,76 @@ describe('DotEditContentSidebarComponent', () => {
});

describe('UI State', () => {
it('should initialize with correct UI state', () => {
beforeEach(fakeAsync(() => {
// Mock the services needed for initializeExistingContent
const dotContentTypeService = spectator.inject(DotContentTypeService);
const workflowActionsService = spectator.inject(DotWorkflowsActionsService);
const dotWorkflowService = spectator.inject(DotWorkflowService);
const dotEditContentService = spectator.inject(DotEditContentService);

// Mock contentlet response with all required DotCMSContentlet properties
const mockContentlet = {
inode: '123',
contentType: 'testContentType',
archived: false,
baseType: 'CONTENT',
folder: 'SYSTEM_FOLDER',
hasTitleImage: false,
host: 'demo.dotcms.com',
hostName: 'demo.dotcms.com',
identifier: '123-456',
languageId: 1,
live: true,
locked: false,
modDate: new Date().toISOString(),
modUser: 'admin',
modUserName: 'Admin User',
owner: 'admin',
permissionId: '123',
permissionType: 'CONTENT',
title: 'Test Content',
working: true,
URL_MAP_FOR_CONTENT: '/test',
sortOrder: 0,
stInode: '123-stInode',
structure: {
name: 'Test Structure',
inode: '456'
},
titleImage: '',
url: '/test-content'
};

dotEditContentService.getContentById.mockReturnValue(of(mockContentlet));
dotContentTypeService.getContentType.mockReturnValue(of(CONTENT_TYPE_MOCK));
workflowActionsService.getByInode.mockReturnValue(of([]));
workflowActionsService.getWorkFlowActions.mockReturnValue(
of(MOCK_SINGLE_WORKFLOW_ACTIONS)
);
dotWorkflowService.getWorkflowStatus.mockReturnValue(of(MOCK_WORKFLOW_STATUS));

// Initialize existing content
store.initializeExistingContent('123');
tick();
spectator.detectChanges();
}));

it('should initialize with correct UI state', fakeAsync(() => {
expect(store.isSidebarOpen()).toBe(true);
expect(store.activeSidebarTab()).toBe(0);
});
}));

it('should update active tab when changed', () => {
it('should update active tab when changed', fakeAsync(() => {
store.setActiveSidebarTab(1);
tick();
expect(store.activeSidebarTab()).toBe(1);
});
}));

it('should toggle sidebar visibility', () => {
it('should toggle sidebar visibility', fakeAsync(() => {
const initialState = store.isSidebarOpen();
store.toggleSidebar();
tick();
expect(store.isSidebarOpen()).toBe(!initialState);
});
}));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface UIState {

export const uiInitialState: UIState = {
activeTab: 0,
isSidebarOpen: false,
isSidebarOpen: true,
activeSidebarTab: 0
};

Expand Down Expand Up @@ -56,7 +56,12 @@ export function withUI() {
/**
* Computed property that returns the active sidebar tab
*/
activeSidebarTab: computed(() => store.uiState().activeSidebarTab)
activeSidebarTab: computed(() => {
const initialState = store.initialContentletState();
const uiState = store.uiState();

return initialState === 'new' ? 0 : uiState.activeSidebarTab;
})
})),
withMethods((store) => ({
/**
Expand Down
Loading