Skip to content

Commit f8a2555

Browse files
authored
Merge pull request #3909 from shesha-io/omolemo/form-configs-updates
Form templates config studio fix
2 parents 7a8c4cd + dd4e40c commit f8a2555

File tree

8 files changed

+112
-31
lines changed

8 files changed

+112
-31
lines changed
Binary file not shown.

shesha-core/src/Shesha.Application/Metadata/IMetadataAppService.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ public interface IMetadataAppService: IApplicationService
4040
/// <summary>
4141
/// Get properties of the specified container
4242
/// </summary>
43-
Task<List<PropertyMetadataDto>> GetPropertiesAsync(string container);
43+
Task<List<PropertyMetadataDto>> GetPropertiesAsync(string container);
44+
45+
/// <summary>
46+
/// Get properties of the specified container excluding framework-related properties (e.g. CreationTime, DeletionTime etc)
47+
/// </summary>
48+
Task<List<PropertyMetadataDto>> GetNonFrameworkRelatedPropertiesAsync(string container);
4449

4550
/// <summary>
4651
/// Get full metadata of the specified container

shesha-core/src/Shesha.Application/Metadata/MetadataAppService.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,18 @@ public async Task<List<PropertyMetadataDto>> GetPropertiesAsync(string container
134134
return properties;
135135
}
136136

137+
/// inheritedDoc
138+
[HttpGet]
139+
public async Task<List<PropertyMetadataDto>> GetNonFrameworkRelatedPropertiesAsync(string container)
140+
{
141+
if (string.IsNullOrWhiteSpace(container))
142+
throw new AbpValidationException($"'{nameof(container)}' is mandatory");
143+
144+
var containerType = await _metadataProvider.GetContainerTypeAsync(null, container);
145+
var properties = await _metadataProvider.GetPropertiesAsync(containerType);
146+
return properties.Where(x => x.IsFrameworkRelated == false).ToList();
147+
}
148+
137149
/// inheritedDoc
138150
[HttpGet]
139151
public async Task<MetadataDto> GetAsync(string container)

shesha-core/src/Shesha.Application/Shesha.Application.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
<None Remove="ConfigMigrations\package20250915_1416.shaconfig" />
8989
<None Remove="ConfigMigrations\package20250909_1553.shaconfig" />
9090
<None Remove="ConfigMigrations\package20250922_0858.shaconfig" />
91+
<None Remove="ConfigMigrations\package20250926_1642.shaconfig" />
9192
<None Remove="ConfigMigrations\package20250926_1654.shaconfig" />
9293
<None Remove="Excel\template.xlsx" />
9394
<None Remove="ConfigMigrations\package20230324_1835.shaconfig" />
@@ -144,6 +145,7 @@
144145
<EmbeddedResource Include="ConfigMigrations\package20250915_1416.shaconfig" />
145146
<EmbeddedResource Include="ConfigMigrations\package20250909_1553.shaconfig" />
146147
<EmbeddedResource Include="ConfigMigrations\package20250922_0858.shaconfig" />
148+
<EmbeddedResource Include="ConfigMigrations\package20250926_1642.shaconfig" />
147149
<EmbeddedResource Include="ConfigMigrations\package20250926_1654.shaconfig" />
148150
<EmbeddedResource Include="Excel\template.xlsx" />
149151
<EmbeddedResource Include="ConfigMigrations\package20230324_1835.shaconfig" />

shesha-reactjs/src/interfaces/toolbarSettings.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ import { IQuickSearchComponentProps } from '@/designer-components/dataTable/quic
4444
import { IPagerComponentProps } from '@/designer-components/dataTable/pager/pagerComponent';
4545
import { ITableViewSelectorComponentProps } from '@/designer-components/dataTable/tableViewSelector/models';
4646
import { nanoid } from '@/utils/uuid';
47+
import { IDateFieldProps } from '@/designer-components/dateField/interfaces';
48+
import { ITimePickerProps } from '@/designer-components/timeField/models';
49+
import { IFileUploadProps } from '@/designer-components/fileUpload';
4750

