({ alias: 'data' });
/** URL to fetch the contentlet as JSON via the REST API. */
- readonly $jsonUrl = computed(() => `/api/v1/content/${this.$data().contentlet.identifier}`);
+ readonly $jsonUrl = computed(
+ () => `/api/v1/content/${this.$data().contentlet?.identifier ?? ''}`
+ );
/** Tooltip message shown when the contentlet has no creation date yet. */
readonly $createdTooltipMessage = computed(() => {
diff --git a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.html b/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.html
deleted file mode 100644
index 5b43d14b5718..000000000000
--- a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.html
+++ /dev/null
@@ -1,30 +0,0 @@
-{{ 'edit.content.sidebar.locales.untranslated.text' | dm }}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.scss b/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.scss
deleted file mode 100644
index 157e54695030..000000000000
--- a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.scss
+++ /dev/null
@@ -1,16 +0,0 @@
-@use "../../../../../../../dotcms-scss/shared/spacing";
-
-@use "variables" as *;
-
-:host {
- display: flex;
- flex-direction: column;
- gap: spacing.$spacing-1;
-
- .untranslated-locale__actions {
- margin-top: spacing.$spacing-3;
- display: flex;
- gap: spacing.$spacing-2;
- justify-content: flex-end;
- }
-}
diff --git a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.spec.ts b/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.spec.ts
deleted file mode 100644
index 44e22bb48876..000000000000
--- a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.spec.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { Spectator, createComponentFactory, byTestId } from '@ngneat/spectator/jest';
-
-import { CommonModule } from '@angular/common';
-import { FormsModule } from '@angular/forms';
-
-import { ButtonDirective } from 'primeng/button';
-import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
-import { RadioButtonModule } from 'primeng/radiobutton';
-
-import { DotMessageService } from '@dotcms/data-access';
-import { DotMessagePipe } from '@dotcms/ui';
-import { MockDotMessageService } from '@dotcms/utils-testing';
-
-import { DotEditContentSidebarUntranslatedLocaleComponent } from './dot-edit-content-sidebar-untranslated-locale.component';
-
-const messageServiceMock = new MockDotMessageService({
- 'edit.content.sidebar.locales.untranslated.populate': 'Populate from Current Locale'
-});
-
-describe('DotEditContentSidebarUntranslatedLocaleComponent', () => {
- let spectator: Spectator;
- const createComponent = createComponentFactory({
- component: DotEditContentSidebarUntranslatedLocaleComponent,
- imports: [CommonModule, RadioButtonModule, FormsModule, ButtonDirective, DotMessagePipe],
- providers: [
- { provide: DynamicDialogRef, useValue: { close: jest.fn() } },
- {
- provide: DynamicDialogConfig,
- useValue: { data: { currentLocale: { isoCode: 'en-us' } } }
- },
- {
- provide: DotMessageService,
- useValue: messageServiceMock
- }
- ]
- });
-
- beforeEach(() => {
- spectator = createComponent();
- });
-
- it('should close dialog with selected option on continue button click', () => {
- const continueButton = spectator.query(byTestId('continue-button'));
- const dialogRefCloseSpy = jest.spyOn(spectator.component.dialogRef, 'close');
-
- spectator.click(continueButton);
-
- expect(dialogRefCloseSpy).toHaveBeenCalledWith(spectator.component.selectedOption);
- });
-
- it('should close dialog on cancel button click', () => {
- const cancelButton = spectator.query(byTestId('cancel-button'));
- const dialogRefCloseSpy = jest.spyOn(spectator.component.dialogRef, 'close');
-
- spectator.click(cancelButton);
-
- expect(dialogRefCloseSpy).toHaveBeenCalledWith();
- });
-
- it('should display the correct label for the populate radio button', () => {
- expect(spectator.query(byTestId('populate-label')).textContent).toContain(
- 'Populate from Current Locale en-US'
- );
- });
-});
diff --git a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.ts b/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.ts
deleted file mode 100644
index ad8406608dad..000000000000
--- a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
-import { FormsModule } from '@angular/forms';
-
-import { ButtonDirective } from 'primeng/button';
-import { DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog';
-import { RadioButtonModule } from 'primeng/radiobutton';
-
-import { DotIsoCodePipe, DotMessagePipe } from '@dotcms/ui';
-
-@Component({
- selector: 'dot-edit-content-sidebar-untranslated-locale',
- imports: [RadioButtonModule, DotMessagePipe, FormsModule, ButtonDirective, DotIsoCodePipe],
- templateUrl: './dot-edit-content-sidebar-untranslated-locale.component.html',
- styleUrl: './dot-edit-content-sidebar-untranslated-locale.component.scss',
- changeDetection: ChangeDetectionStrategy.OnPush
-})
-export class DotEditContentSidebarUntranslatedLocaleComponent {
- selectedOption = 'populate';
-
- dialogRef = inject(DynamicDialogRef);
- config = inject(DynamicDialogConfig);
-}
diff --git a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/dot-edit-content-sidebar.component.html b/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/dot-edit-content-sidebar.component.html
index 53dba168b327..24a8ffc0fd67 100644
--- a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/dot-edit-content-sidebar.component.html
+++ b/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/dot-edit-content-sidebar.component.html
@@ -16,17 +16,29 @@
data-testId="sidebar-tabs">
-
+
-
+
-
+
@if (!isNew) {
-
+
}
diff --git a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/dot-edit-content-sidebar.component.ts b/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/dot-edit-content-sidebar.component.ts
index 0ad84a7fd216..074bb7347172 100644
--- a/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/dot-edit-content-sidebar.component.ts
+++ b/core-web/libs/edit-content/src/lib/components/dot-edit-content-sidebar/dot-edit-content-sidebar.component.ts
@@ -14,6 +14,7 @@ import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { DialogModule } from 'primeng/dialog';
import { SelectModule } from 'primeng/select';
import { TabsModule } from 'primeng/tabs';
+import { TooltipModule } from 'primeng/tooltip';
import { DotCMSBaseTypesContentTypes } from '@dotcms/dotcms-models';
import { DotCopyButtonComponent, DotMessagePipe } from '@dotcms/ui';
@@ -47,6 +48,7 @@ import { DotEditContentStore } from '../../store/edit-content.store';
DotEditContentSidebarInformationComponent,
DotEditContentSidebarWorkflowComponent,
TabsModule,
+ TooltipModule,
DotEditContentSidebarSectionComponent,
DotCopyButtonComponent,
ConfirmDialogModule,
diff --git a/core-web/libs/edit-content/src/lib/pipes/contentlet-status-tag.pipe.spec.ts b/core-web/libs/edit-content/src/lib/pipes/contentlet-status-tag.pipe.spec.ts
deleted file mode 100644
index 7a45d6520436..000000000000
--- a/core-web/libs/edit-content/src/lib/pipes/contentlet-status-tag.pipe.spec.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { TestBed } from '@angular/core/testing';
-
-import { DotMessageService } from '@dotcms/data-access';
-import { DotCMSContentlet } from '@dotcms/dotcms-models';
-
-import { ContentletStatusTagPipe } from './contentlet-status-tag.pipe';
-
-describe('ContentletStatusTagPipe', () => {
- let pipe: ContentletStatusTagPipe;
-
- beforeEach(() => {
- TestBed.configureTestingModule({
- providers: [
- ContentletStatusTagPipe,
- { provide: DotMessageService, useValue: { get: (arg: string) => arg } }
- ]
- });
- pipe = TestBed.inject(ContentletStatusTagPipe);
- });
-
- it('should return Published with success severity', () => {
- const contentlet = { live: true, working: false, archived: false } as DotCMSContentlet;
- const result = pipe.transform(contentlet);
- expect(result).toEqual({ label: 'Published', severity: 'success' });
- });
-
- it('should return Draft with secondary severity', () => {
- const contentlet = { live: false, working: true, archived: false } as DotCMSContentlet;
- const result = pipe.transform(contentlet);
- expect(result).toEqual({ label: 'Draft', severity: 'secondary' });
- });
-
- it('should return Changed with warn severity', () => {
- const contentlet = {
- live: true,
- working: true,
- workingInode: '1',
- liveInode: '2',
- archived: false
- } as DotCMSContentlet;
- const result = pipe.transform(contentlet);
- expect(result).toEqual({ label: 'Changed', severity: 'warn' });
- });
-
- it('should return Archived with contrast severity', () => {
- const contentlet = { live: false, working: false, archived: true } as DotCMSContentlet;
- const result = pipe.transform(contentlet);
- expect(result).toEqual({ label: 'Archived', severity: 'contrast' });
- });
-
- it('should return null for unknown status', () => {
- const contentlet = { live: false, working: false, archived: false } as DotCMSContentlet;
- const result = pipe.transform(contentlet);
- expect(result).toBeNull();
- });
-
- it('should return New with info severity for undefined contentlet', () => {
- const result = pipe.transform(undefined);
- expect(result).toEqual({ label: 'New', severity: 'info' });
- });
-});
diff --git a/core-web/libs/edit-content/src/lib/pipes/contentlet-status-tag.pipe.ts b/core-web/libs/edit-content/src/lib/pipes/contentlet-status-tag.pipe.ts
deleted file mode 100644
index 8102a5dc4fc4..000000000000
--- a/core-web/libs/edit-content/src/lib/pipes/contentlet-status-tag.pipe.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import { Pipe, PipeTransform, inject } from '@angular/core';
-
-import { DotMessageService } from '@dotcms/data-access';
-import { DotCMSContentlet } from '@dotcms/dotcms-models';
-
-import { DotEditContentStatus } from '../models/dot-edit-content-status.enum';
-
-/** PrimeNG Tag severity for p-tag */
-export type ContentletStatusTagSeverity =
- | 'success'
- | 'secondary'
- | 'info'
- | 'warn'
- | 'danger'
- | 'contrast';
-
-export interface ContentletStatusTagResult {
- label: string;
- severity: ContentletStatusTagSeverity;
-}
-
-const STATUS_TAG_CONFIG: Partial<
- Record
-> = {
- [DotEditContentStatus.PUBLISHED]: { label: 'Published', severity: 'success' },
- [DotEditContentStatus.DRAFT]: { label: 'Draft', severity: 'secondary' },
- [DotEditContentStatus.CHANGED]: { label: 'Changed', severity: 'warn' },
- [DotEditContentStatus.ARCHIVED]: { label: 'Archived', severity: 'contrast' },
- [DotEditContentStatus.UNKNOWN]: { label: '', severity: 'secondary' }
-};
-
-/**
- * Pipe that returns contentlet status as label + PrimeNG Tag severity for use with p-tag.
- * Returns null when there is no label to show (e.g. UNKNOWN).
- */
-@Pipe({
- name: 'contentletStatusTag'
-})
-export class ContentletStatusTagPipe implements PipeTransform {
- private readonly dotMessage = inject(DotMessageService);
-
- transform(contentlet?: DotCMSContentlet): ContentletStatusTagResult | null {
- if (!contentlet) {
- return {
- label: this.dotMessage.get('New'),
- severity: 'info'
- };
- }
-
- const status = this.getContentletStatus(contentlet);
- const config = STATUS_TAG_CONFIG[status];
- const label = this.dotMessage.get(config.label);
-
- return label ? { label, severity: config.severity } : null;
- }
-
- private getContentletStatus(contentlet: DotCMSContentlet): DotEditContentStatus {
- if (contentlet.archived) {
- return DotEditContentStatus.ARCHIVED;
- }
- if (contentlet.live) {
- return contentlet.workingInode === contentlet.liveInode
- ? DotEditContentStatus.PUBLISHED
- : DotEditContentStatus.CHANGED;
- }
- if (contentlet.working) {
- return DotEditContentStatus.DRAFT;
- }
- return DotEditContentStatus.UNKNOWN;
- }
-}
diff --git a/core-web/libs/edit-content/src/lib/store/features/locales/locales.feature.spec.ts b/core-web/libs/edit-content/src/lib/store/features/locales/locales.feature.spec.ts
index 9d2c56214317..07db509dc8ee 100644
--- a/core-web/libs/edit-content/src/lib/store/features/locales/locales.feature.spec.ts
+++ b/core-web/libs/edit-content/src/lib/store/features/locales/locales.feature.spec.ts
@@ -181,7 +181,7 @@ describe('LocalesFeature', () => {
onClose: of('populate')
} as DynamicDialogRef);
- tick();
+ spectator.flushEffects();
store.switchLocale(MOCK_LANGUAGES[2]);
tick();
@@ -209,7 +209,7 @@ describe('LocalesFeature', () => {
onClose: of('manual')
} as DynamicDialogRef);
- tick();
+ spectator.flushEffects();
store.switchLocale(MOCK_LANGUAGES[2]);
tick();
diff --git a/core-web/libs/edit-content/src/lib/store/features/locales/locales.feature.ts b/core-web/libs/edit-content/src/lib/store/features/locales/locales.feature.ts
index 522b4dcafa4f..2ab13488f97f 100644
--- a/core-web/libs/edit-content/src/lib/store/features/locales/locales.feature.ts
+++ b/core-web/libs/edit-content/src/lib/store/features/locales/locales.feature.ts
@@ -32,8 +32,12 @@ import {
DotContentletDepths,
DotLanguage
} from '@dotcms/dotcms-models';
+import {
+ BINARY_OPTION,
+ BinaryOptionDialogData,
+ DotBinaryOptionSelectorComponent
+} from '@dotcms/ui';
-import { DotEditContentSidebarUntranslatedLocaleComponent } from '../../../components/dot-edit-content-sidebar/components/dot-edit-content-sidebar-untranslated-locale/dot-edit-content-sidebar-untranslated-locale.component';
import { DotEditContentService } from '../../../services/dot-edit-content.service';
import {
prepareContentletForCopy,
@@ -241,19 +245,53 @@ export function withLocales() {
})
);
} else {
- const ref = dialogService.open(
- DotEditContentSidebarUntranslatedLocaleComponent,
- {
- header: dotMessageService.get(
- 'edit.content.sidebar.locales.untranslated.locale'
+ const currentLocale = store.currentLocale();
+ if (!currentLocale) return of(null);
+
+ const languageLabel = currentLocale.countryCode
+ ? `${currentLocale.language} (${currentLocale.countryCode})`
+ : currentLocale.language;
+
+ const options: BINARY_OPTION = {
+ option1: {
+ value: 'populate',
+ label: dotMessageService.get(
+ 'edit.content.sidebar.locales.untranslated.populate',
+ languageLabel
+ ),
+ message: dotMessageService.get(
+ 'edit.content.sidebar.locales.untranslated.populate.message',
+ languageLabel
),
- width: '35rem',
- data: {
- currentLocale: store.currentLocale()
- },
- modal: true
+ buttonLabel: 'edit.content.sidebar.locales.continue'
+ },
+ option2: {
+ value: 'manual',
+ label: dotMessageService.get(
+ 'edit.content.sidebar.locales.untranslated.manually'
+ ),
+ message: dotMessageService.get(
+ 'edit.content.sidebar.locales.untranslated.manually.message'
+ ),
+ buttonLabel: 'edit.content.sidebar.locales.continue'
}
- );
+ };
+
+ const ref = dialogService.open(DotBinaryOptionSelectorComponent, {
+ header: dotMessageService.get(
+ 'edit.content.sidebar.locales.untranslated.locale'
+ ),
+ width: '35rem',
+ contentStyle: { padding: '0' },
+ closable: true,
+ closeOnEscape: true,
+ modal: true,
+ data: {
+ options,
+ description:
+ 'edit.content.sidebar.locales.untranslated.text'
+ } satisfies BinaryOptionDialogData
+ });
ref.onClose
.pipe(
diff --git a/core-web/libs/ui/src/lib/components/dot-binary-option-selector/dot-binary-option-selector.component.html b/core-web/libs/ui/src/lib/components/dot-binary-option-selector/dot-binary-option-selector.component.html
index a4cb0c976067..14134444bda0 100644
--- a/core-web/libs/ui/src/lib/components/dot-binary-option-selector/dot-binary-option-selector.component.html
+++ b/core-web/libs/ui/src/lib/components/dot-binary-option-selector/dot-binary-option-selector.component.html
@@ -1,3 +1,6 @@
+@if (description) {
+ {{ description | dm }}
+}