Skip to content

Commit

Permalink
fix(Admin UI): add functionality to reorder toStringAttributes (#2334)
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhinegi2 authored Apr 17, 2024
1 parent d64f937 commit 4913dab
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,24 @@ <h2 i18n>General Settings of "{{ entityConstructor.label }}" Records</h2>
</div>

<div class="entity-form-cell">
<mat-form-field floatLabel="always">
<mat-form-field>
<mat-label i18n>
Generated Title of Record
<fa-icon
icon="question-circle"
matTooltip="Select the fields that should be used (in that order) to generate a simple name/title for a record. This generated title is used in previews, search and for form fields that allow to select a record of this type."
matTooltip="Select the fields that should be used (in that order) to generate a simple name/title for a record. This generated title is used in previews, search and for form fields that allow to select a record of this type. (Only text fields can be used here)"
i18n-matTooltip
></fa-icon>
</mat-label>
<input
<app-basic-autocomplete
formControlName="toStringAttributes"
matInput
[placeholder]="formLabel.value"
/>
#formDataType
[options]="toStringAttributesOptions"
[optionToString]="objectToLabel"
[valueMapper]="objectToValue"
[multi]="true"
[reorder]="true"
></app-basic-autocomplete>
</mat-form-field>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { ReactiveFormsModule, FormsModule } from "@angular/forms";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { MatButtonModule } from "@angular/material/button";
import { MatInputModule } from "@angular/material/input";
import { MatTabsModule } from "@angular/material/tabs";
Expand Down Expand Up @@ -51,7 +51,7 @@ describe("AdminEntityGeneralSettingsComponent", () => {
fixture = TestBed.createComponent(AdminEntityGeneralSettingsComponent);
component = fixture.componentInstance;
component.entityConstructor = mockEntityConstructor;
component.config = { label: "Test Label" };
component.generalSettings = { label: "Test Label" };
fixture.detectChanges();
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
import {
Component,
EventEmitter,
Input,
Output,
OnChanges,
SimpleChanges,
OnInit,
} from "@angular/core";
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { EntityConstructor } from "../../../entity/model/entity";
import { MatButtonModule } from "@angular/material/button";
import { DialogCloseComponent } from "../../../common-components/dialog-close/dialog-close.component";
Expand All @@ -26,6 +18,7 @@ import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import { MatTooltipModule } from "@angular/material/tooltip";
import { BasicAutocompleteComponent } from "../../../common-components/basic-autocomplete/basic-autocomplete.component";
import { EntityConfig } from "../../../entity/entity-config";
import { StringDatatype } from "../../../basic-datatypes/string/string.datatype";

@Component({
selector: "app-admin-entity-general-settings",
Expand All @@ -47,59 +40,74 @@ import { EntityConfig } from "../../../entity/entity-config";
BasicAutocompleteComponent,
],
})
export class AdminEntityGeneralSettingsComponent implements OnChanges, OnInit {
export class AdminEntityGeneralSettingsComponent implements OnInit {
@Input() entityConstructor: EntityConstructor;
@Output() generalSettingsChange: EventEmitter<EntityConfig> =
new EventEmitter<EntityConfig>();
@Input() config: EntityConfig;
@Input() generalSettings: EntityConfig;

form: FormGroup;
basicSettingsForm: FormGroup;
toStringAttributesOptions: SimpleDropdownValue[] = [];

constructor(private fb: FormBuilder) {}

ngOnInit(): void {
this.init();
}

ngOnChanges(changes: SimpleChanges): void {
if (changes.config) {
this.init();
}
}

private init() {
this.basicSettingsForm = this.fb.group({
label: [this.config.label, Validators.required],
labelPlural: [this.config.labelPlural],
icon: [this.config.icon, Validators.required],
toStringAttributes: [this.config.toStringAttributes, Validators.required],
label: [this.generalSettings.label, Validators.required],
labelPlural: [this.generalSettings.labelPlural],
icon: [this.generalSettings.icon, Validators.required],
toStringAttributes: [
this.generalSettings.toStringAttributes,
Validators.required,
],
});
this.form = this.fb.group({
basicSettings: this.basicSettingsForm,
});
this.initToStringAttributesOptions();

this.form.valueChanges.subscribe((value) => {
this.emitStaticDetails(); // Optionally, emit the initial value
// Emit the updated value
this.generalSettingsChange.emit(this.basicSettingsForm.getRawValue()); // Optionally, emit the initial value
});
}

emitStaticDetails() {
const toStringAttributesControl =
this.basicSettingsForm.get("toStringAttributes");
let toStringAttributesValue = toStringAttributesControl.value;
// Convert toStringAttributesValue to an array if it's a string
if (typeof toStringAttributesValue === "string") {
toStringAttributesValue = toStringAttributesValue
.split(",")
.map((item) => item.trim());
private initToStringAttributesOptions() {
if (!this.generalSettings.toStringAttributes) {
return;
}

// Update the form control with the modified value
toStringAttributesControl.setValue(toStringAttributesValue, {
emitEvent: false,
});
const selectedOptions = this.generalSettings.toStringAttributes;
const unselectedOptions = Array.from(
this.entityConstructor.schema.entries(),
)
.filter(
([key, field]) =>
field.dataType === StringDatatype.dataType &&
field.label &&
!selectedOptions.includes(key),
)
.map(([key, field]) => ({ key: key, label: field.label }));

// Emit the updated value
this.generalSettingsChange.emit(this.basicSettingsForm.getRawValue());
this.toStringAttributesOptions = [
...selectedOptions.map((key) => ({
key: key,
label: this.entityConstructor.schema.get(key)?.label,
})),
...unselectedOptions,
];
}

objectToLabel = (v: SimpleDropdownValue) => v?.label;
objectToValue = (v: SimpleDropdownValue) => v?.key;
}

interface SimpleDropdownValue {
key: string;
label: string;
}
3 changes: 1 addition & 2 deletions src/app/core/admin/admin-entity/admin-entity.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@
@case ("general") {
<app-admin-entity-general-settings
[entityConstructor]="entityConstructor"
(generalSettingsChange)="configEntitySettings = $event"
[config]="configEntitySettings"
[(generalSettings)]="configEntitySettings"
></app-admin-entity-general-settings>
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,42 @@
autoActiveFirstOption
[hideSingleSelectionIndicator]="multi"
>
<mat-option
*ngFor="let item of autocompleteSuggestedOptions | async"
[value]="item"
<div
cdkDropList
(cdkDropListDropped)="drop($event)"
cdkDropListGroup
[cdkDropListDisabled]="!reorder"
>
<div class="flex-row disable-autocomplete-active-color">
<mat-checkbox *ngIf="multi" [checked]="item.selected"></mat-checkbox>

<ng-container *ngIf="!templateRef; else itemTemplate">
{{ item.asString }}
</ng-container>

<ng-template
class="item-option"
#itemTemplate
[ngTemplateOutlet]="templateRef"
[ngTemplateOutletContext]="{ $implicit: item.initial }"
></ng-template>
</div>
</mat-option>
<ng-container
*ngFor="
let item of reorder
? autocompleteDraggableOptions
: (autocompleteSuggestedOptions | async)
"
>
<mat-option [value]="item" cdkDrag>
<div class="flex-row disable-autocomplete-active-color align-center">
<div *ngIf="reorder">
<fa-icon
icon="grip-vertical"
size="sm"
class="drag-handle"
></fa-icon>
</div>
<mat-checkbox *ngIf="multi" [checked]="item.selected"></mat-checkbox>
<ng-container *ngIf="!templateRef; else itemTemplate">
{{ item.asString }}
</ng-container>
<ng-template
class="item-option"
#itemTemplate
[ngTemplateOutlet]="templateRef"
[ngTemplateOutletContext]="{ $implicit: item.initial }"
></ng-template>
</div>
</mat-option>
</ng-container>
</div>

<!-- Create new option -->
<mat-option
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ import {
import { FaIconComponent } from "@fortawesome/angular-fontawesome";
import { MatTooltip } from "@angular/material/tooltip";
import { MatIcon } from "@angular/material/icon";
import {
CdkDragDrop,
DragDropModule,
moveItemInArray,
} from "@angular/cdk/drag-drop";

interface SelectableOption<O, V> {
initial: O;
Expand Down Expand Up @@ -79,6 +84,7 @@ interface SelectableOption<O, V> {
MatTooltip,
MatIcon,
MatChipRemove,
DragDropModule,
],
})
export class BasicAutocompleteComponent<O, V = O>
Expand All @@ -101,6 +107,8 @@ export class BasicAutocompleteComponent<O, V = O>
* Whether the user should be able to select multiple values.
*/
@Input() multi?: boolean;
@Input() reorder?: boolean;
autocompleteDraggableOptions: SelectableOption<O, V>[] = [];

autocompleteForm = new FormControl("");
autocompleteSuggestedOptions = this.autocompleteForm.valueChanges.pipe(
Expand Down Expand Up @@ -164,6 +172,12 @@ export class BasicAutocompleteComponent<O, V = O>
);
}

ngOnInit() {
this.autocompleteSuggestedOptions.subscribe((options) => {
this.autocompleteDraggableOptions = options;
});
}

ngOnChanges(changes: { [key in keyof this]?: any }) {
if (changes.valueMapper) {
this._options.forEach(
Expand All @@ -185,6 +199,27 @@ export class BasicAutocompleteComponent<O, V = O>
}
}

drop(event: CdkDragDrop<any[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(
this.autocompleteDraggableOptions,
event.previousIndex,
event.currentIndex,
);
}
this._selectedOptions = this.autocompleteDraggableOptions.filter(
(o) => o.selected,
);
if (this.multi) {
this.value = this._selectedOptions.map((o) => o.asValue);
} else {
this.value = undefined;
}
this.setInitialInputValue();
this.onChange(this.value);
this.showAutocomplete(this.autocompleteForm.value);
}

showAutocomplete(valueToRevertTo?: string) {
if (this.multi) {
this.autocompleteForm.setValue("");
Expand Down

0 comments on commit 4913dab

Please sign in to comment.