4851
interface ToolbarSettingsProp extends Omit<IConfigurableFormComponent, 'id' | 'hidden' | 'type'> {
4952
id?: string;
@@ -91,6 +94,12 @@ type ReferenceListAutocompleteType = ToolbarSettingsProp & Omit<IReferenceListAu
9194

9295
type CheckboxType = ToolbarSettingsProp & Omit<ICheckboxComponentProps, 'hidden' | 'type'>;
9396

97+
type DateFieldType = ToolbarSettingsProp & Omit<IDateFieldProps, 'hidden' | 'type'>;
98+
99+
type TimePickerType = ToolbarSettingsProp & Omit<ITimePickerProps, 'hidden' | 'type'>;
100+
101+
type FileUploadType = ToolbarSettingsProp & Omit<IFileUploadProps, 'hidden' | 'type'>;
102+
94103
type SwitchType = ToolbarSettingsProp & Omit<ISwitchComponentProps, 'hidden' | 'type'>;
95104

96105
type NumberFieldType = ToolbarSettingsProp & Omit<INumberFieldComponentProps, 'hidden' | 'type'>;
@@ -284,6 +293,18 @@ export class DesignerToolbarSettings<T> {
284293
return this.addProperty(props, 'checkbox');
285294
}
286295

296+
public addDateField(props: DateFieldType | ((data: T) => DateFieldType)) {
297+
return this.addProperty(props, 'dateField');
298+
}
299+
300+
public addTimePicker(props: TimePickerType | ((data: T) => TimePickerType)) {
301+
return this.addProperty(props, 'timePicker');
302+
}
303+
304+
public addFileUpload(props: FileUploadType | ((data: T) => FileUploadType)) {
305+
return this.addProperty(props, 'fileUpload');
306+
}
307+
287308
public addSwitch(props: SwitchType | ((data: T) => SwitchType)) {
288309
return this.addProperty(props, 'switch');
289310
}

shesha-reactjs/src/providers/sheshaApplication/publicApi/forms/generation-logic/details-view/detailsViewGenerationLogic.ts

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,17 @@ export class DetailsViewGenerationLogic extends BaseGenerationLogic {
3131
try {
3232
const extensionJson = castToExtensionType<DetailsViewExtensionJson>(replacements);
3333

34-
// Add header components
35-
this.addHeader(entity, nonFrameworkProperties, markup, extensionJson, metadataHelper);
34+
// Add header components and get properties used in key information bar
35+
const usedKeyInfoPropertyPaths = this.addHeader(entity, nonFrameworkProperties, markup, extensionJson, metadataHelper);
3636

37-
// Add details panel - using shared function
38-
addDetailsPanel(nonFrameworkProperties, markup, metadataHelper);
37+
// Filter out properties shown in the key information bar
38+
const propertiesForDetailsPanel = nonFrameworkProperties.filter((prop) => {
39+
const propIdentifier = prop.path || prop.label || '';
40+
return !usedKeyInfoPropertyPaths.includes(propIdentifier);
41+
});
42+
43+
// Add details panel - using shared function with filtered properties
44+
addDetailsPanel(propertiesForDetailsPanel, markup, metadataHelper);
3945

4046
// Add child tables if configured
4147
if (extensionJson.addChildTables) {
@@ -69,8 +75,9 @@ export class DetailsViewGenerationLogic extends BaseGenerationLogic {
6975
* @param markup The JSON markup object.
7076
* @param extensionJson The extension configuration.
7177
* @param metadataHelper The metadata helper instance.
78+
* @returns Array of property paths used in key information bar, empty array if none used
7279
*/
73-
private addHeader(entity: IEntityMetadata, metadata: PropertyMetadataDto[], markup: any, extensionJson: DetailsViewExtensionJson, metadataHelper: FormMetadataHelper): void {
80+
private addHeader(entity: IEntityMetadata, metadata: PropertyMetadataDto[], markup: any, extensionJson: DetailsViewExtensionJson, metadataHelper: FormMetadataHelper): string[] {
7481
const title = `${entity.typeAccessor} Details`;
7582

7683
const titleContainer = findContainersWithPlaceholder(markup, "//*TITLE*//");
@@ -81,23 +88,33 @@ export class DetailsViewGenerationLogic extends BaseGenerationLogic {
8188

8289
titleContainer[0].content = title;
8390

91+
// Keep track of property paths used in key information bar
92+
const usedKeyInfoPropertyPaths: string[] = [];
93+
8494
// Add key information bar if configured
85-
const builder = new DesignerToolbarSettings({});
86-
if (extensionJson.showKeyInformationBar) {
95+
if (extensionJson.showKeyInformationBar && extensionJson.keyInformationBarProperties?.length) {
8796
const keyInfoBarContainer = findContainersWithPlaceholder(markup, "//*KEYINFOBAR*//");
8897

8998
if (keyInfoBarContainer.length === 0) {
9099
throw new Error("No key information bar container found in the markup.");
91100
}
101+
102+
// Save paths of properties that will be used in the key info bar
103+
extensionJson.keyInformationBarProperties.forEach((path) => {
104+
usedKeyInfoPropertyPaths.push(path);
105+
});
106+
92107
const keyInfoProperties = metadata.filter((x) =>
93108
extensionJson.keyInformationBarProperties?.includes(x.path || x.label || '')
94109
);
95110

96111
if (keyInfoProperties.length === 0) {
97112
console.warn(`No key information properties found for the key information bar. Requested properties: ${extensionJson.keyInformationBarProperties?.join(', ')}`);
98-
return;
113+
return usedKeyInfoPropertyPaths;
99114
} else {
100-
builder.addKeyInformationBar({
115+
const keyInfoBarBuilder = new DesignerToolbarSettings({});
116+
117+
keyInfoBarBuilder.addKeyInformationBar({
101118
id: nanoid(),
102119
propertyName: "keyInformationBar",
103120
label: "Key Information Bar",
@@ -107,7 +124,6 @@ export class DetailsViewGenerationLogic extends BaseGenerationLogic {
107124
componentName: "keyInformationBar",
108125
columns: keyInfoProperties.map((prop) => {
109126
const keyInfoBuilder = new DesignerToolbarSettings({});
110-
const keyInfoBarContainer = new DesignerToolbarSettings({});
111127

112128
keyInfoBuilder.addText({
113129
id: nanoid(),
@@ -129,35 +145,23 @@ export class DetailsViewGenerationLogic extends BaseGenerationLogic {
129145

130146
metadataHelper.getConfigFields(prop, keyInfoBuilder, true);
131147

132-
keyInfoBarContainer.addContainer({
133-
id: nanoid(),
134-
propertyName: 'keyInfoContainer',
135-
label: 'Key Information',
136-
editMode: 'inherited' as EditMode,
137-
hidden: false,
138-
componentName: 'keyInfoContainer',
139-
direction: 'vertical',
140-
desktop: {
141-
justifyContent: 'center',
142-
},
143-
components: keyInfoBuilder.toJson(),
144-
});
145-
146148
return {
147149
id: nanoid(),
148150
width: 200,
149-
flexDirection: 'row',
150-
textAlign: 'start',
151-
components: keyInfoBarContainer.toJson(),
151+
flexDirection: 'column',
152+
textAlign: 'center',
153+
components: keyInfoBuilder.toJson(),
152154
};
153155
}),
154156
});
155157

156158
if (keyInfoBarContainer[0].components && Array.isArray(keyInfoBarContainer[0].components)) {
157-
keyInfoBarContainer[0].components.push(...builder.toJson());
159+
keyInfoBarContainer[0].components.push(...keyInfoBarBuilder.toJson());
158160
}
159161
}
160162
}
163+
164+
return usedKeyInfoPropertyPaths;
161165
}
162166

163167
/**
@@ -254,6 +258,7 @@ export class DetailsViewGenerationLogic extends BaseGenerationLogic {
254258
itemType: 'item',
255259
minWidth: width.min,
256260
maxWidth: width.max,
261+
allowSorting: true,
257262
};
258263
});
259264

shesha-reactjs/src/providers/sheshaApplication/publicApi/forms/generation-logic/formMetadataHelper.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { isPropertiesArray, isPropertiesLoader } from "@/interfaces/metadata";
1212
export class FormMetadataHelper {
1313
private _metadataDispatcher: IMetadataDispatcher;
1414

15+
private _modelType: string | null = null;
16+
1517
/**
1618
* Creates an instance of FormMetadataHelper.
1719
* @param metadataDispatcher The metadata dispatcher to use for fetching entity metadata.
@@ -32,6 +34,8 @@ export class FormMetadataHelper {
3234
}
3335

3436
try {
37+
// Store the model type for use in other methods
38+
this._modelType = modelType;
3539
const metadata = await this._metadataDispatcher.getMetadata({
3640
modelType: modelType,
3741
dataType: DataTypes.entityReference,
@@ -194,17 +198,46 @@ export class FormMetadataHelper {
194198
builder.addDropdown({
195199
...commonProps,
196200
dataSourceType: 'referenceList',
201+
border: {
202+
hideBorder: false,
203+
radiusType: 'all',
204+
borderType: 'all',
205+
border: {
206+
all: { width: 1, style: 'solid', color: '#d9d9d9' },
207+
},
208+
radius: { all: 8 },
209+
},
197210
referenceListName: property.referenceListName,
198211
referenceListId: {
199212
module: property.referenceListModule,
200-
name: property.referenceListName },
213+
name: property.referenceListName,
214+
},
201215
});
202216
break;
203217

204218
case DataTypes.boolean:
205219
builder.addCheckbox(commonProps);
206220
break;
207221

222+
case DataTypes.date:
223+
case DataTypes.dateTime:
224+
builder.addDateField(commonProps);
225+
break;
226+
227+
case DataTypes.time:
228+
builder.addTimePicker(commonProps);
229+
break;
230+
231+
case DataTypes.file:
232+
builder.addFileUpload({
233+
...commonProps,
234+
font: {
235+
size: 14,
236+
},
237+
ownerId: '{data.id}',
238+
ownerType: this._modelType || '',
239+
});
240+
break;
208241
default:
209242
break;
210243
}

shesha-reactjs/src/providers/sheshaApplication/publicApi/forms/generation-logic/table-view/tableViewGenerationLogic.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,11 @@ export class TableViewGenerationLogic extends BaseGenerationLogic {
134134
// Implementation for adding columns to the markup
135135
const builder = new DesignerToolbarSettings({});
136136

137+
const dataTableName = `datatable ${nanoid()}`;
137138
builder.addDatatable({
138139
id: nanoid(),
139-
propertyName: `datatable ${nanoid()}`,
140+
propertyName: dataTableName,
141+
componentName: dataTableName,
140142
items: sortedProperties.map((prop, idx) => {
141143
// Get column width based on data type
142144
const width = getColumnWidthByDataType(prop.dataType, prop.dataFormat);
@@ -152,6 +154,7 @@ export class TableViewGenerationLogic extends BaseGenerationLogic {
152154
itemType: 'item',
153155
minWidth: width.min,
154156
maxWidth: width.max,
157+
allowSorting: true,
155158
};
156159
}),
157160
});

0 commit comments

Comments
 (0)