Skip to content

Commit

Permalink
feat(edit-content): Render TextField and TextArea Field to the Form #…
Browse files Browse the repository at this point in the history
…26442

* dev (edit content lib): add text area, default value and inputmode/type support

* dev (dot edit content field): add comments to new code

* dev (dot edit content form): add comment

* dev (dot edit content field): change steps from any to 0.1 in decimals

* dev (dot edit content lib): create field wrappers for text area and text field

* dev (dot edit content): add and clean test cases

* dev (edit content mock): remove duplicated code

* dev (edit content): address feedback

* fix (edit-content-form): styles were off

* fix (edit content text area): min height was too high

* dev (edit content field): address feedback

* dev (mocks): separate fields

* dev (edit content field): enhance testing

* dev (edit content): general clean up

* dev (edit content form): delete todo
  • Loading branch information
zJaaal authored Oct 20, 2023
1 parent f1c2d90 commit eabbb0a
Show file tree
Hide file tree
Showing 22 changed files with 784 additions and 402 deletions.
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
<label
[attr.data-testId]="'label-' + field.variable"
[for]="field.variable"
[checkIsRequiredControl]="field.variable"
dotFieldRequired
>{{ field.name }}</label
>
<ng-container [ngSwitch]="field.fieldType">
<div class="field" *ngSwitchCase="'Text'">
<label
[attr.data-testId]="'label-' + field.variable"
[for]="field.variable"
[checkIsRequiredControl]="field.variable"
dotFieldRequired
>{{ field.name }}</label
>
<input
[id]="field.variable"
[formControlName]="field.variable"
[attr.data-testId]="'input-' + field.variable"
type="text"
pInputText />
<small *ngIf="field.hint" [attr.data-testId]="'hint-' + field.variable">{{
field.hint
}}</small>
</div>
<dot-edit-content-text-field
*ngSwitchCase="fieldTypes.TEXT"
[field]="field"
[attr.data-testId]="'field-' + field.variable"></dot-edit-content-text-field>
<dot-edit-content-text-area
*ngSwitchCase="fieldTypes.TEXTAREA"
[field]="field"
[attr.data-testId]="'field-' + field.variable"></dot-edit-content-text-area>
</ng-container>
<small *ngIf="field.hint" [attr.data-testId]="'hint-' + field.variable">{{ field.hint }}</small>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:host {
display: block;
height: fit-content;
}
Original file line number Diff line number Diff line change
@@ -1,65 +1,32 @@
import { describe } from '@jest/globals';
import { Spectator, byTestId, createComponentFactory } from '@ngneat/spectator';

import { CommonModule } from '@angular/common';
import {
ControlContainer,
FormControl,
FormGroup,
FormGroupDirective,
ReactiveFormsModule
} from '@angular/forms';

import { InputTextModule } from 'primeng/inputtext';

import { DotCMSContentTypeField } from '@dotcms/dotcms-models';
import { DotFieldRequiredDirective } from '@dotcms/ui';
import { ControlContainer, FormGroupDirective } from '@angular/forms';
import { By } from '@angular/platform-browser';

import { DotEditContentFieldComponent } from './dot-edit-content-field.component';
import { FIELD_TYPES, FIELD_TYPES_COMPONENTS } from './utils';

export const FIELD_MOCK: DotCMSContentTypeField = {
clazz: 'com.dotcms.contenttype.model.field.ImmutableTextField',
contentTypeId: 'd46d6404125ac27e6ab68fad09266241',
dataType: 'TEXT',
fieldType: 'Text',
fieldTypeLabel: 'Text',
fieldVariables: [],
fixed: false,
iDate: 1696896882000,
id: 'c3b928bc2b59fc22c67022de4dd4b5c4',
indexed: false,
listed: false,
hint: 'A helper text',
modDate: 1696896882000,
name: 'testVariable',
readOnly: false,
required: false,
searchable: false,
sortOrder: 2,
unique: false,
variable: 'testVariable'
};
import { FIELDS_MOCK, createFormGroupDirectiveMock } from '../../utils/mocks';

