mirror of https://github.com/Squidex/squidex.git
Browse Source
* Temp * Temp * Update * Temp * Fix track-by * Build fixes * Migration to new flow. * More manual fixes. * Reformat templates. * Fix tests * Improve tests * Revert change.pull/1098/head
committed by
GitHub
527 changed files with 26559 additions and 26910 deletions
@ -1,18 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Microsoft.AspNetCore.Builder; |
|||
|
|||
namespace Squidex.Web; |
|||
|
|||
public static class BuilderExtensions |
|||
{ |
|||
public static void UseWhenPath(this IApplicationBuilder builder, string path, Action<IApplicationBuilder> configurator) |
|||
{ |
|||
builder.UseWhen(c => c.Request.Path.StartsWithSegments(path, StringComparison.OrdinalIgnoreCase), configurator); |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
{ |
|||
"plugins": ["squidex-prettier-plugin-organize-attributes"], |
|||
"overrides": [ |
|||
{ |
|||
"files": "*.html", |
|||
"options": { |
|||
"attributeGroups": ["$ANGULAR"], |
|||
"attributeIgnoreChars": "[]()*", |
|||
"attributeSort": "ASC", |
|||
"parser": "angular", |
|||
"printWidth": 140, |
|||
"bracketSameLine": true, |
|||
"bracketSpacing": true, |
|||
"singleAttributePerLine": false, |
|||
"tabWidth": 4 |
|||
} |
|||
} |
|||
], |
|||
"tabWidth": 4 |
|||
} |
|||
File diff suppressed because it is too large
@ -1,27 +1,36 @@ |
|||
<tr [class.faulted]="eventConsumer.error && eventConsumer.error && eventConsumer.error.length > 0"> |
|||
<td class="cell-auto"> |
|||
<span class="truncate"> |
|||
<i class="faulted-icon icon icon-bug" (click)="failure.emit()" [class.hidden]="!eventConsumer.error || eventConsumer.error.length === 0"></i> |
|||
<i |
|||
class="faulted-icon icon icon-bug" |
|||
[class.hidden]="!eventConsumer.error || eventConsumer.error.length === 0" |
|||
(click)="failure.emit()"></i> |
|||
|
|||
{{eventConsumer.name}} |
|||
{{ eventConsumer.name }} |
|||
</span> |
|||
</td> |
|||
<td class="cell-auto-right"> |
|||
<span>{{eventConsumer.count}}</span> |
|||
<span>{{ eventConsumer.count }}</span> |
|||
</td> |
|||
<td class="cell-auto-right"> |
|||
<span>{{eventConsumer.position}}</span> |
|||
<span>{{ eventConsumer.position }}</span> |
|||
</td> |
|||
<td class="cell-actions-lg"> |
|||
<button type="button" class="btn btn-text-secondary" (click)="reset()" *ngIf="eventConsumer.canReset" title="i18n:eventConsumers.resetTooltip"> |
|||
<i class="icon icon-reset"></i> |
|||
</button> |
|||
<button type="button" class="btn btn-text-secondary" (click)="start()" *ngIf="eventConsumer.canStart" title="i18n:eventConsumers.startTooltip"> |
|||
<i class="icon icon-play"></i> |
|||
</button> |
|||
<button type="button" class="btn btn-text-secondary" (click)="stop()" *ngIf="eventConsumer.canStop" title="i18n:eventConsumers.stopTooltip"> |
|||
<i class="icon icon-pause"></i> |
|||
</button> |
|||
@if (eventConsumer.canReset) { |
|||
<button class="btn btn-text-secondary" (click)="reset()" title="i18n:eventConsumers.resetTooltip" type="button"> |
|||
<i class="icon icon-reset"></i> |
|||
</button> |
|||
} |
|||
@if (eventConsumer.canStart) { |
|||
<button class="btn btn-text-secondary" (click)="start()" title="i18n:eventConsumers.startTooltip" type="button"> |
|||
<i class="icon icon-play"></i> |
|||
</button> |
|||
} |
|||
@if (eventConsumer.canStop) { |
|||
<button class="btn btn-text-secondary" (click)="stop()" title="i18n:eventConsumers.stopTooltip" type="button"> |
|||
<i class="icon icon-pause"></i> |
|||
</button> |
|||
} |
|||
</td> |
|||
</tr> |
|||
<tr class="spacer"></tr> |
|||
<tr class="spacer"></tr> |
|||
|
|||
@ -1,79 +1,104 @@ |
|||
|
|||
<form [formGroup]="userForm.form" (ngSubmit)="save()"> |
|||
<input style="display: none;" type="password" name="foilautofill"> |
|||
<input name="foilautofill" style="display: none" type="password" /> |
|||
|
|||
<sqx-layout layout="right" width="30" white="true" padding="true" overflow="true"> |
|||
<sqx-layout layout="right" overflow="true" padding="true" white="true" width="30"> |
|||
<ng-container title> |
|||
<ng-container *ngIf="usersState.selectedUser | async; else noUserTitle"> |
|||
@if (usersState.selectedUser | async) { |
|||
<sqx-title message="i18n:users.editPageTitle"></sqx-title> |
|||
|
|||
<h3>{{ 'users.editTitle' | sqxTranslate }}</h3> |
|||
</ng-container> |
|||
|
|||
<ng-template #noUserTitle> |
|||
<h3>{{ "users.editTitle" | sqxTranslate }}</h3> |
|||
} @else { |
|||
<sqx-title message="i18n:users.createPageTitle"></sqx-title> |
|||
|
|||
<h3>{{ 'users.createTitle' | sqxTranslate }}</h3> |
|||
</ng-template> |
|||
<h3>{{ "users.createTitle" | sqxTranslate }}</h3> |
|||
} |
|||
</ng-container> |
|||
|
|||
<ng-container menu> |
|||
<ng-container *ngIf="usersState.selectedUser | async; let user; else noUserMenu"> |
|||
<button type="submit" class="btn btn-primary" shortcut="CTRL + SHIFT + S" *ngIf="isEditable"> |
|||
{{ 'common.save' | sqxTranslate }} |
|||
</button> |
|||
</ng-container> |
|||
|
|||
<ng-template #noUserMenu> |
|||
<button type="submit" class="btn btn-primary" shortcut="CTRL + SHIFT + S"> |
|||
{{ 'common.save' | sqxTranslate }} |
|||
@if (usersState.selectedUser | async; as user) { |
|||
@if (isEditable) { |
|||
<button class="btn btn-primary" shortcut="CTRL + SHIFT + S" type="submit"> |
|||
{{ "common.save" | sqxTranslate }} |
|||
</button> |
|||
} |
|||
} @else { |
|||
<button class="btn btn-primary" shortcut="CTRL + SHIFT + S" type="submit"> |
|||
{{ "common.save" | sqxTranslate }} |
|||
</button> |
|||
</ng-template> |
|||
} |
|||
</ng-container> |
|||
|
|||
<ng-container > |
|||
<ng-container> |
|||
<sqx-form-error [error]="userForm.error | async"></sqx-form-error> |
|||
|
|||
<div class="form-group"> |
|||
<label for="email">{{ 'common.email' | sqxTranslate }} <small class="hint">({{ 'common.requiredHint' | sqxTranslate }})</small></label> |
|||
<label for="email"> |
|||
{{ "common.email" | sqxTranslate }} |
|||
<small class="hint">({{ "common.requiredHint" | sqxTranslate }})</small> |
|||
</label> |
|||
|
|||
<sqx-control-errors for="email"></sqx-control-errors> |
|||
|
|||
<input type="email" class="form-control" id="email" maxlength="100" formControlName="email" autocomplete="off"> |
|||
<input class="form-control" id="email" autocomplete="off" formControlName="email" maxlength="100" type="email" /> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="displayName">{{ 'common.displayName' | sqxTranslate }} <small class="hint">({{ 'common.requiredHint' | sqxTranslate }})</small></label> |
|||
<label for="displayName"> |
|||
{{ "common.displayName" | sqxTranslate }} |
|||
<small class="hint">({{ "common.requiredHint" | sqxTranslate }})</small> |
|||
</label> |
|||
|
|||
<sqx-control-errors for="displayName"></sqx-control-errors> |
|||
|
|||
<input class="form-control" id="displayName" maxlength="100" formControlName="displayName" autocomplete="off" spellcheck="false"> |
|||
<input |
|||
class="form-control" |
|||
id="displayName" |
|||
autocomplete="off" |
|||
formControlName="displayName" |
|||
maxlength="100" |
|||
spellcheck="false" /> |
|||
</div> |
|||
|
|||
<div class="form-group form-group-section"> |
|||
<div class="form-group"> |
|||
<label for="password">{{ 'common.password' | sqxTranslate }}</label> |
|||
<label for="password">{{ "common.password" | sqxTranslate }}</label> |
|||
|
|||
<sqx-control-errors for="password"></sqx-control-errors> |
|||
|
|||
<input type="password" class="form-control" id="password" maxlength="100" formControlName="password" autocomplete="off"> |
|||
<input |
|||
class="form-control" |
|||
id="password" |
|||
autocomplete="off" |
|||
formControlName="password" |
|||
maxlength="100" |
|||
type="password" /> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label for="password">{{ 'common.passwordConfirm' | sqxTranslate }}</label> |
|||
<label for="password">{{ "common.passwordConfirm" | sqxTranslate }}</label> |
|||
|
|||
<sqx-control-errors for="passwordConfirm"></sqx-control-errors> |
|||
|
|||
<input type="password" class="form-control" id="passwordConfirm" maxlength="100" formControlName="passwordConfirm" autocomplete="off"> |
|||
<input |
|||
class="form-control" |
|||
id="passwordConfirm" |
|||
autocomplete="off" |
|||
formControlName="passwordConfirm" |
|||
maxlength="100" |
|||
type="password" /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group form-group-section"> |
|||
<label for="permissions">{{ 'common.permissions' | sqxTranslate }}</label> |
|||
<label for="permissions">{{ "common.permissions" | sqxTranslate }}</label> |
|||
|
|||
<sqx-control-errors for="permissions"></sqx-control-errors> |
|||
|
|||
<textarea class="form-control" id="permissions" formControlName="permissions" placeholder="{{ 'common.separateByLine' | sqxTranslate }}" autocomplete="off" spellcheck="false"></textarea> |
|||
<textarea |
|||
class="form-control" |
|||
id="permissions" |
|||
autocomplete="off" |
|||
formControlName="permissions" |
|||
placeholder="{{ 'common.separateByLine' | sqxTranslate }}" |
|||
spellcheck="false"></textarea> |
|||
</div> |
|||
</ng-container> |
|||
</sqx-layout> |
|||
</form> |
|||
</form> |
|||
|
|||
@ -1,29 +1,36 @@ |
|||
<tr [routerLink]="user.id" queryParamsHandling="preserve" routerLinkActive="active"> |
|||
<tr queryParamsHandling="preserve" [routerLink]="user.id" routerLinkActive="active"> |
|||
<td class="cell-user"> |
|||
<img class="user-picture" title="{{user.displayName}}" [src]="user | sqxUserDtoPicture"> |
|||
<img class="user-picture" [src]="user | sqxUserDtoPicture" title="{{ user.displayName }}" /> |
|||
</td> |
|||
<td class="cell-auto"> |
|||
<span class="user-name table-cell">{{user.displayName}}</span> |
|||
<span class="user-name table-cell">{{ user.displayName }}</span> |
|||
</td> |
|||
<td class="cell-auto"> |
|||
<span class="user-email table-cell">{{user.email}}</span> |
|||
<span class="user-email table-cell">{{ user.email }}</span> |
|||
</td> |
|||
<td class="cell-actions-lg"> |
|||
<button type="button" class="btn btn-text-secondary" (click)="lock()" sqxStopClick *ngIf="user.canLock" title="i18n:users.lockTooltip"> |
|||
<i class="icon icon-unlocked"></i> |
|||
</button> |
|||
<button type="button" class="btn btn-text-secondary" (click)="unlock()" sqxStopClick *ngIf="user.canUnlock" title="i18n:users.unlockTooltip"> |
|||
<i class="icon icon-lock"></i> |
|||
</button> |
|||
@if (user.canLock) { |
|||
<button class="btn btn-text-secondary" (click)="lock()" sqxStopClick title="i18n:users.lockTooltip" type="button"> |
|||
<i class="icon icon-unlocked"></i> |
|||
</button> |
|||
} |
|||
@if (user.canUnlock) { |
|||
<button class="btn btn-text-secondary" (click)="unlock()" sqxStopClick title="i18n:users.unlockTooltip" type="button"> |
|||
<i class="icon icon-lock"></i> |
|||
</button> |
|||
} |
|||
|
|||
<button type="button" class="btn btn-text-danger" [disabled]="!user.canDelete" |
|||
(sqxConfirmClick)="delete()" |
|||
confirmTitle="i18n:users.deleteConfirmTitle" |
|||
confirmText="i18n:users.deleteConfirmText" |
|||
<button |
|||
class="btn btn-text-danger" |
|||
confirmRememberKey="deleteUser" |
|||
sqxStopClick> |
|||
confirmText="i18n:users.deleteConfirmText" |
|||
confirmTitle="i18n:users.deleteConfirmTitle" |
|||
[disabled]="!user.canDelete" |
|||
(sqxConfirmClick)="delete()" |
|||
sqxStopClick |
|||
type="button"> |
|||
<i class="icon-bin2"></i> |
|||
</button> |
|||
</td> |
|||
</tr> |
|||
<tr class="spacer"></tr> |
|||
<tr class="spacer"></tr> |
|||
|
|||
@ -1,29 +1,29 @@ |
|||
<sqx-title message="i18n:api.pageTitle"></sqx-title> |
|||
|
|||
<sqx-layout layout="left" titleText="i18n:api.title" titleIcon="api" width="16" white="true" overflow="true" padding="true"> |
|||
<sqx-layout layout="left" overflow="true" padding="true" titleIcon="api" titleText="i18n:api.title" white="true" width="16"> |
|||
<ng-container> |
|||
<ul class="nav nav-light flex-column"> |
|||
<li class="nav-item" sqxTourStep="graphql"> |
|||
<a class="nav-link" routerLink="graphql" routerLinkActive="active"> |
|||
{{ 'api.graphql' | sqxTranslate }} |
|||
{{ "api.graphql" | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
|
|||
<li class="nav-item nav-heading"> |
|||
{{ 'common.openAPI' | sqxTranslate }} |
|||
{{ "common.openAPI" | sqxTranslate }} |
|||
</li> |
|||
<li class="nav-item" sqxTourStep="contentApi"> |
|||
<a class="nav-link" href="/api/content/{{appsState.appName}}/docs" sqxExternalLink> |
|||
{{ 'api.contentApi' | sqxTranslate }} |
|||
<a class="nav-link" href="/api/content/{{ appsState.appName }}/docs" sqxExternalLink> |
|||
{{ "api.contentApi" | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
<li class="nav-item" sqxTourStep="generalAPi"> |
|||
<a class="nav-link" href="/api/docs" sqxExternalLink> |
|||
{{ 'api.generalApi' | sqxTranslate }} |
|||
{{ "api.generalApi" | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
</ul> |
|||
</ng-container> |
|||
</sqx-layout> |
|||
|
|||
<router-outlet></router-outlet> |
|||
<router-outlet></router-outlet> |
|||
|
|||
@ -1,38 +1,40 @@ |
|||
<sqx-title message="i18n:api.graphqlPageTitle"></sqx-title> |
|||
|
|||
<sqx-layout layout="main" hideHeader="true" hideSidebar="true"> |
|||
<div inner #graphiQLContainer sqxTourStep="graphQLExplorer"></div> |
|||
|
|||
<button class="btn btn-simple btn-options" *ngIf="clientsReadable" (click)="clientsDialog.show()"> |
|||
<i class="icon-clients"></i> |
|||
</button> |
|||
<sqx-layout hideHeader="true" hideSidebar="true" layout="main"> |
|||
<div #graphiQLContainer inner sqxTourStep="graphQLExplorer"></div> |
|||
|
|||
@if (clientsReadable) { |
|||
<button class="btn btn-simple btn-options" (click)="clientsDialog.show()"> |
|||
<i class="icon-clients"></i> |
|||
</button> |
|||
} |
|||
</sqx-layout> |
|||
|
|||
<sqx-modal-dialog *sqxModal="clientsDialog" (dialogClose)="clientsDialog.hide()"> |
|||
<sqx-modal-dialog (dialogClose)="clientsDialog.hide()" *sqxModal="clientsDialog"> |
|||
<ng-container title> |
|||
{{ 'api.selectClient' | sqxTranslate }} |
|||
{{ "api.selectClient" | sqxTranslate }} |
|||
</ng-container> |
|||
|
|||
<ng-container content> |
|||
<sqx-form-hint> |
|||
{{ 'api.selectClientDescription' | sqxTranslate }} |
|||
{{ "api.selectClientDescription" | sqxTranslate }} |
|||
</sqx-form-hint> |
|||
|
|||
<div class="form-group"> |
|||
<label for="client">{{ 'common.client' | sqxTranslate }}</label> |
|||
|
|||
<select class="form-control" id="client" |
|||
[ngModel]="clientSelected" |
|||
(ngModelChange)="selectClient($event)"> |
|||
<option [ngValue]="null">{{ 'api.noClient' | sqxTranslate }}</option> |
|||
<option *ngFor="let client of clientsState.clients | async" [ngValue]="client">{{client.id}}</option> |
|||
<label for="client">{{ "common.client" | sqxTranslate }}</label> |
|||
|
|||
<select class="form-control" id="client" [ngModel]="clientSelected" (ngModelChange)="selectClient($event)"> |
|||
<option [ngValue]="null">{{ "api.noClient" | sqxTranslate }}</option> |
|||
@for (client of clientsState.clients | async; track client) { |
|||
<option [ngValue]="client">{{ client.id }}</option> |
|||
} |
|||
</select> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container footer> |
|||
<button type="button" class="btn btn-text-secondary" (click)="clientsDialog.hide()"> |
|||
{{ 'common.close' | sqxTranslate }} |
|||
<button class="btn btn-text-secondary" (click)="clientsDialog.hide()" type="button"> |
|||
{{ "common.close" | sqxTranslate }} |
|||
</button> |
|||
</ng-container> |
|||
</sqx-modal-dialog> |
|||
</sqx-modal-dialog> |
|||
|
|||
@ -1,79 +1,77 @@ |
|||
<sqx-title message="i18n:apps.listPageTitle"></sqx-title> |
|||
|
|||
<div class="panel-container page" *ngIf="authState.userChanges | async; let user"> |
|||
<div class="apps-section"> |
|||
<h1 class="apps-title">{{ 'apps.welcomeTitle' | sqxTranslate: { user: user.displayName } }}</h1> |
|||
|
|||
<div class="subtext"> |
|||
{{ 'apps.welcomeSubtitle' | sqxTranslate }} |
|||
</div> |
|||
</div> |
|||
|
|||
<ng-container *ngIf="groupedApps | async; let groups"> |
|||
<div class="apps-section" sqxTourStep="allApps"> |
|||
<div class="empty" *ngIf="groups.length === 0"> |
|||
<h3 class="empty-headline">{{ 'apps.empty' | sqxTranslate }}</h3> |
|||
</div> |
|||
|
|||
<div class="team" *ngFor="let group of groups; trackBy: trackByGroup"> |
|||
<div class="team-header" *ngIf="group.team"> |
|||
<sqx-team [team]="group.team" (leave)="leaveTeam($event)"></sqx-team> |
|||
</div> |
|||
|
|||
<div class="team-body" [class.padded]="group.team"> |
|||
<sqx-app *ngFor="let app of group.apps; trackBy: trackByApp" [app]="app" (leave)="leaveApp($event)"></sqx-app> |
|||
|
|||
<small class="team-empty" *ngIf="group.apps.length === 0"> |
|||
{{ 'teams.empty' | sqxTranslate }} |
|||
</small> |
|||
</div> |
|||
@if (authState.userChanges | async; as user) { |
|||
<div class="panel-container page"> |
|||
<div class="apps-section"> |
|||
<h1 class="apps-title">{{ "apps.welcomeTitle" | sqxTranslate: { user: user.displayName } }}</h1> |
|||
<div class="subtext"> |
|||
{{ "apps.welcomeSubtitle" | sqxTranslate }} |
|||
</div> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<div class="apps-section" *ngIf="(uiState.settings | async)?.canCreateApps"> |
|||
<div class="card card-template card-href" data-testid="new-app" (click)="createNewApp()" sqxTourStep="addApp"> |
|||
<div class="card-body"> |
|||
<div class="card-image"> |
|||
<img src="./images/add-app.svg"> |
|||
</div> |
|||
|
|||
<h3 class="card-title">{{ 'apps.createBlankApp' | sqxTranslate }}</h3> |
|||
|
|||
<sqx-form-hint> |
|||
{{ 'apps.createBlankAppDescription' | sqxTranslate }} |
|||
</sqx-form-hint> |
|||
@if (groupedApps | async; as groups) { |
|||
<div class="apps-section" sqxTourStep="allApps"> |
|||
@for (group of groups; track trackByGroup($index, group)) { |
|||
<div class="team"> |
|||
@if (group.team) { |
|||
<div class="team-header"> |
|||
<sqx-team (leave)="leaveTeam($event)" [team]="group.team"></sqx-team> |
|||
</div> |
|||
} |
|||
<div class="team-body" [class.padded]="group.team"> |
|||
@for (app of group.apps; track app.id) { |
|||
<sqx-app [app]="app" (leave)="leaveApp($event)"></sqx-app> |
|||
} @empty { |
|||
<small class="team-empty"> |
|||
{{ "teams.empty" | sqxTranslate }} |
|||
</small> |
|||
} |
|||
</div> |
|||
</div> |
|||
} @empty { |
|||
<div class="empty"> |
|||
<h3 class="empty-headline">{{ "apps.empty" | sqxTranslate }}</h3> |
|||
</div> |
|||
} |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="card card-template card-href" *ngFor="let template of templates | async" (click)="createNewApp(template)"> |
|||
<div class="card-body"> |
|||
<div class="card-image"> |
|||
<img src="./images/add-template.svg"> |
|||
} |
|||
@if ((uiState.settings | async)?.canCreateApps) { |
|||
<div class="apps-section"> |
|||
<div class="card card-template card-href" (click)="createNewApp()" data-testid="new-app" sqxTourStep="addApp"> |
|||
<div class="card-body"> |
|||
<div class="card-image"> |
|||
<img src="./images/add-app.svg" /> |
|||
</div> |
|||
<h3 class="card-title">{{ "apps.createBlankApp" | sqxTranslate }}</h3> |
|||
<sqx-form-hint> |
|||
{{ "apps.createBlankAppDescription" | sqxTranslate }} |
|||
</sqx-form-hint> |
|||
</div> |
|||
</div> |
|||
|
|||
<h3 class="card-title">{{template.title}}</h3> |
|||
|
|||
<sqx-form-hint> |
|||
{{template.description}} |
|||
</sqx-form-hint> |
|||
@for (template of templates | async; track template) { |
|||
<div class="card card-template card-href" (click)="createNewApp(template)"> |
|||
<div class="card-body"> |
|||
<div class="card-image"> |
|||
<img src="./images/add-template.svg" /> |
|||
</div> |
|||
<h3 class="card-title">{{ template.title }}</h3> |
|||
<sqx-form-hint> |
|||
{{ template.description }} |
|||
</sqx-form-hint> |
|||
</div> |
|||
</div> |
|||
} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div *ngIf="info" class="apps-section"> |
|||
<small class="info">{{info}}</small> |
|||
} |
|||
@if (info) { |
|||
<div class="apps-section"> |
|||
<small class="info">{{ info }}</small> |
|||
</div> |
|||
} |
|||
</div> |
|||
</div> |
|||
} |
|||
|
|||
<sqx-app-form *sqxModal="addAppDialog" |
|||
(dialogClose)="addAppDialog.hide()" [template]="addAppTemplate"> |
|||
</sqx-app-form> |
|||
<sqx-app-form (dialogClose)="addAppDialog.hide()" *sqxModal="addAppDialog" [template]="addAppTemplate"></sqx-app-form> |
|||
|
|||
<sqx-onboarding-dialog *sqxModal="onboardingDialog" |
|||
(dialogClose)="onboardingDialog.hide()"> |
|||
</sqx-onboarding-dialog> |
|||
<sqx-onboarding-dialog (dialogClose)="onboardingDialog.hide()" *sqxModal="onboardingDialog"></sqx-onboarding-dialog> |
|||
|
|||
<sqx-news-dialog *sqxModal="newsDialog" [features]="newsFeatures!" |
|||
(dialogClose)="newsDialog.hide()"> |
|||
</sqx-news-dialog> |
|||
<sqx-news-dialog (dialogClose)="newsDialog.hide()" [features]="newsFeatures!" *sqxModal="newsDialog"></sqx-news-dialog> |
|||
|
|||
@ -1,19 +1,19 @@ |
|||
<sqx-modal-dialog size="lg" (dialogClose)="dialogClose.emit()"> |
|||
<sqx-modal-dialog (dialogClose)="dialogClose.emit()" size="lg"> |
|||
<ng-container title> |
|||
{{ 'news.title' | sqxTranslate }} |
|||
{{ "news.title" | sqxTranslate }} |
|||
</ng-container> |
|||
|
|||
<ng-container content> |
|||
<div class="help"> |
|||
<h1>{{ 'news.headline' | sqxTranslate }}</h1> |
|||
<h1>{{ "news.headline" | sqxTranslate }}</h1> |
|||
|
|||
<div *ngFor="let feature of features; trackBy: trackByFeature; let last = last"> |
|||
<h4>{{feature.name}}</h4> |
|||
|
|||
<div [innerHTML]="feature.text | sqxHelpMarkdown"></div> |
|||
|
|||
<hr [class.hidden]="last" /> |
|||
</div> |
|||
@for (feature of features; track feature; let last = $last) { |
|||
<div> |
|||
<h4>{{ feature.name }}</h4> |
|||
<div [innerHTML]="feature.text | sqxHelpMarkdown"></div> |
|||
<hr [class.hidden]="last" /> |
|||
</div> |
|||
} |
|||
</div> |
|||
</ng-container> |
|||
</sqx-modal-dialog> |
|||
|
|||
@ -1,100 +1,95 @@ |
|||
<sqx-modal-dialog showHeader="false"> |
|||
<ng-container tabs> |
|||
<div class="squid d-flex align-items-center justify-content-center"> |
|||
<img src="./images/squid.svg"> |
|||
<img src="./images/squid.svg" /> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container content> |
|||
<a class="header-right modal-close force" (click)="cancel()">{{ 'tour.skip' | sqxTranslate }}</a> |
|||
<a class="header-right modal-close force" (click)="cancel()">{{ "tour.skip" | sqxTranslate }}</a> |
|||
|
|||
<div class="onboarding-step " *ngIf="step === 0"> |
|||
<img @fade class="header-left" src="./images/logo-white-small.png"> |
|||
|
|||
<div @slide class="onboarding-enter-leave text-center"> |
|||
<h1>{{ 'tour.welcome' | sqxTranslate }} <span class="header-focus">{{ 'tour.welcomeProduct' | sqxTranslate }}</span></h1> |
|||
|
|||
<div [innerHTML]="'tour.stepIntroText' | sqxTranslate | sqxMarkdown | sqxSafeHtml"></div> |
|||
|
|||
<div class="mt-4"> |
|||
<button (click)="next()" class="btn btn-success"> |
|||
{{ 'tour.stepIntroNext' | sqxTranslate }} |
|||
</button> |
|||
@if (step === 0) { |
|||
<div class="onboarding-step"> |
|||
<img class="header-left" @fade src="./images/logo-white-small.png" /> |
|||
<div class="onboarding-enter-leave text-center" @slide> |
|||
<h1> |
|||
{{ "tour.welcome" | sqxTranslate }} |
|||
<span class="header-focus">{{ "tour.welcomeProduct" | sqxTranslate }}</span> |
|||
</h1> |
|||
<div [innerHTML]="'tour.stepIntroText' | sqxTranslate | sqxMarkdown | sqxSafeHtml"></div> |
|||
<div class="mt-4"> |
|||
<button class="btn btn-success" (click)="next()"> |
|||
{{ "tour.stepIntroNext" | sqxTranslate }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
} |
|||
|
|||
<div *ngIf="step === 1"> |
|||
<img @fade class="header-left" src="./images/logo-white-small.png"> |
|||
|
|||
<div @slide class="onboarding-enter-leave"> |
|||
<form [formGroup]="answersForm" (ngSubmit)="submitAnswers()"> |
|||
<h2>{{ 'tour.stepDataTitle' | sqxTranslate }}</h2> |
|||
|
|||
<div [innerHTML]="'tour.stepDataText' | sqxTranslate | sqxMarkdown | sqxSafeHtml"></div> |
|||
|
|||
<div class="form-group mt-4"> |
|||
<label for="role">{{ 'tour.stepDataCompanyRole' | sqxTranslate }}</label> |
|||
|
|||
<select class="form-select" id="companyRole" formControlName="companyRole"> |
|||
<option [ngValue]="'RoleEmployee'">{{ 'tour.roleEmployee' | sqxTranslate }}</option> |
|||
<option [ngValue]="'RoleBusinessOwner'">{{ 'tour.roleBusinessOwner' | sqxTranslate }}</option> |
|||
<option [ngValue]="'RoleProductManager'">{{ 'tour.roleProductManager' | sqxTranslate }}</option> |
|||
<option [ngValue]="'RoleContentCreator'">{{ 'tour.roleContentCreator' | sqxTranslate }}</option> |
|||
<option [ngValue]="'RoleSoftwareDeveloper'">{{ 'tour.roleSoftwareDeveloper' | sqxTranslate }}</option> |
|||
<option [ngValue]="'RoleBusinessAnalyst'">{{ 'tour.roleBusinessAnalyst' | sqxTranslate }}</option> |
|||
</select> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label for="companySize">{{ 'tour.stepDataCompanySize' | sqxTranslate }}</label> |
|||
|
|||
<select class="form-select" id="companySize" formControlName="companySize"> |
|||
<option [ngValue]="'SizeSingle'">{{ 'tour.sizeSingle' | sqxTranslate }}</option> |
|||
<option [ngValue]="'SizeSmall'">{{ 'tour.sizeSmall' | sqxTranslate }}</option> |
|||
<option [ngValue]="'SizeMedium'">{{ 'tour.sizeMedium' | sqxTranslate }}</option> |
|||
<option [ngValue]="'SizeLarge'">{{ 'tour.sizeLarge' | sqxTranslate }}</option> |
|||
<option [ngValue]="'SizeVeryLarge'">{{ 'tour.sizeVeryLarge' | sqxTranslate }}</option> |
|||
</select> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label for="project">{{ 'tour.stepDataProject' | sqxTranslate }}</label> |
|||
|
|||
<select class="form-select" id="project" formControlName="project"> |
|||
<option [ngValue]="'ProjectNewsMagazine'">{{ 'tour.projectNewsMagazine' | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectPersonalBlog'">{{ 'tour.projectPersonalBlog' | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectSmallBusiness'">{{ 'tour.projectSmallBusiness' | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectCommerce'">{{ 'tour.projectCommerce' | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectMobileApp'">{{ 'tour.projectMobileApp' | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectBackend'">{{ 'tour.projectBackend' | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectLearning'">{{ 'tour.projectLearning' | sqxTranslate }}</option> |
|||
</select> |
|||
</div> |
|||
|
|||
<button type="submit" class="btn btn-success">{{ 'tour.stepDataNext' | sqxTranslate }}</button> |
|||
</form> |
|||
@if (step === 1) { |
|||
<div> |
|||
<img class="header-left" @fade src="./images/logo-white-small.png" /> |
|||
<div class="onboarding-enter-leave" @slide> |
|||
<form [formGroup]="answersForm" (ngSubmit)="submitAnswers()"> |
|||
<h2>{{ "tour.stepDataTitle" | sqxTranslate }}</h2> |
|||
<div [innerHTML]="'tour.stepDataText' | sqxTranslate | sqxMarkdown | sqxSafeHtml"></div> |
|||
<div class="form-group mt-4"> |
|||
<label for="role">{{ "tour.stepDataCompanyRole" | sqxTranslate }}</label> |
|||
<select class="form-select" id="companyRole" formControlName="companyRole"> |
|||
<option [ngValue]="'RoleEmployee'">{{ "tour.roleEmployee" | sqxTranslate }}</option> |
|||
<option [ngValue]="'RoleBusinessOwner'">{{ "tour.roleBusinessOwner" | sqxTranslate }}</option> |
|||
<option [ngValue]="'RoleProductManager'">{{ "tour.roleProductManager" | sqxTranslate }}</option> |
|||
<option [ngValue]="'RoleContentCreator'">{{ "tour.roleContentCreator" | sqxTranslate }}</option> |
|||
<option [ngValue]="'RoleSoftwareDeveloper'">{{ "tour.roleSoftwareDeveloper" | sqxTranslate }}</option> |
|||
<option [ngValue]="'RoleBusinessAnalyst'">{{ "tour.roleBusinessAnalyst" | sqxTranslate }}</option> |
|||
</select> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="companySize">{{ "tour.stepDataCompanySize" | sqxTranslate }}</label> |
|||
<select class="form-select" id="companySize" formControlName="companySize"> |
|||
<option [ngValue]="'SizeSingle'">{{ "tour.sizeSingle" | sqxTranslate }}</option> |
|||
<option [ngValue]="'SizeSmall'">{{ "tour.sizeSmall" | sqxTranslate }}</option> |
|||
<option [ngValue]="'SizeMedium'">{{ "tour.sizeMedium" | sqxTranslate }}</option> |
|||
<option [ngValue]="'SizeLarge'">{{ "tour.sizeLarge" | sqxTranslate }}</option> |
|||
<option [ngValue]="'SizeVeryLarge'">{{ "tour.sizeVeryLarge" | sqxTranslate }}</option> |
|||
</select> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="project">{{ "tour.stepDataProject" | sqxTranslate }}</label> |
|||
<select class="form-select" id="project" formControlName="project"> |
|||
<option [ngValue]="'ProjectNewsMagazine'">{{ "tour.projectNewsMagazine" | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectPersonalBlog'">{{ "tour.projectPersonalBlog" | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectSmallBusiness'">{{ "tour.projectSmallBusiness" | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectCommerce'">{{ "tour.projectCommerce" | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectMobileApp'">{{ "tour.projectMobileApp" | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectBackend'">{{ "tour.projectBackend" | sqxTranslate }}</option> |
|||
<option [ngValue]="'ProjectLearning'">{{ "tour.projectLearning" | sqxTranslate }}</option> |
|||
</select> |
|||
</div> |
|||
<button class="btn btn-success" type="submit"> |
|||
{{ "tour.stepDataNext" | sqxTranslate }} |
|||
</button> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="onboarding-step" *ngIf="step === 2"> |
|||
<img @fade class="header-left" src="./images/logo-white-small.png"> |
|||
|
|||
<div @slide class="onboarding-enter-leave text-center"> |
|||
<h2>{{ 'tour.stepTourTitle' | sqxTranslate }}</h2> |
|||
} |
|||
|
|||
<div [innerHTML]="'tour.stepTourText' | sqxTranslate | sqxMarkdown | sqxSafeHtml"></div> |
|||
|
|||
<div class="mt-4"> |
|||
<button (click)="start()" class="btn btn-success"> |
|||
{{ 'tour.startYes' | sqxTranslate }} |
|||
</button> |
|||
|
|||
<button (click)="cancel()" class="btn btn-outline-secondary ms-2"> |
|||
{{ 'tour.startNo' | sqxTranslate }} |
|||
</button> |
|||
@if (step === 2) { |
|||
<div class="onboarding-step"> |
|||
<img class="header-left" @fade src="./images/logo-white-small.png" /> |
|||
<div class="onboarding-enter-leave text-center" @slide> |
|||
<h2>{{ "tour.stepTourTitle" | sqxTranslate }}</h2> |
|||
<div [innerHTML]="'tour.stepTourText' | sqxTranslate | sqxMarkdown | sqxSafeHtml"></div> |
|||
<div class="mt-4"> |
|||
<button class="btn btn-success" (click)="start()"> |
|||
{{ "tour.startYes" | sqxTranslate }} |
|||
</button> |
|||
<button class="btn btn-outline-secondary ms-2" (click)="cancel()"> |
|||
{{ "tour.startNo" | sqxTranslate }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
} |
|||
</ng-container> |
|||
</sqx-modal-dialog> |
|||
|
|||
@ -1,26 +1,27 @@ |
|||
<div class="team-header"> |
|||
<div class="row align-items-center"> |
|||
<div class="col"> |
|||
<h3>{{team.name}}</h3> |
|||
<h3>{{ team.name }}</h3> |
|||
</div> |
|||
<div class="col-auto"> |
|||
<a class="link" [routerLink]="['/app/teams', team.id]" sqxStopClick>{{ 'common.edit' | sqxTranslate }}</a> |
|||
<a class="link" [routerLink]="['/app/teams', team.id]" sqxStopClick>{{ "common.edit" | sqxTranslate }}</a> |
|||
</div> |
|||
<div class="col-auto"> |
|||
<button type="button" class="btn btn-sm btn-text-secondary" (click)="dropdown.toggle()" sqxStopClick #buttonOptions> |
|||
<span class="hidden">{{ 'common.options' | sqxTranslate }}</span> |
|||
<button class="btn btn-sm btn-text-secondary" #buttonOptions (click)="dropdown.toggle()" sqxStopClick type="button"> |
|||
<span class="hidden">{{ "common.options" | sqxTranslate }}</span> |
|||
<i class="icon-dots"></i> |
|||
</button> |
|||
|
|||
<sqx-dropdown-menu *sqxModal="dropdown;closeAlways:true" [sqxAnchoredTo]="buttonOptions" scrollY="true"> |
|||
<a class="dropdown-item dropdown-item-delete" |
|||
(sqxConfirmClick)="leave.emit(team)" |
|||
confirmTitle="i18n:teams.leaveConfirmTitle" |
|||
|
|||
<sqx-dropdown-menu scrollY="true" [sqxAnchoredTo]="buttonOptions" *sqxModal="dropdown; closeAlways: true"> |
|||
<a |
|||
class="dropdown-item dropdown-item-delete" |
|||
confirmRememberKey="leaveApp" |
|||
confirmText="i18n:teams.leaveConfirmText" |
|||
confirmRememberKey="leaveApp"> |
|||
{{ 'teams.leave' | sqxTranslate }} |
|||
confirmTitle="i18n:teams.leaveConfirmTitle" |
|||
(sqxConfirmClick)="leave.emit(team)"> |
|||
{{ "teams.leave" | sqxTranslate }} |
|||
</a> |
|||
</sqx-dropdown-menu> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
@ -1,29 +1,32 @@ |
|||
<form [formGroup]="editForm.form" (ngSubmit)="renameAssetTag()"> |
|||
<sqx-modal-dialog (dialogClose)="emitClose()"> |
|||
<ng-container title> |
|||
{{ 'common.renameTag' | sqxTranslate }} |
|||
{{ "common.renameTag" | sqxTranslate }} |
|||
</ng-container> |
|||
|
|||
<ng-container content> |
|||
<sqx-form-error [error]="editForm.error | async"></sqx-form-error> |
|||
|
|||
|
|||
<div class="form-group"> |
|||
<label for="tagName">{{ 'common.name' | sqxTranslate }} <small class="hint">({{ 'common.requiredHint' | sqxTranslate }})</small></label> |
|||
|
|||
<label for="tagName"> |
|||
{{ "common.name" | sqxTranslate }} |
|||
<small class="hint">({{ "common.requiredHint" | sqxTranslate }})</small> |
|||
</label> |
|||
|
|||
<sqx-control-errors for="tagName"></sqx-control-errors> |
|||
|
|||
<input class="form-control" id="tagName" formControlName="tagName" autocomplete="off" sqxFocusOnInit> |
|||
|
|||
<input class="form-control" id="tagName" autocomplete="off" formControlName="tagName" sqxFocusOnInit /> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container footer> |
|||
<button type="button" class="btn btn-text-secondary" (click)="emitClose()"> |
|||
{{ 'common.cancel' | sqxTranslate }} |
|||
<button class="btn btn-text-secondary" (click)="emitClose()" type="button"> |
|||
{{ "common.cancel" | sqxTranslate }} |
|||
</button> |
|||
|
|||
<button type="submit" class="btn btn-success"> |
|||
{{ 'common.rename' | sqxTranslate }} |
|||
|
|||
<button class="btn btn-success" type="submit"> |
|||
{{ "common.rename" | sqxTranslate }} |
|||
</button> |
|||
</ng-container> |
|||
</sqx-modal-dialog> |
|||
</form> |
|||
</form> |
|||
|
|||
@ -1,28 +1,32 @@ |
|||
<div class="nav nav-light flex-column"> |
|||
<div class="nav-item"> |
|||
<a class="nav-link" (click)="tagsReset.emit()" [class.active]="isEmpty()"> |
|||
{{ 'common.tagsAll' | sqxTranslate }} |
|||
<a class="nav-link" [class.active]="isEmpty()" (click)="tagsReset.emit()"> |
|||
{{ "common.tagsAll" | sqxTranslate }} |
|||
</a> |
|||
</div> |
|||
|
|||
<div class="nav-item" *ngFor="let tag of tags; trackBy: trackByTag"> |
|||
<a class="nav-link" (click)="toggle.emit(tag.name)" [class.active]="isSelected(tag)"> |
|||
<div class="row g-0"> |
|||
<div class="col"> |
|||
<span class="truncate">{{tag.name}}</span> |
|||
@for (tag of tags; track tag.name) { |
|||
<div class="nav-item"> |
|||
<a class="nav-link" [class.active]="isSelected(tag)" (click)="toggle.emit(tag.name)"> |
|||
<div class="row g-0"> |
|||
<div class="col"> |
|||
<span class="truncate">{{ tag.name }}</span> |
|||
</div> |
|||
<div class="col-auto"> |
|||
<div class="badge badge-secondary rounded-pill">{{ tag.count }}</div> |
|||
@if (canRename) { |
|||
<a class="btn-sm btn-text-secondary btn-rename" (click)="renameTag(tag)" sqxStopClick> |
|||
<i class="icon-pencil"></i> |
|||
</a> |
|||
} |
|||
</div> |
|||
</div> |
|||
<div class="col-auto"> |
|||
<div class="badge badge-secondary rounded-pill">{{tag.count}}</div> |
|||
|
|||
<a class="btn-sm btn-text-secondary btn-rename" (click)="renameTag(tag)" *ngIf="canRename" sqxStopClick> |
|||
<i class="icon-pencil"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
} |
|||
</div> |
|||
|
|||
<sqx-asset-tag-dialog *sqxModal="tagRenameDialog" |
|||
(dialogClose)="tagRenameDialog.hide()" [tagName]="tagRenaming!.name"> |
|||
</sqx-asset-tag-dialog> |
|||
<sqx-asset-tag-dialog |
|||
(dialogClose)="tagRenameDialog.hide()" |
|||
*sqxModal="tagRenameDialog" |
|||
[tagName]="tagRenaming!.name"></sqx-asset-tag-dialog> |
|||
|
|||
@ -1,20 +1,18 @@ |
|||
<sqx-layout layout="right" titleText="i18n:common.filters" width="20" white="true" padding="true" overflow="true"> |
|||
<h3>{{ 'common.tags' | sqxTranslate }}</h3> |
|||
<sqx-layout layout="right" overflow="true" padding="true" titleText="i18n:common.filters" white="true" width="20"> |
|||
<h3>{{ "common.tags" | sqxTranslate }}</h3> |
|||
|
|||
<sqx-asset-tags |
|||
<sqx-asset-tags |
|||
[canRename]="(assetsState.canRenameTag | async)!" |
|||
[tags]="(assetsState.tags | async)!" |
|||
(tagsReset)="resetTags()" |
|||
[tagsSelected]="(assetsState.tagsSelected | async)!" |
|||
(toggle)="toggleTag($event)"> |
|||
</sqx-asset-tags> |
|||
(toggle)="toggleTag($event)"></sqx-asset-tags> |
|||
|
|||
<hr> |
|||
<hr /> |
|||
|
|||
<sqx-shared-queries |
|||
[types]="'common.assets' | sqxTranslate" |
|||
[queryUsed]="assetsState.query | async" |
|||
[queries]="assetsQueries" |
|||
(search)="search($event)"> |
|||
</sqx-shared-queries> |
|||
</sqx-layout> |
|||
[queryUsed]="assetsState.query | async" |
|||
(search)="search($event)" |
|||
[types]="'common.assets' | sqxTranslate"></sqx-shared-queries> |
|||
</sqx-layout> |
|||
|
|||
@ -1,3 +1,3 @@ |
|||
<sqx-layout layout="right" titleText="i18n:comments.title" width="20" white="true"> |
|||
<sqx-layout layout="right" titleText="i18n:comments.title" white="true" width="20"> |
|||
<sqx-comments [commentsId]="commentsId | async"></sqx-comments> |
|||
</sqx-layout> |
|||
</sqx-layout> |
|||
|
|||
@ -1,21 +1,21 @@ |
|||
<div class="event row g-0"> |
|||
<div class="col-auto"> |
|||
<img class="user-picture" title="{{event.actor | sqxUserNameRef}}" [src]="event.actor | sqxUserPictureRef"> |
|||
<img class="user-picture" [src]="event.actor | sqxUserPictureRef" title="{{ event.actor | sqxUserNameRef }}" /> |
|||
</div> |
|||
<div class="col ps-2 event-right"> |
|||
<div class="event-message"> |
|||
<span class="event-actor user-ref me-1" [title]="event.actor | sqxUserNameRef:null">{{event.actor | sqxUserNameRef:null}}</span> |
|||
<span class="event-actor user-ref me-1" [title]="event.actor | sqxUserNameRef: null"> |
|||
{{ event.actor | sqxUserNameRef: null }} |
|||
</span> |
|||
<span [innerHTML]="event | sqxHistoryMessage"></span> |
|||
</div> |
|||
|
|||
<div class="event-created">{{event.created | sqxFromNow}}</div> |
|||
<div class="event-created">{{ event.created | sqxFromNow }}</div> |
|||
|
|||
<ng-container *ngIf="canLoadOrCompare"> |
|||
<a class="event-load force" (click)="dataLoad.emit()">{{ 'contents.loadContent' | sqxTranslate }}</a> |
|||
|
|||
· |
|||
|
|||
<a class="event-load force" (click)="dataCompare.emit()">{{ 'contents.versionCompare' | sqxTranslate }}</a> |
|||
</ng-container> |
|||
@if (canLoadOrCompare) { |
|||
<a class="event-load force" (click)="dataLoad.emit()">{{ "contents.loadContent" | sqxTranslate }}</a> |
|||
· |
|||
<a class="event-load force" (click)="dataCompare.emit()">{{ "contents.versionCompare" | sqxTranslate }}</a> |
|||
} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
@ -1,141 +1,154 @@ |
|||
<sqx-layout layout="right" titleText="i18n:common.workflow" width="20" white="true" overflow="true" padding="true"> |
|||
<sqx-layout layout="right" overflow="true" padding="true" titleText="i18n:common.workflow" white="true" width="20"> |
|||
<ng-container> |
|||
<div class="section mb-2"> |
|||
<label for="id">{{ 'common.id' | sqxTranslate }}</label> |
|||
<label for="id">{{ "common.id" | sqxTranslate }}</label> |
|||
|
|||
<div class="input-group"> |
|||
<input readonly class="form-control" name="id" id="id" value="{{content.id}}" #inputId> |
|||
|
|||
<button type="button" class="btn btn-outline-secondary" [sqxCopy]="inputId"> |
|||
<input class="form-control" id="id" #inputId name="id" readonly value="{{ content.id }}" /> |
|||
|
|||
<button class="btn btn-outline-secondary" [sqxCopy]="inputId" type="button"> |
|||
<i class="icon-copy"></i> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
<div class="section mb-4"> |
|||
<label for="version">{{ 'common.version' | sqxTranslate }}</label>: <span id="version">{{content.version}}</span> |
|||
<label for="version">{{ "common.version" | sqxTranslate }}</label>: <span id="version">{{ content.version }}</span> |
|||
</div> |
|||
|
|||
<div class="section mb-4" *ngIf="content.canDraftCreate || content.canDraftDelete"> |
|||
<ng-container *ngIf="!content.newStatus; else newVersion"> |
|||
<button class="btn btn-success btn-block" (click)="createDraft()"> |
|||
{{ 'contents.draftNew' | sqxTranslate }} |
|||
</button> |
|||
</ng-container> |
|||
|
|||
<ng-template #newVersion> |
|||
<label>{{ 'contents.draftStatus' | sqxTranslate }}</label> |
|||
|
|||
<button type="button" class="btn btn-outline-secondary btn-block btn-status" (click)="dropdownNew.toggle()" #buttonOptions sqxTourStep="status"> |
|||
<sqx-content-status |
|||
layout="multiline" |
|||
[status]="content.newStatus!" |
|||
[statusColor]="content.newStatusColor!" |
|||
[scheduled]="content.scheduleJob"> |
|||
</sqx-content-status> |
|||
</button> |
|||
|
|||
<sqx-dropdown-menu *sqxModal="dropdownNew;closeAlways:true" [sqxAnchoredTo]="buttonOptions" scrollY="true"> |
|||
<ng-container *ngIf="content.statusUpdates.length > 0"> |
|||
<a class="dropdown-item" *ngFor="let info of content.statusUpdates" (click)="changeStatus(info.status)"> |
|||
{{ 'common.statusChangeTo' | sqxTranslate }} <i class="icon-circle icon-sm" [style.color]="info.color"></i> {{info.status}} |
|||
@if (content.canDraftCreate || content.canDraftDelete) { |
|||
<div class="section mb-4"> |
|||
@if (!content.newStatus) { |
|||
<button class="btn btn-success btn-block" (click)="createDraft()"> |
|||
{{ "contents.draftNew" | sqxTranslate }} |
|||
</button> |
|||
} @else { |
|||
<label>{{ "contents.draftStatus" | sqxTranslate }}</label> |
|||
<button |
|||
class="btn btn-outline-secondary btn-block btn-status" |
|||
#buttonOptions |
|||
(click)="dropdownNew.toggle()" |
|||
sqxTourStep="status" |
|||
type="button"> |
|||
<sqx-content-status |
|||
layout="multiline" |
|||
[scheduled]="content.scheduleJob" |
|||
[status]="content.newStatus!" |
|||
[statusColor]="content.newStatusColor!"></sqx-content-status> |
|||
</button> |
|||
<sqx-dropdown-menu scrollY="true" [sqxAnchoredTo]="buttonOptions" *sqxModal="dropdownNew; closeAlways: true"> |
|||
@if (content.statusUpdates.length > 0) { |
|||
@for (info of content.statusUpdates; track info) { |
|||
<a class="dropdown-item" (click)="changeStatus(info.status)"> |
|||
{{ "common.statusChangeTo" | sqxTranslate }} |
|||
<i class="icon-circle icon-sm" [style.color]="info.color"></i> |
|||
{{ info.status }} |
|||
</a> |
|||
} |
|||
<div class="dropdown-divider"></div> |
|||
} |
|||
<a |
|||
class="dropdown-item dropdown-item-delete" |
|||
[class.disabled]="!content.canDraftDelete" |
|||
confirmRememberKey="deleteDraft" |
|||
confirmText="i18n:contents.deleteVersionConfirmText" |
|||
confirmTitle="i18n:contents.deleteConfirmTitle" |
|||
(sqxConfirmClick)="deleteDraft()"> |
|||
{{ "contents.versionDelete" | sqxTranslate }} |
|||
</a> |
|||
|
|||
<div class="dropdown-divider"></div> |
|||
</ng-container> |
|||
|
|||
<a class="dropdown-item dropdown-item-delete" [class.disabled]="!content.canDraftDelete" |
|||
(sqxConfirmClick)="deleteDraft()" |
|||
confirmTitle="i18n:contents.deleteConfirmTitle" |
|||
confirmText="i18n:contents.deleteVersionConfirmText" |
|||
confirmRememberKey="deleteDraft"> |
|||
{{ 'contents.versionDelete' | sqxTranslate }} |
|||
</a> |
|||
|
|||
<div class="dropdown-divider"></div> |
|||
|
|||
<a class="dropdown-item dropdown-item-delete" [class.disabled]="!content.canDelete" |
|||
(sqxConfirmClick)="delete()" |
|||
confirmTitle="i18n:contents.deleteConfirmTitle" |
|||
confirmText="i18n:contents.deleteConfirmText" |
|||
confirmRememberKey="deleteContent"> |
|||
{{ 'common.delete' | sqxTranslate }} |
|||
</a> |
|||
</sqx-dropdown-menu> |
|||
</ng-template> |
|||
</div> |
|||
<a |
|||
class="dropdown-item dropdown-item-delete" |
|||
[class.disabled]="!content.canDelete" |
|||
confirmRememberKey="deleteContent" |
|||
confirmText="i18n:contents.deleteConfirmText" |
|||
confirmTitle="i18n:contents.deleteConfirmTitle" |
|||
(sqxConfirmClick)="delete()"> |
|||
{{ "common.delete" | sqxTranslate }} |
|||
</a> |
|||
</sqx-dropdown-menu> |
|||
} |
|||
</div> |
|||
} |
|||
|
|||
<div class="section"> |
|||
<label>{{ 'contents.currentStatusLabel' | sqxTranslate }}</label> |
|||
|
|||
<div *ngIf="!content.newStatus; else newStatusOld"> |
|||
<button type="button" class="btn btn-outline-secondary btn-block btn-status" (click)="dropdown.toggle()" #buttonOptions sqxTourStep="status"> |
|||
<label>{{ "contents.currentStatusLabel" | sqxTranslate }}</label> |
|||
|
|||
@if (!content.newStatus) { |
|||
<div> |
|||
<button |
|||
class="btn btn-outline-secondary btn-block btn-status" |
|||
#buttonOptions |
|||
(click)="dropdown.toggle()" |
|||
sqxTourStep="status" |
|||
type="button"> |
|||
<sqx-content-status |
|||
layout="multiline" |
|||
[scheduled]="content.scheduleJob" |
|||
small="true" |
|||
[status]="content.status" |
|||
[statusColor]="content.statusColor"></sqx-content-status> |
|||
</button> |
|||
<sqx-dropdown-menu scrollY="true" [sqxAnchoredTo]="buttonOptions" *sqxModal="dropdown; closeAlways: true"> |
|||
@if (content.statusUpdates.length > 0) { |
|||
@for (info of content.statusUpdates; track info) { |
|||
<a class="dropdown-item" (click)="changeStatus(info.status)"> |
|||
{{ "common.statusChangeTo" | sqxTranslate }} |
|||
<sqx-content-status |
|||
layout="text" |
|||
small="true" |
|||
[status]="info.status" |
|||
[statusColor]="info.color"></sqx-content-status> |
|||
</a> |
|||
} |
|||
<div class="dropdown-divider"></div> |
|||
} |
|||
<a |
|||
class="dropdown-item dropdown-item-delete" |
|||
[class.disabled]="!content.canCancelStatus" |
|||
confirmRememberKey="cancelStatus" |
|||
confirmText="i18n:contents.cancelStatusConfirmText" |
|||
confirmTitle="i18n:contents.cancelStatusConfirmTitle" |
|||
(sqxConfirmClick)="cancelStatus()"> |
|||
{{ "contents.cancelStatus" | sqxTranslate }} |
|||
</a> |
|||
<div class="dropdown-divider"></div> |
|||
<a |
|||
class="dropdown-item dropdown-item-delete" |
|||
[class.disabled]="!content.canDelete" |
|||
confirmRememberKey="deleteContent" |
|||
confirmText="i18n:contents.deleteConfirmText" |
|||
confirmTitle="i18n:contents.deleteConfirmTitle" |
|||
(sqxConfirmClick)="delete()"> |
|||
{{ "common.delete" | sqxTranslate }} |
|||
</a> |
|||
</sqx-dropdown-menu> |
|||
</div> |
|||
} @else { |
|||
<button class="btn btn-outline-secondary btn-block btn-status" type="button"> |
|||
<sqx-content-status |
|||
layout="multiline" |
|||
[status]="content.status" |
|||
[statusColor]="content.statusColor" |
|||
[scheduled]="content.scheduleJob" |
|||
small="true"> |
|||
</sqx-content-status> |
|||
</button> |
|||
|
|||
<sqx-dropdown-menu *sqxModal="dropdown;closeAlways:true" [sqxAnchoredTo]="buttonOptions" scrollY="true"> |
|||
<ng-container *ngIf="content.statusUpdates.length > 0"> |
|||
<a class="dropdown-item" *ngFor="let info of content.statusUpdates" (click)="changeStatus(info.status)"> |
|||
{{ 'common.statusChangeTo' | sqxTranslate }} |
|||
|
|||
<sqx-content-status |
|||
layout="text" |
|||
[status]="info.status" |
|||
[statusColor]="info.color" |
|||
small="true"> |
|||
</sqx-content-status> |
|||
</a> |
|||
|
|||
<div class="dropdown-divider"></div> |
|||
</ng-container> |
|||
|
|||
<a class="dropdown-item dropdown-item-delete" [class.disabled]="!content.canCancelStatus" |
|||
(sqxConfirmClick)="cancelStatus()" |
|||
confirmTitle="i18n:contents.cancelStatusConfirmTitle" |
|||
confirmText="i18n:contents.cancelStatusConfirmText" |
|||
confirmRememberKey="cancelStatus"> |
|||
{{ 'contents.cancelStatus' | sqxTranslate }} |
|||
</a> |
|||
|
|||
<div class="dropdown-divider"></div> |
|||
|
|||
<a class="dropdown-item dropdown-item-delete" [class.disabled]="!content.canDelete" |
|||
(sqxConfirmClick)="delete()" |
|||
confirmTitle="i18n:contents.deleteConfirmTitle" |
|||
confirmText="i18n:contents.deleteConfirmText" |
|||
confirmRememberKey="deleteContent"> |
|||
{{ 'common.delete' | sqxTranslate }} |
|||
</a> |
|||
</sqx-dropdown-menu> |
|||
</div> |
|||
|
|||
<ng-template #newStatusOld> |
|||
<button type="button" class="btn btn-outline-secondary btn-block btn-status"> |
|||
<sqx-content-status [status]="content.status" [statusColor]="content.statusColor" layout="multiline"></sqx-content-status> |
|||
[statusColor]="content.statusColor"></sqx-content-status> |
|||
</button> |
|||
</ng-template> |
|||
} |
|||
|
|||
<sqx-form-hint marginTop="1"> |
|||
{{ 'contents.lastUpdatedLabel' | sqxTranslate }}: {{content.lastModified | sqxFromNow}} |
|||
{{ "contents.lastUpdatedLabel" | sqxTranslate }}: {{ content.lastModified | sqxFromNow }} |
|||
</sqx-form-hint> |
|||
</div> |
|||
|
|||
<div class="section"> |
|||
<h3 class="bordered">{{ 'common.history' | sqxTranslate }}</h3> |
|||
|
|||
<sqx-content-event *ngFor="let event of contentEvents | async; trackBy: trackByEvent" |
|||
[content]="content" |
|||
[event]="event" |
|||
(dataLoad)="loadVersion(event)" |
|||
(dataCompare)="compareVersion(event)"> |
|||
</sqx-content-event> |
|||
<h3 class="bordered">{{ "common.history" | sqxTranslate }}</h3> |
|||
|
|||
@for (event of contentEvents | async; track event.eventId) { |
|||
<sqx-content-event |
|||
[content]="content" |
|||
(dataCompare)="compareVersion(event)" |
|||
(dataLoad)="loadVersion(event)" |
|||
[event]="event"></sqx-content-event> |
|||
} |
|||
</div> |
|||
</ng-container> |
|||
</sqx-layout> |
|||
|
|||
<sqx-due-time-selector [disabled]="disableScheduler" #dueTimeSelector></sqx-due-time-selector> |
|||
<sqx-due-time-selector #dueTimeSelector [disabled]="disableScheduler"></sqx-due-time-selector> |
|||
|
|||
@ -1,47 +1,60 @@ |
|||
<sqx-form-error bubble="true" closeable="true" [error]="(contentForm.error | async)"></sqx-form-error> |
|||
<sqx-form-error bubble="true" closeable="true" [error]="contentForm.error | async"></sqx-form-error> |
|||
|
|||
<sqx-list-view noPadding="true"> |
|||
<ng-container topHeader> |
|||
<div class="alert alert-danger" *ngIf="!contentVersion && isDeleted"> |
|||
{{ 'contents.deleted' | sqxTranslate }} |
|||
</div> |
|||
|
|||
<div class="alert alert-danger" *ngIf="contentVersion"> |
|||
<div class="float-end"> |
|||
<a (click)="loadLatest.emit()">{{ 'contents.viewLatest' | sqxTranslate }}</a> |
|||
<ng-container topHeader> |
|||
@if (!contentVersion && isDeleted) { |
|||
<div class="alert alert-danger"> |
|||
{{ "contents.deleted" | sqxTranslate }} |
|||
</div> |
|||
} |
|||
|
|||
<div *ngIf="isDeleted" |
|||
[innerHTML]="'contents.versionViewingDeleted' | sqxTranslate: { version: contentVersion } | sqxMarkdownInline | sqxSafeHtml"> |
|||
@if (contentVersion) { |
|||
<div class="alert alert-danger"> |
|||
<div class="float-end"> |
|||
<a (click)="loadLatest.emit()">{{ "contents.viewLatest" | sqxTranslate }}</a> |
|||
</div> |
|||
@if (isDeleted) { |
|||
<div |
|||
[innerHTML]=" |
|||
'contents.versionViewingDeleted' | sqxTranslate: { version: contentVersion } | sqxMarkdownInline | sqxSafeHtml |
|||
"></div> |
|||
} |
|||
@if (!isDeleted) { |
|||
<div |
|||
[innerHTML]=" |
|||
'contents.versionViewing' | sqxTranslate: { version: contentVersion } | sqxMarkdownInline | sqxSafeHtml |
|||
"></div> |
|||
} |
|||
</div> |
|||
|
|||
<div *ngIf="!isDeleted" |
|||
[innerHTML]="'contents.versionViewing' | sqxTranslate: { version: contentVersion } | sqxMarkdownInline | sqxSafeHtml"> |
|||
} |
|||
|
|||
@if (isNew && showIdInput) { |
|||
<div> |
|||
<input |
|||
class="form-control" |
|||
[ngModel]="contentId" |
|||
(ngModelChange)="contentIdChange.emit($event)" |
|||
placeholder="{{ 'contents.idPlaceholder' | sqxTranslate }}" /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div *ngIf="isNew && showIdInput"> |
|||
<input class="form-control" placeholder="{{ 'contents.idPlaceholder' | sqxTranslate }}" |
|||
[ngModel]="contentId" |
|||
(ngModelChange)="contentIdChange.emit($event)" /> |
|||
</div> |
|||
} |
|||
</ng-container> |
|||
|
|||
<ng-container> |
|||
<div class="cursors" sqxCursors> |
|||
<sqx-cursors></sqx-cursors> |
|||
|
|||
<sqx-content-section *ngFor="let section of contentForm.sections; trackBy: trackBySection" |
|||
[form]="contentForm" |
|||
[formCompare]="contentFormCompare" |
|||
[formContext]="formContext" |
|||
[formLevel]="0" |
|||
[formSection]="section" |
|||
[language]="language" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[languages]="languages" |
|||
[schema]="schema"> |
|||
</sqx-content-section> |
|||
@for (section of contentForm.sections; track section.separator?.fieldId) { |
|||
<sqx-content-section |
|||
[form]="contentForm" |
|||
[formCompare]="contentFormCompare" |
|||
[formContext]="formContext" |
|||
[formLevel]="0" |
|||
[formSection]="section" |
|||
[language]="language" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[languages]="languages" |
|||
[schema]="schema"></sqx-content-section> |
|||
} |
|||
</div> |
|||
</ng-container> |
|||
</sqx-list-view> |
|||
</sqx-list-view> |
|||
|
|||
@ -1,30 +1,27 @@ |
|||
<sqx-form-error bubble="true" closeable="true" [error]="contentError"></sqx-form-error> |
|||
|
|||
<div class="inner-menu"> |
|||
<ul class="nav nav-tabs2" *ngIf="mode | async; let currentMode"> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" [class.active]="currentMode === 'Content'" (click)="setMode('Content')"> |
|||
{{ 'contents.inspectContent' | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" [class.active]="currentMode === 'Data'" (click)="setMode('Data')"> |
|||
{{ 'contents.inspectData' | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" [class.active]="currentMode === 'FlatData'" (click)="setMode('FlatData')"> |
|||
{{ 'contents.inspectFlatData' | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
</ul> |
|||
@if (mode | async; as currentMode) { |
|||
<ul class="nav nav-tabs2"> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" [class.active]="currentMode === 'Content'" (click)="setMode('Content')"> |
|||
{{ "contents.inspectContent" | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" [class.active]="currentMode === 'Data'" (click)="setMode('Data')"> |
|||
{{ "contents.inspectData" | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" [class.active]="currentMode === 'FlatData'" (click)="setMode('FlatData')"> |
|||
{{ "contents.inspectFlatData" | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
</ul> |
|||
} |
|||
</div> |
|||
|
|||
<div class="inner-main"> |
|||
<sqx-code-editor |
|||
borderless="true" |
|||
[ngModel]="actualData | async" |
|||
(ngModelChange)="setData($event)" |
|||
valueMode="Json"> |
|||
</sqx-code-editor> |
|||
<sqx-code-editor borderless="true" [ngModel]="actualData | async" (ngModelChange)="setData($event)" valueMode="Json"></sqx-code-editor> |
|||
</div> |
|||
|
|||
@ -1,32 +1,40 @@ |
|||
<sqx-list-view [isLoading]="contentsState.isLoading | async" table="true"> |
|||
<ng-container> |
|||
<table class="table table-items table-fixed" *ngIf="contentsState.contents | async; let contents"> |
|||
<tbody *ngFor="let content of contents; trackBy: trackByContent" |
|||
[sqxReferenceItem]="content" |
|||
[canRemove]="false" |
|||
[columns]="contents | sqxContentsColumns" |
|||
[isCompact]="false" |
|||
[isDisabled]="false" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[validations]="(contentsState.validationResults | async)!" |
|||
[validityVisible]="true"> |
|||
</tbody> |
|||
|
|||
<tbody *ngIf="(contentsState.isLoaded | async) && contents.length === 0"> |
|||
<tr> |
|||
<td class="table-items-row-empty" *ngIf="mode === 'references'"> |
|||
{{ 'contents.noReferences' | sqxTranslate }} |
|||
</td> |
|||
<td class="table-items-row-empty" *ngIf="mode === 'referencing'"> |
|||
{{ 'contents.noReferencing' | sqxTranslate }} |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
@if (contentsState.contents | async; as contents) { |
|||
<table class="table table-items table-fixed"> |
|||
@for (content of contents; track content.id) { |
|||
<tbody |
|||
[canRemove]="false" |
|||
[columns]="contents | sqxContentsColumns" |
|||
[isCompact]="false" |
|||
[isDisabled]="false" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[sqxReferenceItem]="content" |
|||
[validations]="(contentsState.validationResults | async)!" |
|||
[validityVisible]="true"></tbody> |
|||
} |
|||
@if ((contentsState.isLoaded | async) && contents.length === 0) { |
|||
<tbody> |
|||
<tr> |
|||
@if (mode === "references") { |
|||
<td class="table-items-row-empty"> |
|||
{{ "contents.noReferences" | sqxTranslate }} |
|||
</td> |
|||
} |
|||
@if (mode === "referencing") { |
|||
<td class="table-items-row-empty"> |
|||
{{ "contents.noReferencing" | sqxTranslate }} |
|||
</td> |
|||
} |
|||
</tr> |
|||
</tbody> |
|||
} |
|||
</table> |
|||
} |
|||
</ng-container> |
|||
|
|||
<ng-container footer> |
|||
<sqx-pager [paging]="contentsState.paging | async" (pagingChange)="contentsState.page($event)"></sqx-pager> |
|||
</ng-container> |
|||
</sqx-list-view> |
|||
</sqx-list-view> |
|||
|
|||
@ -1,10 +1,16 @@ |
|||
<sqx-layout layout="main" titleText="i18n:common.contents" titleIcon="contents" hideHeader="true" hideSidebar="true" white="true" overflow="true"> |
|||
<ng-container *ngIf="schema | async; let schema"> |
|||
<sqx-content-extension |
|||
[editorUrl]="schema.properties.contentsListUrl" |
|||
<sqx-layout |
|||
hideHeader="true" |
|||
hideSidebar="true" |
|||
layout="main" |
|||
overflow="true" |
|||
titleIcon="contents" |
|||
titleText="i18n:common.contents" |
|||
white="true"> |
|||
@if (schema | async; as schema) { |
|||
<sqx-content-extension |
|||
[contentItem]="undefined" |
|||
[contentSchema]="schema" |
|||
scrollable="true"> |
|||
</sqx-content-extension> |
|||
</ng-container> |
|||
</sqx-layout> |
|||
[editorUrl]="schema.properties.contentsListUrl" |
|||
scrollable="true"></sqx-content-extension> |
|||
} |
|||
</sqx-layout> |
|||
|
|||
@ -1,32 +1,24 @@ |
|||
<sqx-layout layout="right" titleText="i18n:common.filters" width="20" white="true" padding="true" overflow="true"> |
|||
<ng-container *ngIf="schemaQueries | async; let queries"> |
|||
<sqx-layout layout="right" overflow="true" padding="true" titleText="i18n:common.filters" white="true" width="20"> |
|||
@if (schemaQueries | async; as queries) { |
|||
<sqx-query-list |
|||
[types]="'common.contents' | sqxTranslate" |
|||
[queryUsed]="contentsState.query | async" |
|||
[queries]="queries.defaultQueries" |
|||
(search)="search($event)"> |
|||
</sqx-query-list> |
|||
|
|||
<hr> |
|||
|
|||
[queryUsed]="contentsState.query | async" |
|||
(search)="search($event)" |
|||
[types]="'common.contents' | sqxTranslate"></sqx-query-list> |
|||
<hr /> |
|||
<div class="sidebar-section"> |
|||
<h3>{{ 'contents.statusQueries' | sqxTranslate }}</h3> |
|||
|
|||
<h3>{{ "contents.statusQueries" | sqxTranslate }}</h3> |
|||
<sqx-query-list |
|||
[types]="'common.contents' | sqxTranslate" |
|||
[queryUsed]="contentsState.query | async" |
|||
[queries]="contentsState.statusQueries | async" |
|||
(search)="search($event)"> |
|||
</sqx-query-list> |
|||
[queryUsed]="contentsState.query | async" |
|||
(search)="search($event)" |
|||
[types]="'common.contents' | sqxTranslate"></sqx-query-list> |
|||
</div> |
|||
|
|||
<hr> |
|||
|
|||
<hr /> |
|||
<sqx-shared-queries |
|||
[types]="'common.contents' | sqxTranslate" |
|||
[queryUsed]="contentsState.query | async" |
|||
[queries]="queries" |
|||
(search)="search($event)"> |
|||
</sqx-shared-queries> |
|||
</ng-container> |
|||
</sqx-layout> |
|||
[queryUsed]="contentsState.query | async" |
|||
(search)="search($event)" |
|||
[types]="'common.contents' | sqxTranslate"></sqx-shared-queries> |
|||
} |
|||
</sqx-layout> |
|||
|
|||
@ -1,177 +1,211 @@ |
|||
<sqx-title [message]="schema.displayName"></sqx-title> |
|||
|
|||
<sqx-layout layout="main" titleText="i18n:common.contents" titleIcon="contents"> |
|||
<sqx-layout layout="main" titleIcon="contents" titleText="i18n:common.contents"> |
|||
<ng-container menu> |
|||
<div class="row flex-nowrap flex-grow-1 gx-2"> |
|||
<div class="col-auto ms-8"> |
|||
<sqx-notifo topic="apps/{{contentsState.appId}}/schemas/{{schema.id}}/contents" position="bottom-left"></sqx-notifo> |
|||
<sqx-notifo position="bottom-left" topic="apps/{{ contentsState.appId }}/schemas/{{ schema.id }}/contents"></sqx-notifo> |
|||
|
|||
<button type="button" class="btn btn-text-secondary" (click)="reload()" title="i18n:contents.refreshTooltip" shortcut="CTRL + B"> |
|||
<i class="icon-reset"></i> {{ 'common.refresh' | sqxTranslate }} |
|||
<button |
|||
class="btn btn-text-secondary" |
|||
(click)="reload()" |
|||
shortcut="CTRL + B" |
|||
title="i18n:contents.refreshTooltip" |
|||
type="button"> |
|||
<i class="icon-reset"></i> |
|||
{{ "common.refresh" | sqxTranslate }} |
|||
</button> |
|||
</div> |
|||
<div class="col"> |
|||
<sqx-search-form formClass="form" placeholder="{{ 'contents.searchPlaceholder' | sqxTranslate }}" |
|||
<sqx-search-form |
|||
enableShortcut="true" |
|||
formClass="form" |
|||
[language]="(languagesState.isoMasterLanguage | async)!" |
|||
[languages]="languages" |
|||
placeholder="{{ 'contents.searchPlaceholder' | sqxTranslate }}" |
|||
[queries]="queries | async" |
|||
[queriesTypes]="'common.contents' | sqxTranslate" |
|||
(queryChange)="search($event)" |
|||
[query]="contentsState.query | async" |
|||
(queryChange)="search($event)" |
|||
[queryModel]="queryModel | async" |
|||
[statuses]="contentsState.statuses | async"> |
|||
</sqx-search-form> |
|||
</div> |
|||
<div class="col-auto" *ngIf="languages.length > 1"> |
|||
<sqx-language-selector class="languages-buttons" |
|||
(languageChange)="changeLanguage($event)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[percents]="translationStatus"> |
|||
</sqx-language-selector> |
|||
[statuses]="contentsState.statuses | async"></sqx-search-form> |
|||
</div> |
|||
@if (languages.length > 1) { |
|||
<div class="col-auto"> |
|||
<sqx-language-selector |
|||
class="languages-buttons" |
|||
[language]="language" |
|||
(languageChange)="changeLanguage($event)" |
|||
[languages]="languages" |
|||
[percents]="translationStatus"></sqx-language-selector> |
|||
</div> |
|||
} |
|||
<div class="col-auto"> |
|||
<button type="button" class="btn btn-success" routerLink="new" title="i18n:contents.createContentTooltip" shortcut="CTRL + U" [disabled]="(contentsState.canCreateAny | async) === false" sqxTourStep="addContent"> |
|||
<i class="icon-plus"></i> {{ 'contents.create' | sqxTranslate }} |
|||
<button |
|||
class="btn btn-success" |
|||
[disabled]="(contentsState.canCreateAny | async) === false" |
|||
routerLink="new" |
|||
shortcut="CTRL + U" |
|||
sqxTourStep="addContent" |
|||
title="i18n:contents.createContentTooltip" |
|||
type="button"> |
|||
<i class="icon-plus"></i> |
|||
{{ "contents.create" | sqxTranslate }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container> |
|||
<ng-container *ngIf="tableSettings | async; let tableSettings"> |
|||
<ng-container *ngIf="tableSettings.listFields | async; let tableFields"> |
|||
@if (tableSettings | async; as tableSettings) { |
|||
@if (tableSettings.listFields | async; as tableFields) { |
|||
<sqx-list-view [isLoading]="contentsState.isLoading | async" syncedHeader="true" tableNoPadding="true"> |
|||
<ng-container topHeader> |
|||
<div class="selection" *ngIf="selectionCount > 0"> |
|||
{{ 'contents.selectionCount' | sqxTranslate: { count: selectionCount } }} |
|||
|
|||
<button type="button" class="btn btn-outline-secondary btn-status me-2" *ngFor="let status of selectionStatuses | sqxKeys" (click)="changeSelectedStatus(status)"> |
|||
<sqx-content-status layout="text" |
|||
[status]="status" |
|||
[statusColor]="selectionStatuses[status]"> |
|||
</sqx-content-status> |
|||
</button> |
|||
|
|||
<button type="button" class="btn btn-danger" *ngIf="selectionCanDelete" |
|||
(sqxConfirmClick)="deleteSelected()" |
|||
confirmTitle="i18n:contents.deleteConfirmTitle" |
|||
confirmText="i18n:contents.deleteManyConfirmText" |
|||
confirmRememberKey="deleteContents"> |
|||
{{ 'common.delete' | sqxTranslate }} |
|||
</button> |
|||
</div> |
|||
|
|||
@if (selectionCount > 0) { |
|||
<div class="selection"> |
|||
{{ "contents.selectionCount" | sqxTranslate: { count: selectionCount } }} |
|||
@for (status of selectionStatuses | sqxKeys; track status) { |
|||
<button |
|||
class="btn btn-outline-secondary btn-status me-2" |
|||
(click)="changeSelectedStatus(status)" |
|||
type="button"> |
|||
<sqx-content-status |
|||
layout="text" |
|||
[status]="status" |
|||
[statusColor]="selectionStatuses[status]"></sqx-content-status> |
|||
</button> |
|||
} |
|||
@if (selectionCanDelete) { |
|||
<button |
|||
class="btn btn-danger" |
|||
confirmRememberKey="deleteContents" |
|||
confirmText="i18n:contents.deleteManyConfirmText" |
|||
confirmTitle="i18n:contents.deleteConfirmTitle" |
|||
(sqxConfirmClick)="deleteSelected()" |
|||
type="button"> |
|||
{{ "common.delete" | sqxTranslate }} |
|||
</button> |
|||
} |
|||
</div> |
|||
} |
|||
<div class="settings-container"> |
|||
<button type="button" class="btn btn-sm settings-button" (click)="tableViewModal.toggle()" #buttonSettings> |
|||
<span class="hidden">{{ 'common.settings' | sqxTranslate }}</span> |
|||
<button class="btn btn-sm settings-button" #buttonSettings (click)="tableViewModal.toggle()" type="button"> |
|||
<span class="hidden">{{ "common.settings" | sqxTranslate }}</span> |
|||
<i class="icon-settings"></i> |
|||
</button> |
|||
|
|||
<sqx-dropdown-menu *sqxModal="tableViewModal" [sqxAnchoredTo]="buttonSettings" scrollY="true" position="bottom-end"> |
|||
<sqx-dropdown-menu |
|||
position="bottom-end" |
|||
scrollY="true" |
|||
[sqxAnchoredTo]="buttonSettings" |
|||
*sqxModal="tableViewModal"> |
|||
<sqx-custom-view-editor |
|||
[allFields]="tableSettings.schemaFields" |
|||
[allFields]="tableSettings.schemaFields" |
|||
[listFields]="$any(tableFields)" |
|||
(listFieldsChange)="tableSettings.updateFields($event)" |
|||
(listFieldsReset)="tableSettings.reset()" |
|||
[listFields]="$any(tableFields)"> |
|||
</sqx-custom-view-editor> |
|||
(listFieldsReset)="tableSettings.reset()"></sqx-custom-view-editor> |
|||
</sqx-dropdown-menu> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container header> |
|||
<table class="table table-items table-fixed" [sqxContentListWidth]="tableFields" [fields]="tableSettings" #header> |
|||
<table class="table table-items table-fixed" #header [fields]="tableSettings" [sqxContentListWidth]="tableFields"> |
|||
<thead> |
|||
<tr> |
|||
<th class="cell-select"> |
|||
<div class="form-check"> |
|||
<input class="form-check-input" type="checkbox" id="all_selected" |
|||
[ngModel]="selectedAll" |
|||
(ngModelChange)="selectAll($event)"> |
|||
|
|||
<input |
|||
class="form-check-input" |
|||
id="all_selected" |
|||
[ngModel]="selectedAll" |
|||
(ngModelChange)="selectAll($event)" |
|||
type="checkbox" /> |
|||
<label class="form-check-label" for="all_selected"></label> |
|||
</div> |
|||
</th> |
|||
<th class="cell-actions cell-actions-left"> |
|||
<span class="truncate">{{ 'common.actions' | sqxTranslate }}</span> |
|||
</th> |
|||
<th *ngFor="let field of tableFields" |
|||
sqxContentListCell |
|||
sqxContentListCellResize |
|||
[field]="field" |
|||
[fields]="tableSettings"> |
|||
<sqx-content-list-header |
|||
[field]="field" |
|||
(queryChange)="search($event)" |
|||
[query]="(contentsState.query | async)!" |
|||
[language]="language"> |
|||
</sqx-content-list-header> |
|||
<span class="truncate">{{ "common.actions" | sqxTranslate }}</span> |
|||
</th> |
|||
@for (field of tableFields; track field) { |
|||
<th [field]="field" [fields]="tableSettings" sqxContentListCell sqxContentListCellResize> |
|||
<sqx-content-list-header |
|||
[field]="field" |
|||
[language]="language" |
|||
[query]="(contentsState.query | async)!" |
|||
(queryChange)="search($event)"></sqx-content-list-header> |
|||
</th> |
|||
} |
|||
<th></th> |
|||
</tr> |
|||
</thead> |
|||
</table> |
|||
</ng-container> |
|||
|
|||
<ng-container> |
|||
<div class="table-container"> |
|||
<table class="table table-center table-fixed" [sqxContentListWidth]="tableFields" [fields]="tableSettings" [sqxSyncWidth]="header"> |
|||
<tbody *ngFor="let content of contentsState.contents | async; trackBy: trackByContent" |
|||
[sqxContent]="content" |
|||
(clone)="clone(content)" |
|||
[cloneable]="contentsState.snapshot.canCreate" |
|||
(delete)="delete(content)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[link]="[content.id, 'history']" |
|||
[schema]="schema" |
|||
[selected]="isItemSelected(content)" |
|||
(selectedChange)="selectItem(content, $event)" |
|||
(statusChange)="changeStatus(content, $event)" |
|||
[tableFields]="tableFields" |
|||
[tableSettings]="tableSettings"> |
|||
</tbody> |
|||
<table |
|||
class="table table-center table-fixed" |
|||
[fields]="tableSettings" |
|||
[sqxContentListWidth]="tableFields" |
|||
[sqxSyncWidth]="header"> |
|||
@for (content of contentsState.contents | async; track content.id) { |
|||
<tbody |
|||
(clone)="clone(content)" |
|||
[cloneable]="contentsState.snapshot.canCreate" |
|||
(delete)="delete(content)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[link]="[content.id, 'history']" |
|||
[schema]="schema" |
|||
[selected]="isItemSelected(content)" |
|||
(selectedChange)="selectItem(content, $event)" |
|||
[sqxContent]="content" |
|||
(statusChange)="changeStatus(content, $event)" |
|||
[tableFields]="tableFields" |
|||
[tableSettings]="tableSettings"></tbody> |
|||
} |
|||
</table> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container footer> |
|||
<sqx-pager (loadTotal)="reloadTotal()" [paging]="contentsState.paging | async" (pagingChange)="contentsState.page($event)"></sqx-pager> |
|||
<sqx-pager |
|||
(loadTotal)="reloadTotal()" |
|||
[paging]="contentsState.paging | async" |
|||
(pagingChange)="contentsState.page($event)"></sqx-pager> |
|||
</ng-container> |
|||
</sqx-list-view> |
|||
</ng-container> |
|||
</ng-container> |
|||
} |
|||
} |
|||
</ng-container> |
|||
|
|||
<ng-template sidebarMenu> |
|||
<div class="panel-nav"> |
|||
<a class="panel-link" |
|||
<a |
|||
class="panel-link" |
|||
queryParamsHandling="preserve" |
|||
replaceUrl="true" |
|||
routerLink="filters" |
|||
routerLinkActive="active" |
|||
queryParamsHandling="preserve" |
|||
sqxTourStep="filters" |
|||
title="i18n:common.filters" |
|||
titlePosition="left" |
|||
sqxTourStep="filters"> |
|||
titlePosition="left"> |
|||
<i class="icon-filter"></i> |
|||
</a> |
|||
|
|||
<a class="panel-link" |
|||
replaceUrl="true" |
|||
routerLink="sidebar" |
|||
routerLinkActive="active" |
|||
queryParamsHandling="preserve" |
|||
title="i18n:common.sidebar" |
|||
titlePosition="left" |
|||
sqxTourStep="plugin" |
|||
*ngIf="schema.properties.contentsSidebarUrl"> |
|||
<i class="icon-plugin"></i> |
|||
</a> |
|||
@if (schema.properties.contentsSidebarUrl) { |
|||
<a |
|||
class="panel-link" |
|||
queryParamsHandling="preserve" |
|||
replaceUrl="true" |
|||
routerLink="sidebar" |
|||
routerLinkActive="active" |
|||
sqxTourStep="plugin" |
|||
title="i18n:common.sidebar" |
|||
titlePosition="left"> |
|||
<i class="icon-plugin"></i> |
|||
</a> |
|||
} |
|||
</div> |
|||
</ng-template> |
|||
</sqx-layout> |
|||
|
|||
<router-outlet></router-outlet> |
|||
|
|||
<sqx-due-time-selector [disabled]="disableScheduler" #dueTimeSelector></sqx-due-time-selector> |
|||
<sqx-due-time-selector #dueTimeSelector [disabled]="disableScheduler"></sqx-due-time-selector> |
|||
|
|||
@ -1,52 +1,62 @@ |
|||
<div class="container"> |
|||
<div class="header"> |
|||
<button type="button" class="btn btn-secondary btn-sm" (click)="resetDefault()"> |
|||
{{ 'contents.viewReset' | sqxTranslate }} |
|||
<button class="btn btn-secondary btn-sm" (click)="resetDefault()" type="button"> |
|||
{{ "contents.viewReset" | sqxTranslate }} |
|||
</button> |
|||
</div> |
|||
|
|||
<hr> |
|||
|
|||
<div |
|||
cdkDropList |
|||
[cdkDropListData]="listFields" |
|||
(cdkDropListDropped)="drop($event)"> |
|||
<div *ngFor="let field of listFields" cdkDrag> |
|||
<i class="icon-drag2 drag-handle"></i> |
|||
|
|||
<div class="form-check"> |
|||
<input class="form-check-input" type="checkbox" checked (click)="removeField(field)" id="field_{{field}}" [disabled]="!field"> |
|||
<label class="form-check-label" for="field_{{field}}"> |
|||
<span *ngIf="field.name"> |
|||
{{(field.title || field.label) | sqxTranslate}}: <code>{{field.name}}</code> |
|||
</span> |
|||
<span class="text-muted" *ngIf="!field.name"> |
|||
- Placeholder - |
|||
</span> |
|||
</label> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<ng-container *ngIf="fieldsNotAdded.length > 0"> |
|||
<hr> |
|||
|
|||
<div > |
|||
<div *ngFor="let field of fieldsNotAdded"> |
|||
<i class="icon-drag2 drag-handle invisible"></i> |
|||
|
|||
<hr /> |
|||
|
|||
<div cdkDropList [cdkDropListData]="listFields" (cdkDropListDropped)="drop($event)"> |
|||
@for (field of listFields; track field) { |
|||
<div cdkDrag> |
|||
<i class="icon-drag2 drag-handle"></i> |
|||
<div class="form-check"> |
|||
<input class="form-check-input" type="checkbox" (click)="addField(field)" id="field_{{field}}"> |
|||
<label class="form-check-label" for="field_{{field}}"> |
|||
<span *ngIf="field.name"> |
|||
{{(field.title || field.label) | sqxTranslate}}: <code>{{field.name}}</code> |
|||
</span> |
|||
<span class="text-muted" *ngIf="!field.name"> |
|||
- Placeholder - |
|||
</span> |
|||
<input |
|||
class="form-check-input" |
|||
id="field_{{ field }}" |
|||
checked |
|||
(click)="removeField(field)" |
|||
[disabled]="!field" |
|||
type="checkbox" /> |
|||
<label class="form-check-label" for="field_{{ field }}"> |
|||
@if (field.name) { |
|||
<span> |
|||
{{ field.title || field.label | sqxTranslate }}: |
|||
<code>{{ field.name }}</code> |
|||
</span> |
|||
} |
|||
@if (!field.name) { |
|||
<span class="text-muted">- Placeholder -</span> |
|||
} |
|||
</label> |
|||
</div> |
|||
</div> |
|||
} |
|||
</div> |
|||
|
|||
@if (fieldsNotAdded.length > 0) { |
|||
<hr /> |
|||
<div> |
|||
@for (field of fieldsNotAdded; track field) { |
|||
<div> |
|||
<i class="icon-drag2 drag-handle invisible"></i> |
|||
<div class="form-check"> |
|||
<input class="form-check-input" id="field_{{ field }}" (click)="addField(field)" type="checkbox" /> |
|||
<label class="form-check-label" for="field_{{ field }}"> |
|||
@if (field.name) { |
|||
<span> |
|||
{{ field.title || field.label | sqxTranslate }}: |
|||
<code>{{ field.name }}</code> |
|||
</span> |
|||
} |
|||
@if (!field.name) { |
|||
<span class="text-muted">- Placeholder -</span> |
|||
} |
|||
</label> |
|||
</div> |
|||
</div> |
|||
} |
|||
</div> |
|||
</ng-container> |
|||
</div> |
|||
} |
|||
</div> |
|||
|
|||
@ -1,52 +1,64 @@ |
|||
<sqx-title message="i18n:common.references"></sqx-title> |
|||
|
|||
<sqx-layout layout="main" titleText="i18n:common.references" titleIcon="contents"> |
|||
<sqx-layout layout="main" titleIcon="contents" titleText="i18n:common.references"> |
|||
<ng-container menu> |
|||
<div class="row flex-nowrap flex-grow-1 gx-2"> |
|||
<div class="col-auto ms-8"> |
|||
<button type="button" class="btn btn-text-secondary" (click)="reload()" title="i18n:contents.refreshTooltip" shortcut="CTRL + B"> |
|||
<i class="icon-reset"></i> {{ 'common.refresh' | sqxTranslate }} |
|||
<button |
|||
class="btn btn-text-secondary" |
|||
(click)="reload()" |
|||
shortcut="CTRL + B" |
|||
title="i18n:contents.refreshTooltip" |
|||
type="button"> |
|||
<i class="icon-reset"></i> |
|||
{{ "common.refresh" | sqxTranslate }} |
|||
</button> |
|||
</div> |
|||
<div class="col-auto" *ngIf="languages.length > 1"> |
|||
<sqx-language-selector class="languages-buttons" |
|||
(languageChange)="changeLanguage($event)" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-language-selector> |
|||
</div> |
|||
@if (languages.length > 1) { |
|||
<div class="col-auto"> |
|||
<sqx-language-selector |
|||
class="languages-buttons" |
|||
[language]="language" |
|||
(languageChange)="changeLanguage($event)" |
|||
[languages]="languages"></sqx-language-selector> |
|||
</div> |
|||
} |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container> |
|||
<sqx-list-view [isLoading]="contentsState.isLoading | async" table="true"> |
|||
<ng-container> |
|||
<table class="table table-items table-fixed" *ngIf="contentsState.contents | async; let contents"> |
|||
<tbody *ngFor="let content of contents; trackBy: trackByContent" |
|||
[sqxReferenceItem]="content" |
|||
[canRemove]="false" |
|||
[columns]="contents | sqxContentsColumns" |
|||
[isCompact]="false" |
|||
[isDisabled]="false" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[validations]="(contentsState.validationResults | async)!" |
|||
[validityVisible]="true"> |
|||
</tbody> |
|||
|
|||
<tbody *ngIf="(contentsState.isLoaded | async) && contents.length === 0"> |
|||
<tr> |
|||
<td class="table-items-row-empty"> |
|||
{{ 'contents.noReferencing' | sqxTranslate }} |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
@if (contentsState.contents | async; as contents) { |
|||
<table class="table table-items table-fixed"> |
|||
@for (content of contents; track content.id) { |
|||
<tbody |
|||
[canRemove]="false" |
|||
[columns]="contents | sqxContentsColumns" |
|||
[isCompact]="false" |
|||
[isDisabled]="false" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[sqxReferenceItem]="content" |
|||
[validations]="(contentsState.validationResults | async)!" |
|||
[validityVisible]="true"></tbody> |
|||
} |
|||
@if ((contentsState.isLoaded | async) && contents.length === 0) { |
|||
<tbody> |
|||
<tr> |
|||
<td class="table-items-row-empty"> |
|||
{{ "contents.noReferencing" | sqxTranslate }} |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
} |
|||
</table> |
|||
} |
|||
</ng-container> |
|||
|
|||
|
|||
<ng-container footer> |
|||
<sqx-pager [paging]="contentsState.paging | async" (pagingChange)="contentsState.page($event)"></sqx-pager> |
|||
</ng-container> |
|||
</sqx-list-view> |
|||
</ng-container> |
|||
</sqx-layout> |
|||
</sqx-layout> |
|||
|
|||
@ -1,30 +1,31 @@ |
|||
<sqx-title message="i18n:contents.schemasPageTitle"></sqx-title> |
|||
|
|||
<sqx-layout layout="left" titleCollapsed="i18n:common.schemas" width="18" white="true" padding="true" overflow="true" *ngIf="!isEmbedded"> |
|||
<ng-container menu> |
|||
<div class="search-form"> |
|||
<input class="form-control" [formControl]="schemasFilter" placeholder="{{ 'contents.searchSchemasPlaceholder' | sqxTranslate }}"> |
|||
|
|||
<i class="icon-search"></i> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container> |
|||
<ul class="nav nav-light mb-2 flex-column"> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" routerLink="__calendar" routerLinkActive="active"> |
|||
{{ 'contents.calendar' | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
</ul> |
|||
|
|||
@if (!isEmbedded) { |
|||
<sqx-layout layout="left" overflow="true" padding="true" titleCollapsed="i18n:common.schemas" white="true" width="18"> |
|||
<ng-container menu> |
|||
<div class="search-form"> |
|||
<input |
|||
class="form-control" |
|||
[formControl]="schemasFilter" |
|||
placeholder="{{ 'contents.searchSchemasPlaceholder' | sqxTranslate }}" /> |
|||
<i class="icon-search"></i> |
|||
</div> |
|||
</ng-container> |
|||
<ng-container> |
|||
<sqx-schema-category *ngFor="let category of categories | async; trackBy: trackByCategory" |
|||
[schemaCategory]="category" |
|||
[schemaTarget]="'Contents'"> |
|||
</sqx-schema-category> |
|||
<ul class="nav nav-light mb-2 flex-column"> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" routerLink="__calendar" routerLinkActive="active"> |
|||
{{ "contents.calendar" | sqxTranslate }} |
|||
</a> |
|||
</li> |
|||
</ul> |
|||
<ng-container> |
|||
@for (category of categories | async; track category.name) { |
|||
<sqx-schema-category [schemaCategory]="category" [schemaTarget]="'Contents'"></sqx-schema-category> |
|||
} |
|||
</ng-container> |
|||
</ng-container> |
|||
</ng-container> |
|||
</sqx-layout> |
|||
</sqx-layout> |
|||
} |
|||
|
|||
<router-outlet></router-outlet> |
|||
|
|||
@ -1 +1 @@ |
|||
<iframe #iframe [attr.scrollable]="scrollable ? 'yes' : 'no'" width="100%" [attr.src]="computedUrl | sqxSafeResourceUrl"></iframe> |
|||
<iframe #iframe [attr.scrollable]="scrollable ? 'yes' : 'no'" [attr.src]="computedUrl | sqxSafeResourceUrl" width="100%"></iframe> |
|||
|
|||
@ -1,33 +1,49 @@ |
|||
<sqx-modal-dialog *sqxModal="dueTimeDialog" (dialogClose)="cancelStatusChange()"> |
|||
<sqx-modal-dialog (dialogClose)="cancelStatusChange()" *sqxModal="dueTimeDialog"> |
|||
<ng-container title> |
|||
{{ 'contents.changeStatusTo' | sqxTranslate: { action: dueTimeAction } }} |
|||
{{ "contents.changeStatusTo" | sqxTranslate: { action: dueTimeAction } }} |
|||
</ng-container> |
|||
|
|||
<ng-container content> |
|||
<div class="form-check"> |
|||
<input class="form-check-input" type="radio" [(ngModel)]="dueTimeMode" value="Immediately" id="immediately" name="dueTimeMode"> |
|||
<input |
|||
class="form-check-input" |
|||
id="immediately" |
|||
name="dueTimeMode" |
|||
[(ngModel)]="dueTimeMode" |
|||
type="radio" |
|||
value="Immediately" /> |
|||
<label class="form-check-label" for="immediately"> |
|||
{{ 'contents.changeStatusToImmediately' | sqxTranslate: { action: dueTimeAction } }} |
|||
{{ "contents.changeStatusToImmediately" | sqxTranslate: { action: dueTimeAction } }} |
|||
</label> |
|||
</div> |
|||
|
|||
<div class="form-check"> |
|||
<input class="form-check-input" type="radio" [(ngModel)]="dueTimeMode" value="Scheduled" id="scheduled" name="dueTimeMode"> |
|||
<input class="form-check-input" id="scheduled" name="dueTimeMode" [(ngModel)]="dueTimeMode" type="radio" value="Scheduled" /> |
|||
<label class="form-check-label" for="scheduled"> |
|||
{{ 'contents.changeStatusToLater' | sqxTranslate: { action: dueTimeAction } }} |
|||
{{ "contents.changeStatusToLater" | sqxTranslate: { action: dueTimeAction } }} |
|||
</label> |
|||
</div> |
|||
|
|||
<sqx-date-time-editor [disabled]="dueTimeMode === 'Immediately'" enforceTime="true" mode="DateTime" hideClear="true" [(ngModel)]="dueTime"></sqx-date-time-editor> |
|||
<sqx-date-time-editor |
|||
[disabled]="dueTimeMode === 'Immediately'" |
|||
enforceTime="true" |
|||
hideClear="true" |
|||
mode="DateTime" |
|||
[(ngModel)]="dueTime"></sqx-date-time-editor> |
|||
</ng-container> |
|||
|
|||
<ng-container footer> |
|||
<button type="button" class="btn btn-text-secondary" (click)="cancelStatusChange()"> |
|||
{{ 'common.cancel' | sqxTranslate }} |
|||
<button class="btn btn-text-secondary" (click)="cancelStatusChange()" type="button"> |
|||
{{ "common.cancel" | sqxTranslate }} |
|||
</button> |
|||
|
|||
<button type="button" class="btn btn-primary" [disabled]="dueTimeMode === 'Scheduled' && !dueTime" (click)="confirmStatusChange()" sqxFocusOnInit> |
|||
{{ 'common.confirm' | sqxTranslate }} |
|||
<button |
|||
class="btn btn-primary" |
|||
(click)="confirmStatusChange()" |
|||
[disabled]="dueTimeMode === 'Scheduled' && !dueTime" |
|||
sqxFocusOnInit |
|||
type="button"> |
|||
{{ "common.confirm" | sqxTranslate }} |
|||
</button> |
|||
</ng-container> |
|||
</sqx-modal-dialog> |
|||
|
|||
@ -1,122 +1,139 @@ |
|||
<ng-container *ngIf="formModel.itemChanges | async; let items"> |
|||
<div class="array-container static" [class.expanded]="isExpanded" *ngIf="items.length > 0 && items.length <= 20;" |
|||
cdkDropList |
|||
[cdkDropListSortingDisabled]="isDisabled | async" |
|||
[cdkDropListDisabled]="isDisabled | async" |
|||
[cdkDropListData]="items" |
|||
(cdkDropListDropped)="sort($event)"> |
|||
<div *ngFor="let itemForm of items; index as i; last as isLast; first as isFirst;" class="table-drag item" |
|||
cdkDrag |
|||
cdkDragLockAxis="y" |
|||
[class.first]="isFirst" |
|||
[class.last]="isLast"> |
|||
<sqx-array-item |
|||
(clone)="addCopy(itemForm)" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel + 1" |
|||
[formModel]="itemForm" |
|||
[index]="i" |
|||
[isComparing]="isComparing" |
|||
[isCollapsedInitial]="isCollapsedInitial" |
|||
[isDisabled]="isDisabled | async" |
|||
[isFirst]="isFirst" |
|||
[isLast]="isLast" |
|||
(itemRemove)="removeItem(i)" |
|||
(itemMove)="move(itemForm, $event)" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
<i cdkDragHandle class="icon-drag2" [class.disabled]="isDisabled | async"></i> |
|||
</sqx-array-item> |
|||
@if (formModel.itemChanges | async; as items) { |
|||
@if (items.length > 0 && items.length <= 20) { |
|||
<div |
|||
class="array-container static" |
|||
cdkDropList |
|||
[cdkDropListData]="items" |
|||
[cdkDropListDisabled]="isDisabled | async" |
|||
(cdkDropListDropped)="sort($event)" |
|||
[cdkDropListSortingDisabled]="isDisabled | async" |
|||
[class.expanded]="isExpanded"> |
|||
@for (itemForm of items; track itemForm; let i = $index; let isLast = $last; let isFirst = $first) { |
|||
<div class="table-drag item" cdkDrag cdkDragLockAxis="y" [class.first]="isFirst" [class.last]="isLast"> |
|||
<sqx-array-item |
|||
(clone)="addCopy(itemForm)" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel + 1" |
|||
[formModel]="itemForm" |
|||
[hasChatBot]="hasChatBot" |
|||
[index]="i" |
|||
[isCollapsedInitial]="isCollapsedInitial" |
|||
[isComparing]="isComparing" |
|||
[isDisabled]="isDisabled | async" |
|||
[isFirst]="isFirst" |
|||
[isLast]="isLast" |
|||
(itemMove)="move(itemForm, $event)" |
|||
(itemRemove)="removeItem(i)" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
<i class="icon-drag2" cdkDragHandle [class.disabled]="isDisabled | async"></i> |
|||
</sqx-array-item> |
|||
</div> |
|||
} |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="array-container" [class.expanded]="isExpanded" *ngIf="items.length > 20"> |
|||
<virtual-scroller #scroll [items]="$any(items)" [enableUnequalChildrenSizes]="true"> |
|||
<div *ngFor="let itemForm of scroll.viewPortItems; index as i" class="item" |
|||
[class.first]="scroll.viewPortInfo.startIndexWithBuffer + i === 0" |
|||
[class.last]="scroll.viewPortInfo.startIndexWithBuffer + i === items.length - 1"> |
|||
<sqx-array-item |
|||
(clone)="addCopy(itemForm)" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel + 1" |
|||
[formModel]="itemForm" |
|||
[index]="scroll.viewPortInfo.startIndexWithBuffer + i" |
|||
[isCollapsedInitial]="isCollapsedInitial" |
|||
[isComparing]="isComparing" |
|||
[isDisabled]="isDisabled | async" |
|||
[isFirst]="scroll.viewPortInfo.startIndexWithBuffer + i === 0" |
|||
[isLast]="scroll.viewPortInfo.startIndexWithBuffer + i === items.length - 1" |
|||
(itemExpanded)="scroll.invalidateCachedMeasurementAtIndex(scroll.viewPortInfo.startIndexWithBuffer + i)" |
|||
(itemRemove)="removeItem(scroll.viewPortInfo.startIndexWithBuffer + i)" |
|||
(itemMove)="move(itemForm, $event)" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-array-item> |
|||
</div> |
|||
</virtual-scroller> |
|||
</div> |
|||
|
|||
} |
|||
@if (items.length > 20) { |
|||
<div class="array-container" [class.expanded]="isExpanded"> |
|||
<virtual-scroller #scroll [enableUnequalChildrenSizes]="true" [items]="$any(items)"> |
|||
@for (itemForm of scroll.viewPortItems; track itemForm; let i = $index) { |
|||
<div |
|||
class="item" |
|||
[class.first]="scroll.viewPortInfo.startIndexWithBuffer + i === 0" |
|||
[class.last]="scroll.viewPortInfo.startIndexWithBuffer + i === items.length - 1"> |
|||
<sqx-array-item |
|||
(clone)="addCopy(itemForm)" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel + 1" |
|||
[formModel]="itemForm" |
|||
[hasChatBot]="hasChatBot" |
|||
[index]="scroll.viewPortInfo.startIndexWithBuffer + i" |
|||
[isCollapsedInitial]="isCollapsedInitial" |
|||
[isComparing]="isComparing" |
|||
[isDisabled]="isDisabled | async" |
|||
[isFirst]="scroll.viewPortInfo.startIndexWithBuffer + i === 0" |
|||
[isLast]="scroll.viewPortInfo.startIndexWithBuffer + i === items.length - 1" |
|||
(itemExpanded)="scroll.invalidateCachedMeasurementAtIndex(scroll.viewPortInfo.startIndexWithBuffer + i)" |
|||
(itemMove)="move(itemForm, $event)" |
|||
(itemRemove)="removeItem(scroll.viewPortInfo.startIndexWithBuffer + i)" |
|||
[language]="language" |
|||
[languages]="languages"></sqx-array-item> |
|||
</div> |
|||
} |
|||
</virtual-scroller> |
|||
</div> |
|||
} |
|||
<div class="array-buttons row g-0 align-items-center" [class.expanded]="isExpanded"> |
|||
<div class="col-auto"> |
|||
<ng-container *ngIf="isArray; else component"> |
|||
<ng-container *ngIf="hasField"> |
|||
<button type="button" class="btn btn-outline-success" [disabled]="isDisabledOrFull | async" (click)="addItem()"> |
|||
{{ 'contents.arrayAddItem' | sqxTranslate }} |
|||
@if (isArray) { |
|||
@if (hasField) { |
|||
<button class="btn btn-outline-success" (click)="addItem()" [disabled]="isDisabledOrFull | async" type="button"> |
|||
{{ "contents.arrayAddItem" | sqxTranslate }} |
|||
</button> |
|||
</ng-container> |
|||
<ng-container *ngIf="!hasField"> |
|||
} |
|||
@if (!hasField) { |
|||
<sqx-form-hint> |
|||
{{ 'contents.arrayNoFields' | sqxTranslate }} |
|||
{{ "contents.arrayNoFields" | sqxTranslate }} |
|||
</sqx-form-hint> |
|||
</ng-container> |
|||
</ng-container> |
|||
|
|||
<ng-template #component> |
|||
<ng-container *ngIf="schemasList.length > 1"> |
|||
<button type="button" class="btn btn-outline-success dropdown-toggle" [disabled]="isDisabledOrFull | async" (click)="schemasDropdown.show()" #buttonSelect> |
|||
{{ 'contents.addComponent' | sqxTranslate}} |
|||
} |
|||
} @else { |
|||
@if (schemasList.length > 1) { |
|||
<button |
|||
class="btn btn-outline-success dropdown-toggle" |
|||
#buttonSelect |
|||
(click)="schemasDropdown.show()" |
|||
[disabled]="isDisabledOrFull | async" |
|||
type="button"> |
|||
{{ "contents.addComponent" | sqxTranslate }} |
|||
</button> |
|||
|
|||
<sqx-dropdown-menu *sqxModal="schemasDropdown;closeAlways:true" [sqxAnchoredTo]="buttonSelect" scrollY="true"> |
|||
<a class="dropdown-item" *ngFor="let schema of schemasList" (click)="addComponent(schema)"> |
|||
{{schema.displayName}} |
|||
</a> |
|||
<sqx-dropdown-menu scrollY="true" [sqxAnchoredTo]="buttonSelect" *sqxModal="schemasDropdown; closeAlways: true"> |
|||
@for (schema of schemasList; track schema) { |
|||
<a class="dropdown-item" (click)="addComponent(schema)"> |
|||
{{ schema.displayName }} |
|||
</a> |
|||
} |
|||
</sqx-dropdown-menu> |
|||
</ng-container> |
|||
<ng-container *ngIf="schemasList.length === 1"> |
|||
<button type="button" class="btn btn-outline-success" [disabled]="isDisabledOrFull | async" (click)="addComponent(schemasList[0])"> |
|||
{{ 'contents.addComponent' | sqxTranslate}} |
|||
} |
|||
@if (schemasList.length === 1) { |
|||
<button |
|||
class="btn btn-outline-success" |
|||
(click)="addComponent(schemasList[0])" |
|||
[disabled]="isDisabledOrFull | async" |
|||
type="button"> |
|||
{{ "contents.addComponent" | sqxTranslate }} |
|||
</button> |
|||
</ng-container> |
|||
<ng-container *ngIf="schemasList.length === 0"> |
|||
} |
|||
@if (schemasList.length === 0) { |
|||
<sqx-form-hint> |
|||
{{ 'contents.componentsNoSchema' | sqxTranslate }} |
|||
{{ "contents.componentsNoSchema" | sqxTranslate }} |
|||
</sqx-form-hint> |
|||
</ng-container> |
|||
</ng-template> |
|||
</div> |
|||
|
|||
<div class="col"> |
|||
<button type="button" class="btn btn-text-danger ms-2" *ngIf="items.length > 0" [disabled]="isDisabled | async" |
|||
(sqxConfirmClick)="clear()" |
|||
confirmTitle="i18n:contents.arrayClearConfirmTitle" |
|||
confirmText="i18n:contents.arrayClearConfirmText" |
|||
confirmRememberKey="leaveApp"> |
|||
{{ 'contents.arrayClear' | sqxTranslate }} |
|||
</button> |
|||
} |
|||
} |
|||
</div> |
|||
|
|||
<div class="col-auto" *ngIf="items.length > 0"> |
|||
<button type="button" class="btn btn-text-secondary" (click)="expandAll()" title="i18n:contents.arrayExpandAll"> |
|||
<i class="icon-plus-square"></i> |
|||
</button> |
|||
<button type="button" class="btn btn-text-secondary" (click)="collapseAll()" title="i18n:contents.arrayCollapseAll"> |
|||
<i class="icon-minus-square"></i> |
|||
</button> |
|||
<div class="col"> |
|||
@if (items.length > 0) { |
|||
<button |
|||
class="btn btn-text-danger ms-2" |
|||
confirmRememberKey="leaveApp" |
|||
confirmText="i18n:contents.arrayClearConfirmText" |
|||
confirmTitle="i18n:contents.arrayClearConfirmTitle" |
|||
[disabled]="isDisabled | async" |
|||
(sqxConfirmClick)="clear()" |
|||
type="button"> |
|||
{{ "contents.arrayClear" | sqxTranslate }} |
|||
</button> |
|||
} |
|||
</div> |
|||
@if (items.length > 0) { |
|||
<div class="col-auto"> |
|||
<button class="btn btn-text-secondary" (click)="expandAll()" title="i18n:contents.arrayExpandAll" type="button"> |
|||
<i class="icon-plus-square"></i> |
|||
</button> |
|||
<button class="btn btn-text-secondary" (click)="collapseAll()" title="i18n:contents.arrayCollapseAll" type="button"> |
|||
<i class="icon-minus-square"></i> |
|||
</button> |
|||
</div> |
|||
} |
|||
</div> |
|||
</ng-container> |
|||
} |
|||
|
|||
@ -1,28 +1,34 @@ |
|||
<ng-container *ngIf="!(formSection.hiddenChanges | async)"> |
|||
<div class="header" *ngIf="formSection.separator; let separator"> |
|||
<h3>{{separator!.displayName}}</h3> |
|||
|
|||
<sqx-form-hint *ngIf="separator.properties.hints && separator.properties.hints.length > 0"> |
|||
<span [sqxMarkdown]="separator.properties.hints" optional="true" inline="true"></span> |
|||
</sqx-form-hint> |
|||
</div> |
|||
|
|||
<div class="row"> |
|||
<div class="form-group" *ngFor="let child of formSection.fields; trackBy: trackByField" |
|||
[class.col-12]="isComparing || !child.field.properties.isHalfWidth" |
|||
[class.col-6]="!isComparing && child.field.properties.isHalfWidth"> |
|||
<sqx-field-editor *ngIf="!(child.hiddenChanges | async)" |
|||
[comments]="null" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="child" |
|||
[index]="index" |
|||
[isComparing]="isComparing" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-field-editor> |
|||
@if (!(formSection.hiddenChanges | async)) { |
|||
@if (formSection.separator; as separator) { |
|||
<div class="header"> |
|||
<h3>{{ separator!.displayName }}</h3> |
|||
@if (separator.properties.hints && separator.properties.hints.length > 0) { |
|||
<sqx-form-hint> |
|||
<span inline="true" optional="true" [sqxMarkdown]="separator.properties.hints"></span> |
|||
</sqx-form-hint> |
|||
} |
|||
</div> |
|||
} |
|||
<div class="row"> |
|||
@for (child of formSection.fields; track child.field.fieldId) { |
|||
<div |
|||
class="form-group" |
|||
[class.col-12]="isComparing || !child.field.properties.isHalfWidth" |
|||
[class.col-6]="!isComparing && child.field.properties.isHalfWidth"> |
|||
@if (!(child.hiddenChanges | async)) { |
|||
<sqx-field-editor |
|||
[comments]="null" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="child" |
|||
[hasChatBot]="hasChatBot" |
|||
[index]="index" |
|||
[isComparing]="isComparing" |
|||
[language]="language" |
|||
[languages]="languages"></sqx-field-editor> |
|||
} |
|||
</div> |
|||
} |
|||
</div> |
|||
</ng-container> |
|||
} |
|||
|
|||
@ -1,44 +1,50 @@ |
|||
<div class="component"> |
|||
<div *ngIf="formModel.schemaChanges | async; let schema; else noSchema"> |
|||
<sqx-form-hint> |
|||
{{schema.displayName}} |
|||
</sqx-form-hint> |
|||
|
|||
<div class="form-group" *ngFor="let section of formModel.sectionsChanges | async"> |
|||
<sqx-component-section |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel + 1" |
|||
[formSection]="$any(section)" |
|||
[isComparing]="isComparing" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-component-section> |
|||
@if (formModel.schemaChanges | async; as schema) { |
|||
<div> |
|||
<sqx-form-hint> |
|||
{{ schema.displayName }} |
|||
</sqx-form-hint> |
|||
@for (section of formModel.sectionsChanges | async; track section) { |
|||
<div class="form-group"> |
|||
<sqx-component-section |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel + 1" |
|||
[formSection]="$any(section)" |
|||
[hasChatBot]="hasChatBot" |
|||
[isComparing]="isComparing" |
|||
[language]="language" |
|||
[languages]="languages"></sqx-component-section> |
|||
</div> |
|||
} |
|||
</div> |
|||
</div> |
|||
|
|||
<ng-template #noSchema> |
|||
<ng-container *ngIf="schemasList.length > 1"> |
|||
<button type="button" class="btn btn-outline-success dropdown-toggle" [disabled]="isDisabled | async" (click)="schemasDropdown.show()" #buttonSelect> |
|||
{{ 'contents.addComponent' | sqxTranslate}} |
|||
} @else { |
|||
@if (schemasList.length > 1) { |
|||
<button |
|||
class="btn btn-outline-success dropdown-toggle" |
|||
#buttonSelect |
|||
(click)="schemasDropdown.show()" |
|||
[disabled]="isDisabled | async" |
|||
type="button"> |
|||
{{ "contents.addComponent" | sqxTranslate }} |
|||
</button> |
|||
|
|||
<sqx-dropdown-menu *sqxModal="schemasDropdown;closeAlways:true" [sqxAnchoredTo]="buttonSelect" scrollY="true"> |
|||
<a class="dropdown-item" *ngFor="let schema of schemasList" (click)="setSchema(schema)"> |
|||
{{schema.displayName}} |
|||
</a> |
|||
<sqx-dropdown-menu scrollY="true" [sqxAnchoredTo]="buttonSelect" *sqxModal="schemasDropdown; closeAlways: true"> |
|||
@for (schema of schemasList; track schema) { |
|||
<a class="dropdown-item" (click)="setSchema(schema)"> |
|||
{{ schema.displayName }} |
|||
</a> |
|||
} |
|||
</sqx-dropdown-menu> |
|||
</ng-container> |
|||
<ng-container *ngIf="schemasList.length === 1"> |
|||
<button type="button" class="btn btn-outline-success" [disabled]="isDisabled | async" (click)="setSchema(schemasList[0])"> |
|||
{{ 'contents.addComponent' | sqxTranslate}} |
|||
} |
|||
@if (schemasList.length === 1) { |
|||
<button class="btn btn-outline-success" (click)="setSchema(schemasList[0])" [disabled]="isDisabled | async" type="button"> |
|||
{{ "contents.addComponent" | sqxTranslate }} |
|||
</button> |
|||
</ng-container> |
|||
<ng-container *ngIf="schemasList.length === 0"> |
|||
} |
|||
@if (schemasList.length === 0) { |
|||
<sqx-form-hint> |
|||
{{ 'contents.componentNoSchema' | sqxTranslate }} |
|||
{{ "contents.componentNoSchema" | sqxTranslate }} |
|||
</sqx-form-hint> |
|||
</ng-container> |
|||
</ng-template> |
|||
</div> |
|||
} |
|||
} |
|||
</div> |
|||
|
|||
@ -1,113 +1,120 @@ |
|||
<div class="row g-0" [class.compare]="formModelCompare"> |
|||
<div [class.col-12]="!formModelCompare" [class.col-6]="formModelCompare"> |
|||
<sqx-focus-marker [controlId]="formModel.fieldPath"> |
|||
<div class="table-items-row table-items-row-summary" [class.field-invalid]="isInvalid | async" *ngIf="!(formModel.hiddenChanges | async)"> |
|||
<div class="languages-container"> |
|||
<div class="languages-buttons"> |
|||
<div class="languages-inner"> |
|||
<sqx-field-languages |
|||
[formModel]="formModel" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[showAllControls]="showAllControls" |
|||
(showAllControlsChange)="changeShowAllControls($event)"> |
|||
</sqx-field-languages> |
|||
|
|||
<sqx-field-copy-button [formModel]="formModel" [languages]="languages"></sqx-field-copy-button> |
|||
|
|||
<button *ngIf="isTranslatable" type="button" [disabled]="formModel.field.isDisabled" class="btn btn-sm btn-outline-secondary force no-focus-shadow ms-1" title="i18n:contents.autotranslate" (click)="translate()" tabindex="-1"> |
|||
<i class="icon-translate"></i> |
|||
</button> |
|||
@if (!(formModel.hiddenChanges | async)) { |
|||
<div class="table-items-row table-items-row-summary" [class.field-invalid]="isInvalid | async"> |
|||
<div class="languages-container"> |
|||
<div class="languages-buttons"> |
|||
<div class="languages-inner"> |
|||
<sqx-field-languages |
|||
[formModel]="formModel" |
|||
[language]="language" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[languages]="languages" |
|||
[showAllControls]="showAllControls" |
|||
(showAllControlsChange)="changeShowAllControls($event)"></sqx-field-languages> |
|||
<sqx-field-copy-button [formModel]="formModel" [languages]="languages"></sqx-field-copy-button> |
|||
@if (isTranslatable) { |
|||
<button |
|||
class="btn btn-sm btn-outline-secondary force no-focus-shadow ms-1" |
|||
(click)="translate()" |
|||
[disabled]="formModel.field.isDisabled" |
|||
tabindex="-1" |
|||
title="i18n:contents.autotranslate" |
|||
type="button"> |
|||
<i class="icon-translate"></i> |
|||
</button> |
|||
} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<ng-container *ngIf="showAllControls; else singleControl"> |
|||
<div class="form-group" *ngFor="let language of languages"> |
|||
@if (showAllControls) { |
|||
@for (language of languages; track language) { |
|||
<div class="form-group"> |
|||
<sqx-field-editor |
|||
[comments]="commentsState" |
|||
[displaySuffix]="prefix(language)" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="formModel.get(language)" |
|||
[hasChatBot]="hasChatBot" |
|||
[isComparing]="!!formModelCompare" |
|||
[language]="language" |
|||
[languages]="languages"></sqx-field-editor> |
|||
</div> |
|||
} |
|||
} @else { |
|||
<sqx-field-editor |
|||
[comments]="commentsState" |
|||
[displaySuffix]="prefix(language)" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="formModel.get(language)" |
|||
[isComparing]="!!formModelCompare" |
|||
[formModel]="getControl()" |
|||
[hasChatBot]="hasChatBot" |
|||
[isComparing]="!!formModelCompare" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-field-editor> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-template #singleControl> |
|||
<sqx-field-editor |
|||
[comments]="commentsState" |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="getControl()" |
|||
[isComparing]="!!formModelCompare" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-field-editor> |
|||
</ng-template> |
|||
</div> |
|||
[languages]="languages"></sqx-field-editor> |
|||
} |
|||
</div> |
|||
} |
|||
</sqx-focus-marker> |
|||
</div> |
|||
|
|||
<div class="col-6 col-right" *ngIf="formModelCompare && formCompare"> |
|||
<div class="copy-button-container" *ngIf="!(isDisabled | async)"> |
|||
<button type="button" class="btn btn-primary btn-sm field-copy" (click)="copy()" *ngIf="isDifferent | async"> |
|||
<i class="icon-arrow_back"></i> |
|||
</button> |
|||
</div> |
|||
|
|||
<div class="table-items-row table-items-row-summary" *ngIf="!(formModelCompare!.hiddenChanges | async)"> |
|||
<div class="languages-container"> |
|||
<div class="languages-buttons-compare"> |
|||
<div class="languages-inner"> |
|||
<sqx-field-languages |
|||
[formModel]="formModelCompare!" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[showAllControls]="showAllControls" |
|||
(showAllControlsChange)="changeShowAllControls($event)"> |
|||
</sqx-field-languages> |
|||
</div> |
|||
@if (formModelCompare && formCompare) { |
|||
<div class="col-6 col-right"> |
|||
@if (!(isDisabled | async)) { |
|||
<div class="copy-button-container"> |
|||
@if (isDifferent | async) { |
|||
<button class="btn btn-primary btn-sm field-copy" (click)="copy()" type="button"> |
|||
<i class="icon-arrow_back"></i> |
|||
</button> |
|||
} |
|||
</div> |
|||
</div> |
|||
|
|||
<ng-container *ngIf="showAllControls; else singleControlCompare"> |
|||
<div class="form-group" *ngFor="let language of languages"> |
|||
<sqx-field-editor |
|||
[displaySuffix]="prefix(language)" |
|||
[form]="formCompare" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="formModelCompare.get(language)" |
|||
[isComparing]="!!formModelCompare" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-field-editor> |
|||
} |
|||
@if (!(formModelCompare!.hiddenChanges | async)) { |
|||
<div class="table-items-row table-items-row-summary"> |
|||
<div class="languages-container"> |
|||
<div class="languages-buttons-compare"> |
|||
<div class="languages-inner"> |
|||
<sqx-field-languages |
|||
[formModel]="formModelCompare!" |
|||
[language]="language" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[languages]="languages" |
|||
[showAllControls]="showAllControls" |
|||
(showAllControlsChange)="changeShowAllControls($event)"></sqx-field-languages> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@if (showAllControls) { |
|||
@for (language of languages; track language) { |
|||
<div class="form-group"> |
|||
<sqx-field-editor |
|||
[displaySuffix]="prefix(language)" |
|||
[form]="formCompare" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="formModelCompare.get(language)" |
|||
[hasChatBot]="hasChatBot" |
|||
[isComparing]="!!formModelCompare" |
|||
[language]="language" |
|||
[languages]="languages"></sqx-field-editor> |
|||
</div> |
|||
} |
|||
} @else { |
|||
<sqx-field-editor |
|||
[form]="formCompare" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="getControlCompare()!" |
|||
[hasChatBot]="hasChatBot" |
|||
[isComparing]="!!formModelCompare" |
|||
[language]="language" |
|||
[languages]="languages"></sqx-field-editor> |
|||
} |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-template #singleControlCompare> |
|||
<sqx-field-editor |
|||
[form]="formCompare" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="getControlCompare()!" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[isComparing]="!!formModelCompare" |
|||
[hasChatBot]="hasChatBot"> |
|||
</sqx-field-editor> |
|||
</ng-template> |
|||
} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
} |
|||
</div> |
|||
|
|||
@ -1,34 +1,38 @@ |
|||
<ng-container *ngIf="(formSection.visibleChanges | async) || formCompare"> |
|||
<div class="header" *ngIf="formSection.separator; let separator"> |
|||
<div class="row g-0 align"> |
|||
<div class="col-auto"> |
|||
<button type="button" class="btn btn-sm btn-text-secondary" (click)="toggle()"> |
|||
<i [class.icon-caret-right]="snapshot.isCollapsed" [class.icon-caret-down]="!snapshot.isCollapsed"></i> |
|||
</button> |
|||
</div> |
|||
<div class="col"> |
|||
<h3>{{separator.displayName}}</h3> |
|||
|
|||
<sqx-form-hint *ngIf="separator.properties.hints && separator.properties.hints.length > 0"> |
|||
<span [sqxMarkdown]="separator.properties.hints" optional="true" inline="true"></span> |
|||
</sqx-form-hint> |
|||
@if ((formSection.visibleChanges | async) || formCompare) { |
|||
@if (formSection.separator; as separator) { |
|||
<div class="header"> |
|||
<div class="row g-0 align"> |
|||
<div class="col-auto"> |
|||
<button class="btn btn-sm btn-text-secondary" (click)="toggle()" type="button"> |
|||
<i [class.icon-caret-down]="!snapshot.isCollapsed" [class.icon-caret-right]="snapshot.isCollapsed"></i> |
|||
</button> |
|||
</div> |
|||
<div class="col"> |
|||
<h3>{{ separator.displayName }}</h3> |
|||
@if (separator.properties.hints && separator.properties.hints.length > 0) { |
|||
<sqx-form-hint> |
|||
<span inline="true" optional="true" [sqxMarkdown]="separator.properties.hints"></span> |
|||
</sqx-form-hint> |
|||
} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</ng-container> |
|||
} |
|||
} |
|||
|
|||
<div class="row gx-1" [class.hidden]="snapshot.isCollapsed && !formCompare"> |
|||
<sqx-content-field *ngFor="let field of formSection.fields; trackBy: trackByField" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[form]="form" |
|||
[formCompare]="formCompare" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="field" |
|||
[formModelCompare]="getFieldFormCompare(field)" |
|||
[isCompact]="isCompact" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schema]="schema"> |
|||
</sqx-content-field> |
|||
</div> |
|||
@for (field of formSection.fields; track field.field.fieldId) { |
|||
<sqx-content-field |
|||
[form]="form" |
|||
[formCompare]="formCompare" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="field" |
|||
[formModelCompare]="getFieldFormCompare(field)" |
|||
[isCompact]="isCompact" |
|||
[language]="language" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[languages]="languages" |
|||
[schema]="schema"></sqx-content-field> |
|||
} |
|||
</div> |
|||
|
|||
@ -1,37 +1,36 @@ |
|||
<ng-container *ngIf="isLocalized"> |
|||
<button type="button" class="btn btn-outline-secondary btn-sm ms-1 dropdown-toggle" title="{{ 'common.copy' | sqxTranslate }}" (click)="dropdown.toggle()" #button tabindex="-1"> |
|||
@if (isLocalized) { |
|||
<button |
|||
class="btn btn-outline-secondary btn-sm ms-1 dropdown-toggle" |
|||
#button |
|||
(click)="dropdown.toggle()" |
|||
tabindex="-1" |
|||
title="{{ 'common.copy' | sqxTranslate }}" |
|||
type="button"> |
|||
<i class="icon-copy"></i> |
|||
</button> |
|||
|
|||
<sqx-dropdown-menu *sqxModal="dropdown" [sqxAnchoredTo]="button" scrollY="true"> |
|||
<sqx-dropdown-menu scrollY="true" [sqxAnchoredTo]="button" *sqxModal="dropdown"> |
|||
<div class="section d-flex justify-content-end"> |
|||
<button type="button" class="btn btn-primary" (click)="copy()" tabindex="-1"> |
|||
{{ 'common.copy' | sqxTranslate }} |
|||
<button class="btn btn-primary" (click)="copy()" tabindex="-1" type="button"> |
|||
{{ "common.copy" | sqxTranslate }} |
|||
</button> |
|||
</div> |
|||
|
|||
<div class="dropdown-divider"></div> |
|||
|
|||
<div class="section"> |
|||
<div class="row"> |
|||
<label class="col-auto col-form-label" for="languageSource">{{ 'common.from' | sqxTranslate }}</label> |
|||
|
|||
<label class="col-auto col-form-label" for="languageSource">{{ "common.from" | sqxTranslate }}</label> |
|||
<div class="col"> |
|||
<select class="form-select" id="languagesSource" |
|||
[ngModel]="copySource" |
|||
(ngModelChange)="setCopySource($event)"> |
|||
<option *ngFor="let language of languages" [ngValue]="language.iso2Code">{{language.iso2Code}}</option> |
|||
<select class="form-select" id="languagesSource" [ngModel]="copySource" (ngModelChange)="setCopySource($event)"> |
|||
@for (language of languages; track language) { |
|||
<option [ngValue]="language.iso2Code">{{ language.iso2Code }}</option> |
|||
} |
|||
</select> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="dropdown-divider"></div> |
|||
|
|||
<div class="section"> |
|||
<label>{{ 'common.to' | sqxTranslate }}</label> |
|||
|
|||
<sqx-checkbox-group [(ngModel)]="copyTargets" [values]="languageCodes" layout="Multiline"></sqx-checkbox-group> |
|||
<label>{{ "common.to" | sqxTranslate }}</label> |
|||
<sqx-checkbox-group layout="Multiline" [(ngModel)]="copyTargets" [values]="languageCodes"></sqx-checkbox-group> |
|||
</div> |
|||
</sqx-dropdown-menu> |
|||
</ng-container> |
|||
} |
|||
|
|||
@ -1,297 +1,345 @@ |
|||
<div class="field" [class.expanded]="isExpanded" *ngIf="formModel"> |
|||
<fieldset class="buttons-container" [disabled]="isDisabled | async"> |
|||
<div class="buttons"> |
|||
<button type="button" class="btn btn-sm btn-outline-secondary force no-focus-shadow" (click)="chatDialog.show()" [disabled]="!hasChatBot || !isString" tabindex="-1"> |
|||
AI |
|||
</button> |
|||
|
|||
<button type="button" class="btn btn-sm btn-outline-secondary force no-focus-shadow ms-1" title="i18n:contents.fieldFullscreen" (click)="toggleExpanded()" tabindex="-1"> |
|||
<i class="icon-fullscreen"></i> |
|||
</button> |
|||
|
|||
<button type="button" class="btn btn-sm btn-outline-secondary btn-clear force no-focus-shadow ms-1" [disabled]="isEmpty | async" tabindex="-1" |
|||
(sqxConfirmClick)="unset()" |
|||
confirmTitle="i18n:contents.unsetValueConfirmTitle" |
|||
confirmText="i18n:contents.unsetValueConfirmText" |
|||
confirmRememberKey="unsetValue" |
|||
title="i18n:contents.unsetValue"> |
|||
<i class="icon-close"></i> |
|||
</button> |
|||
@if (formModel) { |
|||
<div class="field" [class.expanded]="isExpanded"> |
|||
<fieldset class="buttons-container" [disabled]="isDisabled | async"> |
|||
<div class="buttons"> |
|||
<button |
|||
class="btn btn-sm btn-outline-secondary force no-focus-shadow" |
|||
(click)="chatDialog.show()" |
|||
[disabled]="!hasChatBot || !isString" |
|||
tabindex="-1" |
|||
type="button"> |
|||
AI |
|||
</button> |
|||
<button |
|||
class="btn btn-sm btn-outline-secondary force no-focus-shadow ms-1" |
|||
(click)="toggleExpanded()" |
|||
tabindex="-1" |
|||
title="i18n:contents.fieldFullscreen" |
|||
type="button"> |
|||
<i class="icon-fullscreen"></i> |
|||
</button> |
|||
<button |
|||
class="btn btn-sm btn-outline-secondary btn-clear force no-focus-shadow ms-1" |
|||
confirmRememberKey="unsetValue" |
|||
confirmText="i18n:contents.unsetValueConfirmText" |
|||
confirmTitle="i18n:contents.unsetValueConfirmTitle" |
|||
[disabled]="isEmpty | async" |
|||
(sqxConfirmClick)="unset()" |
|||
tabindex="-1" |
|||
title="i18n:contents.unsetValue" |
|||
type="button"> |
|||
<i class="icon-close"></i> |
|||
</button> |
|||
</div> |
|||
</fieldset> |
|||
<label> |
|||
{{ field.displayName }} {{ displaySuffix }} |
|||
<span class="field-required" [class.hidden]="!field.properties.isRequired">*</span> |
|||
</label> |
|||
@if (field.isDisabled) { |
|||
<small class="field-disabled ps-1">Disabled</small> |
|||
} |
|||
@if (form) { |
|||
<sqx-control-errors [fieldName]="field.displayName" [for]="$any(fieldForm)"></sqx-control-errors> |
|||
} |
|||
<div> |
|||
@if (field.properties.editorUrl) { |
|||
<sqx-iframe-editor |
|||
#editor |
|||
[context]="formContext" |
|||
[formControlBinding]="$any(fieldForm)" |
|||
[formField]="formModel.field.name" |
|||
[formIndex]="index" |
|||
[formValue]="form.valueChanges | async" |
|||
[isExpanded]="isExpanded" |
|||
(isExpandedChange)="toggleExpanded()" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schemaIds]="field.rawProperties.schemaIds" |
|||
[url]="field.properties.editorUrl"></sqx-iframe-editor> |
|||
} @else { |
|||
@switch (field.properties.fieldType) { |
|||
@case ("Array") { |
|||
<sqx-array-editor |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="$any(formModel)" |
|||
[hasChatBot]="hasChatBot" |
|||
[isComparing]="isComparing" |
|||
[isExpanded]="isExpanded" |
|||
[language]="language" |
|||
[languages]="languages"></sqx-array-editor> |
|||
} |
|||
@case ("Assets") { |
|||
<sqx-assets-editor |
|||
[folderId]="field.rawProperties.folderId" |
|||
[formControl]="$any(fieldForm)" |
|||
[hasChatBot]="hasChatBot" |
|||
[isExpanded]="isExpanded"></sqx-assets-editor> |
|||
} |
|||
@case ("Boolean") { |
|||
@switch (field.rawProperties.editor) { |
|||
@case ("Toggle") { |
|||
<sqx-toggle [formControl]="$any(fieldForm)" [threeStates]="!field.properties.isRequired"></sqx-toggle> |
|||
} |
|||
@case ("Checkbox") { |
|||
<div class="form-check"> |
|||
<input |
|||
class="form-check-input" |
|||
id="{{ uniqueId }}" |
|||
[formControl]="$any(fieldForm)" |
|||
sqxIndeterminateValue |
|||
[threeStates]="!field.properties.isRequired" |
|||
type="checkbox" /> |
|||
<label class="form-check-label" for="{{ uniqueId }}"></label> |
|||
</div> |
|||
} |
|||
} |
|||
} |
|||
@case ("Component") { |
|||
<sqx-component |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="$any(formModel)" |
|||
[hasChatBot]="hasChatBot" |
|||
[isComparing]="isComparing" |
|||
[language]="language" |
|||
[languages]="languages"></sqx-component> |
|||
} |
|||
@case ("Components") { |
|||
<sqx-array-editor |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="$any(formModel)" |
|||
[hasChatBot]="hasChatBot" |
|||
[isComparing]="isComparing" |
|||
[isExpanded]="isExpanded" |
|||
[language]="language" |
|||
[languages]="languages"></sqx-array-editor> |
|||
} |
|||
@case ("DateTime") { |
|||
<sqx-date-time-editor |
|||
enforceTime="true" |
|||
[formControl]="$any(fieldForm)" |
|||
[mode]="field.rawProperties.editor"></sqx-date-time-editor> |
|||
} |
|||
@case ("Geolocation") { |
|||
<sqx-geolocation-editor [formControl]="$any(fieldForm)"></sqx-geolocation-editor> |
|||
} |
|||
@case ("Json") { |
|||
<sqx-code-editor [formControl]="$any(fieldForm)" [height]="350" valueMode="Json"></sqx-code-editor> |
|||
} |
|||
@case ("Number") { |
|||
@switch (field.rawProperties.editor) { |
|||
@case ("Input") { |
|||
<input |
|||
class="form-control" |
|||
[formControl]="$any(fieldForm)" |
|||
[placeholder]="field.displayPlaceholder" |
|||
type="number" /> |
|||
} |
|||
@case ("Stars") { |
|||
<sqx-stars [formControl]="$any(fieldForm)" [maximumStars]="field.rawProperties.maxValue"></sqx-stars> |
|||
} |
|||
@case ("Radio") { |
|||
<sqx-radio-group |
|||
[formControl]="$any(fieldForm)" |
|||
unsorted="true" |
|||
[values]="field.rawProperties.allowedValues"></sqx-radio-group> |
|||
} |
|||
@case ("Dropdown") { |
|||
<select class="form-select" [formControl]="$any(fieldForm)"> |
|||
<option [ngValue]="null"></option> |
|||
@for (value of field.rawProperties.allowedValues; track value) { |
|||
<option [ngValue]="value">{{ value }}</option> |
|||
} |
|||
</select> |
|||
} |
|||
} |
|||
} |
|||
@case ("References") { |
|||
@switch (field.rawProperties.editor) { |
|||
@case ("List") { |
|||
<sqx-references-editor |
|||
[allowDuplicates]="field.rawProperties.allowDuplicated" |
|||
[formContext]="formContext" |
|||
[formControl]="$any(fieldForm)" |
|||
[isExpanded]="isExpanded" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[query]="field.rawProperties.query" |
|||
[schemaIds]="field.rawProperties.schemaIds"></sqx-references-editor> |
|||
} |
|||
@case ("Dropdown") { |
|||
<sqx-reference-dropdown |
|||
[formControl]="$any(fieldForm)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
mode="Array" |
|||
[schemaId]="field.rawProperties.singleId"></sqx-reference-dropdown> |
|||
} |
|||
@case ("Input") { |
|||
<sqx-reference-input |
|||
[formControl]="$any(fieldForm)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
mode="Array" |
|||
[query]="field.rawProperties.query" |
|||
[schemaIds]="field.rawProperties.schemaIds"></sqx-reference-input> |
|||
} |
|||
@case ("Tags") { |
|||
<sqx-references-tags |
|||
[formControl]="$any(fieldForm)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schemaId]="field.rawProperties.singleId"></sqx-references-tags> |
|||
} |
|||
@case ("Checkboxes") { |
|||
<sqx-references-checkboxes |
|||
[formControl]="$any(fieldForm)" |
|||
[language]="language" |
|||
[schemaId]="field.rawProperties.singleId"></sqx-references-checkboxes> |
|||
} |
|||
} |
|||
} |
|||
@case ("String") { |
|||
@switch (field.rawProperties.editor) { |
|||
@case ("Input") { |
|||
<input class="form-control" [formControl]="$any(fieldForm)" [placeholder]="field.displayPlaceholder" /> |
|||
} |
|||
@case ("Slug") { |
|||
<input |
|||
class="form-control" |
|||
[formControl]="$any(fieldForm)" |
|||
[placeholder]="field.displayPlaceholder" |
|||
sqxTransformInput="Slugify" /> |
|||
} |
|||
@case ("TextArea") { |
|||
<textarea |
|||
class="form-control" |
|||
[formControl]="$any(fieldForm)" |
|||
[placeholder]="field.displayPlaceholder" |
|||
rows="5"></textarea> |
|||
} |
|||
@case ("RichText") { |
|||
<sqx-rich-editor |
|||
#editor |
|||
[annotations]="annotations | async" |
|||
(annotationsCreate)="annotationCreate($event)" |
|||
(annotationsSelect)="annotationsSelect($event)" |
|||
(annotationsUpdate)="annotationsUpdate($event)" |
|||
[classNames]="field.rawProperties.classNames" |
|||
[folderId]="field.rawProperties.folderId" |
|||
[formControl]="$any(fieldForm)" |
|||
[hasAnnotations]="!!comments" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
mode="Html" |
|||
[schemaIds]="field.rawProperties.schemaIds"></sqx-rich-editor> |
|||
} |
|||
@case ("Html") { |
|||
<sqx-code-editor |
|||
#editor |
|||
[formControl]="$any(fieldForm)" |
|||
[height]="350" |
|||
mode="ace/mode/html"></sqx-code-editor> |
|||
} |
|||
@case ("Markdown") { |
|||
<sqx-rich-editor |
|||
#editor |
|||
[annotations]="annotations | async" |
|||
(annotationsCreate)="annotationCreate($event)" |
|||
(annotationsSelect)="annotationsSelect($event)" |
|||
(annotationsUpdate)="annotationsUpdate($event)" |
|||
[classNames]="undefined" |
|||
[folderId]="field.rawProperties.folderId" |
|||
[formControl]="$any(fieldForm)" |
|||
[hasAnnotations]="!!comments" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
mode="Markdown" |
|||
[schemaIds]="field.rawProperties.schemaIds"></sqx-rich-editor> |
|||
} |
|||
@case ("StockPhoto") { |
|||
<sqx-stock-photo-editor [formControl]="$any(fieldForm)"></sqx-stock-photo-editor> |
|||
} |
|||
@case ("Dropdown") { |
|||
<select class="form-select" [formControl]="$any(fieldForm)"> |
|||
<option [ngValue]="null"></option> |
|||
@for (value of field.rawProperties.allowedValues; track value) { |
|||
<option [ngValue]="value">{{ value }}</option> |
|||
} |
|||
</select> |
|||
} |
|||
@case ("Radio") { |
|||
<sqx-radio-group |
|||
[formControl]="$any(fieldForm)" |
|||
unsorted="true" |
|||
[values]="field.rawProperties.allowedValues"></sqx-radio-group> |
|||
} |
|||
@case ("Color") { |
|||
<sqx-color-picker |
|||
[formControl]="$any(fieldForm)" |
|||
[placeholder]="field.displayPlaceholder"></sqx-color-picker> |
|||
} |
|||
} |
|||
} |
|||
@case ("RichText") { |
|||
<sqx-rich-editor |
|||
#editor |
|||
[annotations]="annotations | async" |
|||
(annotationsCreate)="annotationCreate($event)" |
|||
(annotationsSelect)="annotationsSelect($event)" |
|||
(annotationsUpdate)="annotationsUpdate($event)" |
|||
[classNames]="field.rawProperties.classNames" |
|||
[folderId]="field.rawProperties.folderId" |
|||
[formControl]="$any(fieldForm)" |
|||
[hasAnnotations]="!!comments" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
mode="State" |
|||
[schemaIds]="field.rawProperties.schemaIds"></sqx-rich-editor> |
|||
} |
|||
@case ("Tags") { |
|||
@switch (field.rawProperties.editor) { |
|||
@case ("Tags") { |
|||
<sqx-tag-editor |
|||
[formControl]="$any(fieldForm)" |
|||
[itemsSource]="field.rawProperties.allowedValues" |
|||
[placeholder]="field.displayPlaceholder"></sqx-tag-editor> |
|||
} |
|||
@case ("Checkboxes") { |
|||
<sqx-checkbox-group |
|||
[formControl]="$any(fieldForm)" |
|||
[values]="field.rawProperties.allowedValues"></sqx-checkbox-group> |
|||
} |
|||
@case ("Dropdown") { |
|||
<select class="form-select" [formControl]="$any(fieldForm)" multiple> |
|||
@for (value of field.rawProperties.allowedValues; track value) { |
|||
<option [ngValue]="value">{{ value }}</option> |
|||
} |
|||
</select> |
|||
} |
|||
} |
|||
} |
|||
@case ("UI") { |
|||
<h4 class="ui-separator">{{ field.displayName }}</h4> |
|||
} |
|||
} |
|||
} |
|||
</div> |
|||
</fieldset> |
|||
|
|||
<label> |
|||
{{field.displayName}} {{displaySuffix}} <span class="field-required" [class.hidden]="!field.properties.isRequired">*</span> |
|||
</label> |
|||
|
|||
<small class="field-disabled ps-1" *ngIf="field.isDisabled">Disabled</small> |
|||
|
|||
<sqx-control-errors *ngIf="form" [for]="$any(fieldForm)" [fieldName]="field.displayName"></sqx-control-errors> |
|||
|
|||
<div> |
|||
<ng-container *ngIf="field.properties.editorUrl; else noEditor"> |
|||
<sqx-iframe-editor [url]="field.properties.editorUrl" #editor |
|||
[context]="formContext" |
|||
[isExpanded]="isExpanded" |
|||
(isExpandedChange)="toggleExpanded()" |
|||
[formControlBinding]="$any(fieldForm)" |
|||
[formValue]="form.valueChanges | async" |
|||
[formIndex]="index" |
|||
[formField]="formModel.field.name" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schemaIds]="field.rawProperties.schemaIds"> |
|||
</sqx-iframe-editor> |
|||
</ng-container> |
|||
|
|||
<ng-template #noEditor> |
|||
<ng-container [ngSwitch]="field.properties.fieldType"> |
|||
<ng-container *ngSwitchCase="'Array'"> |
|||
<sqx-array-editor |
|||
[form]="form" |
|||
[formLevel]="formLevel" |
|||
[formModel]="$any(formModel)" |
|||
[formContext]="formContext" |
|||
[isComparing]="isComparing" |
|||
[isExpanded]="isExpanded" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-array-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Assets'"> |
|||
<sqx-assets-editor |
|||
[formControl]="$any(fieldForm)" |
|||
[folderId]="field.rawProperties.folderId" |
|||
[hasChatBot]="hasChatBot" |
|||
[isExpanded]="isExpanded"> |
|||
</sqx-assets-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Boolean'"> |
|||
<ng-container [ngSwitch]="field.rawProperties.editor"> |
|||
<ng-container *ngSwitchCase="'Toggle'"> |
|||
<sqx-toggle [formControl]="$any(fieldForm)" [threeStates]="!field.properties.isRequired"></sqx-toggle> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Checkbox'"> |
|||
<div class="form-check"> |
|||
<input class="form-check-input" type="checkbox" [formControl]="$any(fieldForm)" id="{{uniqueId}}" sqxIndeterminateValue [threeStates]="!field.properties.isRequired"> |
|||
<label class="form-check-label" for="{{uniqueId}}"></label> |
|||
</div> |
|||
</ng-container> |
|||
</ng-container> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Component'"> |
|||
<sqx-component |
|||
[form]="form" |
|||
[formContext]="formContext" |
|||
[formLevel]="formLevel" |
|||
[formModel]="$any(formModel)" |
|||
[isComparing]="isComparing" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-component> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Components'"> |
|||
<sqx-array-editor |
|||
[form]="form" |
|||
[formLevel]="formLevel" |
|||
[formModel]="$any(formModel)" |
|||
[formContext]="formContext" |
|||
[isComparing]="isComparing" |
|||
[isExpanded]="isExpanded" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages"> |
|||
</sqx-array-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'DateTime'"> |
|||
<sqx-date-time-editor [formControl]="$any(fieldForm)" [mode]="field.rawProperties.editor" enforceTime="true"></sqx-date-time-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Geolocation'"> |
|||
<sqx-geolocation-editor [formControl]="$any(fieldForm)"></sqx-geolocation-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Json'"> |
|||
<sqx-code-editor [formControl]="$any(fieldForm)" valueMode="Json" [height]="350"></sqx-code-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Number'"> |
|||
<ng-container [ngSwitch]="field.rawProperties.editor"> |
|||
<ng-container *ngSwitchCase="'Input'"> |
|||
<input class="form-control" type="number" [formControl]="$any(fieldForm)" [placeholder]="field.displayPlaceholder"> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Stars'"> |
|||
<sqx-stars [formControl]="$any(fieldForm)" [maximumStars]="field.rawProperties.maxValue"></sqx-stars> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Radio'"> |
|||
<sqx-radio-group [formControl]="$any(fieldForm)" [values]="field.rawProperties.allowedValues" unsorted="true"></sqx-radio-group> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Dropdown'"> |
|||
<select class="form-select" [formControl]="$any(fieldForm)"> |
|||
<option [ngValue]="null"></option> |
|||
<option *ngFor="let value of field.rawProperties.allowedValues" [ngValue]="value">{{value}}</option> |
|||
</select> |
|||
</ng-container> |
|||
</ng-container> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'References'"> |
|||
<ng-container [ngSwitch]="field.rawProperties.editor"> |
|||
<ng-container *ngSwitchCase="'List'"> |
|||
<sqx-references-editor |
|||
[allowDuplicates]="field.rawProperties.allowDuplicated" |
|||
[formContext]="formContext" |
|||
[formControl]="$any(fieldForm)" |
|||
[isExpanded]="isExpanded" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[query]="field.rawProperties.query" |
|||
[schemaIds]="field.rawProperties.schemaIds"> |
|||
</sqx-references-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Dropdown'"> |
|||
<sqx-reference-dropdown |
|||
mode="Array" |
|||
[formControl]="$any(fieldForm)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schemaId]="field.rawProperties.singleId"> |
|||
</sqx-reference-dropdown> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Input'"> |
|||
<sqx-reference-input |
|||
mode="Array" |
|||
[formControl]="$any(fieldForm)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[query]="field.rawProperties.query" |
|||
[schemaIds]="field.rawProperties.schemaIds"> |
|||
</sqx-reference-input> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Tags'"> |
|||
<sqx-references-tags |
|||
[formControl]="$any(fieldForm)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schemaId]="field.rawProperties.singleId"> |
|||
</sqx-references-tags> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Checkboxes'"> |
|||
<sqx-references-checkboxes |
|||
[formControl]="$any(fieldForm)" |
|||
[language]="language" |
|||
[schemaId]="field.rawProperties.singleId"> |
|||
</sqx-references-checkboxes> |
|||
</ng-container> |
|||
</ng-container> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'String'"> |
|||
<ng-container [ngSwitch]="field.rawProperties.editor"> |
|||
<ng-container *ngSwitchCase="'Input'"> |
|||
<input class="form-control" [formControl]="$any(fieldForm)" [placeholder]="field.displayPlaceholder"> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Slug'"> |
|||
<input class="form-control" [formControl]="$any(fieldForm)" [placeholder]="field.displayPlaceholder" sqxTransformInput="Slugify"> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'TextArea'"> |
|||
<textarea class="form-control" [formControl]="$any(fieldForm)" [placeholder]="field.displayPlaceholder" rows="5"></textarea> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'RichText'"> |
|||
<sqx-rich-editor #editor |
|||
mode="Html" |
|||
[annotations]="annotations | async" |
|||
(annotationsCreate)="annotationCreate($event)" |
|||
(annotationsSelect)="annotationsSelect($event)" |
|||
(annotationsUpdate)="annotationsUpdate($event)" |
|||
[classNames]="field.rawProperties.classNames" |
|||
[formControl]="$any(fieldForm)" |
|||
[folderId]="field.rawProperties.folderId" |
|||
[hasAnnotations]="!!comments" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schemaIds]="field.rawProperties.schemaIds"> |
|||
</sqx-rich-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Html'"> |
|||
<sqx-code-editor [formControl]="$any(fieldForm)" #editor mode="ace/mode/html" [height]="350" ></sqx-code-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Markdown'"> |
|||
<sqx-rich-editor #editor |
|||
mode="Markdown" |
|||
[annotations]="annotations | async" |
|||
(annotationsCreate)="annotationCreate($event)" |
|||
(annotationsSelect)="annotationsSelect($event)" |
|||
(annotationsUpdate)="annotationsUpdate($event)" |
|||
[classNames]="undefined" |
|||
[formControl]="$any(fieldForm)" |
|||
[folderId]="field.rawProperties.folderId" |
|||
[hasAnnotations]="!!comments" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schemaIds]="field.rawProperties.schemaIds"> |
|||
</sqx-rich-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'StockPhoto'"> |
|||
<sqx-stock-photo-editor [formControl]="$any(fieldForm)"></sqx-stock-photo-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Dropdown'"> |
|||
<select class="form-select" [formControl]="$any(fieldForm)"> |
|||
<option [ngValue]="null"></option> |
|||
<option *ngFor="let value of field.rawProperties.allowedValues" [ngValue]="value">{{value}}</option> |
|||
</select> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Radio'"> |
|||
<sqx-radio-group [formControl]="$any(fieldForm)" [values]="field.rawProperties.allowedValues" unsorted="true"></sqx-radio-group> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Color'"> |
|||
<sqx-color-picker [formControl]="$any(fieldForm)" [placeholder]="field.displayPlaceholder"></sqx-color-picker> |
|||
</ng-container> |
|||
</ng-container> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'RichText'"> |
|||
<sqx-rich-editor #editor |
|||
mode="State" |
|||
[annotations]="annotations | async" |
|||
(annotationsCreate)="annotationCreate($event)" |
|||
(annotationsSelect)="annotationsSelect($event)" |
|||
(annotationsUpdate)="annotationsUpdate($event)" |
|||
[classNames]="field.rawProperties.classNames" |
|||
[formControl]="$any(fieldForm)" |
|||
[folderId]="field.rawProperties.folderId" |
|||
[hasAnnotations]="!!comments" |
|||
[hasChatBot]="hasChatBot" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schemaIds]="field.rawProperties.schemaIds"> |
|||
</sqx-rich-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Tags'"> |
|||
<ng-container [ngSwitch]="field.rawProperties.editor"> |
|||
<ng-container *ngSwitchCase="'Tags'"> |
|||
<sqx-tag-editor [formControl]="$any(fieldForm)" [placeholder]="field.displayPlaceholder" [itemsSource]="field.rawProperties.allowedValues"></sqx-tag-editor> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Checkboxes'"> |
|||
<sqx-checkbox-group [formControl]="$any(fieldForm)" [values]="field.rawProperties.allowedValues"></sqx-checkbox-group> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Dropdown'"> |
|||
<select multiple class="form-select" [formControl]="$any(fieldForm)"> |
|||
<option *ngFor="let value of field.rawProperties.allowedValues" [ngValue]="value">{{value}}</option> |
|||
</select> |
|||
</ng-container> |
|||
</ng-container> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'UI'"> |
|||
<h4 class="ui-separator">{{field.displayName}}</h4> |
|||
</ng-container> |
|||
</ng-container> |
|||
</ng-template> |
|||
@if (field.properties.hints && field.properties.hints.length > 0) { |
|||
<sqx-form-hint> |
|||
<span inline="true" optional="true" [sqxMarkdown]="field.properties.hints"></span> |
|||
</sqx-form-hint> |
|||
} |
|||
</div> |
|||
} |
|||
|
|||
<sqx-form-hint *ngIf="field.properties.hints && field.properties.hints.length > 0"> |
|||
<span [sqxMarkdown]="field.properties.hints" optional="true" inline="true"></span> |
|||
</sqx-form-hint> |
|||
</div> |
|||
|
|||
<sqx-chat-dialog *sqxModal="chatDialog" |
|||
(contentSelect)="setValue($event)"> |
|||
</sqx-chat-dialog> |
|||
<sqx-chat-dialog (contentSelect)="setValue($event)" *sqxModal="chatDialog"></sqx-chat-dialog> |
|||
|
|||
@ -1,27 +1,25 @@ |
|||
<ng-container *ngIf="formModel.field.isLocalizable && languages.length > 1"> |
|||
<button *ngIf="!formModel.field.properties.isComplexUI" type="button" class="btn btn-sm btn-outline-secondary force no-focus-shadow" (click)="toggleShowAllControls()"> |
|||
<ng-container *ngIf="showAllControls; else singleLanguage"> |
|||
<span>{{ 'contents.languageModeSingle' | sqxTranslate }}</span> |
|||
</ng-container> |
|||
|
|||
<ng-template #singleLanguage> |
|||
<span>{{ 'contents.languageModeAll' | sqxTranslate }}</span> |
|||
</ng-template> |
|||
</button> |
|||
|
|||
<ng-container *ngIf="formModel.field.properties.isComplexUI || !showAllControls"> |
|||
@if (formModel.field.isLocalizable && languages.length > 1) { |
|||
@if (!formModel.field.properties.isComplexUI) { |
|||
<button class="btn btn-sm btn-outline-secondary force no-focus-shadow" (click)="toggleShowAllControls()" type="button"> |
|||
@if (showAllControls) { |
|||
<span>{{ "contents.languageModeSingle" | sqxTranslate }}</span> |
|||
} @else { |
|||
<span>{{ "contents.languageModeAll" | sqxTranslate }}</span> |
|||
} |
|||
</button> |
|||
} |
|||
@if (formModel.field.properties.isComplexUI || !showAllControls) { |
|||
<div class="button-container ms-1"> |
|||
<sqx-language-selector |
|||
size="sm" |
|||
[exists]="formModel.translationStatus | async" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
hintText="i18n:contents.validationHint" |
|||
hintAfter="120000" |
|||
hintPosition="top-end" |
|||
sqxTourStep="languages"> |
|||
</sqx-language-selector> |
|||
hintText="i18n:contents.validationHint" |
|||
[language]="language" |
|||
(languageChange)="languageChange.emit($event)" |
|||
[languages]="languages" |
|||
size="sm" |
|||
sqxTourStep="languages"></sqx-language-selector> |
|||
</div> |
|||
</ng-container> |
|||
</ng-container> |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,21 @@ |
|||
<div #container> |
|||
<div #inner [class.fullscreen]="snapshot.isFullscreen" [class.expanded]="isExpanded"> |
|||
<iframe #iframe [scrolling]="!isExpanded ? 'no' : 'yes'" width="100%" [style.height]="0" [attr.src]="computedUrl | sqxSafeResourceUrl"></iframe> |
|||
<div #inner [class.expanded]="isExpanded" [class.fullscreen]="snapshot.isFullscreen"> |
|||
<iframe |
|||
#iframe |
|||
[attr.src]="computedUrl | sqxSafeResourceUrl" |
|||
[scrolling]="!isExpanded ? 'no' : 'yes'" |
|||
[style.height]="0" |
|||
width="100%"></iframe> |
|||
</div> |
|||
</div> |
|||
|
|||
<sqx-asset-selector *sqxModal="assetsDialog" |
|||
(assetSelect)="pickAssets($event)"> |
|||
</sqx-asset-selector> |
|||
<sqx-asset-selector (assetSelect)="pickAssets($event)" *sqxModal="assetsDialog"></sqx-asset-selector> |
|||
|
|||
<sqx-content-selector *sqxModal="contentsDialog" |
|||
(contentSelect)="pickContents($event)" |
|||
<sqx-content-selector |
|||
[alreadySelectedIds]="contentsSelectedIds" |
|||
[query]="contentsQuery" |
|||
(contentSelect)="pickContents($event)" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[schemaIdentifiers]="contentsSchemas"> |
|||
</sqx-content-selector> |
|||
[query]="contentsQuery" |
|||
[schemaIdentifiers]="contentsSchemas" |
|||
*sqxModal="contentsDialog"></sqx-content-selector> |
|||
|
|||
@ -1,50 +1,64 @@ |
|||
|
|||
<div class="input-group"> |
|||
<button type="button" class="btn btn-outline-secondary" (click)="reset()" [disabled]="!valueControl.value"> |
|||
<button class="btn btn-outline-secondary" (click)="reset()" [disabled]="!valueControl.value" type="button"> |
|||
<i class="icon-close"></i> |
|||
</button> |
|||
|
|||
<button type="button" class="btn btn-outline-secondary" (click)="searchDialog.show()"> |
|||
<button class="btn btn-outline-secondary" (click)="searchDialog.show()" type="button"> |
|||
<i class="icon-search"></i> |
|||
</button> |
|||
|
|||
<input readonly [disabled]="true" class="form-control" [formControl]="valueControl"> |
|||
<input class="form-control" [disabled]="true" [formControl]="valueControl" readonly /> |
|||
</div> |
|||
|
|||
<div *ngIf="stockPhotoThumbnail | async; let url;" class="preview mt-1" [class.hidden-important]="snapshot.thumbnailStatus === 'Failed'"> |
|||
<img [src]="url" (error)="onThumbnailFailed()" (load)="onThumbnailLoaded()"> |
|||
|
|||
<sqx-loader color="white" *ngIf="snapshot.thumbnailStatus !== 'Loaded'"></sqx-loader> |
|||
</div> |
|||
@if (stockPhotoThumbnail | async; as url) { |
|||
<div class="preview mt-1" [class.hidden-important]="snapshot.thumbnailStatus === 'Failed'"> |
|||
<img (error)="onThumbnailFailed()" (load)="onThumbnailLoaded()" [src]="url" /> |
|||
@if (snapshot.thumbnailStatus !== "Loaded") { |
|||
<sqx-loader color="white"></sqx-loader> |
|||
} |
|||
</div> |
|||
} |
|||
|
|||
<sqx-modal-dialog *sqxModal="searchDialog" size="lg" fullHeight="true" (dialogClose)="searchDialog.hide()"> |
|||
<sqx-modal-dialog (dialogClose)="searchDialog.hide()" fullHeight="true" size="lg" *sqxModal="searchDialog"> |
|||
<ng-container title> |
|||
<input class="form-control search" [formControl]="stockPhotoSearch" sqxFocusOnInit placeholder="{{ 'contents.stockPhotoSearch' | sqxTranslate }}"> |
|||
|
|||
<sqx-loader *ngIf="snapshot.isLoading"></sqx-loader> |
|||
<input |
|||
class="form-control search" |
|||
[formControl]="stockPhotoSearch" |
|||
placeholder="{{ 'contents.stockPhotoSearch' | sqxTranslate }}" |
|||
sqxFocusOnInit /> |
|||
|
|||
@if (snapshot.isLoading) { |
|||
<sqx-loader></sqx-loader> |
|||
} |
|||
</ng-container> |
|||
|
|||
<ng-container content> |
|||
<div class="photos"> |
|||
<div *ngFor="let photo of snapshot.stockPhotos; trackBy: trackByPhoto" class="photo" [class.selected]="isSelected(photo)" (click)="selectPhoto(photo)"> |
|||
<img [src]="photo.thumbUrl"> |
|||
|
|||
<div class="photo-user"> |
|||
<a class="photo-user-link" [href]="photo.userProfileUrl" sqxExternalLink sqxStopClick> |
|||
{{photo.user}} |
|||
</a> |
|||
@for (photo of snapshot.stockPhotos; track photo.thumbUrl) { |
|||
<div class="photo" [class.selected]="isSelected(photo)" (click)="selectPhoto(photo)"> |
|||
<img [src]="photo.thumbUrl" /> |
|||
<div class="photo-user"> |
|||
<a class="photo-user-link" [href]="photo.userProfileUrl" sqxExternalLink sqxStopClick> |
|||
{{ photo.user }} |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="empty small text-muted text-center" *ngIf="snapshot.stockPhotos.length === 0"> |
|||
{{ 'contents.stockPhotoSearchEmpty' | sqxTranslate }} |
|||
} @empty { |
|||
<div class="empty small text-muted text-center"> |
|||
{{ "contents.stockPhotoSearchEmpty" | sqxTranslate }} |
|||
</div> |
|||
} |
|||
</div> |
|||
|
|||
<div class="mt-4 text-center" *ngIf="snapshot.hasMore"> |
|||
<button class="btn btn-outline-secondary" type="button" (click)="loadMore()" [disabled]="snapshot.isLoading"> |
|||
{{ 'common.loadMore' | sqxTranslate }} <sqx-loader *ngIf="snapshot.isLoading"></sqx-loader> |
|||
</button> |
|||
</div> |
|||
@if (snapshot.hasMore) { |
|||
<div class="mt-4 text-center"> |
|||
<button class="btn btn-outline-secondary" (click)="loadMore()" [disabled]="snapshot.isLoading" type="button"> |
|||
{{ "common.loadMore" | sqxTranslate }} |
|||
@if (snapshot.isLoading) { |
|||
<sqx-loader></sqx-loader> |
|||
} |
|||
</button> |
|||
</div> |
|||
} |
|||
</ng-container> |
|||
</sqx-modal-dialog> |
|||
|
|||
@ -1,79 +1,82 @@ |
|||
<tr [sqxTabRouterLink]="link"> |
|||
<td class="cell-select inline-edit" sqxStopClick> |
|||
<div class="form-check"> |
|||
<input class="form-check-input" type="checkbox" id="{{content.id}}_selected" |
|||
<input |
|||
class="form-check-input" |
|||
id="{{ content.id }}_selected" |
|||
[ngModel]="selected" |
|||
(ngModelChange)="selectedChange.emit($event)" /> |
|||
(ngModelChange)="selectedChange.emit($event)" |
|||
type="checkbox" /> |
|||
|
|||
<label class="form-check-label" for="{{content.id}}_selected" ></label> |
|||
<label class="form-check-label" for="{{ content.id }}_selected"></label> |
|||
</div> |
|||
|
|||
<ng-container *ngIf="isDirty"> |
|||
@if (isDirty) { |
|||
<div class="edit-menu"> |
|||
<button type="button" class="btn btn-text-secondary btn-cancel me-2" (click)="cancel()" sqxStopClick> |
|||
<button class="btn btn-text-secondary btn-cancel me-2" (click)="cancel()" sqxStopClick type="button"> |
|||
<i class="icon-close"></i> |
|||
</button> |
|||
|
|||
<button type="button" class="btn btn-success" (click)="save()" sqxStopClick> |
|||
<button class="btn btn-success" (click)="save()" sqxStopClick type="button"> |
|||
<i class="icon-checkmark"></i> |
|||
</button> |
|||
</div> |
|||
</ng-container> |
|||
} |
|||
</td> |
|||
|
|||
|
|||
<td class="cell-actions cell-actions-left" sqxStopClick> |
|||
<button type="button" class="btn btn-text-secondary" attr.aria-label="{{ 'common.options' | sqxTranslate }}" (click)="dropdown.toggle()" #buttonOptions> |
|||
<button |
|||
class="btn btn-text-secondary" |
|||
#buttonOptions |
|||
attr.aria-label="{{ 'common.options' | sqxTranslate }}" |
|||
(click)="dropdown.toggle()" |
|||
type="button"> |
|||
<i class="icon-dots"></i> |
|||
</button> |
|||
|
|||
<sqx-dropdown-menu *sqxModal="dropdown;closeAlways:true" [sqxAnchoredTo]="buttonOptions" scrollY="true" position="bottom-start"> |
|||
<a class="dropdown-item" [routerLink]="link" target="_blank" sqxExternalLink> |
|||
{{ 'common.editInNewTab' | sqxTranslate }} |
|||
<sqx-dropdown-menu position="bottom-start" scrollY="true" [sqxAnchoredTo]="buttonOptions" *sqxModal="dropdown; closeAlways: true"> |
|||
<a class="dropdown-item" [routerLink]="link" sqxExternalLink target="_blank"> |
|||
{{ "common.editInNewTab" | sqxTranslate }} |
|||
</a> |
|||
|
|||
<a class="dropdown-item" *ngFor="let info of content.statusUpdates" (click)="statusChange.emit(info.status)"> |
|||
{{ 'common.statusChangeTo' | sqxTranslate }} |
|||
@for (info of content.statusUpdates; track info) { |
|||
<a class="dropdown-item" (click)="statusChange.emit(info.status)"> |
|||
{{ "common.statusChangeTo" | sqxTranslate }} |
|||
<sqx-content-status layout="text" small="true" [status]="info.status" [statusColor]="info.color"></sqx-content-status> |
|||
</a> |
|||
} |
|||
@if (cloneable) { |
|||
<a class="dropdown-item" (click)="clone.emit(); dropdown.hide()"> |
|||
{{ "common.clone" | sqxTranslate }} |
|||
</a> |
|||
} |
|||
|
|||
<sqx-content-status |
|||
layout="text" |
|||
[status]="info.status" |
|||
[statusColor]="info.color" |
|||
small="true"> |
|||
</sqx-content-status> |
|||
</a> |
|||
<a class="dropdown-item" (click)="clone.emit(); dropdown.hide()" *ngIf="cloneable"> |
|||
{{ 'common.clone' | sqxTranslate }} |
|||
</a> |
|||
|
|||
<div class="dropdown-divider"></div> |
|||
|
|||
<a class="dropdown-item dropdown-item-delete" [class.disabled]="!content.canDelete" |
|||
(sqxConfirmClick)="delete.emit()" |
|||
confirmTitle="i18n:contents.deleteConfirmTitle" |
|||
<a |
|||
class="dropdown-item dropdown-item-delete" |
|||
[class.disabled]="!content.canDelete" |
|||
confirmRememberKey="deleteContent" |
|||
confirmText="i18n:contents.deleteConfirmText" |
|||
confirmRememberKey="deleteContent"> |
|||
{{ 'common.delete' | sqxTranslate }} |
|||
confirmTitle="i18n:contents.deleteConfirmTitle" |
|||
(sqxConfirmClick)="delete.emit()"> |
|||
{{ "common.delete" | sqxTranslate }} |
|||
</a> |
|||
</sqx-dropdown-menu> |
|||
</td> |
|||
|
|||
<td *ngFor="let field of tableFields" |
|||
sqxContentListCell |
|||
sqxContentListCellResize |
|||
[field]="field" |
|||
[fields]="tableSettings" |
|||
[sqxStopClick]="shouldStop(field)"> |
|||
<sqx-content-list-field |
|||
[content]="content" |
|||
[field]="field" |
|||
[fields]="tableSettings" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[patchAllowed]="patchAllowed" |
|||
[patchForm]="patchForm?.form" |
|||
[schema]="schema"> |
|||
</sqx-content-list-field> |
|||
</td> |
|||
@for (field of tableFields; track field) { |
|||
<td [field]="field" [fields]="tableSettings" sqxContentListCell sqxContentListCellResize [sqxStopClick]="shouldStop(field)"> |
|||
<sqx-content-list-field |
|||
[content]="content" |
|||
[field]="field" |
|||
[fields]="tableSettings" |
|||
[language]="language" |
|||
[languages]="languages" |
|||
[patchAllowed]="patchAllowed" |
|||
[patchForm]="patchForm?.form" |
|||
[schema]="schema"></sqx-content-list-field> |
|||
</td> |
|||
} |
|||
|
|||
<td></td> |
|||
</tr> |
|||
</tr> |
|||
|
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue