Browse Source

WIP: Form row (#1273)

* Improved mongo config.

* Update dependencies.

* Disable test in CI for now.

* Temp

* Temp

* More form rows.

* Fix label.

* Form row improvements.
pull/1276/head
Sebastian Stehle 5 months ago
committed by GitHub
parent
commit
2f87a50273
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 50
      frontend/src/app/features/administration/pages/users/user-page.component.html
  2. 3
      frontend/src/app/features/administration/pages/users/user-page.component.scss
  3. 4
      frontend/src/app/features/administration/pages/users/user-page.component.ts
  4. 5
      frontend/src/app/features/api/pages/graphql/graphql-page.component.html
  5. 3
      frontend/src/app/features/api/pages/graphql/graphql-page.component.ts
  6. 16
      frontend/src/app/features/apps/pages/onboarding-dialog.component.html
  7. 3
      frontend/src/app/features/apps/pages/onboarding-dialog.component.ts
  8. 8
      frontend/src/app/features/assets/pages/asset-tag-dialog.component.html
  9. 6
      frontend/src/app/features/assets/pages/asset-tag-dialog.component.ts
  10. 83
      frontend/src/app/features/content/pages/calendar/calendar-page.component.html
  11. 3
      frontend/src/app/features/content/pages/calendar/calendar-page.component.ts
  12. 157
      frontend/src/app/features/rules/pages/rule/step-dialog.component.html
  13. 4
      frontend/src/app/features/rules/pages/rule/step-dialog.component.ts
  14. 2
      frontend/src/app/features/rules/shared/actions/branches-input.component.html
  15. 21
      frontend/src/app/features/rules/shared/state-step-property.component.html
  16. 3
      frontend/src/app/features/rules/shared/state-step-property.component.ts
  17. 45
      frontend/src/app/features/rules/shared/triggers/asset-changed-trigger.component.html
  18. 4
      frontend/src/app/features/rules/shared/triggers/asset-changed-trigger.component.ts
  19. 37
      frontend/src/app/features/rules/shared/triggers/comment-trigger.component.html
  20. 4
      frontend/src/app/features/rules/shared/triggers/comment-trigger.component.ts
  21. 85
      frontend/src/app/features/rules/shared/triggers/cron-job-trigger.component.html
  22. 4
      frontend/src/app/features/rules/shared/triggers/cron-job-trigger.component.ts
  23. 37
      frontend/src/app/features/rules/shared/triggers/schema-changed-trigger.component.html
  24. 4
      frontend/src/app/features/rules/shared/triggers/schema-changed-trigger.component.ts
  25. 24
      frontend/src/app/features/rules/shared/triggers/usage-trigger.component.html
  26. 6
      frontend/src/app/features/rules/shared/triggers/usage-trigger.component.ts
  27. 64
      frontend/src/app/features/schemas/pages/schema/common/schema-edit-form.component.html
  28. 6
      frontend/src/app/features/schemas/pages/schema/common/schema-edit-form.component.ts
  29. 21
      frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.html
  30. 5
      frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.ts
  31. 42
      frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-common.component.html
  32. 6
      frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-common.component.ts
  33. 28
      frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.html
  34. 5
      frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.ts
  35. 41
      frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.html
  36. 8
      frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.ts
  37. 4
      frontend/src/app/features/schemas/pages/schema/fields/forms/field-form.component.ts
  38. 17
      frontend/src/app/features/schemas/pages/schema/fields/types/array-ui.component.html
  39. 4
      frontend/src/app/features/schemas/pages/schema/fields/types/array-ui.component.ts
  40. 36
      frontend/src/app/features/schemas/pages/schema/fields/types/array-validation.component.html
  41. 3
      frontend/src/app/features/schemas/pages/schema/fields/types/array-validation.component.ts
  42. 80
      frontend/src/app/features/schemas/pages/schema/fields/types/assets-ui.component.html
  43. 5
      frontend/src/app/features/schemas/pages/schema/fields/types/assets-ui.component.ts
  44. 195
      frontend/src/app/features/schemas/pages/schema/fields/types/assets-validation.component.html
  45. 5
      frontend/src/app/features/schemas/pages/schema/fields/types/assets-validation.component.scss
  46. 8
      frontend/src/app/features/schemas/pages/schema/fields/types/assets-validation.component.ts
  47. 44
      frontend/src/app/features/schemas/pages/schema/fields/types/boolean-ui.component.html
  48. 5
      frontend/src/app/features/schemas/pages/schema/fields/types/boolean-ui.component.ts
  49. 30
      frontend/src/app/features/schemas/pages/schema/fields/types/boolean-validation.component.html
  50. 9
      frontend/src/app/features/schemas/pages/schema/fields/types/boolean-validation.component.ts
  51. 18
      frontend/src/app/features/schemas/pages/schema/fields/types/component-validation.component.html
  52. 3
      frontend/src/app/features/schemas/pages/schema/fields/types/component-validation.component.ts
  53. 17
      frontend/src/app/features/schemas/pages/schema/fields/types/components-ui.component.html
  54. 4
      frontend/src/app/features/schemas/pages/schema/fields/types/components-ui.component.ts
  55. 62
      frontend/src/app/features/schemas/pages/schema/fields/types/components-validation.component.html
  56. 3
      frontend/src/app/features/schemas/pages/schema/fields/types/components-validation.component.ts
  57. 45
      frontend/src/app/features/schemas/pages/schema/fields/types/date-time-ui.component.html
  58. 6
      frontend/src/app/features/schemas/pages/schema/fields/types/date-time-ui.component.ts
  59. 57
      frontend/src/app/features/schemas/pages/schema/fields/types/date-time-validation.component.html
  60. 11
      frontend/src/app/features/schemas/pages/schema/fields/types/date-time-validation.component.ts
  61. 15
      frontend/src/app/features/schemas/pages/schema/fields/types/geolocation-ui.component.html
  62. 4
      frontend/src/app/features/schemas/pages/schema/fields/types/geolocation-ui.component.ts
  63. 6
      frontend/src/app/features/schemas/pages/schema/fields/types/json-more.component.html
  64. 5
      frontend/src/app/features/schemas/pages/schema/fields/types/json-more.component.ts
  65. 51
      frontend/src/app/features/schemas/pages/schema/fields/types/number-ui.component.html
  66. 5
      frontend/src/app/features/schemas/pages/schema/fields/types/number-ui.component.ts
  67. 65
      frontend/src/app/features/schemas/pages/schema/fields/types/number-validation.component.html
  68. 8
      frontend/src/app/features/schemas/pages/schema/fields/types/number-validation.component.ts
  69. 51
      frontend/src/app/features/schemas/pages/schema/fields/types/references-ui.component.html
  70. 5
      frontend/src/app/features/schemas/pages/schema/fields/types/references-ui.component.ts
  71. 99
      frontend/src/app/features/schemas/pages/schema/fields/types/references-validation.component.html
  72. 8
      frontend/src/app/features/schemas/pages/schema/fields/types/references-validation.component.ts
  73. 40
      frontend/src/app/features/schemas/pages/schema/fields/types/rich-text-ui.component.html
  74. 5
      frontend/src/app/features/schemas/pages/schema/fields/types/rich-text-ui.component.ts
  75. 105
      frontend/src/app/features/schemas/pages/schema/fields/types/rich-text-validation.component.html
  76. 3
      frontend/src/app/features/schemas/pages/schema/fields/types/rich-text-validation.component.ts
  77. 148
      frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.html
  78. 4
      frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.ts
  79. 245
      frontend/src/app/features/schemas/pages/schema/fields/types/string-validation.component.html
  80. 8
      frontend/src/app/features/schemas/pages/schema/fields/types/string-validation.component.ts
  81. 52
      frontend/src/app/features/schemas/pages/schema/fields/types/tags-ui.component.html
  82. 5
      frontend/src/app/features/schemas/pages/schema/fields/types/tags-ui.component.ts
  83. 46
      frontend/src/app/features/schemas/pages/schema/fields/types/tags-validation.component.html
  84. 8
      frontend/src/app/features/schemas/pages/schema/fields/types/tags-validation.component.ts
  85. 2
      frontend/src/app/features/schemas/pages/schema/indexes/index-form.component.html
  86. 52
      frontend/src/app/features/schemas/pages/schemas/schema-form.component.html
  87. 4
      frontend/src/app/features/schemas/pages/schemas/schema-form.component.ts
  88. 133
      frontend/src/app/features/settings/pages/clients/client.component.html
  89. 4
      frontend/src/app/features/settings/pages/clients/client.component.ts
  90. 140
      frontend/src/app/features/settings/pages/languages/language.component.html
  91. 4
      frontend/src/app/features/settings/pages/languages/language.component.ts
  92. 18
      frontend/src/app/features/settings/pages/more/more-page.component.html
  93. 4
      frontend/src/app/features/settings/pages/more/more-page.component.ts
  94. 46
      frontend/src/app/features/settings/pages/workflows/workflow.component.html
  95. 4
      frontend/src/app/features/settings/pages/workflows/workflow.component.ts
  96. 99
      frontend/src/app/features/teams/pages/auth/auth-page.component.html
  97. 4
      frontend/src/app/features/teams/pages/auth/auth-page.component.ts
  98. 8
      frontend/src/app/features/teams/pages/more/more-page.component.html
  99. 4
      frontend/src/app/features/teams/pages/more/more-page.component.ts
  100. 2
      frontend/src/app/features/teams/state/team-auth.state.ts

50
frontend/src/app/features/administration/pages/users/user-page.component.html

@ -21,46 +21,34 @@
</ng-container>
<ng-container>
<sqx-form-error [error]="userForm.error | async" />
<div class="form-group">
<label for="email">
{{ "common.email" | sqxTranslate }} <small class="hint">({{ "common.requiredHint" | sqxTranslate }})</small>
</label>
<sqx-control-errors for="email" />
<sqx-form-row for="email" label="common.email" required vertical>
<input class="form-control" id="email" autocomplete="off" formControlName="email" maxlength="100" type="email" />
</div>
</sqx-form-row>
<div class="form-group">
<label for="displayName">
{{ "common.displayName" | sqxTranslate }} <small class="hint">({{ "common.requiredHint" | sqxTranslate }})</small>
</label>
<sqx-control-errors for="displayName" />
<sqx-form-row for="displayName" label="common.displayName" required vertical>
<input class="form-control" id="displayName" autocomplete="off" formControlName="displayName" maxlength="100" spellcheck="false" />
</div>
</sqx-form-row>
<div class="form-group form-group-section">
<div class="form-group">
<label for="password">{{ "common.password" | sqxTranslate }}</label>
<sqx-control-errors for="password" />
<div class="form-section">
<sqx-form-row for="password" label="common.password" vertical>
<input class="form-control" id="password" autocomplete="off" formControlName="password" maxlength="100" type="password" />
</div>
</sqx-form-row>
<div class="form-group">
<label for="password">{{ "common.passwordConfirm" | sqxTranslate }}</label>
<sqx-control-errors for="passwordConfirm" />
<sqx-form-row for="passwordConfirm" label="common.passwordConfirm" vertical>
<input class="form-control" id="passwordConfirm" autocomplete="off" formControlName="passwordConfirm" maxlength="100" type="password" />
</div>
</sqx-form-row>
</div>
<div class="form-group form-group-section">
<label for="permissions">{{ "common.permissions" | sqxTranslate }}</label>
<sqx-control-errors for="permissions" />
<textarea
class="form-control"
id="permissions"
autocomplete="off"
formControlName="permissions"
placeholder="{{ 'common.separateByLine' | sqxTranslate }}"
spellcheck="false"></textarea>
<div class="form-section">
<sqx-form-row for="permissions" label="common.permissions" vertical>
<textarea
class="form-control"
id="permissions"
autocomplete="off"
formControlName="permissions"
placeholder="{{ 'common.separateByLine' | sqxTranslate }}"
spellcheck="false"></textarea>
</sqx-form-row>
</div>
</ng-container>
</sqx-layout>

3
frontend/src/app/features/administration/pages/users/user-page.component.scss

@ -1,8 +1,9 @@
@import 'mixins';
@import 'vars';
.form-group-section {
.form-section {
margin-top: 2rem;
margin-bottom: 1.25rem;
}
textarea {

4
frontend/src/app/features/administration/pages/users/user-page.component.ts

@ -9,7 +9,7 @@ import { AsyncPipe } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { ControlErrorsComponent, FormErrorComponent, LayoutComponent, ShortcutDirective, Subscriptions, TitleComponent, TooltipDirective, TranslatePipe, UpdateUserDto } from '@app/shared';
import { FormErrorComponent, FormRowComponent, LayoutComponent, ShortcutDirective, Subscriptions, TitleComponent, TooltipDirective, TranslatePipe, UpdateUserDto } from '@app/shared';
import { UserDto, UserForm, UsersState } from '../../internal';
@Component({
@ -18,8 +18,8 @@ import { UserDto, UserForm, UsersState } from '../../internal';
templateUrl: './user-page.component.html',
imports: [
AsyncPipe,
ControlErrorsComponent,
FormErrorComponent,
FormRowComponent,
FormsModule,
LayoutComponent,
ReactiveFormsModule,

5
frontend/src/app/features/api/pages/graphql/graphql-page.component.html

@ -10,8 +10,7 @@
<ng-container title> {{ "api.selectClient" | sqxTranslate }} </ng-container>
<ng-container content>
<sqx-form-hint> {{ "api.selectClientDescription" | sqxTranslate }} </sqx-form-hint>
<div class="form-group">
<label for="client">{{ "common.client" | sqxTranslate }}</label>
<sqx-form-row for="client" label="common.client" vertical>
<select class="form-control" id="client" [ngModel]="clientSelected" (ngModelChange)="selectClient($event)">
<option [ngValue]="null">{{ "api.noClient" | sqxTranslate }}</option>
@ -19,7 +18,7 @@
<option [ngValue]="client">{{ client.id }}</option>
}
</select>
</div>
</sqx-form-row>
</ng-container>
<ng-container footer>
<button class="btn btn-text-secondary" (click)="clientsDialog.hide()" type="button">{{ "common.close" | sqxTranslate }}</button>

3
frontend/src/app/features/api/pages/graphql/graphql-page.component.ts

@ -12,7 +12,7 @@ import { createGraphiQLFetcher } from '@graphiql/toolkit';
import { GraphiQL } from 'graphiql';
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import { ApiUrlConfig, AppsState, AuthService, ClientDto, ClientsService, ClientsState, DialogModel, FormHintComponent, LayoutComponent, MessageBus, ModalDialogComponent, ModalDirective, QueryExecuted, TitleComponent, TooltipDirective, TourStepDirective, TranslatePipe, Types } from '@app/shared';
import { ApiUrlConfig, AppsState, AuthService, ClientDto, ClientsService, ClientsState, DialogModel, FormHintComponent, FormRowComponent, LayoutComponent, MessageBus, ModalDialogComponent, ModalDirective, QueryExecuted, TitleComponent, TooltipDirective, TourStepDirective, TranslatePipe, Types } from '@app/shared';
@Component({
selector: 'sqx-graphql-page',
@ -22,6 +22,7 @@ import { ApiUrlConfig, AppsState, AuthService, ClientDto, ClientsService, Client
AsyncPipe,
FormHintComponent,
FormsModule,
FormRowComponent,
LayoutComponent,
ModalDialogComponent,
ModalDirective,

16
frontend/src/app/features/apps/pages/onboarding-dialog.component.html

@ -30,8 +30,7 @@
<div [sqxMarkdown]="'tour.stepDataText' | sqxTranslate"></div>
<div class="form-group mt-4">
<label for="role">{{ "tour.stepDataCompanyRole" | sqxTranslate }}</label>
<sqx-form-row for="companyRole" label="tour.stepDataCompanyRole" class="mt-4">
<select class="form-select" id="companyRole" formControlName="companyRole">
<option [ngValue]="'RoleEmployee'">{{ "tour.roleEmployee" | sqxTranslate }}</option>
<option [ngValue]="'RoleBusinessOwner'">{{ "tour.roleBusinessOwner" | sqxTranslate }}</option>
@ -40,10 +39,9 @@
<option [ngValue]="'RoleSoftwareDeveloper'">{{ "tour.roleSoftwareDeveloper" | sqxTranslate }}</option>
<option [ngValue]="'RoleBusinessAnalyst'">{{ "tour.roleBusinessAnalyst" | sqxTranslate }}</option>
</select>
</div>
</sqx-form-row>
<div class="form-group">
<label for="companySize">{{ "tour.stepDataCompanySize" | sqxTranslate }}</label>
<sqx-form-row for="companySize" label="tour.stepDataCompanySize">
<select class="form-select" id="companySize" formControlName="companySize">
<option [ngValue]="'SizeSingle'">{{ "tour.sizeSingle" | sqxTranslate }}</option>
<option [ngValue]="'SizeSmall'">{{ "tour.sizeSmall" | sqxTranslate }}</option>
@ -51,10 +49,9 @@
<option [ngValue]="'SizeLarge'">{{ "tour.sizeLarge" | sqxTranslate }}</option>
<option [ngValue]="'SizeVeryLarge'">{{ "tour.sizeVeryLarge" | sqxTranslate }}</option>
</select>
</div>
</sqx-form-row>
<div class="form-group">
<label for="project">{{ "tour.stepDataProject" | sqxTranslate }}</label>
<sqx-form-row for="project" label="tour.stepDataProject">
<select class="form-select" id="project" formControlName="project">
<option [ngValue]="'ProjectNewsMagazine'">{{ "tour.projectNewsMagazine" | sqxTranslate }}</option>
<option [ngValue]="'ProjectPersonalBlog'">{{ "tour.projectPersonalBlog" | sqxTranslate }}</option>
@ -64,7 +61,8 @@
<option [ngValue]="'ProjectBackend'">{{ "tour.projectBackend" | sqxTranslate }}</option>
<option [ngValue]="'ProjectLearning'">{{ "tour.projectLearning" | sqxTranslate }}</option>
</select>
</div>
</sqx-form-row>
<button class="btn btn-success" type="submit">{{ "tour.stepDataNext" | sqxTranslate }}</button>
</form>
</div>

3
frontend/src/app/features/apps/pages/onboarding-dialog.component.ts

@ -8,7 +8,7 @@
import { Component, EventEmitter, Output } from '@angular/core';
import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { fadeAnimation, MarkdownDirective, ModalDialogComponent, slideAnimation, TourState, TranslatePipe, UsersService } from '@app/shared';
import { fadeAnimation, FormRowComponent, MarkdownDirective, ModalDialogComponent, slideAnimation, TourState, TranslatePipe, UsersService } from '@app/shared';
@Component({
selector: 'sqx-onboarding-dialog',
@ -18,6 +18,7 @@ import { fadeAnimation, MarkdownDirective, ModalDialogComponent, slideAnimation,
fadeAnimation, slideAnimation,
],
imports: [
FormRowComponent,
FormsModule,
MarkdownDirective,
ModalDialogComponent,

8
frontend/src/app/features/assets/pages/asset-tag-dialog.component.html

@ -3,13 +3,9 @@
<ng-container title> {{ "common.renameTag" | sqxTranslate }} </ng-container>
<ng-container content>
<sqx-form-error [error]="editForm.error | async" />
<div class="form-group">
<label for="tagName">
{{ "common.name" | sqxTranslate }} <small class="hint">({{ "common.requiredHint" | sqxTranslate }})</small>
</label>
<sqx-control-errors for="tagName" />
<sqx-form-row for="tagName" label="common.name" vertical required>
<input class="form-control" id="tagName" autocomplete="off" formControlName="tagName" sqxFocusOnInit />
</div>
</sqx-form-row>
</ng-container>
<ng-container footer>
<button class="btn btn-text-secondary" (click)="emitClose()" type="button">{{ "common.cancel" | sqxTranslate }}</button>

6
frontend/src/app/features/assets/pages/asset-tag-dialog.component.ts

@ -8,8 +8,8 @@
import { AsyncPipe } from '@angular/common';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ControlErrorsComponent, FocusOnInitDirective, FormErrorComponent, ModalDialogComponent, TooltipDirective, TranslatePipe } from '@app/shared';
import { AssetsState, RenameAssetTagForm } from '@app/shared/internal';
import { FocusOnInitDirective, FormErrorComponent, ModalDialogComponent, TooltipDirective, TranslatePipe } from '@app/shared';
import { AssetsState, FormRowComponent, RenameAssetTagForm } from '@app/shared/internal';
@Component({
selector: 'sqx-asset-tag-dialog',
@ -17,9 +17,9 @@ import { AssetsState, RenameAssetTagForm } from '@app/shared/internal';
templateUrl: './asset-tag-dialog.component.html',
imports: [
AsyncPipe,
ControlErrorsComponent,
FocusOnInitDirective,
FormErrorComponent,
FormRowComponent,
FormsModule,
ModalDialogComponent,
ReactiveFormsModule,

83
frontend/src/app/features/content/pages/calendar/calendar-page.component.html

@ -25,66 +25,47 @@
<ng-container content>
@if (contentSelected && contentSelected.scheduleJob) {
<div>
<div class="form-group row">
<label class="col-4 col-form-label">{{ "common.id" | sqxTranslate }}</label>
<div class="col-8">
<div class="input-group">
<input class="form-control" id="id" #inputId name="id" readonly value="{{ contentSelected.id }}" />
<button class="btn btn-outline-secondary" [sqxCopy]="inputId" type="button">
<i class="icon-copy"></i>
</button>
</div>
<sqx-form-row for="id" hideError label="common.id" labelSize="lg">
<div class="input-group">
<input class="form-control" id="id" #inputId name="id" readonly value="{{ contentSelected.id }}" />
<button class="btn btn-outline-secondary" [sqxCopy]="inputId" type="button">
<i class="icon-copy"></i>
</button>
</div>
</div>
</sqx-form-row>
<div class="form-group form-group-aligned row">
<label class="col-4 col-form-label">{{ "common.content" | sqxTranslate }}</label>
<div class="col-8">
<a class="truncate" [routerLink]="['../', contentSelected.schemaName, contentSelected.id]">
{{ createContentName(contentSelected) }}
</a>
</div>
</div>
<sqx-form-row centered for="content" hideError label="common.content" labelSize="lg">
<a class="truncate" [routerLink]="['../', contentSelected.schemaName, contentSelected.id]">
{{ createContentName(contentSelected) }}
</a>
</sqx-form-row>
<div class="form-group form-group-aligned row">
<label class="col-4 col-form-label">{{ "common.schema" | sqxTranslate }}</label>
<div class="col-8">
<a class="truncate" [routerLink]="['../', contentSelected.schemaName]"> {{ contentSelected.schemaDisplayName }} </a>
</div>
</div>
<sqx-form-row centered for="schema" hideError label="common.schema" labelSize="lg">
<a class="truncate" [routerLink]="['../', contentSelected.schemaName]"> {{ contentSelected.schemaDisplayName }} </a>
</sqx-form-row>
<div class="form-group form-group-aligned row">
<label class="col-4 col-form-label">{{ "common.status" | sqxTranslate }}</label>
<div class="col-8">
<sqx-content-status layout="text" small="true" [status]="contentSelected.status" [statusColor]="contentSelected.statusColor" />
</div>
</div>
<sqx-form-row centered for="status" hideError label="common.status" labelSize="lg">
<sqx-content-status layout="text" small="true" [status]="contentSelected.status" [statusColor]="contentSelected.statusColor" />
</sqx-form-row>
<hr />
<div class="form-group form-group-aligned row">
<label class="col-4 col-form-label">{{ "contents.scheduledToLabel" | sqxTranslate }}</label>
<div class="col-8">
<sqx-content-status
layout="text"
small="true"
[status]="contentSelected.scheduleJob.status"
[statusColor]="contentSelected.scheduleJob.color" />
</div>
</div>
<sqx-form-row centered for="scheduledTo" hideError label="contents.scheduledToLabel" labelSize="lg">
<sqx-content-status
layout="text"
small="true"
[status]="contentSelected.scheduleJob.status"
[statusColor]="contentSelected.scheduleJob.color" />
</sqx-form-row>
<div class="form-group form-group-aligned row">
<label class="col-4 col-form-label">{{ "contents.scheduledAt" | sqxTranslate }}</label>
<div class="col-8">{{ contentSelected.scheduleJob.dueTime | sqxFullDateTime }}</div>
</div>
<sqx-form-row centered for="scheduledAt" hideError label="contents.scheduledAt" labelSize="lg">
{{ contentSelected.scheduleJob.dueTime | sqxFullDateTime }}
</sqx-form-row>
<div class="form-group form-group-aligned row">
<label class="col-4 col-form-label">{{ "contents.scheduledBy" | sqxTranslate }}</label>
<div class="col-8">
<img class="user-picture" [src]="contentSelected.scheduleJob.scheduledBy | sqxUserPictureRef" />
{{ contentSelected.scheduleJob.scheduledBy | sqxUserNameRef }}
</div>
</div>
<sqx-form-row centered for="scheduledBy" hideError label="contents.scheduledBy" labelSize="lg">
<img class="user-picture" [src]="contentSelected.scheduleJob.scheduledBy | sqxUserPictureRef" />
{{ contentSelected.scheduleJob.scheduledBy | sqxUserNameRef }}
</sqx-form-row>
@if (contentSelected.canCancelStatus) {
<hr />

3
frontend/src/app/features/content/pages/calendar/calendar-page.component.ts

@ -9,7 +9,7 @@
import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, HostListener, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterLink } from '@angular/router';
import { AppLanguageDto, AppsState, ConfirmClickDirective, ContentDto, ContentsService, ContentStatusComponent, CopyDirective, DateTime, DialogModel, FullDateTimePipe, getContentValue, LanguagesState, LayoutComponent, LocalizerService, ModalDialogComponent, ModalDirective, ResourceLoaderService, TitleComponent, TooltipDirective, TranslatePipe, UserNameRefPipe, UserPictureRefPipe } from '@app/shared';
import { AppLanguageDto, AppsState, ConfirmClickDirective, ContentDto, ContentsService, ContentStatusComponent, CopyDirective, DateTime, DialogModel, FormRowComponent, FullDateTimePipe, getContentValue, LanguagesState, LayoutComponent, LocalizerService, ModalDialogComponent, ModalDirective, ResourceLoaderService, TitleComponent, TooltipDirective, TranslatePipe, UserNameRefPipe, UserPictureRefPipe } from '@app/shared';
declare const tui: any;
@ -23,6 +23,7 @@ type ViewMode = 'day' | 'week' | 'month';
ConfirmClickDirective,
ContentStatusComponent,
CopyDirective,
FormRowComponent,
FormsModule,
FullDateTimePipe,
LayoutComponent,

157
frontend/src/app/features/rules/pages/rule/step-dialog.component.html

@ -10,111 +10,92 @@
<ng-container content>
@if (currentStep) {
<div class="form-horizontal" [formGroup]="currentStep.form">
<div class="form-group row">
<label class="col-3 col-form-label" for="stepName">{{ "common.name" | sqxTranslate }}</label>
<div class="col-9">
<input class="form-control" id="stepName" maxlength="40" [(ngModel)]="stepName" [ngModelOptions]="{ standalone: true }" />
<sqx-form-hint> {{ "rules.stepNameHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row for="stepName" hint="rules.stepNameHint" label="common.name">
<input class="form-control" id="stepName" maxlength="40" [(ngModel)]="stepName" [ngModelOptions]="{ standalone: true }" />
</sqx-form-row>
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input
class="form-check-input"
id="stepIgnore"
[(ngModel)]="stepIgnoreError"
[ngModelOptions]="{ standalone: true }"
type="checkbox" />
<label class="form-check-label" for="stepIgnore"> {{ "rules.stepIgnoreError" | sqxTranslate }} </label>
</div>
<sqx-form-hint> {{ "rules.stepIgnoreErrorHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row check for="stepIgnore" hint="rules.stepIgnoreErrorHint" label="rules.stepIgnoreError">
<input class="form-check-input" id="stepIgnore" [(ngModel)]="stepIgnoreError" [ngModelOptions]="{ standalone: true }" type="checkbox" />
</sqx-form-row>
<hr />
<sqx-form-error [error]="currentStep.error | async" />
@for (property of currentStep.editableProperties; track property.name) {
<div class="form-group row">
<label class="col-3 col-form-label" [for]="property.name">
@if (property.editor !== "Checkbox") {
{{ property.display }}
}
@if (property.isRequired) {
<small class="hint">&nbsp;*</small>
}
</label>
<div class="col-9">
<sqx-control-errors [for]="property.name" />
@switch (property.editor) {
@case ("Text") {
@if (property.isFormattable) {
<sqx-formattable-input [formControlName]="property.name" type="Text" />
} @else {
<input class="form-control" id="{{ property.name }}" [formControlName]="property.name" />
}
<sqx-form-row
[check]="property.editor === 'Checkbox'"
[for]="property.name"
[label]="property.display"
[required]="property.isRequired">
@switch (property.editor) {
@case ("Text") {
@if (property.isFormattable) {
<sqx-formattable-input [id]="property.name" [formControlName]="property.name" type="Text" />
} @else {
<input class="form-control" id="{{ property.name }}" [formControlName]="property.name" />
}
}
@case ("TextArea") {
@if (property.isFormattable) {
<sqx-formattable-input [completion]="scriptCompletions" [formControlName]="property.name" type="Code" />
} @else {
<textarea class="form-control" id="{{ property.name }}" [formControlName]="property.name"></textarea>
}
@case ("TextArea") {
@if (property.isFormattable) {
<sqx-formattable-input
[id]="property.name"
[completion]="scriptCompletions"
[formControlName]="property.name"
type="Code" />
} @else {
<textarea class="form-control" id="{{ property.name }}" [formControlName]="property.name"></textarea>
}
}
@case ("Javascript") {
<sqx-code-editor [completion]="scriptCompletions" [formControlName]="property.name" [height]="350" />
}
@case ("Javascript") {
<sqx-code-editor [completion]="scriptCompletions" [formControlName]="property.name" [height]="350" />
}
@case ("Checkbox") {
<div class="form-check">
<input class="form-check-input" id="{{ property.name }}" [formControlName]="property.name" type="checkbox" />
<label class="form-check-label" for="{{ property.name }}"> {{ property.display }} </label>
</div>
}
@case ("Checkbox") {
<div class="form-check">
<input class="form-check-input" id="{{ property.name }}" [formControlName]="property.name" type="checkbox" />
<label class="form-check-label" for="{{ property.name }}"> {{ property.display }} </label>
</div>
}
@case ("Dropdown") {
<select class="form-select" [formControlName]="property.name">
@if (!property.isRequired) {
<option></option>
}
@case ("Dropdown") {
<select class="form-select" [id]="property.name" [formControlName]="property.name">
@if (!property.isRequired) {
<option></option>
}
@for (option of property.options; track option) {
<option [ngValue]="option">{{ option }}</option>
}
</select>
}
@for (option of property.options; track option) {
<option [ngValue]="option">{{ option }}</option>
}
</select>
}
@case ("Branches") {
<sqx-branches-input [control]="currentStep.branch(property.name)" [isEditable]="isEditable" />
}
@case ("Branches") {
<sqx-branches-input [control]="currentStep.branch(property.name)" [isEditable]="isEditable" />
}
@default {
<input
class="form-control"
id="{{ property.name }}"
[formControlName]="property.name"
type="{{ property.editor | lowercase }}" />
}
@default {
<input
class="form-control"
id="{{ property.name }}"
[formControlName]="property.name"
type="{{ property.editor | lowercase }}" />
}
<sqx-form-hint>
<span inline="true" [sqxMarkdown]="property.description"></span>
@if (property.isFormattable) {
<div>
{{ "rules.advancedFormattingHint" | sqxTranslate }}:
<a href="https://docs.squidex.io/concepts/rules#3-formatting" sqxExternalLink tabindex="-1">
{{ "common.documentation" | sqxTranslate }}
</a>
</div>
}
</sqx-form-hint>
</div>
</div>
}
<sqx-form-hint>
<span inline="true" [sqxMarkdown]="property.description"></span>
@if (property.isFormattable) {
<div>
{{ "rules.advancedFormattingHint" | sqxTranslate }}:
<a href="https://docs.squidex.io/concepts/rules#3-formatting" sqxExternalLink tabindex="-1">
{{ "common.documentation" | sqxTranslate }}
</a>
</div>
}
</sqx-form-hint>
</sqx-form-row>
}
</div>
} @else {

4
frontend/src/app/features/rules/pages/rule/step-dialog.component.ts

@ -8,7 +8,7 @@
import { AsyncPipe, LowerCasePipe } from '@angular/common';
import { booleanAttribute, Component, EventEmitter, Input, Output } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppsState, CodeEditorComponent, ControlErrorsComponent, DynamicFlowStepDefinitionDto, EntriesPipe, FormErrorComponent, FormHintComponent, MarkdownDirective, ModalDialogComponent, RuleElementDto, RulesService, ScriptCompletions, StepForm, TranslatePipe, TypedSimpleChanges } from '@app/shared';
import { AppsState, CodeEditorComponent, DynamicFlowStepDefinitionDto, EntriesPipe, FormErrorComponent, FormHintComponent, FormRowComponent, MarkdownDirective, ModalDialogComponent, RuleElementDto, RulesService, ScriptCompletions, StepForm, TranslatePipe, TypedSimpleChanges } from '@app/shared';
import { BranchesInputComponent } from '../../shared/actions/branches-input.component';
import { FormattableInputComponent } from '../../shared/actions/formattable-input.component';
import { RuleElementComponent } from '../../shared/rule-element.component';
@ -21,11 +21,11 @@ import { RuleElementComponent } from '../../shared/rule-element.component';
AsyncPipe,
BranchesInputComponent,
CodeEditorComponent,
ControlErrorsComponent,
EntriesPipe,
FormattableInputComponent,
FormErrorComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
LowerCasePipe,
MarkdownDirective,

2
frontend/src/app/features/rules/shared/actions/branches-input.component.html

@ -1,5 +1,5 @@
@for (form of branchesControls; track form; let i = $index) {
<div class="form-group row gx-2" attr.data-testid="pattern_{{ form.get('name')?.value }}" [formGroup]="form">
<div class="form-group row gx-2" [formGroup]="form">
<div class="col">
<sqx-control-errors for="condition" />
<input class="form-control" formControlName="condition" maxlength="1000" placeholder="{{ 'common.condition' | sqxTranslate }}" />

21
frontend/src/app/features/rules/shared/state-step-property.component.html

@ -1,12 +1,9 @@
<div class="row form-group mt-3">
<label class="col-3 text-end">{{ property.display }}</label>
<div class="col-9">
@if (valueType === "MultilineJson") {
<sqx-code-editor disabled="true" height="auto" [ngModel]="valueFormatted" />
} @else if (valueType === "MultilineAny") {
<sqx-code-editor disabled="true" height="auto" mode="ace/mode/text" [ngModel]="valueFormatted" />
} @else {
<div class="simple-value">{{ valueFormatted }}</div>
}
</div>
</div>
<sqx-form-row [for]="property.name" hideError label="property.display">
@if (valueType === "MultilineJson") {
<sqx-code-editor disabled="true" height="auto" [ngModel]="valueFormatted" />
} @else if (valueType === "MultilineAny") {
<sqx-code-editor disabled="true" height="auto" mode="ace/mode/text" [ngModel]="valueFormatted" />
} @else {
<div class="simple-value">{{ valueFormatted }}</div>
}
</sqx-form-row>

3
frontend/src/app/features/rules/shared/state-step-property.component.ts

@ -8,7 +8,7 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CodeEditorComponent, RuleElementPropertyDto, Types } from '@app/shared';
import { CodeEditorComponent, FormRowComponent, RuleElementPropertyDto, Types } from '@app/shared';
@Component({
selector: 'sqx-state-step-property',
@ -17,6 +17,7 @@ import { CodeEditorComponent, RuleElementPropertyDto, Types } from '@app/shared'
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
CodeEditorComponent,
FormRowComponent,
FormsModule,
],
})

45
frontend/src/app/features/rules/shared/triggers/asset-changed-trigger.component.html

@ -1,31 +1,26 @@
<div class="form-horizontal" [formGroup]="triggerForm.form">
<div class="form-group row">
<label class="col-3 col-form-label" for="condition">{{ "common.condition" | sqxTranslate }}</label>
<sqx-form-row for="condition" label="common.condition">
<textarea class="form-control code" id="condition" formControlName="condition" placeholder="{{ 'rules.conditionHint' | sqxTranslate }}"></textarea>
<div class="col-9">
<sqx-control-errors for="condition" />
<textarea class="form-control code" id="condition" formControlName="condition" placeholder="{{ 'rules.conditionHint' | sqxTranslate }}"></textarea>
<div class="help">
<h4>{{ "common.conditions" | sqxTranslate }}</h4>
<sqx-form-hint> {{ "rules.conditionHint2" | sqxTranslate }} </sqx-form-hint>
<ul class="help-examples">
<li class="help-example">
{{ "rules.conditions.event" | sqxTranslate }}: <br />
<sqx-code>event.type == 'Created' || event.type == 'Updated'</sqx-code>
</li>
<div class="help">
<h4>{{ "common.conditions" | sqxTranslate }}</h4>
<sqx-form-hint> {{ "rules.conditionHint2" | sqxTranslate }} </sqx-form-hint>
<ul class="help-examples">
<li class="help-example">
{{ "rules.conditions.event" | sqxTranslate }}: <br />
<sqx-code>event.type == 'Created' || event.type == 'Updated'</sqx-code>
</li>
<li class="help-example">
{{ "rules.conditions.largeAssets" | sqxTranslate }}: <br />
<sqx-code>event.fileSize > 100000000</sqx-code>
</li>
<li class="help-example">
{{ "rules.conditions.largeAssets" | sqxTranslate }}: <br />
<sqx-code>event.fileSize > 100000000</sqx-code>
</li>
<li class="help-example">
{{ "rules.conditions.images" | sqxTranslate }}: <br />
<sqx-code>event.isImage</sqx-code>
</li>
</ul>
</div>
<li class="help-example">
{{ "rules.conditions.images" | sqxTranslate }}: <br />
<sqx-code>event.isImage</sqx-code>
</li>
</ul>
</div>
</div>
</sqx-form-row>
</div>

4
frontend/src/app/features/rules/shared/triggers/asset-changed-trigger.component.ts

@ -7,7 +7,7 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CodeComponent, ControlErrorsComponent, FormHintComponent, TranslatePipe, TriggerForm } from '@app/shared';
import { CodeComponent, FormHintComponent, FormRowComponent, TranslatePipe, TriggerForm } from '@app/shared';
@Component({
selector: 'sqx-asset-changed-trigger',
@ -15,8 +15,8 @@ import { CodeComponent, ControlErrorsComponent, FormHintComponent, TranslatePipe
templateUrl: './asset-changed-trigger.component.html',
imports: [
CodeComponent,
ControlErrorsComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,

37
frontend/src/app/features/rules/shared/triggers/comment-trigger.component.html

@ -1,26 +1,21 @@
<div class="form-horizontal" [formGroup]="triggerForm.form">
<div class="form-group row">
<label class="col-3 col-form-label" for="condition">{{ "common.condition" | sqxTranslate }}</label>
<sqx-form-row for="condition" label="common.condition">
<textarea class="form-control code" id="condition" formControlName="condition" placeholder="{{ 'rules.conditionHint' | sqxTranslate }}"></textarea>
<div class="col-9">
<sqx-control-errors for="condition" />
<textarea class="form-control code" id="condition" formControlName="condition" placeholder="{{ 'rules.conditionHint' | sqxTranslate }}"></textarea>
<div class="help">
<h4>{{ "common.conditions" | sqxTranslate }}</h4>
<sqx-form-hint> {{ "rules.conditionHint2" | sqxTranslate }} </sqx-form-hint>
<ul class="help-examples">
<li class="help-example">
{{ "rules.conditions.commentUser" | sqxTranslate }}: <br />
<sqx-code>event.mentionedUser.email === 'mail2stehle&#64;gmail.com'</sqx-code>
</li>
<div class="help">
<h4>{{ "common.conditions" | sqxTranslate }}</h4>
<sqx-form-hint> {{ "rules.conditionHint2" | sqxTranslate }} </sqx-form-hint>
<ul class="help-examples">
<li class="help-example">
{{ "rules.conditions.commentUser" | sqxTranslate }}: <br />
<sqx-code>event.mentionedUser.email === 'mail2stehle&#64;gmail.com'</sqx-code>
</li>
<li class="help-example">
{{ "rules.conditions.commentKeyword" | sqxTranslate }}: <br />
<sqx-code>event.text.indexOf('urgent') >= 0</sqx-code>
</li>
</ul>
</div>
<li class="help-example">
{{ "rules.conditions.commentKeyword" | sqxTranslate }}: <br />
<sqx-code>event.text.indexOf('urgent') >= 0</sqx-code>
</li>
</ul>
</div>
</div>
</sqx-form-row>
</div>

4
frontend/src/app/features/rules/shared/triggers/comment-trigger.component.ts

@ -7,7 +7,7 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CodeComponent, ControlErrorsComponent, FormHintComponent, TranslatePipe, TriggerForm } from '@app/shared';
import { CodeComponent, FormHintComponent, FormRowComponent, TranslatePipe, TriggerForm } from '@app/shared';
@Component({
selector: 'sqx-comment-trigger',
@ -15,8 +15,8 @@ import { CodeComponent, ControlErrorsComponent, FormHintComponent, TranslatePipe
templateUrl: './comment-trigger.component.html',
imports: [
CodeComponent,
ControlErrorsComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,

85
frontend/src/app/features/rules/shared/triggers/cron-job-trigger.component.html

@ -1,56 +1,45 @@
<div class="form-horizontal" [formGroup]="triggerForm.form">
<div class="form-group row">
<label class="col-3 col-form-label" for="cronExpression"> {{ "rules.conditions.cronExpression" | sqxTranslate }}</label>
<sqx-form-row for="cronExpression" label="rules.conditions.cronExpression">
<input class="form-control" id="cronExpression" formControlName="cronExpression" />
<div class="col-9">
<sqx-control-errors for="cronExpression" />
<input class="form-control" id="cronExpression" formControlName="cronExpression" />
<sqx-form-hint>
{{ "rules.conditions.cronExpressionHint" | sqxTranslate }}
<div>
{{ "rules.readMore" | sqxTranslate }}:
<a href="https://en.wikipedia.org/wiki/Cron" sqxExternalLink tabindex="-1">
{{ "common.documentation" | sqxTranslate }}
</a>
</div>
</sqx-form-hint>
<sqx-form-hint>
{{ "rules.conditions.cronExpressionHint" | sqxTranslate }}
<div>
{{ "rules.readMore" | sqxTranslate }}:
<a href="https://en.wikipedia.org/wiki/Cron" sqxExternalLink tabindex="-1">
{{ "common.documentation" | sqxTranslate }}
</a>
</div>
</sqx-form-hint>
<div class="help">
<h4>{{ "rules.conditions.cronExpressionsTitle" | sqxTranslate }}</h4>
<sqx-form-hint> {{ "rules.conditions.cronExpressionsHint" | sqxTranslate }} </sqx-form-hint>
<ul class="help-examples">
<li class="help-example">
{{ "rules.conditions.cronExpressionEvery4Hours" | sqxTranslate }}: <br />
<sqx-code>0 */4 * * *</sqx-code>
</li>
<div class="help">
<h4>{{ "rules.conditions.cronExpressionsTitle" | sqxTranslate }}</h4>
<sqx-form-hint> {{ "rules.conditions.cronExpressionsHint" | sqxTranslate }} </sqx-form-hint>
<ul class="help-examples">
<li class="help-example">
{{ "rules.conditions.cronExpressionEvery4Hours" | sqxTranslate }}: <br />
<sqx-code>0 */4 * * *</sqx-code>
</li>
<li class="help-example">
{{ "rules.conditions.cronExpressionEveryMorning" | sqxTranslate }}: <br />
<sqx-code>0 6 * * *</sqx-code>
</li>
<li class="help-example">
{{ "rules.conditions.cronExpressionEveryMorning" | sqxTranslate }}: <br />
<sqx-code>0 6 * * *</sqx-code>
</li>
<li class="help-example">
{{ "rules.conditions.cronExpressionEveryMonth" | sqxTranslate }}: <br />
<sqx-code>0 6 1 * *</sqx-code>
</li>
</ul>
</div>
<li class="help-example">
{{ "rules.conditions.cronExpressionEveryMonth" | sqxTranslate }}: <br />
<sqx-code>0 6 1 * *</sqx-code>
</li>
</ul>
</div>
</div>
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="cronTimezone">{{ "rules.conditions.cronTimezone" | sqxTranslate }}</label>
<div class="col-9">
<sqx-control-errors for="cronTimezone" />
<select class="form-select" id="cronTimezone" formControlName="cronTimezone">
<option></option>
@for (timezone of timezones | async; track timezone) {
<option [ngValue]="timezone">{{ timezone }}</option>
}
</select>
<sqx-form-hint> {{ "rules.conditions.cronTimezoneHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row for="cronTimezone" hint="rules.conditions.cronTimezoneHint" label="rules.conditions.cronTimezone">
<select class="form-select" id="cronTimezone" formControlName="cronTimezone">
<option></option>
@for (timezone of timezones | async; track timezone) {
<option [ngValue]="timezone">{{ timezone }}</option>
}
</select>
</sqx-form-row>
</div>

4
frontend/src/app/features/rules/shared/triggers/cron-job-trigger.component.ts

@ -8,7 +8,7 @@
import { AsyncPipe } from '@angular/common';
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppsState, CodeComponent, ControlErrorsComponent, FormHintComponent, RulesService, TranslatePipe, TriggerForm } from '@app/shared';
import { AppsState, CodeComponent, FormHintComponent, FormRowComponent, RulesService, TranslatePipe, TriggerForm } from '@app/shared';
@Component({
selector: 'sqx-cron-job-trigger',
@ -17,8 +17,8 @@ import { AppsState, CodeComponent, ControlErrorsComponent, FormHintComponent, Ru
imports: [
AsyncPipe,
CodeComponent,
ControlErrorsComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,

37
frontend/src/app/features/rules/shared/triggers/schema-changed-trigger.component.html

@ -1,26 +1,21 @@
<div class="form-horizontal" [formGroup]="triggerForm.form">
<div class="form-group row">
<label class="col-3 col-form-label" for="condition">{{ "common.condition" | sqxTranslate }}</label>
<sqx-form-row for="condition" label="common.condition">
<textarea class="form-control code" id="condition" formControlName="condition" placeholder="{{ 'rules.conditionHint' | sqxTranslate }}"></textarea>
<div class="col-9">
<sqx-control-errors for="condition" />
<textarea class="form-control code" id="condition" formControlName="condition" placeholder="{{ 'rules.conditionHint' | sqxTranslate }}"></textarea>
<div class="help">
<h4>{{ "common.conditions" | sqxTranslate }}</h4>
<sqx-form-hint> {{ "rules.conditionHint2" | sqxTranslate }} </sqx-form-hint>
<ul class="help-examples">
<li class="help-example">
{{ "rules.conditions.event" | sqxTranslate }}: <br />
<sqx-code>event.type == 'Created' || event.type == 'Updated'</sqx-code>
</li>
<div class="help">
<h4>{{ "common.conditions" | sqxTranslate }}</h4>
<sqx-form-hint> {{ "rules.conditionHint2" | sqxTranslate }} </sqx-form-hint>
<ul class="help-examples">
<li class="help-example">
{{ "rules.conditions.event" | sqxTranslate }}: <br />
<sqx-code>event.type == 'Created' || event.type == 'Updated'</sqx-code>
</li>
<li class="help-example">
{{ "rules.conditions.schema" | sqxTranslate }}: <br />
<sqx-code>schemaId.name === 'my-schema'</sqx-code>
</li>
</ul>
</div>
<li class="help-example">
{{ "rules.conditions.schema" | sqxTranslate }}: <br />
<sqx-code>schemaId.name === 'my-schema'</sqx-code>
</li>
</ul>
</div>
</div>
</sqx-form-row>
</div>

4
frontend/src/app/features/rules/shared/triggers/schema-changed-trigger.component.ts

@ -7,7 +7,7 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CodeComponent, ControlErrorsComponent, FormHintComponent, TranslatePipe, TriggerForm } from '@app/shared';
import { CodeComponent, FormHintComponent, FormRowComponent, TranslatePipe, TriggerForm } from '@app/shared';
@Component({
selector: 'sqx-schema-changed-trigger',
@ -15,8 +15,8 @@ import { CodeComponent, ControlErrorsComponent, FormHintComponent, TranslatePipe
templateUrl: './schema-changed-trigger.component.html',
imports: [
CodeComponent,
ControlErrorsComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,

24
frontend/src/app/features/rules/shared/triggers/usage-trigger.component.html

@ -1,21 +1,9 @@
<div class="form-horizontal" [formGroup]="triggerForm.form">
<div class="form-group row">
<label class="col-3 col-form-label" for="limit">{{ "rules.conditions.usageLimit" | sqxTranslate }}</label>
<sqx-form-row for="limit" hint="rules.conditions.usageLimitHint" label="rules.conditions.usageLimit">
<input class="form-control" id="limit" formControlName="limit" step="1" type="number" />
</sqx-form-row>
<div class="col-9">
<sqx-control-errors for="limit" />
<input class="form-control" id="limit" formControlName="limit" step="1" type="number" />
<sqx-form-hint> {{ "rules.conditions.usageLimitHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label" for="condition">{{ "rules.conditions.usageDays" | sqxTranslate }}</label>
<div class="col-9">
<sqx-control-errors for="numDays" />
<input class="form-control" id="condition" formControlName="numDays" step="1" type="number" />
<sqx-form-hint> {{ "rules.conditions.usageDaysHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row for="numDays" hint="rules.conditions.usageDaysHint" label="rules.conditions.usageDays">
<input class="form-control" id="condition" formControlName="numDays" step="1" type="number" />
</sqx-form-row>
</div>

6
frontend/src/app/features/rules/shared/triggers/usage-trigger.component.ts

@ -7,18 +7,16 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ControlErrorsComponent, FormHintComponent, TranslatePipe, TriggerForm } from '@app/shared';
import { FormRowComponent, TriggerForm } from '@app/shared';
@Component({
selector: 'sqx-usage-trigger',
styleUrls: ['./usage-trigger.component.scss'],
templateUrl: './usage-trigger.component.html',
imports: [
ControlErrorsComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,
],
})
export class UsageTriggerComponent {

64
frontend/src/app/features/schemas/pages/schema/common/schema-edit-form.component.html

@ -3,67 +3,41 @@
<div class="card">
<div class="card-body">
<div class="form-group">
<label for="name">{{ "common.name" | sqxTranslate }}</label>
<sqx-form-row for="name" label="common.name" vertical>
<input class="form-control" id="name" [ngModel]="schema.name" [ngModelOptions]="{ standalone: true }" readonly />
</div>
<div class="form-group">
<label for="label">{{ "common.label" | sqxTranslate }}</label>
<sqx-control-errors for="label" />
</sqx-form-row>
<sqx-form-row for="label" label="common.label" vertical hint="schemas.schemaLabelHint">
<input class="form-control" id="label" formControlName="label" />
<sqx-form-hint> {{ "schemas.schemaLabelHint" | sqxTranslate }} </sqx-form-hint>
</div>
</sqx-form-row>
<div class="form-group">
<label for="hints">{{ "common.hints" | sqxTranslate }}</label>
<sqx-control-errors for="hints" />
<sqx-form-row for="hints" label="common.hints" vertical hint="schemas.schemaHintsHint">
<textarea class="form-control" id="hints" formControlName="hints" rows="4"></textarea>
<sqx-form-hint> {{ "schemas.schemaHintsHint" | sqxTranslate }} </sqx-form-hint>
</div>
</sqx-form-row>
<div class="form-group">
<label for="hints">{{ "schemas.contentsSidebarUrl" | sqxTranslate }}</label>
<sqx-control-errors for="contentsSidebarUrl" />
<sqx-form-row for="contentsSidebarUrl" label="schemas.contentsSidebarUrl" vertical hint="schemas.contentsSidebarUrlHint">
<input class="form-control" id="contentsSidebarUrl" formControlName="contentsSidebarUrl" type="url" />
<sqx-form-hint> {{ "schemas.contentsSidebarUrlHint" | sqxTranslate }} </sqx-form-hint>
</div>
</sqx-form-row>
<div class="form-group">
<label for="hints">{{ "schemas.contentSidebarUrl" | sqxTranslate }}</label>
<sqx-control-errors for="contentSidebarUrl" />
<sqx-form-row for="contentSidebarUrl" label="schemas.contentSidebarUrl" vertical hint="schemas.contentSidebarUrlHint">
<input class="form-control" id="contentSidebarUrl" formControlName="contentSidebarUrl" type="url" />
<sqx-form-hint> {{ "schemas.contentSidebarUrlHint" | sqxTranslate }} </sqx-form-hint>
</div>
</sqx-form-row>
<div class="form-group">
<label for="hints">{{ "schemas.contentEditorUrl" | sqxTranslate }}</label>
<sqx-control-errors for="contentEditorUrl" />
<sqx-form-row for="contentEditorUrl" label="schemas.contentEditorUrl" vertical hint="schemas.contentEditorUrlHint">
<input class="form-control" id="contentEditorUrl" formControlName="contentEditorUrl" type="url" />
<sqx-form-hint> {{ "schemas.contentEditorUrlHint" | sqxTranslate }} </sqx-form-hint>
</div>
</sqx-form-row>
<div class="form-group">
<label for="hints">{{ "schemas.contentsListUrl" | sqxTranslate }}</label>
<sqx-control-errors for="contentsListUrl" />
<sqx-form-row for="contentsListUrl" label="schemas.contentsListUrl" vertical hint="schemas.contentsListUrlHint">
<input class="form-control" id="contentsListUrl" formControlName="contentsListUrl" type="url" />
<sqx-form-hint> {{ "schemas.contentsListUrlHint" | sqxTranslate }} </sqx-form-hint>
</div>
</sqx-form-row>
<div class="form-group">
<label for="tags">{{ "common.tags" | sqxTranslate }}</label>
<sqx-control-errors for="tags" />
<sqx-form-row for="tags" label="common.tags" vertical hint="schemas.schemaTagsHint">
<sqx-tag-editor id="tags" formControlName="tags" />
<sqx-form-hint> {{ "schemas.schemaTagsHint" | sqxTranslate }} </sqx-form-hint>
</div>
</sqx-form-row>
<div class="form-group">
<div class="form-check">
<sqx-form-row for="validateOnPublish" label="schemas.validateOnPublish" check vertical hint="schemas.validateOnPublishHint" alert="schemas.validateOnPublishHint">
<input class="form-check-input" id="validateOnPublish" formControlName="validateOnPublish" type="checkbox" />
<label class="form-check-label" for="validateOnPublish"> {{ "schemas.validateOnPublish" | sqxTranslate }} </label>
</div>
<sqx-form-alert> {{ "schemas.validateOnPublishHint" | sqxTranslate }} </sqx-form-alert>
</div>
</sqx-form-row>
</div>
<div class="card-footer">

6
frontend/src/app/features/schemas/pages/schema/common/schema-edit-form.component.ts

@ -8,16 +8,14 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ControlErrorsComponent, EditSchemaForm, FormAlertComponent, FormHintComponent, SchemaDto, SchemasState, TagEditorComponent, TranslatePipe } from '@app/shared';
import { EditSchemaForm, FormRowComponent, SchemaDto, SchemasState, TagEditorComponent, TranslatePipe } from '@app/shared';
@Component({
selector: 'sqx-schema-edit-form',
styleUrls: ['./schema-edit-form.component.scss'],
templateUrl: './schema-edit-form.component.html',
imports: [
ControlErrorsComponent,
FormAlertComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TagEditorComponent,

21
frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.html

@ -21,7 +21,8 @@
} @else {
<form [formGroup]="addFieldForm.form" (ngSubmit)="addField('Close')">
<sqx-form-error [error]="addFieldForm.error | async" />
<div class="form-group">
<sqx-form-row for="type" hideError vertical>
<div class="row">
@for (fieldType of fieldTypes; track fieldType) {
<div class="col-4 type">
@ -44,10 +45,9 @@
</div>
}
</div>
</div>
</sqx-form-row>
<div class="form-group">
<sqx-control-errors for="name" [submitCount]="addFieldForm.submitCount | async" />
<sqx-form-row for="name" [submitCount]="addFieldForm.submitCount | async" vertical>
<input
class="form-control"
#nameInput
@ -55,17 +55,14 @@
maxlength="40"
placeholder="{{ 'schemas.field.namePlaceholder' | sqxTranslate }}"
sqxFocusOnInit />
</div>
</sqx-form-row>
@if (schema.type !== "Component" && !parent && (addFieldForm.isContentField | async)) {
<div class="form-group">
<div class="form-check">
<input class="form-check-input" id="isLocalizable" formControlName="isLocalizable" type="checkbox" />
<label class="form-check-label" for="isLocalizable"> {{ "schemas.field.localizable" | sqxTranslate }} </label>
</div>
<sqx-form-hint> {{ "schemas.field.localizableHint" | sqxTranslate }} </sqx-form-hint>
</div>
<sqx-form-row check for="isLocalizable" hint="schemas.field.localizableHint" label="schemas.field.localizable" vertical>
<input class="form-check-input" id="isLocalizable" formControlName="isLocalizable" type="checkbox" />
</sqx-form-row>
}
<sqx-form-alert class="mt-4"> {{ "schemas.nameWarning" | sqxTranslate }} </sqx-form-alert>
</form>
}

5
frontend/src/app/features/schemas/pages/schema/fields/field-wizard.component.ts

@ -8,7 +8,7 @@
import { AsyncPipe } from '@angular/common';
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AddFieldForm, AppSettingsDto, ControlErrorsComponent, createProperties, DropdownMenuComponent, EditFieldForm, FieldDto, fieldTypes, FocusOnInitDirective, FormAlertComponent, FormErrorComponent, FormHintComponent, LanguagesState, ModalDialogComponent, ModalDirective, ModalModel, ModalPlacementDirective, SchemaDto, SchemasState, TooltipDirective, TranslatePipe, Types, UpdateFieldDto } from '@app/shared';
import { AddFieldForm, AppSettingsDto, createProperties, DropdownMenuComponent, EditFieldForm, FieldDto, fieldTypes, FocusOnInitDirective, FormAlertComponent, FormErrorComponent, FormRowComponent, LanguagesState, ModalDialogComponent, ModalDirective, ModalModel, ModalPlacementDirective, SchemaDto, SchemasState, TooltipDirective, TranslatePipe, Types, UpdateFieldDto } from '@app/shared';
import { FieldFormComponent } from './forms/field-form.component';
@ -20,13 +20,12 @@ type SaveNavigationMode = 'Close' | 'Add' | 'Edit';
templateUrl: './field-wizard.component.html',
imports: [
AsyncPipe,
ControlErrorsComponent,
DropdownMenuComponent,
FieldFormComponent,
FocusOnInitDirective,
FormAlertComponent,
FormErrorComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
ModalDialogComponent,
ModalDirective,

42
frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-common.component.html

@ -1,37 +1,19 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldName">{{ "common.name" | sqxTranslate }}</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_fieldName" [ngModel]="field.name" [ngModelOptions]="{ standalone: true }" readonly />
<sqx-form-hint> {{ "schemas.field.nameHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #nameRow for="name" hint="schemas.field.nameHint" label="common.name" [prefix]="field.fieldId">
<input class="form-control" [id]="nameRow.fieldName" [ngModel]="field.name" [ngModelOptions]="{ standalone: true }" readonly />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldLabel">{{ "common.label" | sqxTranslate }}</label>
<div class="col-9">
<sqx-control-errors for="label" />
<input class="form-control" id="{{ field.fieldId }}_fieldLabel" formControlName="label" maxlength="100" />
<sqx-form-hint> {{ "schemas.field.labelHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #labelRow for="label" hint="schemas.field.labelHint" label="common.label" [prefix]="field.fieldId">
<input class="form-control" [id]="labelRow.fieldName" formControlName="label" maxlength="100" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldHints">{{ "common.hints" | sqxTranslate }}</label>
<div class="col-9">
<sqx-control-errors for="hints" />
<input class="form-control" id="{{ field.fieldId }}_fieldHints" formControlName="hints" maxlength="1000" />
<sqx-form-hint> {{ "schemas.field.hintsHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #hintsRow for="hints" hint="schemas.field.hintsHint" label="common.hints" [prefix]="field.fieldId">
<input class="form-control" [id]="hintsRow.fieldName" formControlName="hints" maxlength="1000" />
</sqx-form-row>
@if (field.properties.isContentField) {
<div class="form-group row">
<label class="col-3 col-form-label">{{ "common.tags" | sqxTranslate }}</label>
<div class="col-9">
<sqx-tag-editor id="schemaTags" formControlName="tags" />
<sqx-form-hint> {{ "schemas.field.tagsHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #tagsRow for="tags" hint="schemas.field.tagsHint" label="common.tags" [prefix]="field.fieldId">
<sqx-tag-editor [id]="tagsRow.fieldName" formControlName="tags" />
</sqx-form-row>
}
</div>

6
frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-common.component.ts

@ -8,19 +8,17 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { ControlErrorsComponent, FieldDto, FormHintComponent, SchemaDto, TagEditorComponent, TranslatePipe } from '@app/shared';
import { FieldDto, FormRowComponent, SchemaDto, TagEditorComponent } from '@app/shared';
@Component({
selector: 'sqx-field-form-common',
styleUrls: ['./field-form-common.component.scss'],
templateUrl: './field-form-common.component.html',
imports: [
ControlErrorsComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TagEditorComponent,
TranslatePipe,
],
})
export class FieldFormCommonComponent {

28
frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.html

@ -1,11 +1,7 @@
<div [formGroup]="fieldForm">
<div class="form-group row mb-3">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_editorUrl">{{ "schemas.field.editorUrl" | sqxTranslate }}</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_editorUrl" formControlName="editorUrl" type="url" />
<sqx-form-hint> {{ "schemas.field.editorUrlHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="mb-3" [formGroup]="fieldForm">
<sqx-form-row #editorUrlRow for="editorUrl" hints="schemas.field.editorUrlHint" label="schemas.field.editorUrl" [prefix]="field.fieldId">
<input class="form-control" [id]="editorUrlRow.fieldName" formControlName="editorUrl" type="url" />
</sqx-form-row>
</div>
@switch (field.rawProperties.fieldType) {
@ -62,16 +58,8 @@
}
}
<div [formGroup]="fieldForm">
<div class="form-group row mt-3">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldHalfWidth" formControlName="isHalfWidth" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldHalfWidth">
{{ "schemas.field.halfWidth" | sqxTranslate }}
</label>
</div>
<sqx-form-hint> {{ "schemas.field.halfWidthHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="mt-3" [formGroup]="fieldForm">
<sqx-form-row #isHalfWidthRow check for="isHalfWidth" hint="schemas.field.halfWidthHint" label="schemas.field.halfWidth" [prefix]="field.fieldId">
<input class="form-check-input" [id]="isHalfWidthRow.fieldName" formControlName="isHalfWidth" type="checkbox" />
</sqx-form-row>
</div>

5
frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.ts

@ -8,7 +8,7 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { FieldDto, FormHintComponent, SchemaDto, TranslatePipe } from '@app/shared';
import { FieldDto, FormRowComponent, SchemaDto } from '@app/shared';
import { ArrayUIComponent } from '../types/array-ui.component';
import { AssetsUIComponent } from '../types/assets-ui.component';
import { BooleanUIComponent } from '../types/boolean-ui.component';
@ -34,7 +34,7 @@ import { TagsUIComponent } from '../types/tags-ui.component';
ComponentUIComponent,
ComponentsUIComponent,
DateTimeUIComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
GeolocationUIComponent,
JsonUIComponent,
@ -44,7 +44,6 @@ import { TagsUIComponent } from '../types/tags-ui.component';
ReferencesUIComponent,
StringUIComponent,
TagsUIComponent,
TranslatePipe,
],
})
export class FieldFormUIComponent {

41
frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.html

@ -1,36 +1,15 @@
<div [formGroup]="fieldForm">
<div class="form-group row mb-3">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldRequired" formControlName="isRequired" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldRequired">
{{ "schemas.field.required" | sqxTranslate }}
</label>
</div>
</div>
</div>
<div [formGroup]="fieldForm" class="mb-3">
<sqx-form-row #requiredRow check for="isRequired" label="schemas.field.required" [prefix]="field.fieldId">
<input class="form-check-input" [id]="requiredRow.fieldName" formControlName="isRequired" type="checkbox" />
</sqx-form-row>
<div class="form-group row mb-3">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldRequiredOnPublish" formControlName="isRequiredOnPublish" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldRequiredOnPublish">
{{ "schemas.field.requiredOnPublish" | sqxTranslate }}
</label>
</div>
</div>
</div>
<sqx-form-row #requiredOnPublishRow check for="isRequiredOnPublish" label="schemas.field.requiredOnPublish" [prefix]="field.fieldId">
<input class="form-check-input" [id]="requiredOnPublishRow.fieldName" formControlName="isRequiredOnPublish" type="checkbox" />
</sqx-form-row>
<div class="form-group row mb-3">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldCreateOnly" formControlName="isCreateOnly" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldCreateOnly">
{{ "schemas.field.createOnly" | sqxTranslate }}
</label>
</div>
</div>
</div>
<sqx-form-row #createOnlyRow check for="isCreateOnly" label="schemas.field.createOnly" [prefix]="field.fieldId">
<input class="form-check-input" [id]="createOnlyRow.fieldName" formControlName="isCreateOnly" type="checkbox" />
</sqx-form-row>
</div>
@switch (field.rawProperties.fieldType) {

8
frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.ts

@ -8,7 +8,7 @@
import { booleanAttribute, Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { AppLanguageDto, AppSettingsDto, FieldDto, SchemaDto, TranslatePipe } from '@app/shared';
import { AppLanguageDto, AppSettingsDto, FieldDto, FormRowComponent, SchemaDto } from '@app/shared';
import { ArrayValidationComponent } from '../types/array-validation.component';
import { AssetsValidationComponent } from '../types/assets-validation.component';
import { BooleanValidationComponent } from '../types/boolean-validation.component';
@ -38,12 +38,12 @@ import { TagsValidationComponent } from '../types/tags-validation.component';
GeolocationValidationComponent,
JsonValidationComponent,
NumberValidationComponent,
FormRowComponent,
ReactiveFormsModule,
ReferencesValidationComponent,
RichTextValidationComponent,
StringValidationComponent,
TagsValidationComponent,
TranslatePipe,
],
})
export class FieldFormValidationComponent {
@ -62,6 +62,6 @@ export class FieldFormValidationComponent {
@Input({ required: true })
public languages!: ReadonlyArray<AppLanguageDto>;
@Input({ transform: booleanAttribute })
public isLocalizable?: boolean | null;
@Input({ required: true, transform: booleanAttribute })
public isLocalizable!: boolean;
}

4
frontend/src/app/features/schemas/pages/schema/fields/forms/field-form.component.ts

@ -48,8 +48,8 @@ export class FieldFormComponent implements AfterViewInit {
@Input({ required: true })
public languages!: ReadonlyArray<AppLanguageDto>;
@Input({ transform: booleanAttribute })
public isLocalizable?: boolean | null;
@Input({ required: true, transform: booleanAttribute })
public isLocalizable!: boolean;
@Output()
public dialogClose = new EventEmitter();

17
frontend/src/app/features/schemas/pages/schema/fields/types/array-ui.component.html

@ -1,12 +1,9 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.defaultValue" | sqxTranslate }}</label>
<div class="col-3">
<select class="form-select" formControlName="calculatedDefaultValue">
@for (value of calculatedDefaultValues; track value) {
<option [ngValue]="value">{{ value }}</option>
}
</select>
</div>
</div>
<sqx-form-row for="calculatedDefaultValue" label="schemas.field.defaultValue">
<select class="form-select" formControlName="calculatedDefaultValue">
@for (value of calculatedDefaultValues; track value) {
<option [ngValue]="value">{{ value }}</option>
}
</select>
</sqx-form-row>
</div>

4
frontend/src/app/features/schemas/pages/schema/fields/types/array-ui.component.ts

@ -8,7 +8,7 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { ArrayFieldPropertiesDto, FieldDto, TranslatePipe } from '@app/shared';
import { ArrayFieldPropertiesDto, FieldDto, FormRowComponent } from '@app/shared';
const CALCULATED_DEFAULT_VALUES: ReadonlyArray<string> = ['EmptyArray', 'Null'];
@ -17,9 +17,9 @@ const CALCULATED_DEFAULT_VALUES: ReadonlyArray<string> = ['EmptyArray', 'Null'];
styleUrls: ['array-ui.component.scss'],
templateUrl: 'array-ui.component.html',
imports: [
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,
],
})
export class ArrayUIComponent {

36
frontend/src/app/features/schemas/pages/schema/fields/types/array-validation.component.html

@ -1,31 +1,19 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.array.count" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minItems"
placeholder="{{ 'schemas.fieldTypes.array.countMin' | sqxTranslate }}"
type="number" />
</div>
<sqx-form-row for="minItems" label="schemas.fieldTypes.array.count" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input class="form-control" formControlName="minItems" placeholder="{{ 'schemas.fieldTypes.array.countMin' | sqxTranslate }}" type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxItems"
placeholder="{{ 'schemas.fieldTypes.array.countMax' | sqxTranslate }}"
type="number" />
</div>
<div class="col">
<input class="form-control" formControlName="maxItems" placeholder="{{ 'schemas.fieldTypes.array.countMax' | sqxTranslate }}" type="number" />
</div>
</div>
</div>
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.array.uniqueFields" | sqxTranslate }}</label>
<div class="col-9"><sqx-tag-editor formControlName="uniqueFields" /></div>
</div>
<sqx-form-row #uniqueFieldsRow for="uniqueFields" label="schemas.fieldTypes.array.uniqueFields" [prefix]="field.fieldId">
<sqx-tag-editor [id]="uniqueFieldsRow.fieldName" formControlName="uniqueFields" />
</sqx-form-row>
</div>

3
frontend/src/app/features/schemas/pages/schema/fields/types/array-validation.component.ts

@ -7,13 +7,14 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { ArrayFieldPropertiesDto, FieldDto, TagEditorComponent, TranslatePipe } from '@app/shared';
import { ArrayFieldPropertiesDto, FieldDto, FormRowComponent, TagEditorComponent, TranslatePipe } from '@app/shared';
@Component({
selector: 'sqx-array-validation',
styleUrls: ['array-validation.component.scss'],
templateUrl: 'array-validation.component.html',
imports: [
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TagEditorComponent,

80
frontend/src/app/features/schemas/pages/schema/fields/types/assets-ui.component.html

@ -1,53 +1,37 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_previewMode">
{{ "schemas.fieldTypes.assets.previewMode" | sqxTranslate }}
</label>
<div class="col-9">
<select class="form-select" id="{{ field.fieldId }}_previewMode" formControlName="previewMode">
<option value="ImageAndFileName">{{ "schemas.fieldTypes.assets.previewImageAndFileName" | sqxTranslate }}</option>
<sqx-form-row
#previewRow
for="previewMode"
hint="schemas.fieldTypes.assets.previewModeHint"
label="schemas.fieldTypes.assets.previewMode"
[prefix]="field.fieldId">
<select class="form-select" [id]="previewRow.fieldName" formControlName="previewMode">
<option value="ImageAndFileName">{{ "schemas.fieldTypes.assets.previewImageAndFileName" | sqxTranslate }}</option>
<option value="Image">{{ "schemas.fieldTypes.assets.previewImage" | sqxTranslate }}</option>
<option value="FileName">{{ "schemas.fieldTypes.assets.previewFileName" | sqxTranslate }}</option>
</select>
</sqx-form-row>
<option value="Image">{{ "schemas.fieldTypes.assets.previewImage" | sqxTranslate }}</option>
<sqx-form-row
#previewFormatRow
for="previewFormat"
hint="schemas.fieldTypes.assets.previewFormatHint"
label="schemas.fieldTypes.assets.previewFormat"
[prefix]="field.fieldId">
<input class="form-control" [id]="previewFormatRow.fieldName" formControlName="previewFormat" />
</sqx-form-row>
<option value="FileName">{{ "schemas.fieldTypes.assets.previewFileName" | sqxTranslate }}</option>
</select>
<sqx-form-hint> {{ "schemas.fieldTypes.assets.previewModeHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row
#resolveFirstRow
check
for="resolveFirst"
hint="schemas.fieldTypes.assets.resolveHint"
label="schemas.fieldTypes.assets.resolve"
[prefix]="field.fieldId">
<input class="form-check-input" [id]="resolveFirstRow.fieldName" formControlName="resolveFirst" type="checkbox" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_previewFormat">
{{ "schemas.fieldTypes.assets.previewFormat" | sqxTranslate }}
</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_previewFormat" formControlName="previewFormat" />
<sqx-form-hint>
<span inline="true" [sqxMarkdown]="'schemas.fieldTypes.assets.previewFormatHint' | sqxTranslate"></span>
</sqx-form-hint>
</div>
</div>
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldResolveFirst" formControlName="resolveFirst" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldResolveFirst">
{{ "schemas.fieldTypes.assets.resolve" | sqxTranslate }}
</label>
</div>
<sqx-form-hint>
<span inline="true" [sqxMarkdown]="'schemas.fieldTypes.assets.resolveHint' | sqxTranslate"></span>
</sqx-form-hint>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_folderId">
{{ "schemas.fieldTypes.assets.folderId" | sqxTranslate }}
</label>
<div class="col-9">
<sqx-asset-folder-dropdown formControlName="folderId" />
<sqx-form-hint> {{ "schemas.fieldTypes.assets.folderIdHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row for="folderId" hint="schemas.fieldTypes.assets.folderIdHint" label="schemas.fieldTypes.assets.folderId" [prefix]="field.fieldId">
<sqx-asset-folder-dropdown formControlName="folderId" />
</sqx-form-row>
</div>

5
frontend/src/app/features/schemas/pages/schema/fields/types/assets-ui.component.ts

@ -7,7 +7,7 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { AssetFolderDropdownComponent, AssetsFieldPropertiesDto, FieldDto, FormHintComponent, MarkdownDirective, TranslatePipe } from '@app/shared';
import { AssetFolderDropdownComponent, AssetsFieldPropertiesDto, FieldDto, FormRowComponent, TranslatePipe } from '@app/shared';
@Component({
selector: 'sqx-assets-ui',
@ -15,9 +15,8 @@ import { AssetFolderDropdownComponent, AssetsFieldPropertiesDto, FieldDto, FormH
templateUrl: 'assets-ui.component.html',
imports: [
AssetFolderDropdownComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
MarkdownDirective,
ReactiveFormsModule,
TranslatePipe,
],

195
frontend/src/app/features/schemas/pages/schema/fields/types/assets-validation.component.html

@ -1,160 +1,97 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.assets.count" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minItems"
placeholder="{{ 'schemas.fieldTypes.assets.countMin' | sqxTranslate }}"
type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxItems"
placeholder="{{ 'schemas.fieldTypes.assets.countMax' | sqxTranslate }}"
type="number" />
</div>
<div class="col col-label"></div>
<sqx-form-row for="minItems" hideError label="schemas.fieldTypes.assets.count" [prefix]="field.fieldId" showUnit="true">
<div class="row g-0">
<div class="col">
<input class="form-control" formControlName="minItems" placeholder="{{ 'schemas.fieldTypes.assets.countMin' | sqxTranslate }}" type="number" />
</div>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.assets.size" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minSize"
placeholder="{{ 'schemas.fieldTypes.assets.sizeMin' | sqxTranslate }}"
type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxSize"
placeholder="{{ 'schemas.fieldTypes.assets.sizeMax' | sqxTranslate }}"
type="number" />
</div>
<div class="col col-label">
<label class="col-form-label">{{ "common.bytes" | sqxTranslate }}</label>
</div>
</div>
</div>
</div>
<hr />
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.assets.expectedType" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<select class="form-select" formControlName="expectedType">
<option></option>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<option ngValue="Image">Image</option>
<option ngValue="Audio">Audio</option>
<div class="col">
<input class="form-control" formControlName="maxItems" placeholder="{{ 'schemas.fieldTypes.assets.countMax' | sqxTranslate }}" type="number" />
</div>
</div>
</sqx-form-row>
<option ngValue="Video">Video</option>
<sqx-form-row for="minSize" hideError label="schemas.fieldTypes.assets.size" [prefix]="field.fieldId" unit="common.bytes">
<div class="row g-0">
<div class="col">
<input class="form-control" formControlName="minSize" placeholder="{{ 'schemas.fieldTypes.assets.sizeMin' | sqxTranslate }}" type="number" />
</div>
<option ngValue="Unknown">Unknown</option>
</select>
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col col-label"></div>
<div class="col">
<input class="form-control" formControlName="maxSize" placeholder="{{ 'schemas.fieldTypes.assets.sizeMax' | sqxTranslate }}" type="number" />
</div>
</div>
</div>
</sqx-form-row>
<hr />
<div class="form-group row">
<label class="col-3 col-form-label">{{ "common.width" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col"><input class="form-control" formControlName="minWidth" type="number" /></div>
<sqx-form-row for="minSize" label="schemas.fieldTypes.assets.expectedType" [prefix]="field.fieldId" showUnit="true">
<select class="form-select" formControlName="expectedType">
<option></option>
<option ngValue="Image">Image</option>
<option ngValue="Audio">Audio</option>
<option ngValue="Video">Video</option>
<option ngValue="Unknown">Unknown</option>
</select>
</sqx-form-row>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<sqx-form-row for="minWidth" hideError label="common.width" [prefix]="field.fieldId" unit="px">
<div class="row g-0">
<div class="col"><input class="form-control" formControlName="minWidth" type="number" /></div>
<div class="col"><input class="form-control" formControlName="maxWidth" type="number" /></div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col col-label"><label class="col-form-label">px</label></div>
</div>
<div class="col"><input class="form-control" formControlName="maxWidth" type="number" /></div>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "common.height" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col"><input class="form-control" formControlName="minHeight" type="number" /></div>
</sqx-form-row>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<sqx-form-row for="minHeight" hideError label="common.height" [prefix]="field.fieldId" unit="px">
<div class="row g-0">
<div class="col"><input class="form-control" formControlName="minHeight" type="number" /></div>
<div class="col"><input class="form-control" formControlName="maxHeight" type="number" /></div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col col-label"><label class="col-form-label">px</label></div>
</div>
<div class="col"><input class="form-control" formControlName="maxHeight" type="number" /></div>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "common.aspectRatio" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col"><input class="form-control" formControlName="aspectWidth" type="number" /></div>
</sqx-form-row>
<div class="col-auto"><label class="col-form-label minmax">:</label></div>
<sqx-form-row for="aspectRatio" hideError label="common.aspectRatio" [prefix]="field.fieldId" unit="px">
<div class="row g-0">
<div class="col"><input class="form-control" formControlName="aspectWidth" type="number" /></div>
<div class="col"><input class="form-control" formControlName="aspectHeight" type="number" /></div>
<div class="col-auto"><label class="col-form-label minmax">:</label></div>
<div class="col col-label"><label class="col-form-label">px</label></div>
</div>
<div class="col"><input class="form-control" formControlName="aspectHeight" type="number" /></div>
</div>
</div>
</sqx-form-row>
<hr />
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldAllowDuplicates" formControlName="allowDuplicates" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldAllowDuplicates">
{{ "schemas.fieldTypes.assets.allowDuplicates" | sqxTranslate }}
</label>
</div>
</div>
</div>
<sqx-form-row #allowDuplicatesRow check for="allowDuplicates" hideError label="schemas.fieldTypes.assets.allowDuplicates" [prefix]="field.fieldId">
<input class="form-check-input" [id]="allowDuplicatesRow.fieldName" formControlName="allowDuplicates" type="checkbox" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.assets.fileExtensions" | sqxTranslate }}</label>
<div class="col-9"><sqx-tag-editor formControlName="allowedExtensions" /></div>
</div>
<sqx-form-row #allowedExtensionsRow for="allowedExtensions" hideError label="schemas.fieldTypes.assets.fileExtensions" [prefix]="field.fieldId">
<sqx-tag-editor [id]="allowedExtensionsRow.fieldName" formControlName="allowedExtensions" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.defaultValue" | sqxTranslate }}</label>
<div class="col-9"><sqx-tag-editor formControlName="defaultValue" /></div>
</div>
<sqx-form-row #defaultValueRow for="defaultValue" hideError label="schemas.field.defaultValue" [prefix]="field.fieldId">
<sqx-tag-editor [id]="defaultValueRow.fieldName" formControlName="defaultValue" />
</sqx-form-row>
@if (isLocalizable) {
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.defaultValues" | sqxTranslate }}</label>
<div class="col-9">
<sqx-localized-input formControlName="defaultValues" [languages]="languages" type="tags" />
<sqx-form-hint> {{ "schemas.field.defaultValuesHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row
#defaultValuesRow
for="defaultValues"
hideError
hint="schemas.field.defaultValuesHint"
label="schemas.field.defaultValues"
[prefix]="field.fieldId">
<sqx-localized-input [id]="defaultValuesRow.fieldName" formControlName="defaultValues" [languages]="languages" type="tags" />
</sqx-form-row>
}
</div>

5
frontend/src/app/features/schemas/pages/schema/fields/types/assets-validation.component.scss

@ -5,9 +5,4 @@
text-align: center;
text-decoration: none;
width: 2rem;
}
.col-label {
@include force-width(5rem);
padding-left: .5rem;
}

8
frontend/src/app/features/schemas/pages/schema/fields/types/assets-validation.component.ts

@ -8,15 +8,15 @@
import { booleanAttribute, Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { AppLanguageDto, AssetsFieldPropertiesDto, FieldDto, FormHintComponent, LocalizedInputComponent, TagEditorComponent, TranslatePipe } from '@app/shared';
import { AppLanguageDto, AssetsFieldPropertiesDto, FieldDto, FormRowComponent, LocalizedInputComponent, TagEditorComponent, TranslatePipe } from '@app/shared';
@Component({
selector: 'sqx-assets-validation',
styleUrls: ['assets-validation.component.scss'],
templateUrl: 'assets-validation.component.html',
imports: [
FormHintComponent,
FormsModule,
FormRowComponent,
LocalizedInputComponent,
ReactiveFormsModule,
TagEditorComponent,
@ -36,6 +36,6 @@ export class AssetsValidationComponent {
@Input({ required: true })
public languages!: ReadonlyArray<AppLanguageDto>;
@Input({ transform: booleanAttribute })
public isLocalizable?: boolean | null;
@Input({ required: true, transform: booleanAttribute })
public isLocalizable!: boolean;
}

44
frontend/src/app/features/schemas/pages/schema/fields/types/boolean-ui.component.html

@ -1,34 +1,18 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldPlaceholder">
{{ "schemas.field.placeholder" | sqxTranslate }}
</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_fieldPlaceholder" formControlName="placeholder" maxlength="100" />
<sqx-form-hint> {{ "schemas.field.placeholderHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #placeholderRow for="placeholder" hint="schemas.field.placeholderHint" label="schemas.field.placeholder" [prefix]="field.fieldId">
<input class="form-control" [id]="placeholderRow.fieldName" formControlName="placeholder" maxlength="100" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.editor" | sqxTranslate }}</label>
<div class="col-9">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</div>
</div>
<sqx-form-row for="editor" label="schemas.field.editor" [prefix]="field.fieldId">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</sqx-form-row>
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldInlineEditable" formControlName="inlineEditable" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldInlineEditable">
{{ "schemas.field.inlineEditable" | sqxTranslate }}
</label>
</div>
</div>
</div>
<sqx-form-row #inlineEditableRow check for="inlineEditable" label="schemas.field.inlineEditable" [prefix]="field.fieldId">
<input class="form-check-input" [id]="inlineEditableRow.fieldName" formControlName="inlineEditable" type="checkbox" />
</sqx-form-row>
</div>

5
frontend/src/app/features/schemas/pages/schema/fields/types/boolean-ui.component.ts

@ -8,17 +8,16 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { BooleanFieldEditorValues, BooleanFieldPropertiesDto, FieldDto, FormHintComponent, TranslatePipe } from '@app/shared';
import { BooleanFieldEditorValues, BooleanFieldPropertiesDto, FieldDto, FormRowComponent } from '@app/shared';
@Component({
selector: 'sqx-boolean-ui',
styleUrls: ['boolean-ui.component.scss'],
templateUrl: 'boolean-ui.component.html',
imports: [
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,
],
})
export class BooleanUIComponent {

30
frontend/src/app/features/schemas/pages/schema/fields/types/boolean-validation.component.html

@ -1,29 +1,11 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input
class="form-check-input"
id="{{ field.fieldId }}_fieldDefaultValue"
formControlName="defaultValue"
sqxIndeterminateValue
type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldDefaultValue">
{{ "schemas.field.defaultValue" | sqxTranslate }}
</label>
</div>
</div>
</div>
<sqx-form-row #defaultValueRow for="defaultValue" label="schemas.field.defaultValue" [prefix]="field.fieldId">
<input class="form-check-input" [id]="defaultValueRow.fieldName" formControlName="defaultValue" sqxIndeterminateValue type="checkbox" />
</sqx-form-row>
@if (isLocalizable) {
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldDefaultValues">
{{ "schemas.field.defaultValues" | sqxTranslate }}
</label>
<div class="col-9">
<sqx-localized-input id="{{ field.fieldId }}_fieldDefaultValues" formControlName="defaultValues" [languages]="languages" type="boolean" />
<sqx-form-hint> {{ "schemas.field.defaultValuesHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #defaultValueRows for="defaultValues" hint="schemas.field.defaultValuesHint" label="schemas.field.defaultValues" [prefix]="field.fieldId">
<sqx-localized-input [id]="defaultValueRows.fieldName" formControlName="defaultValues" [languages]="languages" type="boolean" />
</sqx-form-row>
}
</div>

9
frontend/src/app/features/schemas/pages/schema/fields/types/boolean-validation.component.ts

@ -9,19 +9,18 @@
import { booleanAttribute, Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import { AppLanguageDto, BooleanFieldPropertiesDto, FieldDto, FormHintComponent, hasNoValue$, IndeterminateValueDirective, LocalizedInputComponent, TranslatePipe, TypedSimpleChanges } from '@app/shared';
import { AppLanguageDto, BooleanFieldPropertiesDto, FieldDto, FormRowComponent, hasNoValue$, IndeterminateValueDirective, LocalizedInputComponent, TypedSimpleChanges } from '@app/shared';
@Component({
selector: 'sqx-boolean-validation',
styleUrls: ['boolean-validation.component.scss'],
templateUrl: 'boolean-validation.component.html',
imports: [
FormHintComponent,
FormRowComponent,
FormsModule,
IndeterminateValueDirective,
LocalizedInputComponent,
ReactiveFormsModule,
TranslatePipe,
],
})
export class BooleanValidationComponent {
@ -37,8 +36,8 @@ export class BooleanValidationComponent {
@Input({ required: true })
public languages!: ReadonlyArray<AppLanguageDto>;
@Input({ transform: booleanAttribute })
public isLocalizable?: boolean | null;
@Input({ required: true, transform: booleanAttribute })
public isLocalizable!: boolean;
public showDefaultValue?: Observable<boolean>;

18
frontend/src/app/features/schemas/pages/schema/fields/types/component-validation.component.html

@ -1,12 +1,10 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldSchemaIds">{{ "common.schemas" | sqxTranslate }}</label>
<div class="col-9">
<sqx-tag-editor
formControlName="schemaIds"
[itemConverter]="(schemasSource.converter | async)!"
[itemsSource]="(schemasSource.converter | async)?.suggestions"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</div>
</div>
<sqx-form-row for="schemaIds" label="common.schemas" [prefix]="field.fieldId">
<sqx-tag-editor
id="schemaIds"
formControlName="schemaIds"
[itemConverter]="(schemasSource.converter | async)!"
[itemsSource]="(schemasSource.converter | async)?.suggestions"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</sqx-form-row>
</div>

3
frontend/src/app/features/schemas/pages/schema/fields/types/component-validation.component.ts

@ -8,7 +8,7 @@
import { AsyncPipe } from '@angular/common';
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { FieldDto, ReferencesFieldPropertiesDto, SchemaTagSource, TagEditorComponent, TranslatePipe } from '@app/shared';
import { FieldDto, FormRowComponent, ReferencesFieldPropertiesDto, SchemaTagSource, TagEditorComponent, TranslatePipe } from '@app/shared';
@Component({
selector: 'sqx-component-validation',
@ -16,6 +16,7 @@ import { FieldDto, ReferencesFieldPropertiesDto, SchemaTagSource, TagEditorCompo
templateUrl: 'component-validation.component.html',
imports: [
AsyncPipe,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TagEditorComponent,

17
frontend/src/app/features/schemas/pages/schema/fields/types/components-ui.component.html

@ -1,12 +1,9 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.defaultValue" | sqxTranslate }}</label>
<div class="col-3">
<select class="form-select" formControlName="calculatedDefaultValue">
@for (value of calculatedDefaultValues; track value) {
<option [ngValue]="value">{{ value }}</option>
}
</select>
</div>
</div>
<sqx-form-row for="calculatedDefaultValue" label="schemas.field.defaultValue" [prefix]="field.fieldId">
<select class="form-select" formControlName="calculatedDefaultValue">
@for (value of calculatedDefaultValues; track value) {
<option [ngValue]="value">{{ value }}</option>
}
</select>
</sqx-form-row>
</div>

4
frontend/src/app/features/schemas/pages/schema/fields/types/components-ui.component.ts

@ -8,7 +8,7 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { FieldDto, ReferencesFieldPropertiesDto, TranslatePipe } from '@app/shared';
import { FieldDto, FormRowComponent, ReferencesFieldPropertiesDto } from '@app/shared';
const CALCULATED_DEFAULT_VALUES: ReadonlyArray<string> = ['EmptyArray', 'Null'];
@ -17,9 +17,9 @@ const CALCULATED_DEFAULT_VALUES: ReadonlyArray<string> = ['EmptyArray', 'Null'];
styleUrls: ['components-ui.component.scss'],
templateUrl: 'components-ui.component.html',
imports: [
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,
],
})
export class ComponentsUIComponent {

62
frontend/src/app/features/schemas/pages/schema/fields/types/components-validation.component.html

@ -1,42 +1,36 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.references.count" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minItems"
placeholder="{{ 'schemas.fieldTypes.references.countMin' | sqxTranslate }}"
type="number" />
</div>
<sqx-form-row for="minItems" hideError label="schemas.fieldTypes.references.count" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minItems"
placeholder="{{ 'schemas.fieldTypes.references.countMin' | sqxTranslate }}"
type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxItems"
placeholder="{{ 'schemas.fieldTypes.references.countMax' | sqxTranslate }}"
type="number" />
</div>
<div class="col">
<input
class="form-control"
formControlName="maxItems"
placeholder="{{ 'schemas.fieldTypes.references.countMax' | sqxTranslate }}"
type="number" />
</div>
</div>
</div>
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldSchemaIds">{{ "common.schemas" | sqxTranslate }}</label>
<div class="col-9">
<sqx-tag-editor
formControlName="schemaIds"
[itemConverter]="(schemasSource.converter | async)!"
[itemsSource]="(schemasSource.converter | async)?.suggestions"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</div>
</div>
<sqx-form-row #schemaIdsRow for="schemaIds" label="common.schemas" [prefix]="field.fieldId">
<sqx-tag-editor
[id]="schemaIdsRow.fieldName"
formControlName="schemaIds"
[itemConverter]="(schemasSource.converter | async)!"
[itemsSource]="(schemasSource.converter | async)?.suggestions"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.array.uniqueFields" | sqxTranslate }}</label>
<div class="col-9"><sqx-tag-editor formControlName="uniqueFields" /></div>
</div>
<sqx-form-row #uniqueFieldsRow for="uniqueFields" label="schemas.fieldTypes.array.uniqueFields" [prefix]="field.fieldId">
<sqx-tag-editor [id]="uniqueFieldsRow.fieldName" formControlName="uniqueFields" />
</sqx-form-row>
</div>

3
frontend/src/app/features/schemas/pages/schema/fields/types/components-validation.component.ts

@ -8,7 +8,7 @@
import { AsyncPipe } from '@angular/common';
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { FieldDto, ReferencesFieldPropertiesDto, SchemaTagSource, TagEditorComponent, TranslatePipe } from '@app/shared';
import { FieldDto, FormRowComponent, ReferencesFieldPropertiesDto, SchemaTagSource, TagEditorComponent, TranslatePipe } from '@app/shared';
@Component({
selector: 'sqx-components-validation',
@ -16,6 +16,7 @@ import { FieldDto, ReferencesFieldPropertiesDto, SchemaTagSource, TagEditorCompo
templateUrl: 'components-validation.component.html',
imports: [
AsyncPipe,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TagEditorComponent,

45
frontend/src/app/features/schemas/pages/schema/fields/types/date-time-ui.component.html

@ -1,35 +1,18 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldPlaceholder">
{{ "schemas.field.placeholder" | sqxTranslate }}
</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_fieldPlaceholder" formControlName="placeholder" maxlength="100" />
<sqx-form-hint> {{ "schemas.field.placeholderHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #placeholderRow for="placeholder" hint="schemas.field.placeholderHint" label="schemas.field.placeholder" [prefix]="field.fieldId">
<input class="form-control" [id]="placeholderRow.fieldName" formControlName="placeholder" maxlength="100" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldFormat">
{{ "schemas.fieldTypes.dateTime.format" | sqxTranslate }}
</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_fieldFormat" formControlName="format" maxlength="100" />
<sqx-form-hint>
<span inline="true" [sqxMarkdown]="'schemas.fieldTypes.dateTime.formatHint' | sqxTranslate"></span>
</sqx-form-hint>
</div>
</div>
<sqx-form-row #formatRow for="format" hint="schemas.fieldTypes.dateTime.formatHint" label="schemas.fieldTypes.dateTime.format" [prefix]="field.fieldId">
<input class="form-control" [id]="formatRow.fieldName" formControlName="format" maxlength="100" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.editor" | sqxTranslate }}</label>
<div class="col-9">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</div>
</div>
<sqx-form-row for="editor" label="schemas.field.editor" [prefix]="field.fieldId">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</sqx-form-row>
</div>

6
frontend/src/app/features/schemas/pages/schema/fields/types/date-time-ui.component.ts

@ -8,18 +8,16 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { DateTimeFieldEditorValues, DateTimeFieldPropertiesDto, FieldDto, FloatConverter, FormHintComponent, MarkdownDirective, TranslatePipe } from '@app/shared';
import { DateTimeFieldEditorValues, DateTimeFieldPropertiesDto, FieldDto, FloatConverter, FormRowComponent } from '@app/shared';
@Component({
selector: 'sqx-date-time-ui',
styleUrls: ['date-time-ui.component.scss'],
templateUrl: 'date-time-ui.component.html',
imports: [
FormHintComponent,
FormRowComponent,
FormsModule,
MarkdownDirective,
ReactiveFormsModule,
TranslatePipe,
],
})
export class DateTimeUIComponent {

57
frontend/src/app/features/schemas/pages/schema/fields/types/date-time-validation.component.html

@ -1,45 +1,38 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.dateTime.rangeMin" | sqxTranslate }}</label>
<div class="col-9"><sqx-date-time-editor formControlName="minValue" mode="DateTime" /></div>
</div>
<sqx-form-row for="minValue" label="schemas.fieldTypes.dateTime.rangeMin" [prefix]="field.fieldId">
<sqx-date-time-editor formControlName="minValue" mode="DateTime" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.dateTime.rangeMax" | sqxTranslate }}</label>
<div class="col-9"><sqx-date-time-editor formControlName="maxValue" mode="DateTime" /></div>
</div>
<sqx-form-row for="maxValue" label="schemas.fieldTypes.dateTime.rangeMax" [prefix]="field.fieldId">
<sqx-date-time-editor formControlName="maxValue" mode="DateTime" />
</sqx-form-row>
@if (showDefaultValues | async) {
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.dateTime.defaultMode" | sqxTranslate }}</label>
<div class="col-3">
<select class="form-select" formControlName="calculatedDefaultValue">
<option></option>
<sqx-form-row for="calculatedDefaultValue" label="schemas.fieldTypes.dateTime.defaultMode" [prefix]="field.fieldId">
<select class="form-select" formControlName="calculatedDefaultValue">
<option></option>
@for (value of calculatedDefaultValues; track value) {
<option [ngValue]="value">{{ value }}</option>
}
</select>
</div>
</div>
@for (value of calculatedDefaultValues; track value) {
<option [ngValue]="value">{{ value }}</option>
}
</select>
</sqx-form-row>
@if (showDefaultValue | async) {
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.defaultValue" | sqxTranslate }}</label>
<div class="col-9"><sqx-date-time-editor formControlName="defaultValue" mode="DateTime" /></div>
</div>
<sqx-form-row #defaultValueRow for="defaultValue" label="schemas.field.defaultValue" [prefix]="field.fieldId">
<sqx-date-time-editor [id]="defaultValueRow.fieldName" formControlName="defaultValue" mode="DateTime" />
</sqx-form-row>
}
@if (isLocalizable) {
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldDefaultValues">
{{ "schemas.field.defaultValues" | sqxTranslate }}
</label>
<div class="col-9">
<sqx-localized-input id="{{ field.fieldId }}_fieldDefaultValues" formControlName="defaultValues" [languages]="languages" type="datetime" />
<sqx-form-hint> {{ "schemas.field.defaultValuesHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row
#defaultValueRows
for="defaultValues"
hint="schemas.field.defaultValuesHint"
label="schemas.field.defaultValues"
[prefix]="field.fieldId">
<sqx-localized-input [id]="defaultValueRows.fieldName" formControlName="defaultValues" [languages]="languages" type="datetime" />
</sqx-form-row>
}
}
</div>

11
frontend/src/app/features/schemas/pages/schema/fields/types/date-time-validation.component.ts

@ -9,7 +9,7 @@ import { AsyncPipe } from '@angular/common';
import { booleanAttribute, Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import { AppLanguageDto, DateTimeEditorComponent, DateTimeFieldPropertiesDto, FieldDto, FormHintComponent, hasNoValue$, LocalizedInputComponent, TranslatePipe, TypedSimpleChanges } from '@app/shared';
import { AppLanguageDto, DateTimeEditorComponent, DateTimeFieldPropertiesDto, FieldDto, FormRowComponent, hasNoValue$, LocalizedInputComponent, TypedSimpleChanges, valueProjection$ } from '@app/shared';
const CALCULATED_DEFAULT_VALUES: ReadonlyArray<string> = ['Now', 'Today'];
@ -20,11 +20,10 @@ const CALCULATED_DEFAULT_VALUES: ReadonlyArray<string> = ['Now', 'Today'];
imports: [
AsyncPipe,
DateTimeEditorComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
LocalizedInputComponent,
ReactiveFormsModule,
TranslatePipe,
],
})
export class DateTimeValidationComponent {
@ -40,8 +39,8 @@ export class DateTimeValidationComponent {
@Input({ required: true })
public languages!: ReadonlyArray<AppLanguageDto>;
@Input({ transform: booleanAttribute })
public isLocalizable?: boolean | null;
@Input({ required: true, transform: booleanAttribute })
public isLocalizable!: boolean;
public showDefaultValues?: Observable<boolean>;
public showDefaultValue?: Observable<boolean>;
@ -51,7 +50,7 @@ export class DateTimeValidationComponent {
public ngOnChanges(changes: TypedSimpleChanges<this>) {
if (changes.fieldForm) {
this.showDefaultValues =
hasNoValue$(this.fieldForm.controls['isRequired']);
valueProjection$(this.fieldForm.controls['isRequired'], x => x !== true);
this.showDefaultValue =
hasNoValue$(this.fieldForm.controls['calculatedDefaultValue']);

15
frontend/src/app/features/schemas/pages/schema/fields/types/geolocation-ui.component.html

@ -1,11 +1,8 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.editor" | sqxTranslate }}</label>
<div class="col-9">
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === 'Map'">
<input class="radio-input" formControlName="editor" name="editor" type="radio" value="Map" />
<i class="icon-control-Map"></i> <span class="radio-label">Map</span>
</label>
</div>
</div>
<sqx-form-row for="editor" label="schemas.field.editor" [prefix]="field.fieldId">
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === 'Map'">
<input class="radio-input" formControlName="editor" name="editor" type="radio" value="Map" />
<i class="icon-control-Map"></i> <span class="radio-label">Map</span>
</label>
</sqx-form-row>
</div>

4
frontend/src/app/features/schemas/pages/schema/fields/types/geolocation-ui.component.ts

@ -7,16 +7,16 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { FieldDto, GeolocationFieldPropertiesDto, TranslatePipe } from '@app/shared';
import { FieldDto, FormRowComponent, GeolocationFieldPropertiesDto } from '@app/shared';
@Component({
selector: 'sqx-geolocation-ui',
styleUrls: ['geolocation-ui.component.scss'],
templateUrl: 'geolocation-ui.component.html',
imports: [
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,
],
})
export class GeolocationUIComponent {

6
frontend/src/app/features/schemas/pages/schema/fields/types/json-more.component.html

@ -1,7 +1,5 @@
<div [formGroup]="fieldForm">
<div class="form-group">
<label>{{ "schemas.field.graphQLSchema" | sqxTranslate }}</label>
<sqx-form-row for="graphQLSchema" hint="schemas.field.graphQLSchemaHint" label="schemas.field.graphQLSchema" [prefix]="field.fieldId" vertical>
<sqx-code-editor formControlName="graphQLSchema" [height]="350" mode="ace/mode/graphqlschema" />
<sqx-form-hint> {{ "schemas.field.graphQLSchemaHint" | sqxTranslate }} </sqx-form-hint>
</div>
</sqx-form-row>
</div>

5
frontend/src/app/features/schemas/pages/schema/fields/types/json-more.component.ts

@ -7,7 +7,7 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { CodeEditorComponent, FieldDto, FormHintComponent, JsonFieldPropertiesDto, TranslatePipe } from '@app/shared';
import { CodeEditorComponent, FieldDto, FormRowComponent, JsonFieldPropertiesDto } from '@app/shared';
@Component({
selector: 'sqx-json-more',
@ -15,10 +15,9 @@ import { CodeEditorComponent, FieldDto, FormHintComponent, JsonFieldPropertiesDt
templateUrl: 'json-more.component.html',
imports: [
CodeEditorComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,
],
})
export class JsonMoreComponent {

51
frontend/src/app/features/schemas/pages/schema/fields/types/number-ui.component.html

@ -1,39 +1,22 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldPlaceholder">
{{ "schemas.field.placeholder" | sqxTranslate }}
</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_fieldPlaceholder" formControlName="placeholder" maxlength="100" />
<sqx-form-hint> {{ "schemas.field.placeholderHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #placeholderRow for="placeholder" hint="schemas.field.placeholderHint" label="schemas.field.placeholder" [prefix]="field.fieldId">
<input class="form-control" [id]="placeholderRow.fieldName" formControlName="placeholder" maxlength="100" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.editor" | sqxTranslate }}</label>
<div class="col-9">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</div>
</div>
<sqx-form-row for="editor" label="schemas.field.editor" [prefix]="field.fieldId">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</sqx-form-row>
<div class="form-group row" [class.hidden]="hideAllowedValues | async">
<label class="col-3 col-form-label">{{ "schemas.field.allowedValues" | sqxTranslate }}</label>
<div class="col-9"><sqx-tag-editor formControlName="allowedValues" [itemConverter]="converter" /></div>
</div>
<sqx-form-row #allowedValuesRow [class.hidden]="hideAllowedValues | async" for="allowedValues" label="schemas.field.allowedValues" [prefix]="field.fieldId">
<sqx-tag-editor [id]="allowedValuesRow.fieldName" formControlName="allowedValues" [itemConverter]="converter" />
</sqx-form-row>
<div class="form-group row" [class.hidden]="hideInlineEditable | async">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldInlineEditable" formControlName="inlineEditable" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldInlineEditable">
{{ "schemas.field.inlineEditable" | sqxTranslate }}
</label>
</div>
</div>
</div>
<sqx-form-row #inlineEditableRow check for="inlineEditable" label="schemas.field.inlineEditable" [prefix]="field.fieldId">
<input class="form-check-input" [id]="inlineEditableRow.fieldName" formControlName="inlineEditable" type="checkbox" />
</sqx-form-row>
</div>

5
frontend/src/app/features/schemas/pages/schema/fields/types/number-ui.component.ts

@ -9,7 +9,7 @@ import { AsyncPipe } from '@angular/common';
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import { FieldDto, FloatConverter, FormHintComponent, NumberFieldEditorValues, NumberFieldPropertiesDto, Subscriptions, TagEditorComponent, TranslatePipe, TypedSimpleChanges, valueProjection$ } from '@app/shared';
import { FieldDto, FloatConverter, FormRowComponent, NumberFieldEditorValues, NumberFieldPropertiesDto, Subscriptions, TagEditorComponent, TypedSimpleChanges, valueProjection$ } from '@app/shared';
@Component({
selector: 'sqx-number-ui',
@ -17,11 +17,10 @@ import { FieldDto, FloatConverter, FormHintComponent, NumberFieldEditorValues, N
templateUrl: 'number-ui.component.html',
imports: [
AsyncPipe,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TagEditorComponent,
TranslatePipe,
],
})
export class NumberUIComponent {

65
frontend/src/app/features/schemas/pages/schema/fields/types/number-validation.component.html

@ -1,60 +1,31 @@
<div [formGroup]="fieldForm">
@if (showUnique) {
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldUnique" formControlName="isUnique" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldUnique">
{{ "schemas.field.unique" | sqxTranslate }}
</label>
</div>
</div>
</div>
<sqx-form-row #isUniqueRow check for="isUnique" label="schemas.field.unique" [prefix]="field.fieldId">
<input class="form-check-input" [id]="isUniqueRow.fieldName" formControlName="isUnique" type="checkbox" />
</sqx-form-row>
}
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.number.range" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minValue"
placeholder="{{ 'schemas.fieldTypes.number.rangeMin' | sqxTranslate }}"
type="number" />
</div>
<sqx-form-row for="minValue" hideError label="schemas.fieldTypes.number.range" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input class="form-control" formControlName="minValue" placeholder="{{ 'schemas.fieldTypes.number.rangeMin' | sqxTranslate }}" type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxValue"
placeholder="{{ 'schemas.fieldTypes.number.rangeMax' | sqxTranslate }}"
type="number" />
</div>
<div class="col">
<input class="form-control" formControlName="maxValue" placeholder="{{ 'schemas.fieldTypes.number.rangeMax' | sqxTranslate }}" type="number" />
</div>
</div>
</div>
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldDefaultValue">
{{ "schemas.field.defaultValue" | sqxTranslate }}
</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_fieldDefaultValue" formControlName="defaultValue" type="number" />
</div>
</div>
<sqx-form-row #defaultValueRow for="defaultValue" label="schemas.field.defaultValue" [prefix]="field.fieldId">
<input class="form-control" [id]="defaultValueRow.fieldName" formControlName="defaultValue" type="number" />
</sqx-form-row>
@if (isLocalizable) {
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldDefaultValues">
{{ "schemas.field.defaultValues" | sqxTranslate }}
</label>
<div class="col-9">
<sqx-localized-input id="{{ field.fieldId }}_fieldDefaultValues" formControlName="defaultValues" [languages]="languages" type="number" />
<sqx-form-hint> {{ "schemas.field.defaultValuesHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #defaultValuesRow for="defaultValues" hint="schemas.field.defaultValuesHint" label="schemas.field.defaultValues" [prefix]="field.fieldId">
<sqx-localized-input [id]="defaultValuesRow.fieldName" formControlName="defaultValues" [languages]="languages" type="number" />
</sqx-form-row>
}
</div>

8
frontend/src/app/features/schemas/pages/schema/fields/types/number-validation.component.ts

@ -8,14 +8,14 @@
import { booleanAttribute, Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { AppLanguageDto, FieldDto, FormHintComponent, LocalizedInputComponent, NumberFieldPropertiesDto, SchemaDto, TranslatePipe, Types } from '@app/shared';
import { AppLanguageDto, FieldDto, FormRowComponent, LocalizedInputComponent, NumberFieldPropertiesDto, SchemaDto, TranslatePipe, Types } from '@app/shared';
@Component({
selector: 'sqx-number-validation',
styleUrls: ['number-validation.component.scss'],
templateUrl: 'number-validation.component.html',
imports: [
FormHintComponent,
FormRowComponent,
FormsModule,
LocalizedInputComponent,
ReactiveFormsModule,
@ -38,8 +38,8 @@ export class NumberValidationComponent {
@Input({ required: true })
public languages!: ReadonlyArray<AppLanguageDto>;
@Input({ transform: booleanAttribute })
public isLocalizable?: boolean | null;
@Input({ required: true, transform: booleanAttribute })
public isLocalizable!: boolean;
public get showUnique() {
return Types.is(this.field, FieldDto) && !this.field.isLocalizable && this.schema.type !== 'Component';

51
frontend/src/app/features/schemas/pages/schema/fields/types/references-ui.component.html

@ -1,37 +1,26 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.editor" | sqxTranslate }}</label>
<div class="col-9">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</div>
</div>
<sqx-form-row for="editor" label="schemas.field.editor" [prefix]="field.fieldId">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</sqx-form-row>
@if (field.properties.isContentField) {
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldResolveReference" formControlName="resolveReference" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldResolveReference">
{{ "schemas.fieldTypes.references.resolve" | sqxTranslate }}
</label>
</div>
<sqx-form-hint> {{ "schemas.fieldTypes.references.resolveHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row
#isContentFieldRow
check
for="resolveReference"
hint="schemas.fieldTypes.references.resolveHint"
label="schemas.fieldTypes.references.resolve"
[prefix]="field.fieldId">
<input class="form-check-input" [id]="isContentFieldRow.fieldName" formControlName="resolveReference" type="checkbox" />
</sqx-form-row>
}
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_query">
{{ "schemas.fieldTypes.references.query" | sqxTranslate }}
</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_query" formControlName="query" type="text" />
<sqx-form-hint> {{ "schemas.fieldTypes.references.queryHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #queryRow for="query" hint="schemas.fieldTypes.references.queryHint" label="schemas.fieldTypes.references.query" [prefix]="field.fieldId">
<input class="form-control" [id]="queryRow.fieldName" formControlName="query" type="text" />
</sqx-form-row>
</div>

5
frontend/src/app/features/schemas/pages/schema/fields/types/references-ui.component.ts

@ -8,17 +8,16 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { FieldDto, FormHintComponent, ReferencesFieldEditorValues, ReferencesFieldPropertiesDto, TranslatePipe } from '@app/shared';
import { FieldDto, FormRowComponent, ReferencesFieldEditorValues, ReferencesFieldPropertiesDto } from '@app/shared';
@Component({
selector: 'sqx-references-ui',
styleUrls: ['references-ui.component.scss'],
templateUrl: 'references-ui.component.html',
imports: [
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,
],
})
export class ReferencesUIComponent {

99
frontend/src/app/features/schemas/pages/schema/fields/types/references-validation.component.html

@ -1,74 +1,49 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldSchemaIds">{{ "common.schemas" | sqxTranslate }}</label>
<div class="col-9">
<sqx-tag-editor
formControlName="schemaIds"
[itemConverter]="(schemasSource.normalConverter | async)!"
[itemsSource]="(schemasSource.normalConverter | async)?.suggestions"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</div>
</div>
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldAllowDuplicates" formControlName="allowDuplicates" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldAllowDuplicates">
{{ "schemas.fieldTypes.assets.allowDuplicates" | sqxTranslate }}
</label>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.references.count" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minItems"
placeholder="{{ 'schemas.fieldTypes.references.countMin' | sqxTranslate }}"
type="number" />
</div>
<sqx-form-row #schemaIdsRow for="schemaIds" label="common.schemas" [prefix]="field.fieldId">
<sqx-tag-editor
[id]="schemaIdsRow.fieldName"
formControlName="schemaIds"
[itemConverter]="(schemasSource.normalConverter | async)!"
[itemsSource]="(schemasSource.normalConverter | async)?.suggestions"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</sqx-form-row>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<sqx-form-row #allowDuplicates check for="allowDuplicates" label="schemas.fieldTypes.assets.allowDuplicates" [prefix]="field.fieldId">
<input class="form-check-input" [id]="allowDuplicates.fieldName" formControlName="allowDuplicates" type="checkbox" />
</sqx-form-row>
<div class="col">
<input
class="form-control"
formControlName="maxItems"
placeholder="{{ 'schemas.fieldTypes.references.countMax' | sqxTranslate }}"
type="number" />
</div>
<sqx-form-row for="countMin" hideError="true" label="schemas.fieldTypes.references.count" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minItems"
placeholder="{{ 'schemas.fieldTypes.references.countMin' | sqxTranslate }}"
type="number" />
</div>
</div>
</div>
<div class="form-group row mb-3">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldMustBePublished" formControlName="mustBePublished" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldMustBePublished">
{{ "schemas.fieldTypes.references.mustBePublished" | sqxTranslate }}
</label>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxItems"
placeholder="{{ 'schemas.fieldTypes.references.countMax' | sqxTranslate }}"
type="number" />
</div>
</div>
</div>
</sqx-form-row>
<sqx-form-row #mustBePublishedRow check for="mustBePublished" label="schemas.fieldTypes.references.mustBePublished" [prefix]="field.fieldId">
<input class="form-check-input" [id]="mustBePublishedRow.fieldName" formControlName="mustBePublished" type="checkbox" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.defaultValue" | sqxTranslate }}</label>
<div class="col-9"><sqx-tag-editor formControlName="defaultValue" /></div>
</div>
<sqx-form-row #defaultValueRow for="defaultValue" label="schemas.field.defaultValue" [prefix]="field.fieldId">
<sqx-tag-editor [id]="defaultValueRow.fieldName" formControlName="defaultValue" />
</sqx-form-row>
@if (isLocalizable) {
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.defaultValues" | sqxTranslate }}</label>
<div class="col-9">
<sqx-localized-input formControlName="defaultValues" [languages]="languages" type="tags" />
<sqx-form-hint> {{ "schemas.field.defaultValuesHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #defaultValuesRow for="defaultValues" hint="schemas.field.defaultValuesHint" label="schemas.field.defaultValues" [prefix]="field.fieldId">
<sqx-localized-input [id]="defaultValuesRow.fieldName" formControlName="defaultValues" [languages]="languages" type="tags" />
</sqx-form-row>
}
</div>

8
frontend/src/app/features/schemas/pages/schema/fields/types/references-validation.component.ts

@ -8,7 +8,7 @@
import { AsyncPipe } from '@angular/common';
import { booleanAttribute, Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { AppLanguageDto, FieldDto, FormHintComponent, LocalizedInputComponent, ReferencesFieldPropertiesDto, SchemaTagSource, TagEditorComponent, TranslatePipe } from '@app/shared';
import { AppLanguageDto, FieldDto, FormRowComponent, LocalizedInputComponent, ReferencesFieldPropertiesDto, SchemaTagSource, TagEditorComponent, TranslatePipe } from '@app/shared';
@Component({
selector: 'sqx-references-validation',
@ -16,7 +16,7 @@ import { AppLanguageDto, FieldDto, FormHintComponent, LocalizedInputComponent, R
templateUrl: 'references-validation.component.html',
imports: [
AsyncPipe,
FormHintComponent,
FormRowComponent,
FormsModule,
LocalizedInputComponent,
ReactiveFormsModule,
@ -37,8 +37,8 @@ export class ReferencesValidationComponent {
@Input({ required: true })
public languages!: ReadonlyArray<AppLanguageDto>;
@Input({ transform: booleanAttribute })
public isLocalizable?: boolean | null;
@Input({ required: true, transform: booleanAttribute })
public isLocalizable!: boolean;
constructor(
public readonly schemasSource: SchemaTagSource,

40
frontend/src/app/features/schemas/pages/schema/fields/types/rich-text-ui.component.html

@ -1,30 +1,18 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.string.classNames" | sqxTranslate }}</label>
<div class="col-9">
<sqx-tag-editor formControlName="classNames" />
<sqx-form-hint> {{ "schemas.fieldTypes.string.classNamesHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #classNamesRow for="classNames" hint="schemas.fieldTypes.string.classNamesHint" label="schemas.fieldTypes.string.classNames" [prefix]="field.fieldId">
<sqx-tag-editor [id]="classNamesRow.fieldName" formControlName="classNames" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_folderId">
{{ "schemas.fieldTypes.string.folderId" | sqxTranslate }}
</label>
<div class="col-9">
<sqx-asset-folder-dropdown formControlName="folderId" />
<sqx-form-hint> {{ "schemas.fieldTypes.string.folderIdHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row for="folderId" hint="schemas.fieldTypes.string.folderIdHint" label="schemas.fieldTypes.string.folderId" [prefix]="field.fieldId">
<sqx-asset-folder-dropdown formControlName="folderId" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldSchemaIds">{{ "common.schemas" | sqxTranslate }}</label>
<div class="col-9">
<sqx-tag-editor
formControlName="schemaIds"
[itemConverter]="(schemasSource.normalConverter | async)!"
[itemsSource]="(schemasSource.normalConverter | async)?.suggestions"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</div>
</div>
<sqx-form-row #schemaIdsRow for="schemaIds" label="common.schemas" [prefix]="field.fieldId">
<sqx-tag-editor
[id]="schemaIdsRow.fieldName"
formControlName="schemaIds"
[itemConverter]="(schemasSource.normalConverter | async)!"
[itemsSource]="(schemasSource.normalConverter | async)?.suggestions"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</sqx-form-row>
</div>

5
frontend/src/app/features/schemas/pages/schema/fields/types/rich-text-ui.component.ts

@ -8,15 +8,16 @@
import { AsyncPipe } from '@angular/common';
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { FieldDto, FormHintComponent, RichTextFieldPropertiesDto, SchemaTagSource, TagEditorComponent, TranslatePipe } from '@app/shared';
import { AssetFolderDropdownComponent, FieldDto, FormRowComponent, RichTextFieldPropertiesDto, SchemaTagSource, TagEditorComponent, TranslatePipe } from '@app/shared';
@Component({
selector: 'sqx-rich-text-ui',
styleUrls: ['rich-text-ui.component.scss'],
templateUrl: 'rich-text-ui.component.html',
imports: [
AssetFolderDropdownComponent,
AsyncPipe,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TagEditorComponent,

105
frontend/src/app/features/schemas/pages/schema/fields/types/rich-text-validation.component.html

@ -1,76 +1,59 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.string.length" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minLength"
placeholder="{{ 'schemas.fieldTypes.string.lengthMin' | sqxTranslate }}"
type="number" />
</div>
<sqx-form-row for="minLength" hideError label="schemas.fieldTypes.string.length" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minLength"
placeholder="{{ 'schemas.fieldTypes.string.lengthMin' | sqxTranslate }}"
type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxLength"
placeholder="{{ 'schemas.fieldTypes.string.lengthMax' | sqxTranslate }}"
type="number" />
</div>
<div class="col">
<input
class="form-control"
formControlName="maxLength"
placeholder="{{ 'schemas.fieldTypes.string.lengthMax' | sqxTranslate }}"
type="number" />
</div>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.string.characters" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minCharacters"
placeholder="{{ 'schemas.fieldTypes.string.charactersMin' | sqxTranslate }}"
type="number" />
</div>
</sqx-form-row>
<sqx-form-row for="minCharacters" hideError label="schemas.fieldTypes.string.characters" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minCharacters"
placeholder="{{ 'schemas.fieldTypes.string.charactersMin' | sqxTranslate }}"
type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxCharacters"
placeholder="{{ 'schemas.fieldTypes.string.charactersMax' | sqxTranslate }}"
type="number" />
</div>
<div class="col">
<input
class="form-control"
formControlName="maxCharacters"
placeholder="{{ 'schemas.fieldTypes.string.charactersMax' | sqxTranslate }}"
type="number" />
</div>
</div>
</div>
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.string.words" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minWords"
placeholder="{{ 'schemas.fieldTypes.string.wordsMin' | sqxTranslate }}"
type="number" />
</div>
<sqx-form-row for="minWords" hideError label="schemas.fieldTypes.string.words" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input class="form-control" formControlName="minWords" placeholder="{{ 'schemas.fieldTypes.string.wordsMin' | sqxTranslate }}" type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxWords"
placeholder="{{ 'schemas.fieldTypes.string.wordsMax' | sqxTranslate }}"
type="number" />
</div>
<div class="col">
<input class="form-control" formControlName="maxWords" placeholder="{{ 'schemas.fieldTypes.string.wordsMax' | sqxTranslate }}" type="number" />
</div>
</div>
</div>
</sqx-form-row>
</div>

3
frontend/src/app/features/schemas/pages/schema/fields/types/rich-text-validation.component.ts

@ -7,13 +7,14 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { FieldDto, RichTextFieldPropertiesDto, TranslatePipe } from '@app/shared';
import { FieldDto, FormRowComponent, RichTextFieldPropertiesDto, TranslatePipe } from '@app/shared';
@Component({
selector: 'sqx-rich-text-validation',
styleUrls: ['rich-text-validation.component.scss'],
templateUrl: 'rich-text-validation.component.html',
imports: [
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,

148
frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.html

@ -1,92 +1,60 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldPlaceholder">
{{ "schemas.field.placeholder" | sqxTranslate }}
</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_fieldPlaceholder" formControlName="placeholder" maxlength="100" />
<sqx-form-hint> {{ "schemas.field.placeholderHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.editor" | sqxTranslate }}</label>
<div class="col-9">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</div>
</div>
<div class="form-group row" [class.hidden]="hideClassNames | async">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.string.classNames" | sqxTranslate }}</label>
<div class="col-9">
<sqx-tag-editor formControlName="classNames" />
<sqx-form-hint> {{ "schemas.fieldTypes.string.classNamesHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="form-group row" [class.hidden]="hideAllowedValues | async">
<label class="col-3 col-form-label">{{ "schemas.field.allowedValues" | sqxTranslate }}</label>
<div class="col-9"><sqx-tag-editor formControlName="allowedValues" /></div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_folderId">
{{ "schemas.fieldTypes.string.folderId" | sqxTranslate }}
</label>
<div class="col-9">
<sqx-asset-folder-dropdown formControlName="folderId" />
<sqx-form-hint> {{ "schemas.fieldTypes.string.folderIdHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="form-group row" [class.hidden]="hideAllowedValues | async">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_createEnum" formControlName="createEnum" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_createEnum">
{{ "schemas.field.createEnum" | sqxTranslate }}
</label>
</div>
<sqx-form-hint> {{ "schemas.field.createEnumHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="form-group row" [class.hidden]="hideInlineEditable | async">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldInlineEditable" formControlName="inlineEditable" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldInlineEditable">
{{ "schemas.field.inlineEditable" | sqxTranslate }}
</label>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldIsEmbeddable" formControlName="isEmbeddable" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldIsEmbeddable">
{{ "schemas.field.isEmbeddable" | sqxTranslate }}
</label>
</div>
<sqx-form-hint> {{ "schemas.field.isEmbeddableHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="form-group row" [class.hidden]="hideSchemaIds | async">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldSchemaIds">{{ "common.schemas" | sqxTranslate }}</label>
<div class="col-9">
<sqx-tag-editor
formControlName="schemaIds"
[itemConverter]="(schemasSource.normalConverter | async)!"
[itemsSource]="(schemasSource.normalConverter | async)?.suggestions"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</div>
</div>
<sqx-form-row #placeholderRow for="placeholder" hint="schemas.field.placeholderHint" label="schemas.field.placeholder" [prefix]="field.fieldId">
<input class="form-control" [id]="placeholderRow.fieldName" formControlName="placeholder" maxlength="100" />
</sqx-form-row>
<sqx-form-row for="editor" label="schemas.field.editor" [prefix]="field.fieldId">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</sqx-form-row>
<sqx-form-row
#classNamesRow
[class.hidden]="hideClassNames | async"
for="classNames"
hint="schemas.fieldTypes.string.classNamesHint"
label="schemas.fieldTypes.string.classNames"
[prefix]="field.fieldId">
<sqx-tag-editor [id]="classNamesRow.fieldName" formControlName="classNames" />
</sqx-form-row>
<sqx-form-row #allowedValuesRow [class.hidden]="hideAllowedValues | async" for="allowedValues" label="schemas.field.allowedValues" [prefix]="field.fieldId">
<sqx-tag-editor [id]="allowedValuesRow.fieldName" formControlName="allowedValues" />
</sqx-form-row>
<sqx-form-row for="folderId" hint="schemas.fieldTypes.string.folderIdHint" label="schemas.fieldTypes.string.folderId" [prefix]="field.fieldId">
<sqx-asset-folder-dropdown formControlName="folderId" />
</sqx-form-row>
<sqx-form-row
#createEnumRow
check
[class.hidden]="hideAllowedValues | async"
for="createEnum"
hint="schemas.field.createEnumHint"
label="schemas.field.createEnum"
[prefix]="field.fieldId">
<input class="form-check-input" [id]="createEnumRow.fieldName" formControlName="createEnum" type="checkbox" />
</sqx-form-row>
<sqx-form-row #inlineEditableRow check for="inlineEditable" label="schemas.field.inlineEditable" [prefix]="field.fieldId">
<input class="form-check-input" [id]="inlineEditableRow.fieldName" formControlName="inlineEditable" type="checkbox" />
</sqx-form-row>
<sqx-form-row #isEmbeddableRow check for="isEmbeddable" hint="schemas.field.isEmbeddableHint" label="schemas.field.isEmbeddable" [prefix]="field.fieldId">
<input class="form-check-input" [id]="isEmbeddableRow.fieldName" formControlName="isEmbeddable" type="checkbox" />
</sqx-form-row>
<sqx-form-row #schemaIdsRow for="schemaIds" label="common.schemas" [prefix]="field.fieldId">
<sqx-tag-editor
[id]="schemaIdsRow.fieldName"
formControlName="schemaIds"
[itemConverter]="(schemasSource.normalConverter | async)!"
[itemsSource]="(schemasSource.normalConverter | async)?.suggestions"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</sqx-form-row>
</div>

4
frontend/src/app/features/schemas/pages/schema/fields/types/string-ui.component.ts

@ -9,7 +9,7 @@ import { AsyncPipe } from '@angular/common';
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import { AssetFolderDropdownComponent, FieldDto, FormHintComponent, SchemaTagSource, StringFieldEditorValues, StringFieldPropertiesDto, Subscriptions, TagEditorComponent, TranslatePipe, TypedSimpleChanges, valueProjection$ } from '@app/shared';
import { AssetFolderDropdownComponent, FieldDto, FormRowComponent, SchemaTagSource, StringFieldEditorValues, StringFieldPropertiesDto, Subscriptions, TagEditorComponent, TranslatePipe, TypedSimpleChanges, valueProjection$ } from '@app/shared';
@Component({
selector: 'sqx-string-ui',
@ -18,7 +18,7 @@ import { AssetFolderDropdownComponent, FieldDto, FormHintComponent, SchemaTagSou
imports: [
AssetFolderDropdownComponent,
AsyncPipe,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TagEditorComponent,

245
frontend/src/app/features/schemas/pages/schema/fields/types/string-validation.component.html

@ -1,166 +1,117 @@
<div [formGroup]="fieldForm">
@if (showUnique) {
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_fieldUnique" formControlName="isUnique" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_fieldUnique">
{{ "schemas.field.unique" | sqxTranslate }}
</label>
</div>
</div>
</div>
<sqx-form-row #placeholderRow for="placeholder" hint="schemas.field.placeholderHint" label="schemas.field.placeholder" [prefix]="field.fieldId">
<input class="form-control" [id]="placeholderRow.fieldName" formControlName="placeholder" maxlength="100" />
</sqx-form-row>
}
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.string.length" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minLength"
placeholder="{{ 'schemas.fieldTypes.string.lengthMin' | sqxTranslate }}"
type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxLength"
placeholder="{{ 'schemas.fieldTypes.string.lengthMax' | sqxTranslate }}"
type="number" />
</div>
<sqx-form-row for="minLength" hideError label="schemas.fieldTypes.string.length" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minLength"
placeholder="{{ 'schemas.fieldTypes.string.lengthMin' | sqxTranslate }}"
type="number" />
</div>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldPattern">{{ "common.pattern" | sqxTranslate }}</label>
<div class="col-9">
<input
class="form-control"
id="{{ field.fieldId }}_fieldPattern"
#inputPattern
autocapitalize="off"
autocomplete="off"
autocorrect="off"
(focus)="patternsModal.show()"
formControlName="pattern"
placeholder="{{ 'schemas.fieldTypes.string.pattern' | sqxTranslate }}" />
@if (settings.patterns.length > 0 && (showPatternSuggestions | async)) {
<sqx-dropdown-menu class="control-dropdown" position="bottom-start" scrollY="true" [sqxAnchoredTo]="inputPattern" *sqxModal="patternsModal">
<h4>{{ "schemas.fieldTypes.string.suggestions" | sqxTranslate }}</h4>
@for (pattern of settings.patterns; track pattern) {
<div class="control-dropdown-item control-dropdown-item-selectable" (mousedown)="setPattern(pattern)">
<div class="truncate">{{ pattern.name }}</div>
<div class="truncate text-muted">{{ pattern.regex }}</div>
</div>
}
</sqx-dropdown-menu>
}
<sqx-form-hint> {{ patternName }} </sqx-form-hint>
</div>
</div>
@if (showPatternMessage | async) {
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldPatternMessage">
{{ "schemas.fieldTypes.string.patternMessage" | sqxTranslate }}
</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_fieldPatternMessage" formControlName="patternMessage" />
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxLength"
placeholder="{{ 'schemas.fieldTypes.string.lengthMax' | sqxTranslate }}"
type="number" />
</div>
</div>
</sqx-form-row>
<sqx-form-row #patternRow for="pattern" [hint]="patternName" label="common.pattern" [prefix]="field.fieldId">
<input
class="form-control"
[id]="patternRow.fieldName"
#inputPattern
autocapitalize="off"
autocomplete="off"
autocorrect="off"
(focus)="patternsModal.show()"
formControlName="pattern"
placeholder="{{ 'schemas.fieldTypes.string.pattern' | sqxTranslate }}" />
@if (settings.patterns.length > 0 && (showPatternSuggestions | async)) {
<sqx-dropdown-menu class="control-dropdown" position="bottom-start" scrollY="true" [sqxAnchoredTo]="inputPattern" *sqxModal="patternsModal">
<h4>{{ "schemas.fieldTypes.string.suggestions" | sqxTranslate }}</h4>
@for (pattern of settings.patterns; track pattern) {
<div class="control-dropdown-item control-dropdown-item-selectable" (mousedown)="setPattern(pattern)">
<div class="truncate">{{ pattern.name }}</div>
<div class="truncate text-muted">{{ pattern.regex }}</div>
</div>
}
</sqx-dropdown-menu>
}
</sqx-form-row>
@if (showPatternMessage | async) {
<sqx-form-row #patternMessageRow for="patternMessage" label="schemas.fieldTypes.string.patternMessage" [prefix]="field.fieldId">
<input class="form-control" [id]="patternMessageRow.fieldName" formControlName="patternMessage" />
</sqx-form-row>
}
<div class="form-group row">
<div class="col-9 offset-3">
<sqx-form-hint> {{ "schemas.fieldTypes.string.wordHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.string.contentType" | sqxTranslate }}</label>
<div class="col-9">
<select class="form-select" formControlName="contentType">
@for (contentType of contentTypes; track contentType) {
<option [ngValue]="contentType">{{ contentType }}</option>
}
</select>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.string.characters" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minCharacters"
placeholder="{{ 'schemas.fieldTypes.string.charactersMin' | sqxTranslate }}"
type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxCharacters"
placeholder="{{ 'schemas.fieldTypes.string.charactersMax' | sqxTranslate }}"
type="number" />
</div>
<sqx-form-row check for="none" hideError hint="schemas.fieldTypes.string.wordHint" [prefix]="field.fieldId" />
<sqx-form-row for="contentType" label="schemas.fieldTypes.string.contentType" [prefix]="field.fieldId">
<select class="form-select" formControlName="contentType">
@for (contentType of contentTypes; track contentType) {
<option [ngValue]="contentType">{{ contentType }}</option>
}
</select>
</sqx-form-row>
<sqx-form-row for="minCharacters" hideError label="schemas.fieldTypes.string.characters" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minCharacters"
placeholder="{{ 'schemas.fieldTypes.string.charactersMin' | sqxTranslate }}"
type="number" />
</div>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.string.words" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minWords"
placeholder="{{ 'schemas.fieldTypes.string.wordsMin' | sqxTranslate }}"
type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxWords"
placeholder="{{ 'schemas.fieldTypes.string.wordsMax' | sqxTranslate }}"
type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxCharacters"
placeholder="{{ 'schemas.fieldTypes.string.charactersMax' | sqxTranslate }}"
type="number" />
</div>
</div>
</div>
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldDefaultValue">
{{ "schemas.field.defaultValue" | sqxTranslate }}
</label>
<div class="col-9"><input class="form-control" id="{{ field.fieldId }}_fieldDefaultValue" formControlName="defaultValue" /></div>
</div>
<sqx-form-row for="minWords" hideError label="schemas.fieldTypes.string.words" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input class="form-control" formControlName="minWords" placeholder="{{ 'schemas.fieldTypes.string.wordsMin' | sqxTranslate }}" type="number" />
</div>
@if (isLocalizable) {
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldDefaultValues">
{{ "schemas.field.defaultValues" | sqxTranslate }}
</label>
<div class="col-9">
<sqx-localized-input id="{{ field.fieldId }}_fieldDefaultValues" formControlName="defaultValues" [languages]="languages" />
<sqx-form-hint> {{ "schemas.field.defaultValuesHint" | sqxTranslate }} </sqx-form-hint>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input class="form-control" formControlName="maxWords" placeholder="{{ 'schemas.fieldTypes.string.wordsMax' | sqxTranslate }}" type="number" />
</div>
</div>
</sqx-form-row>
<sqx-form-row #defaultValueRow for="defaultValue" label="schemas.field.defaultValue" [prefix]="field.fieldId">
<input class="form-control" [id]="defaultValueRow.fieldName" formControlName="defaultValue" />
</sqx-form-row>
@if (isLocalizable) {
<sqx-form-row #defaultValuesRow for="defaultValues" hint="schemas.field.defaultValuesHint" label="schemas.field.defaultValues" [prefix]="field.fieldId">
<sqx-localized-input [id]="defaultValuesRow.fieldName" formControlName="defaultValues" [languages]="languages" />
</sqx-form-row>
}
</div>

8
frontend/src/app/features/schemas/pages/schema/fields/types/string-validation.component.ts

@ -9,7 +9,7 @@ import { AsyncPipe } from '@angular/common';
import { booleanAttribute, Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import { AppLanguageDto, AppSettingsDto, DropdownMenuComponent, FieldDto, FormHintComponent, hasNoValue$, hasValue$, LocalizedInputComponent, ModalDirective, ModalModel, ModalPlacementDirective, PatternDto, SchemaDto, StringContentTypeValues, StringFieldPropertiesDto, Subscriptions, TranslatePipe, TypedSimpleChanges, Types, value$ } from '@app/shared';
import { AppLanguageDto, AppSettingsDto, DropdownMenuComponent, FieldDto, FormRowComponent, hasNoValue$, hasValue$, LocalizedInputComponent, ModalDirective, ModalModel, ModalPlacementDirective, PatternDto, SchemaDto, StringContentTypeValues, StringFieldPropertiesDto, Subscriptions, TranslatePipe, TypedSimpleChanges, Types, value$ } from '@app/shared';
@Component({
selector: 'sqx-string-validation',
@ -18,7 +18,7 @@ import { AppLanguageDto, AppSettingsDto, DropdownMenuComponent, FieldDto, FormHi
imports: [
AsyncPipe,
DropdownMenuComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
LocalizedInputComponent,
ModalDirective,
@ -50,8 +50,8 @@ export class StringValidationComponent {
@Input({ required: true })
public languages!: ReadonlyArray<AppLanguageDto>;
@Input({ transform: booleanAttribute })
public isLocalizable?: boolean | null;
@Input({ required: true, transform: booleanAttribute })
public isLocalizable!: boolean;
public showPatternMessage?: Observable<boolean>;
public showPatternSuggestions?: Observable<boolean>;

52
frontend/src/app/features/schemas/pages/schema/fields/types/tags-ui.component.html

@ -1,40 +1,22 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ field.fieldId }}_fieldPlaceholder">
{{ "schemas.field.placeholder" | sqxTranslate }}
</label>
<div class="col-9">
<input class="form-control" id="{{ field.fieldId }}_fieldPlaceholder" formControlName="placeholder" maxlength="100" />
<sqx-form-hint> {{ "schemas.field.placeholderHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #placeholderRow for="placeholder" hint="schemas.field.placeholderHint" label="schemas.field.placeholder" [prefix]="field.fieldId">
<input class="form-control" [id]="placeholderRow.fieldName" formControlName="placeholder" maxlength="100" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.editor" | sqxTranslate }}</label>
<div class="col-9">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</div>
</div>
<sqx-form-row for="editor" label="schemas.field.editor" [prefix]="field.fieldId">
@for (editor of editors; track editor) {
<label class="btn btn-radio" [class.active]="fieldForm.controls['editor'].value === editor">
<input class="radio-input" formControlName="editor" name="editor" type="radio" [value]="editor" />
<i class="icon-control-{{ editor }}"></i> <span class="radio-label">{{ editor }}</span>
</label>
}
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.allowedValues" | sqxTranslate }}</label>
<div class="col-9"><sqx-tag-editor formControlName="allowedValues" /></div>
</div>
<sqx-form-row #allowedValuesRow for="allowedValues" label="schemas.field.allowedValues" [prefix]="field.fieldId">
<sqx-tag-editor [id]="allowedValuesRow.fieldName" formControlName="allowedValues" />
</sqx-form-row>
<div class="form-group row">
<div class="col-9 offset-3">
<div class="form-check">
<input class="form-check-input" id="{{ field.fieldId }}_createEnum" formControlName="createEnum" type="checkbox" />
<label class="form-check-label" for="{{ field.fieldId }}_createEnum">
{{ "schemas.field.createEnum" | sqxTranslate }}
</label>
</div>
<sqx-form-hint> {{ "schemas.field.createEnumHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #createEnumRow check for="createEnum" hint="schemas.field.createEnumHint" label="schemas.field.createEnum" [prefix]="field.fieldId">
<input class="form-check-input" [id]="createEnumRow.fieldName" formControlName="createEnum" type="checkbox" />
</sqx-form-row>
</div>

5
frontend/src/app/features/schemas/pages/schema/fields/types/tags-ui.component.ts

@ -8,18 +8,17 @@
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { FieldDto, FormHintComponent, TagEditorComponent, TagsFieldEditorValues, TagsFieldPropertiesDto, TranslatePipe } from '@app/shared';
import { FieldDto, FormRowComponent, TagEditorComponent, TagsFieldEditorValues, TagsFieldPropertiesDto } from '@app/shared';
@Component({
selector: 'sqx-tags-ui',
styleUrls: ['tags-ui.component.scss'],
templateUrl: 'tags-ui.component.html',
imports: [
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TagEditorComponent,
TranslatePipe,
],
})
export class TagsUIComponent {

46
frontend/src/app/features/schemas/pages/schema/fields/types/tags-validation.component.html

@ -1,41 +1,25 @@
<div [formGroup]="fieldForm">
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.fieldTypes.tags.count" | sqxTranslate }}</label>
<div class="col-9">
<div class="row g-0">
<div class="col">
<input
class="form-control"
formControlName="minItems"
placeholder="{{ 'schemas.fieldTypes.tags.countMin' | sqxTranslate }}"
type="number" />
</div>
<sqx-form-row for="minItems" hideError label="schemas.fieldTypes.tags.count" [prefix]="field.fieldId">
<div class="row g-0">
<div class="col">
<input class="form-control" formControlName="minItems" placeholder="{{ 'schemas.fieldTypes.tags.countMin' | sqxTranslate }}" type="number" />
</div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col-auto"><label class="col-form-label minmax">-</label></div>
<div class="col">
<input
class="form-control"
formControlName="maxItems"
placeholder="{{ 'schemas.fieldTypes.tags.countMax' | sqxTranslate }}"
type="number" />
</div>
<div class="col">
<input class="form-control" formControlName="maxItems" placeholder="{{ 'schemas.fieldTypes.tags.countMax' | sqxTranslate }}" type="number" />
</div>
</div>
</div>
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.defaultValue" | sqxTranslate }}</label>
<div class="col-9"><sqx-tag-editor formControlName="defaultValue" /></div>
</div>
<sqx-form-row #defaultValueRow for="defaultValue" label="schemas.field.defaultValue" [prefix]="field.fieldId">
<sqx-tag-editor [id]="defaultValueRow.fieldName" formControlName="defaultValue" />
</sqx-form-row>
@if (isLocalizable) {
<div class="form-group row">
<label class="col-3 col-form-label">{{ "schemas.field.defaultValues" | sqxTranslate }}</label>
<div class="col-9">
<sqx-localized-input formControlName="defaultValues" [languages]="languages" type="tags" />
<sqx-form-hint> {{ "schemas.field.defaultValuesHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #defaultValuesRow for="defaultValues" hint="schemas.field.defaultValuesHint" label="schemas.field.defaultValues" [prefix]="field.fieldId">
<sqx-localized-input [id]="defaultValuesRow.fieldName" formControlName="defaultValues" [languages]="languages" type="tags" />
</sqx-form-row>
}
</div>

8
frontend/src/app/features/schemas/pages/schema/fields/types/tags-validation.component.ts

@ -8,14 +8,14 @@
import { booleanAttribute, Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { AppLanguageDto, FieldDto, FormHintComponent, LocalizedInputComponent, TagEditorComponent, TagsFieldPropertiesDto, TranslatePipe } from '@app/shared';
import { AppLanguageDto, FieldDto, FormRowComponent, LocalizedInputComponent, TagEditorComponent, TagsFieldPropertiesDto, TranslatePipe } from '@app/shared';
@Component({
selector: 'sqx-tags-validation',
styleUrls: ['tags-validation.component.scss'],
templateUrl: 'tags-validation.component.html',
imports: [
FormHintComponent,
FormRowComponent,
FormsModule,
LocalizedInputComponent,
ReactiveFormsModule,
@ -36,6 +36,6 @@ export class TagsValidationComponent {
@Input({ required: true })
public languages!: ReadonlyArray<AppLanguageDto>;
@Input({ transform: booleanAttribute })
public isLocalizable?: boolean | null;
@Input({ required: true, transform: booleanAttribute })
public isLocalizable!: boolean;
}

2
frontend/src/app/features/schemas/pages/schema/indexes/index-form.component.html

@ -6,7 +6,7 @@
<span inline="true" [sqxMarkdown]="'schemas.indexes.hint' | sqxTranslate" trusted="true"></span>
</sqx-form-hint>
@for (form of createForm.controls; track form; let i = $index) {
<div class="form-group row gx-2" attr.data-testid="pattern_{{ form.get('name')?.value }}" [formGroup]="form">
<div class="form-group row gx-2" [formGroup]="form">
<div class="col">
<sqx-control-errors for="name" />
<select class="form-select" formControlName="name">

52
frontend/src/app/features/schemas/pages/schemas/schema-form.component.html

@ -39,14 +39,9 @@
<sqx-form-error [error]="actualForm.error | async" />
@if (selectedTab !== 2) {
<div class="form-group">
<label for="name">
{{ "common.name" | sqxTranslate }} <small class="hint">({{ "common.requiredHint" | sqxTranslate }})</small>
</label>
<sqx-control-errors for="name" [submitCount]="createForm.submitCount | async" />
<sqx-form-row for="name" hint="schemas.schemaNameHint" label="common.name" required [submitCount]="createForm.submitCount | async" vertical>
<input class="form-control" id="name" autocomplete="off" formControlName="name" sqxFocusOnInit sqxTransformInput="LowerCase" />
<sqx-form-hint> {{ "schemas.schemaNameHint" | sqxTranslate }} </sqx-form-hint>
</div>
</sqx-form-row>
<sqx-form-alert> {{ "schemas.nameWarning" | sqxTranslate }} </sqx-form-alert>
}
@ -115,8 +110,7 @@
@if (schemasState.categoryNames | async; as categories) {
@if (categories.length > 0) {
<div class="form-group">
<label for="category">{{ "common.category" | sqxTranslate }}</label>
<sqx-form-row for="category" label="common.category">
<select class="form-select" id="category" formControlName="initialCategory">
<option></option>
@ -124,34 +118,32 @@
<option [ngValue]="category">{{ category }}</option>
}
</select>
</div>
</sqx-form-row>
}
}
} @else if (selectedTab === 1) {
<sqx-code-editor formControlName="importing" height="auto" minLines="50" valueMode="Json" />
} @else if (selectedTab === 2) {
<div class="row g-2 form-group">
<div class="col">
<label for="prompt">
{{ "common.prompt" | sqxTranslate }} <small class="hint">({{ "common.requiredHint" | sqxTranslate }})</small>
</label>
<sqx-control-errors for="prompt" />
<input class="form-control" id="prompt" autocomplete="off" formControlName="prompt" sqxFocusOnInit />
<sqx-form-hint> {{ "schemas.promptHint" | sqxTranslate }} </sqx-form-hint>
</div>
<div class="col-auto">
<label>&nbsp;</label>
<div>
<button class="btn btn-primary" (click)="generatePreview()" [disabled]="generateForm.submitting | async" type="button">
@if (generateForm.submitting | async) {
<sqx-loader color="white" size="12" />
}
{{ "common.generate" | sqxTranslate }}
</button>
<sqx-form-row for="prompt" label="common.prompt">
<div class="row g-2 form-group">
<div class="col">
<sqx-form-hint> {{ "schemas.promptHint" | sqxTranslate }} </sqx-form-hint>
</div>
<div class="col-auto">
<label>&nbsp;</label>
<div>
<button class="btn btn-primary" (click)="generatePreview()" [disabled]="generateForm.submitting | async" type="button">
@if (generateForm.submitting | async) {
<sqx-loader color="white" size="12" />
}
{{ "common.generate" | sqxTranslate }}
</button>
</div>
</div>
</div>
</div>
</sqx-form-row>
<sqx-form-alert> {{ "schemas.promptExample" | sqxTranslate }} </sqx-form-alert>
<sqx-code-editor disabled="true" [height]="1000" [ngModel]="generateLog" [ngModelOptions]="{ standalone: true }" />

4
frontend/src/app/features/schemas/pages/schemas/schema-form.component.ts

@ -9,7 +9,7 @@ import { AsyncPipe } from '@angular/common';
import { Component, EventEmitter, inject, Input, OnInit, Output } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { switchMap } from 'rxjs';
import { ApiUrlConfig, AppsState, CodeEditorComponent, ControlErrorsComponent, CreateSchemaForm, FocusOnInitDirective, FormAlertComponent, FormErrorComponent, FormHintComponent, GenerateSchemaDto, GenerateSchemaForm, LoaderComponent, ModalDialogComponent, SchemaDto, SchemasService, SchemasState, TooltipDirective, TransformInputDirective, TranslatePipe, UIOptions } from '@app/shared';
import { ApiUrlConfig, AppsState, CodeEditorComponent, CreateSchemaForm, FocusOnInitDirective, FormAlertComponent, FormErrorComponent, FormHintComponent, FormRowComponent, GenerateSchemaDto, GenerateSchemaForm, LoaderComponent, ModalDialogComponent, SchemaDto, SchemasService, SchemasState, TooltipDirective, TransformInputDirective, TranslatePipe, UIOptions } from '@app/shared';
@Component({
selector: 'sqx-schema-form',
@ -18,11 +18,11 @@ import { ApiUrlConfig, AppsState, CodeEditorComponent, ControlErrorsComponent, C
imports: [
AsyncPipe,
CodeEditorComponent,
ControlErrorsComponent,
FocusOnInitDirective,
FormAlertComponent,
FormErrorComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
LoaderComponent,
ModalDialogComponent,

133
frontend/src/app/features/settings/pages/clients/client.component.html

@ -28,89 +28,78 @@
<div class="card-body">
<div class="container">
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ client.id }}_clientId"> {{ "common.clientId" | sqxTranslate }} </label>
<div class="col">
<div class="input-group">
<input class="form-control" id="{{ client.id }}_clientId" #clientId readonly value="{{ appsState.appName }}:{{ client.id }}" />
<button
class="btn btn-outline-secondary"
attr.aria-label="{{ 'clients.copyClientId' | sqxTranslate }}"
[sqxCopy]="clientId"
title="i18n:clients.copyClientId"
type="button">
<i class="icon-copy"></i>
</button>
</div>
<sqx-form-row #clientIdRow for="clientId" hideError label="common.clientId" [prefix]="client.id">
<div class="input-group">
<input class="form-control" [id]="clientIdRow.fieldName" #clientId readonly value="{{ appsState.appName }}:{{ client.id }}" />
<button
class="btn btn-outline-secondary"
attr.aria-label="{{ 'clients.copyClientId' | sqxTranslate }}"
[sqxCopy]="clientId"
title="i18n:clients.copyClientId"
type="button">
<i class="icon-copy"></i>
</button>
</div>
</div>
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="{{ client.id }}_clientSecret"> {{ "common.clientSecret" | sqxTranslate }} </label>
<div class="col">
<div class="input-group">
<input class="form-control" id="{{ client.id }}_clientSecret" #inputSecret readonly [value]="client.secret" />
<button
class="btn btn-outline-secondary"
attr.aria-label="{{ 'clients.copyClientSecret' | sqxTranslate }}"
[sqxCopy]="inputSecret"
title="i18n:clients.copyClientSecret"
type="button">
<i class="icon-copy"></i>
</button>
</div>
<sqx-form-row #clientSecretRow for="clientSecret" hideError label="common.clientSecret" [prefix]="client.id">
<div class="input-group">
<input class="form-control" [id]="clientSecretRow.fieldName" #inputSecret readonly [value]="client.secret" />
<button
class="btn btn-outline-secondary"
attr.aria-label="{{ 'clients.copyClientSecret' | sqxTranslate }}"
[sqxCopy]="inputSecret"
title="i18n:clients.copyClientSecret"
type="button">
<i class="icon-copy"></i>
</button>
</div>
</div>
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label"> {{ "common.role" | sqxTranslate }} </label>
<div class="col">
<select class="form-select" [disabled]="!client.canUpdate" [ngModel]="client.role" (ngModelChange)="updateRole($event)">
@for (role of clientRoles; track role.name) {
<option [ngValue]="role.name">{{ role.name }}</option>
}
</select>
</div>
</div>
<sqx-form-row #roleRow for="role" hideError label="common.role" [prefix]="client.id">
<select
class="form-select"
[id]="roleRow.fieldName"
[disabled]="!client.canUpdate"
[ngModel]="client.role"
(ngModelChange)="updateRole($event)">
@for (role of clientRoles; track role.name) {
<option [ngValue]="role.name">{{ role.name }}</option>
}
</select>
</sqx-form-row>
<div class="form-group row">
<div class="col offset-3">
<div class="form-check">
<sqx-form-row #allowAnonymousRow check for="allowAnonymous" hints="clients.allowAnonymousHint" label="clients.allowAnonymous" [prefix]="client.id">
<input
class="form-check-input"
[id]="allowAnonymousRow.fieldName"
[disabled]="!client.canUpdate"
[ngModel]="client.allowAnonymous"
(ngModelChange)="updateAllowAnonymous($event)"
type="checkbox" />
</sqx-form-row>
<sqx-form-row #apiCallsLimitRow for="apiCallsLimit" hideError hint="clients.apiCallsLimitHint" label="clients.apiCallsLimit" [prefix]="client.id">
<div class="row gx-2">
<div class="col">
<input
class="form-check-input"
id="{{ client.id }}_allowAnonymous"
class="form-control"
[id]="apiCallsLimitRow.fieldName"
[disabled]="!client.canUpdate"
[ngModel]="client.allowAnonymous"
(ngModelChange)="updateAllowAnonymous($event)"
type="checkbox" />
<label class="form-check-label" for="{{ client.id }}_allowAnonymous">
{{ "clients.allowAnonymous" | sqxTranslate }}
</label>
min="0"
[(ngModel)]="apiCallsLimit"
type="number" />
</div>
<sqx-form-hint> {{ "clients.allowAnonymousHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label"> {{ "clients.apiCallsLimit" | sqxTranslate }} </label>
<div class="col">
<div class="row gx-2">
<div class="col">
<input class="form-control" [disabled]="!client.canUpdate" min="0" [(ngModel)]="apiCallsLimit" type="number" />
<sqx-form-hint> {{ "clients.apiCallsLimitHint" | sqxTranslate }} </sqx-form-hint>
@if (client.canUpdate) {
<div class="col-auto">
<button class="btn btn-outline-secondary" (click)="updateApiCallsLimit(apiCallsLimit)">
{{ "common.save" | sqxTranslate }}
</button>
</div>
@if (client.canUpdate) {
<div class="col-auto">
<button class="btn btn-outline-secondary" (click)="updateApiCallsLimit(apiCallsLimit)">
{{ "common.save" | sqxTranslate }}
</button>
</div>
}
</div>
}
</div>
</div>
</sqx-form-row>
</div>
</div>
</div>

4
frontend/src/app/features/settings/pages/clients/client.component.ts

@ -8,7 +8,7 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppsState, ClientDto, ClientsState, ConfirmClickDirective, CopyDirective, DialogModel, EditableTitleComponent, FormHintComponent, ModalDirective, RoleDto, TooltipDirective, TourStepDirective, TranslatePipe, TypedSimpleChanges, UpdateClientDto } from '@app/shared';
import { AppsState, ClientDto, ClientsState, ConfirmClickDirective, CopyDirective, DialogModel, EditableTitleComponent, FormRowComponent, ModalDirective, RoleDto, TooltipDirective, TourStepDirective, TranslatePipe, TypedSimpleChanges, UpdateClientDto } from '@app/shared';
import { ClientConnectFormComponent } from './client-connect-form.component';
@Component({
@ -21,7 +21,7 @@ import { ClientConnectFormComponent } from './client-connect-form.component';
ConfirmClickDirective,
CopyDirective,
EditableTitleComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
ModalDirective,
TooltipDirective,

140
frontend/src/app/features/settings/pages/languages/language.component.html

@ -51,100 +51,76 @@
<div class="table-items-row-details-tab">
@if (isEditable || fallbackLanguages.length > 0) {
<div class="form-group row">
<label class="col-3 col-form-label fallback-label" for="{{ language.iso2Code }}_fallback">{{
"common.fallback" | sqxTranslate
}}</label>
<div class="col-9">
@if (fallbackLanguages.length > 0) {
<div
class="fallback-languages"
cdkDropList
[cdkDropListData]="$any(fallbackLanguages)"
[cdkDropListDisabled]="!isEditable"
(cdkDropListDropped)="sort($event)">
@for (language of fallbackLanguages; track language) {
<div class="fallback-language table-drag" cdkDrag cdkDragLockAxis="y">
<div class="row g-0">
@if (isEditable) {
<div class="col-auto">
<i class="icon-drag2 drag-handle me-1" cdkDragHandle></i>
</div>
}
<sqx-form-row for="fallback" hideError label="common.fallback" [prefix]="language.iso2Code">
@if (fallbackLanguages.length > 0) {
<div
class="fallback-languages"
cdkDropList
[cdkDropListData]="$any(fallbackLanguages)"
[cdkDropListDisabled]="!isEditable"
(cdkDropListDropped)="sort($event)">
@for (language of fallbackLanguages; track language) {
<div class="fallback-language table-drag" cdkDrag cdkDragLockAxis="y">
<div class="row g-0">
@if (isEditable) {
<div class="col-auto">
<i class="icon-drag2 drag-handle me-1" cdkDragHandle></i>
</div>
}
<div class="col">{{ language.englishName }}</div>
<div class="col">{{ language.englishName }}</div>
@if (isEditable) {
<div class="col-auto">
<button
class="btn btn-text-secondary btn-sm"
(click)="removeFallbackLanguage(language)"
type="button">
<i class="icon-close"></i>
</button>
</div>
}
</div>
@if (isEditable) {
<div class="col-auto">
<button class="btn btn-text-secondary btn-sm" (click)="removeFallbackLanguage(language)" type="button">
<i class="icon-close"></i>
</button>
</div>
}
</div>
}
</div>
}
</div>
}
</div>
}
@if (otherLanguage && isEditable) {
<form class="form fallback-form" (ngSubmit)="addFallbackLanguage()">
<div class="row gx-2">
<div class="col">
<select
class="form-select fallback-select"
id="{{ language.iso2Code }}_fallback"
name="otherLanguage"
[(ngModel)]="otherLanguage">
@for (otherLanguage of fallbackLanguagesNew; track language.iso2Code) {
<option [ngValue]="otherLanguage">
{{ otherLanguage.englishName || otherLanguage.iso2Code }}
</option>
}
</select>
</div>
@if (otherLanguage && isEditable) {
<form class="form fallback-form" (ngSubmit)="addFallbackLanguage()">
<div class="row gx-2">
<div class="col">
<select
class="form-select fallback-select"
id="{{ language.iso2Code }}_fallback"
name="otherLanguage"
[(ngModel)]="otherLanguage">
@for (otherLanguage of fallbackLanguagesNew; track language.iso2Code) {
<option [ngValue]="otherLanguage">
{{ otherLanguage.englishName || otherLanguage.iso2Code }}
</option>
}
</select>
</div>
<div class="col-auto">
<button class="btn btn-success" type="submit">
{{ "languages.add" | sqxTranslate }}
</button>
</div>
<div class="col-auto">
<button class="btn btn-success" type="submit">
{{ "languages.add" | sqxTranslate }}
</button>
</div>
</form>
}
</div>
</div>
</div>
</form>
}
</sqx-form-row>
}
@if (!language.isMaster) {
<div class="form-group row">
<div class="col offset-3 col-9">
<div class="form-check">
<input class="form-check-input" id="{{ language.iso2Code }}_isMaster" formControlName="isMaster" type="checkbox" />
<label class="form-check-label" for="{{ language.iso2Code }}_isMaster">
{{ "languages.master" | sqxTranslate }}
</label>
</div>
<sqx-form-hint> {{ "languages.masterHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row check for="isMaster" hint="languages.masterHint" label="languages.master" [prefix]="language.iso2Code">
<input class="form-check-input" id="{{ language.iso2Code }}_isMaster" formControlName="isMaster" type="checkbox" />
</sqx-form-row>
}
@if (!language.isMaster) {
<div class="form-group row">
<div class="col offset-3 col-9">
<div class="form-check">
<input class="form-check-input" id="{{ language.iso2Code }}_isOptional" formControlName="isOptional" type="checkbox" />
<label class="form-check-label" for="{{ language.iso2Code }}_isOptional">
{{ "languages.optional" | sqxTranslate }}
</label>
</div>
<sqx-form-hint> {{ "languages.optionalHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row check for="isOptional" hint="languages.optionalHint" label="languages.optional" [prefix]="language.iso2Code">
<input class="form-check-input" id="{{ language.iso2Code }}_isOptional" formControlName="isOptional" type="checkbox" />
</sqx-form-row>
}
</div>
</form>

4
frontend/src/app/features/settings/pages/languages/language.component.ts

@ -9,7 +9,7 @@ import { CdkDrag, CdkDragDrop, CdkDragHandle, CdkDropList } from '@angular/cdk/d
import { Component, Input } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppLanguageDto, ConfirmClickDirective, EditLanguageForm, FormHintComponent, LanguageDto, LanguagesState, sorted, TranslatePipe, UpdateLanguageDto } from '@app/shared';
import { AppLanguageDto, ConfirmClickDirective, EditLanguageForm, FormRowComponent, LanguageDto, LanguagesState, sorted, TranslatePipe, UpdateLanguageDto } from '@app/shared';
@Component({
selector: 'sqx-language',
@ -20,7 +20,7 @@ import { AppLanguageDto, ConfirmClickDirective, EditLanguageForm, FormHintCompon
CdkDragHandle,
CdkDropList,
ConfirmClickDirective,
FormHintComponent,
FormRowComponent,
FormsModule,
ReactiveFormsModule,
TranslatePipe,

18
frontend/src/app/features/settings/pages/more/more-page.component.html

@ -8,22 +8,18 @@
<div class="card mb-4">
<div class="card-body">
<sqx-form-error [error]="updateForm.error | async" />
<div class="form-group">
<label for="email">{{ "common.name" | sqxTranslate }}</label>
<sqx-form-row for="name" label="common.name" vertical>
<input class="form-control" readonly [value]="app.name" />
</div>
</sqx-form-row>
<div class="form-group">
<label for="label">{{ "common.label" | sqxTranslate }}</label>
<sqx-control-errors for="label" />
<sqx-form-row for="label" label="common.label" vertical>
<input class="form-control" id="label" formControlName="label" maxlength="100" />
</div>
</sqx-form-row>
<div class="form-group">
<label for="description">{{ "common.description" | sqxTranslate }}</label>
<sqx-control-errors for="description" />
<sqx-form-row for="description" label="common.description" vertical>
<input class="form-control" id="description" formControlName="description" maxlength="100" />
</div>
</sqx-form-row>
</div>
<div class="card-footer">

4
frontend/src/app/features/settings/pages/more/more-page.component.ts

@ -9,7 +9,7 @@ import { AsyncPipe } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Router, RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
import { AppDto, AppsState, AvatarComponent, ConfirmClickDirective, ControlErrorsComponent, defined, DialogService, FileDropDirective, FormErrorComponent, FormHintComponent, LayoutComponent, ListViewComponent, ProgressBarComponent, SidebarMenuDirective, Subscriptions, TeamsState, TooltipDirective, TourStepDirective, TransferAppForm, TranslatePipe, Types, UpdateAppForm } from '@app/shared';
import { AppDto, AppsState, AvatarComponent, ConfirmClickDirective, defined, DialogService, FileDropDirective, FormErrorComponent, FormHintComponent, FormRowComponent, LayoutComponent, ListViewComponent, ProgressBarComponent, SidebarMenuDirective, Subscriptions, TeamsState, TooltipDirective, TourStepDirective, TransferAppForm, TranslatePipe, Types, UpdateAppForm } from '@app/shared';
@Component({
selector: 'sqx-more-page',
@ -19,10 +19,10 @@ import { AppDto, AppsState, AvatarComponent, ConfirmClickDirective, ControlError
AsyncPipe,
AvatarComponent,
ConfirmClickDirective,
ControlErrorsComponent,
FileDropDirective,
FormErrorComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
LayoutComponent,
ListViewComponent,

46
frontend/src/app/features/settings/pages/workflows/workflow.component.html

@ -62,33 +62,27 @@
<div class="table-items-row-details-tab">
@if (selectedTab === 0) {
<sqx-form-error [error]="error" />
<div class="form-group row">
<label class="col-form-label" for="{{ workflowView.dto.id }}_name">{{ "common.name" | sqxTranslate }}</label>
<div class="col">
<input
class="form-control"
id="{{ workflowView.dto.id }}_name"
[disabled]="!isEditable"
[ngModel]="workflowView.dto.name"
(ngModelChange)="rename($event)"
[ngModelOptions]="onBlur" />
<sqx-form-hint> {{ "workflows.workflowNameHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<div class="form-group row">
<label class="col-form-label" for="{{ workflowView.dto.id }}_schemas">{{ "common.schemas" | sqxTranslate }}</label>
<div class="col">
<sqx-tag-editor
[disabled]="!isEditable"
[itemConverter]="(schemasSource.converter | async)!"
[itemsSource]="(schemasSource.normalConverter | async)?.suggestions"
[ngModel]="workflowView.dto.schemaIds"
(ngModelChange)="changeSchemaIds($event)"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
<sqx-form-hint> {{ "workflows.schemasHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row #nameRow for="name" hint="workflows.workflowNameHint" label="common.name" [prefix]="workflowView.dto.id" vertical>
<input
class="form-control"
[id]="nameRow.fieldName"
[disabled]="!isEditable"
[ngModel]="workflowView.dto.name"
(ngModelChange)="rename($event)"
[ngModelOptions]="onBlur" />
</sqx-form-row>
<sqx-form-row #schemaIdsRow for="schemaIds" hint="workflows.schemasHint" label="common.schemas" [prefix]="workflowView.dto.id" vertical>
<sqx-tag-editor
[id]="schemaIdsRow.fieldName"
[disabled]="!isEditable"
[itemConverter]="(schemasSource.converter | async)!"
[itemsSource]="(schemasSource.normalConverter | async)?.suggestions"
[ngModel]="workflowView.dto.schemaIds"
(ngModelChange)="changeSchemaIds($event)"
placeholder="{{ 'common.tagAddSchema' | sqxTranslate }}" />
</sqx-form-row>
@for (step of workflowView.steps; track step.name) {
<sqx-workflow-step

4
frontend/src/app/features/settings/pages/workflows/workflow.component.ts

@ -8,7 +8,7 @@
import { AsyncPipe } from '@angular/common';
import { Component, Input } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ConfirmClickDirective, ErrorDto, FormErrorComponent, FormHintComponent, MathHelper, SchemaTagSource, TagEditorComponent, TranslatePipe, WorkflowDto, WorkflowsState, WorkflowView } from '@app/shared';
import { ConfirmClickDirective, ErrorDto, FormErrorComponent, FormRowComponent, MathHelper, SchemaTagSource, TagEditorComponent, TranslatePipe, WorkflowDto, WorkflowsState, WorkflowView } from '@app/shared';
import { WorkflowDiagramComponent } from './workflow-diagram.component';
import { WorkflowStepComponent } from './workflow-step.component';
@ -20,7 +20,7 @@ import { WorkflowStepComponent } from './workflow-step.component';
AsyncPipe,
ConfirmClickDirective,
FormErrorComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
TagEditorComponent,
TranslatePipe,

99
frontend/src/app/features/teams/pages/auth/auth-page.component.html

@ -20,81 +20,44 @@
<form [formGroup]="updateForm.form" (ngSubmit)="save()">
<div class="card-body">
<sqx-form-error [error]="updateForm.error | async" />
<div class="form-group row">
<label class="col-3 col-form-label" for="domain">{{ "teams.auth.domain" | sqxTranslate }}</label>
<div class="col-9">
<sqx-control-errors for="domain" />
<input class="form-control" id="domain" formControlName="domain" />
<sqx-form-hint> {{ "teams.auth.domainHint" | sqxTranslate }} </sqx-form-hint>
<sqx-form-hint>
{{ "teams.auth.domainHintEmail" | sqxTranslate }}:
<strong>user&commat;{{ updateForm.domainValue$ | async }}</strong>
</sqx-form-hint>
</div>
</div>
<div class="form-group row">
<label class="col-3 col-form-label" for="displayName">
{{ "teams.auth.displayName" | sqxTranslate }}
</label>
<div class="col-9">
<sqx-control-errors for="displayName" />
<input class="form-control" id="displayName" formControlName="displayName" />
<sqx-form-hint> {{ "teams.auth.displayNameHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row for="domain" label="teams.auth.domain">
<input class="form-control" id="domain" formControlName="domain" />
<sqx-form-hint> {{ "teams.auth.domainHint" | sqxTranslate }} </sqx-form-hint>
<sqx-form-hint>
{{ "teams.auth.domainHintEmail" | sqxTranslate }}:
<strong>user&commat;{{ updateForm.domainValue$ | async }}</strong>
</sqx-form-hint>
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="clientId">{{ "teams.auth.clientId" | sqxTranslate }}</label>
<div class="col-9">
<sqx-control-errors for="clientId" />
<input class="form-control" id="clientId" formControlName="clientId" />
</div>
</div>
<sqx-form-row for="displayName" hint="teams.auth.displayNameHint" label="teams.auth.displayName">
<input class="form-control" id="displayName" formControlName="displayName" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="clientSecret">
{{ "teams.auth.clientSecret" | sqxTranslate }}
</label>
<div class="col-9">
<sqx-control-errors for="clientSecret" />
<input class="form-control" id="clientSecret" formControlName="clientSecret" />
</div>
</div>
<sqx-form-row for="displayName" label="teams.auth.clientId">
<input class="form-control" id="clientId" formControlName="clientId" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="authority">{{ "teams.auth.authority" | sqxTranslate }}</label>
<div class="col-9">
<sqx-control-errors for="authority" />
<input class="form-control" id="authority" formControlName="authority" />
<sqx-form-hint> {{ "teams.auth.authorityHint" | sqxTranslate }} </sqx-form-hint>
</div>
</div>
<sqx-form-row for="displayName" label="teams.auth.clientSecret">
<input class="form-control" id="clientSecret" formControlName="clientSecret" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="signoutRedirectUrl">
{{ "teams.auth.signoutRedirectUrl" | sqxTranslate }}
</label>
<div class="col-9">
<sqx-control-errors for="signoutRedirectUrl" />
<input class="form-control" id="signoutRedirectUrl" formControlName="signoutRedirectUrl" />
</div>
</div>
<sqx-form-row for="displayName" hint="teams.auth.authorityHint" label="teams.auth.authority">
<input class="form-control" id="authority" formControlName="authority" />
</sqx-form-row>
<sqx-form-row for="signoutRedirectUrl" label="teams.auth.signoutRedirectUrl">
<input class="form-control" id="signoutRedirectUrl" formControlName="signoutRedirectUrl" />
</sqx-form-row>
<div class="form-group row">
<label class="col-3 col-form-label" for="redirectUrl">
{{ "teams.auth.redirectUrl" | sqxTranslate }}
</label>
<div class="col-9">
<div class="input-group">
<input class="form-control" #redirectUri readonly value="{{ urlToRedirect }}" />
<button class="btn btn-outline-secondary" [sqxCopy]="redirectUri" type="button">
<i class="icon-copy"></i>
</button>
</div>
<sqx-form-hint> {{ "teams.auth.redirectUrlHint" | sqxTranslate }} </sqx-form-hint>
<sqx-form-row for="redirectUrl" label="teams.auth.redirectUrl">
<div class="input-group">
<input class="form-control" #redirectUri readonly value="{{ urlToRedirect }}" />
<button class="btn btn-outline-secondary" [sqxCopy]="redirectUri" type="button">
<i class="icon-copy"></i>
</button>
</div>
</div>
</sqx-form-row>
</div>
<div class="card-footer">

4
frontend/src/app/features/teams/pages/auth/auth-page.component.ts

@ -9,7 +9,7 @@ import { AsyncPipe } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
import { ApiUrlConfig, ControlErrorsComponent, CopyDirective, defined, FormErrorComponent, FormHintComponent, LayoutComponent, ListViewComponent, SidebarMenuDirective, Subscriptions, TeamsState, ToggleComponent, TooltipDirective, TourStepDirective, TranslatePipe } from '@app/shared';
import { ApiUrlConfig, CopyDirective, defined, FormErrorComponent, FormHintComponent, FormRowComponent, LayoutComponent, ListViewComponent, SidebarMenuDirective, Subscriptions, TeamsState, ToggleComponent, TooltipDirective, TourStepDirective, TranslatePipe } from '@app/shared';
import { TeamAuthState, UpdateTeamAuthForm } from '../../internal';
@Component({
@ -18,10 +18,10 @@ import { TeamAuthState, UpdateTeamAuthForm } from '../../internal';
templateUrl: './auth-page.component.html',
imports: [
AsyncPipe,
ControlErrorsComponent,
CopyDirective,
FormErrorComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
LayoutComponent,
ListViewComponent,

8
frontend/src/app/features/teams/pages/more/more-page.component.html

@ -8,12 +8,10 @@
<div class="card mb-4">
<div class="card-body">
<sqx-form-error [error]="updateForm.error | async" />
<div class="form-group">
<label for="name">{{ "common.name" | sqxTranslate }}</label>
<sqx-control-errors for="name" />
<sqx-form-row for="name" hint="teams.teamNameHint" label="common.name" vertical>
<input class="form-control" id="name" formControlName="name" maxlength="100" />
<sqx-form-hint> {{ "teams.teamNameHint" | sqxTranslate }} </sqx-form-hint>
</div>
</sqx-form-row>
</div>
<div class="card-footer">

4
frontend/src/app/features/teams/pages/more/more-page.component.ts

@ -9,7 +9,7 @@ import { AsyncPipe } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Router, RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
import { ConfirmClickDirective, ControlErrorsComponent, defined, FormErrorComponent, FormHintComponent, LayoutComponent, ListViewComponent, SidebarMenuDirective, Subscriptions, TeamDto, TeamsState, TooltipDirective, TourStepDirective, TranslatePipe, UpdateTeamForm } from '@app/shared';
import { ConfirmClickDirective, defined, FormErrorComponent, FormHintComponent, FormRowComponent, LayoutComponent, ListViewComponent, SidebarMenuDirective, Subscriptions, TeamDto, TeamsState, TooltipDirective, TourStepDirective, TranslatePipe, UpdateTeamForm } from '@app/shared';
@Component({
selector: 'sqx-more-page',
@ -18,9 +18,9 @@ import { ConfirmClickDirective, ControlErrorsComponent, defined, FormErrorCompon
imports: [
AsyncPipe,
ConfirmClickDirective,
ControlErrorsComponent,
FormErrorComponent,
FormHintComponent,
FormRowComponent,
FormsModule,
LayoutComponent,
ListViewComponent,

2
frontend/src/app/features/teams/state/team-auth.state.ts

@ -81,7 +81,7 @@ export class TeamAuthState extends State<Snapshot> {
}
public update(scheme: AuthSchemeDto | undefined): Observable<AuthSchemeDto | undefined | null> {
return this.teamService.putTeamAuth(this.teamId, new AuthSchemeValueDto({ scheme }), this.version).pipe(
return this.teamService.putTeamAuth(this.teamId, AuthSchemeValueDto.fromJSON({ scheme }), this.version).pipe(
tap(({ version, payload }) => {
this.next({
...payload,

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save