const FORM_GROUP_MOCK = new FormGroup({
testVariable: new FormControl('')
describe('FIELD_TYPES and FIELDS_MOCK', () => {
it('should be in sync', () => {
expect(
Object.values(FIELD_TYPES).every((fieldType) =>
FIELDS_MOCK.find((f) => f.fieldType === fieldType)
)
).toBeTruthy();
});
});
const FORM_GROUP_DIRECTIVE_MOCK: FormGroupDirective = new FormGroupDirective([], []);
FORM_GROUP_DIRECTIVE_MOCK.form = FORM_GROUP_MOCK;

describe('DotFieldComponent', () => {
describe.each([...FIELDS_MOCK])('DotFieldComponent', (fieldMock) => {
let spectator: Spectator<DotEditContentFieldComponent>;
const createComponent = createComponentFactory({
component: DotEditContentFieldComponent,
imports: [
DotEditContentFieldComponent,
CommonModule,
ReactiveFormsModule,
InputTextModule,
DotFieldRequiredDirective
],
componentViewProviders: [
{
provide: ControlContainer,
useValue: FORM_GROUP_DIRECTIVE_MOCK
useValue: createFormGroupDirectiveMock()
}
],
providers: [FormGroupDirective]
Expand All @@ -68,26 +35,31 @@ describe('DotFieldComponent', () => {
beforeEach(async () => {
spectator = createComponent({
props: {
field: FIELD_MOCK
field: fieldMock
}
});
});

it('should render the label', () => {
spectator.detectChanges();
const label = spectator.query(byTestId(`label-${FIELD_MOCK.variable}`));
expect(label?.textContent).toContain(FIELD_MOCK.name);
const label = spectator.query(byTestId(`label-${fieldMock.variable}`));
expect(label?.textContent).toContain(fieldMock.name);
});

it('should render the hint', () => {
spectator.detectChanges();
const hint = spectator.query(byTestId(`hint-${FIELD_MOCK.variable}`));
expect(hint?.textContent).toContain(FIELD_MOCK.hint);
const hint = spectator.query(byTestId(`hint-${fieldMock.variable}`));
expect(hint?.textContent).toContain(fieldMock.hint);
});

it('should render the input', () => {
it('should render the correct field type', () => {
spectator.detectChanges();
const input = spectator.query(byTestId(`input-${FIELD_MOCK.variable}`));
expect(input).toBeDefined();
const field = spectator.debugElement.query(
By.css(`[data-testId="field-${fieldMock.variable}"]`)
);

expect(
field.componentInstance instanceof FIELD_TYPES_COMPONENTS[fieldMock.fieldType]
).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, Input, inject } from '@angular/core';
import { NgIf, NgSwitch, NgSwitchCase } from '@angular/common';
import { ChangeDetectionStrategy, Component, HostBinding, Input, inject } from '@angular/core';
import { ControlContainer, ReactiveFormsModule } from '@angular/forms';

import { InputTextModule } from 'primeng/inputtext';

import { DotCMSContentTypeField } from '@dotcms/dotcms-models';
import { DotFieldRequiredDirective } from '@dotcms/ui';

import { FIELD_TYPES } from './utils';

import { DotEditContentFieldsModule } from '../../fields/dot-edit-content-fields.module';

@Component({
selector: 'dot-edit-content-field',
standalone: true,
imports: [CommonModule, ReactiveFormsModule, InputTextModule, DotFieldRequiredDirective],
imports: [
NgSwitch,
NgSwitchCase,
NgIf,
ReactiveFormsModule,
DotEditContentFieldsModule,
DotFieldRequiredDirective
],
templateUrl: './dot-edit-content-field.component.html',
styleUrls: ['./dot-edit-content-field.component.scss'],
viewProviders: [
Expand All @@ -22,5 +31,7 @@ import { DotFieldRequiredDirective } from '@dotcms/ui';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DotEditContentFieldComponent {
@HostBinding('class') class = 'field';
@Input() field!: DotCMSContentTypeField;
readonly fieldTypes = FIELD_TYPES;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Type } from '@angular/core';

import { DotEditContentTextAreaComponent } from '../../fields/dot-edit-content-text-area/dot-edit-content-text-area.component';
import { DotEditContentTextFieldComponent } from '../../fields/dot-edit-content-text-field/dot-edit-content-text-field.component';

// Map to match the field type to component selector
export enum FIELD_TYPES {
TEXT = 'Text',
TEXTAREA = 'Textarea'
}

// This holds the mapping between the field type and the component that should be used to render it.
export const FIELD_TYPES_COMPONENTS: Record<FIELD_TYPES, Type<unknown>> = {
// We had to use unknown because components have different types.
[FIELD_TYPES.TEXT]: DotEditContentTextFieldComponent,
[FIELD_TYPES.TEXTAREA]: DotEditContentTextAreaComponent
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<form class="p-fluid" *ngIf="form" [formGroup]="form">
<form class="p-fluid edit-content-form" *ngIf="form" [formGroup]="form">
<ng-container *ngFor="let row of formData">
<div class="row">
<div class="column" *ngFor="let column of row.columns">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,24 @@
grid-template-columns: 1fr 16rem;
gap: $spacing-4;
padding: $spacing-4;
padding-bottom: 0;
height: 100%;
}

.edit-content-form {
overflow: auto;
padding-right: $spacing-4;
}

.row {
display: grid;
grid-auto-flow: column;
grid-auto-columns: minmax(0, 1fr);
gap: $spacing-2;
}

.column {
display: grid;
min-height: $spacing-7;
}
.column {
display: flex;
flex-direction: column;
gap: $spacing-3;
}
Loading

0 comments on commit eabbb0a

Please sign in to comment.