mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
[MNT-25612] ADW Metadata Drawer ignores read‑only presets (readOnlyAs… (#12095)
This commit is contained in:
+13
-1
@@ -299,6 +299,18 @@ describe('ContentMetadataComponent', () => {
|
|||||||
expect(contentMetadataService.getGroupedProperties).toHaveBeenCalled();
|
expect(contentMetadataService.getGroupedProperties).toHaveBeenCalled();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should pass preset to getBasicProperties when calling getProperties', fakeAsync(() => {
|
||||||
|
const testNode = { ...node, name: 'test-node' };
|
||||||
|
component.preset = 'custom-preset';
|
||||||
|
const getBasicPropertiesSpy = spyOn(contentMetadataService, 'getBasicProperties').and.returnValue(of([]));
|
||||||
|
getGroupedPropertiesSpy.and.returnValue(of([]));
|
||||||
|
|
||||||
|
component.ngOnChanges({ node: new SimpleChange(null, testNode, false) });
|
||||||
|
tick(600);
|
||||||
|
|
||||||
|
expect(getBasicPropertiesSpy).toHaveBeenCalledWith(testNode, 'custom-preset');
|
||||||
|
}));
|
||||||
|
|
||||||
describe('Save button - Grouped Properties', () => {
|
describe('Save button - Grouped Properties', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
getGroupedPropertiesSpy.and.returnValue(
|
getGroupedPropertiesSpy.and.returnValue(
|
||||||
@@ -858,7 +870,7 @@ describe('ContentMetadataComponent', () => {
|
|||||||
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
|
component.ngOnChanges({ node: new SimpleChange(node, expectedNode, false) });
|
||||||
|
|
||||||
expect(contentMetadataService.getContentTypeProperty).toHaveBeenCalledWith(expectedNode);
|
expect(contentMetadataService.getContentTypeProperty).toHaveBeenCalledWith(expectedNode);
|
||||||
expect(contentMetadataService.getBasicProperties).toHaveBeenCalledWith(expectedNode);
|
expect(contentMetadataService.getBasicProperties).toHaveBeenCalledWith(expectedNode, preset);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pass through the loaded basic properties to the card view', async () => {
|
it('should pass through the loaded basic properties to the card view', async () => {
|
||||||
|
|||||||
+1
-1
@@ -473,7 +473,7 @@ export class ContentMetadataComponent implements OnChanges, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getProperties(node: Node) {
|
private getProperties(node: Node) {
|
||||||
const properties$ = this.contentMetadataService.getBasicProperties(node);
|
const properties$ = this.contentMetadataService.getBasicProperties(node, this.preset);
|
||||||
const contentTypeProperty$ = this.contentMetadataService.getContentTypeProperty(node);
|
const contentTypeProperty$ = this.contentMetadataService.getContentTypeProperty(node);
|
||||||
return zip(properties$, contentTypeProperty$).pipe(
|
return zip(properties$, contentTypeProperty$).pipe(
|
||||||
map(([properties, contentTypeProperty]) => {
|
map(([properties, contentTypeProperty]) => {
|
||||||
|
|||||||
+35
@@ -214,6 +214,41 @@ describe('ContentMetaDataService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should mark basic properties as read-only when preset defines readOnlyProperties (includeAll)', async () => {
|
||||||
|
setConfig('custom', [{ includeAll: true, readOnlyProperties: ['cm:name', 'cm:title'] }]);
|
||||||
|
|
||||||
|
const res = await firstValueFrom(service.getBasicProperties(fakeNode, 'custom'));
|
||||||
|
const nameProperty = res.find((property) => property.key === 'properties.cm:name');
|
||||||
|
const titleProperty = res.find((property) => property.key === 'properties.cm:title');
|
||||||
|
const authorProperty = res.find((property) => property.key === 'properties.cm:author');
|
||||||
|
|
||||||
|
expect(nameProperty.editable).toBeFalse();
|
||||||
|
expect(titleProperty.editable).toBeFalse();
|
||||||
|
expect(authorProperty.editable).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should mark basic properties as read-only when layout items are not editable', async () => {
|
||||||
|
setConfig('custom', [
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{ type: 'cm:content', properties: ['cm:name'], editable: false },
|
||||||
|
{ aspect: 'cm:titled', properties: ['cm:title', 'cm:description'], editable: false }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const res = await firstValueFrom(service.getBasicProperties(fakeNode, 'custom'));
|
||||||
|
const nameProperty = res.find((property) => property.key === 'properties.cm:name');
|
||||||
|
const titleProperty = res.find((property) => property.key === 'properties.cm:title');
|
||||||
|
const descriptionProperty = res.find((property) => property.key === 'properties.cm:description');
|
||||||
|
const authorProperty = res.find((property) => property.key === 'properties.cm:author');
|
||||||
|
|
||||||
|
expect(nameProperty.editable).toBeFalse();
|
||||||
|
expect(titleProperty.editable).toBeFalse();
|
||||||
|
expect(descriptionProperty.editable).toBeFalse();
|
||||||
|
expect(authorProperty.editable).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
it('should return the content type property', () => {
|
it('should return the content type property', () => {
|
||||||
spyOn(contentPropertyService, 'getContentTypeCardItem').and.returnValue(of([{ label: 'hello i am a weird content type' } as CardViewItem]));
|
spyOn(contentPropertyService, 'getContentTypeCardItem').and.returnValue(of([{ label: 'hello i am a weird content type' } as CardViewItem]));
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,22 @@ import { Node } from '@alfresco/js-api';
|
|||||||
import { BasicPropertiesService } from './basic-properties.service';
|
import { BasicPropertiesService } from './basic-properties.service';
|
||||||
import { Observable, of, iif, Subject } from 'rxjs';
|
import { Observable, of, iif, Subject } from 'rxjs';
|
||||||
import { PropertyGroupTranslatorService } from './property-groups-translator.service';
|
import { PropertyGroupTranslatorService } from './property-groups-translator.service';
|
||||||
import { CardViewItem } from '@alfresco/adf-core';
|
import { AppConfigService, CardViewItem } from '@alfresco/adf-core';
|
||||||
import { CardViewGroup, OrganisedPropertyGroup, PresetConfig } from '../interfaces/content-metadata.interfaces';
|
import { CardViewGroup, OrganisedPropertyGroup, PresetConfig } from '../interfaces/content-metadata.interfaces';
|
||||||
import { ContentMetadataConfigFactory } from './config/content-metadata-config.factory';
|
import { ContentMetadataConfigFactory } from './config/content-metadata-config.factory';
|
||||||
import { PropertyDescriptorsService } from './property-descriptors.service';
|
import { PropertyDescriptorsService } from './property-descriptors.service';
|
||||||
import { map, switchMap } from 'rxjs/operators';
|
import { map, switchMap } from 'rxjs/operators';
|
||||||
import { ContentTypePropertiesService } from './content-type-property.service';
|
import { ContentTypePropertiesService } from './content-type-property.service';
|
||||||
|
import { LayoutOrientedConfig, LayoutOrientedConfigLayoutBlock } from '../interfaces/layout-oriented-config.interface';
|
||||||
|
import { Property } from '../interfaces/property.interface';
|
||||||
|
|
||||||
|
interface LayoutBlockWithReadOnly extends LayoutOrientedConfigLayoutBlock {
|
||||||
|
readOnlyProperties?: string | string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const CONTENT_METADATA_CONFIG_KEY = 'content-metadata';
|
||||||
|
const BASIC_PROPERTY_KEY_PREFIX = 'properties.';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
@@ -35,11 +45,62 @@ export class ContentMetadataService {
|
|||||||
private readonly propertyGroupTranslatorService = inject(PropertyGroupTranslatorService);
|
private readonly propertyGroupTranslatorService = inject(PropertyGroupTranslatorService);
|
||||||
private readonly propertyDescriptorsService = inject(PropertyDescriptorsService);
|
private readonly propertyDescriptorsService = inject(PropertyDescriptorsService);
|
||||||
private readonly contentTypePropertyService = inject(ContentTypePropertiesService);
|
private readonly contentTypePropertyService = inject(ContentTypePropertiesService);
|
||||||
|
private readonly appConfig = inject(AppConfigService);
|
||||||
|
|
||||||
error = new Subject<{ statusCode: number; message: string }>();
|
error = new Subject<{ statusCode: number; message: string }>();
|
||||||
|
|
||||||
getBasicProperties(node: Node): Observable<CardViewItem[]> {
|
getBasicProperties(node: Node, preset: string | PresetConfig = 'default'): Observable<CardViewItem[]> {
|
||||||
return of(this.basicPropertiesService.getProperties(node));
|
const properties = this.basicPropertiesService.getProperties(node);
|
||||||
|
const readOnlyProperties = this.getReadOnlyPropertyNames(preset);
|
||||||
|
|
||||||
|
if (readOnlyProperties.length) {
|
||||||
|
properties.forEach((property) => {
|
||||||
|
const propertyName = this.getBasicPropertyName(property.key);
|
||||||
|
if (propertyName && readOnlyProperties.includes(propertyName)) {
|
||||||
|
property.editable = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return of(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBasicPropertyName(key: string): string | undefined {
|
||||||
|
return key?.startsWith(BASIC_PROPERTY_KEY_PREFIX) ? key.slice(BASIC_PROPERTY_KEY_PREFIX.length) : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getReadOnlyPropertyNames(preset: string | PresetConfig): string[] {
|
||||||
|
const presetConfig = typeof preset === 'string' ? this.appConfig.config[CONTENT_METADATA_CONFIG_KEY]?.presets?.[preset] : preset;
|
||||||
|
|
||||||
|
if (this.isLayoutConfig(presetConfig)) {
|
||||||
|
return presetConfig.reduce((readOnly, block) => readOnly.concat(this.getLayoutBlockReadOnlyNames(block)), [] as string[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presetConfig != null && typeof presetConfig === 'object') {
|
||||||
|
return this.normaliseToArray(presetConfig.readOnlyProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private isLayoutConfig(config: unknown): config is LayoutOrientedConfig {
|
||||||
|
return Array.isArray(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getLayoutBlockReadOnlyNames(block: LayoutBlockWithReadOnly): string[] {
|
||||||
|
const blockReadOnly = this.normaliseToArray(block?.readOnlyProperties);
|
||||||
|
const nonEditableItems = (block?.items || [])
|
||||||
|
.filter((item) => item?.editable === false)
|
||||||
|
.reduce((names, item) => names.concat(this.normaliseToArray(item.properties)), [] as string[]);
|
||||||
|
|
||||||
|
return blockReadOnly.concat(nonEditableItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
private normaliseToArray(value: string | string[] | Property[] | undefined): string[] {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map((item) => (typeof item === 'string' ? item : item?.name)).filter((name): name is string => typeof name === 'string');
|
||||||
|
}
|
||||||
|
return typeof value === 'string' ? [value] : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getContentTypeProperty(node: Node): Observable<CardViewItem[]> {
|
getContentTypeProperty(node: Node): Observable<CardViewItem[]> {
|
||||||
|
|||||||
Reference in New Issue
Block a user