Browse Source

Fx flex replacements. Switch to tailwind.css.

pull/11858/head
Igor Kulikov 2 years ago
parent
commit
a289913476
  1. 3
      ui-ngx/package.json
  2. 44
      ui-ngx/src/app/modules/home/home.component.html
  3. 2
      ui-ngx/src/app/modules/home/menu/side-menu.component.html
  4. 2
      ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.html
  5. 5
      ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.ts
  6. 9
      ui-ngx/src/app/modules/login/pages/login/create-password.component.html
  7. 4
      ui-ngx/src/app/modules/login/pages/login/link-expired.component.html
  8. 14
      ui-ngx/src/app/modules/login/pages/login/login.component.html
  9. 9
      ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.html
  10. 9
      ui-ngx/src/app/modules/login/pages/login/reset-password.component.html
  11. 24
      ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.html
  12. 8
      ui-ngx/src/app/shared/components/breadcrumb.component.html
  13. 4
      ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html
  14. 14
      ui-ngx/src/app/shared/components/css.component.html
  15. 2
      ui-ngx/src/app/shared/components/dashboard-autocomplete.component.html
  16. 2
      ui-ngx/src/app/shared/components/dashboard-select-panel.component.html
  17. 4
      ui-ngx/src/app/shared/components/dashboard-select.component.html
  18. 2
      ui-ngx/src/app/shared/components/dialog/alert-dialog.component.html
  19. 2
      ui-ngx/src/app/shared/components/dialog/confirm-dialog.component.html
  20. 4
      ui-ngx/src/app/shared/components/dialog/entity-conflict-dialog/entity-conflict-dialog.component.html
  21. 2
      ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.html
  22. 8
      ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html
  23. 20
      ui-ngx/src/app/shared/components/dialog/node-script-test-dialog.component.html
  24. 2
      ui-ngx/src/app/shared/components/dialog/todo-dialog.component.html
  25. 2
      ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.html
  26. 6
      ui-ngx/src/app/shared/components/entity/entity-list-select.component.html
  27. 2
      ui-ngx/src/app/shared/components/entity/entity-subtype-select.component.html
  28. 2
      ui-ngx/src/app/shared/components/footer-fab-buttons.component.html
  29. 5
      ui-ngx/src/app/shared/components/grid/scroll-grid.component.html
  30. 14
      ui-ngx/src/app/shared/components/html.component.html
  31. 7
      ui-ngx/src/app/shared/components/image/embed-image-dialog.component.html
  32. 2
      ui-ngx/src/app/shared/components/image/image-dialog.component.html
  33. 94
      ui-ngx/src/app/shared/components/image/image-gallery.component.html
  34. 14
      ui-ngx/src/app/shared/components/image/image-gallery.component.scss
  35. 5
      ui-ngx/src/app/shared/components/image/image-gallery.component.ts
  36. 8
      ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.html
  37. 14
      ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.html
  38. 4
      ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html
  39. 18
      ui-ngx/src/app/shared/components/js-func.component.html
  40. 14
      ui-ngx/src/app/shared/components/json-content.component.html
  41. 18
      ui-ngx/src/app/shared/components/json-object-edit.component.html
  42. 6
      ui-ngx/src/app/shared/components/json-object-view.component.html
  43. 20
      ui-ngx/src/app/shared/components/kv-map.component.html
  44. 4
      ui-ngx/src/app/shared/components/logo.component.html
  45. 18
      ui-ngx/src/app/shared/components/markdown-editor.component.html
  46. 2
      ui-ngx/src/app/shared/components/markdown.component.html
  47. 6
      ui-ngx/src/app/shared/components/material-icon-select.component.html
  48. 10
      ui-ngx/src/app/shared/components/material-icons.component.html
  49. 12
      ui-ngx/src/app/shared/components/multiple-image-input.component.html
  50. 16
      ui-ngx/src/app/shared/components/notification/notification.component.html
  51. 2
      ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.html
  52. 12
      ui-ngx/src/app/shared/components/protobuf-content.component.html
  53. 6
      ui-ngx/src/app/shared/components/script-lang.component.html
  54. 27
      ui-ngx/src/app/shared/components/snack-bar-component.html
  55. 3
      ui-ngx/src/app/shared/components/socialshare-panel.component.html
  56. 2
      ui-ngx/src/app/shared/components/string-autocomplete.component.html
  57. 2
      ui-ngx/src/app/shared/components/string-items-list.component.html
  58. 14
      ui-ngx/src/app/shared/components/svg-xml.component.html
  59. 4
      ui-ngx/src/app/shared/components/time/datapoints-limit.component.html
  60. 2
      ui-ngx/src/app/shared/components/time/datetime.component.html
  61. 4
      ui-ngx/src/app/shared/components/time/quick-time-interval.component.html
  62. 4
      ui-ngx/src/app/shared/components/time/timeinterval.component.html
  63. 4
      ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.html
  64. 10
      ui-ngx/src/app/shared/components/time/timewindow-panel.component.html
  65. 4
      ui-ngx/src/app/shared/components/time/timewindow.component.html
  66. 2
      ui-ngx/src/app/shared/components/time/timezone-select.component.html
  67. 2
      ui-ngx/src/app/shared/components/time/timezone.component.html
  68. 4
      ui-ngx/src/app/shared/components/unit-input.component.html
  69. 6
      ui-ngx/src/app/shared/components/user-menu.component.html
  70. 14
      ui-ngx/src/app/shared/components/value-input.component.html
  71. 2
      ui-ngx/src/app/shared/components/widgets-bundle-search.component.html
  72. 78
      ui-ngx/src/styles.scss
  73. 67
      ui-ngx/tailwind.config.js
  74. 189
      ui-ngx/yarn.lock

3
ui-ngx/package.json

@ -147,6 +147,7 @@
"@typescript-eslint/eslint-plugin": "^8.7.0",
"@typescript-eslint/parser": "^8.7.0",
"@typescript-eslint/utils": "^8.7.0",
"autoprefixer": "^10.4.20",
"compression-webpack-plugin": "^11.1.0",
"directory-tree": "^3.5.2",
"eslint": "~8.57.1",
@ -155,8 +156,10 @@
"eslint-plugin-prefer-arrow": "latest",
"ngrx-store-freeze": "^0.2.4",
"patch-package": "^8.0.0",
"postcss": "^8.4.47",
"postinstall-prepare": "^2.0.0",
"raw-loader": "^4.0.2",
"tailwindcss": "^3.4.13",
"ts-node": "^10.9.2",
"typescript": "~5.5.4",
"webpack": "5.95.0"

44
ui-ngx/src/app/modules/home/home.component.html

@ -23,50 +23,58 @@
[opened]="sidenavOpened && !forceFullscreen">
<header class="tb-nav-header">
<mat-toolbar color="primary" class="tb-nav-header-toolbar">
<div fxFlex="auto" fxLayout="row">
<div class="flex flex-auto">
<img [src]="logo"
aria-label="logo" class="tb-logo-title"/>
</div>
</mat-toolbar>
</header>
<mat-toolbar color="primary" fxFlex="0%" class="tb-side-menu-toolbar" fxLayout="column" role="navigation">
<mat-toolbar color="primary" class="flex flex-1 flex-col tb-side-menu-toolbar" role="navigation">
<tb-side-menu></tb-side-menu>
</mat-toolbar>
</mat-sidenav>
<mat-sidenav-content>
<div fxLayout="column" role="main" style="height: 100%;">
<mat-toolbar fxLayout="row" color="primary" class="tb-primary-toolbar">
<button [fxShow]="!forceFullscreen" mat-icon-button id="main"
[ngClass]="{'tb-invisible': displaySearchMode()}"
fxHide.gt-sm (click)="sidenav.toggle()">
<div class="flex flex-col" role="main" style="height: 100%;">
<mat-toolbar color="primary" class="tb-primary-toolbar flex flex-row">
<button [class]="{
'!hidden': forceFullscreen,
'tb-invisible': displaySearchMode()
}"
class="gt-sm:hidden" (click)="sidenav.toggle()">
<mat-icon class="material-icons">menu</mat-icon>
</button>
<button [fxShow]="forceFullscreen" mat-icon-button
[ngClass]="{'tb-invisible': displaySearchMode()}"
<button mat-icon-button
[class]="{
'!hidden': !forceFullscreen,
'tb-invisible': displaySearchMode()
}"
(click)="goBack()">
<mat-icon class="material-icons">arrow_back</mat-icon>
</button>
<button mat-icon-button
[ngClass]="{'tb-invisible': !displaySearchMode()}"
[class.tb-invisible]="!displaySearchMode()"
(click)="closeSearch()">
<mat-icon class="material-icons">arrow_back</mat-icon>
</button>
<tb-breadcrumb [fxShow]="!displaySearchMode()"
fxFlex class="mat-toolbar-tools">
<tb-breadcrumb
[class.!hidden]="displaySearchMode()"
class="mat-toolbar-tools flex-1">
</tb-breadcrumb>
<div [fxShow]="displaySearchMode()" fxFlex fxLayout="row" class="tb-dark">
<mat-form-field fxFlex class="tb-appearance-transparent">
<div [class.!hidden]="!displaySearchMode()" class="tb-dark flex-1 flex flex-row">
<mat-form-field class="tb-appearance-transparent flex-1">
<input #searchInput matInput
[formControl]="textSearch"
placeholder="{{ 'common.enter-search' | translate }}"/>
</mat-form-field>
</div>
<button [fxShow]="searchEnabled"
<button [class.!hidden]="!searchEnabled"
mat-icon-button (click)="openSearch()">
<mat-icon class="material-icons">search</mat-icon>
</button>
<button *ngIf="fullscreenEnabled" [fxShow]="!displaySearchMode()"
mat-icon-button fxHide.lt-md (click)="toggleFullscreen()">
<button *ngIf="fullscreenEnabled"
[class.!hidden]="displaySearchMode()"
class="lt-md:!hidden"
mat-icon-button (click)="toggleFullscreen()">
<mat-icon class="material-icons">{{ isFullscreen() ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
</button>
<tb-notification-bell></tb-notification-bell>
@ -75,7 +83,7 @@
<mat-progress-bar color="warn" style="z-index: 10; margin-bottom: -4px; width: 100%;" mode="indeterminate"
*ngIf="!hideLoadingBar && (isLoading$ | async)">
</mat-progress-bar>
<div fxFlex fxLayout="column" tb-toast class="tb-main-content">
<div tb-toast class="tb-main-content flex flex-1 flex-col">
<router-outlet (activate)="activeComponentChanged($event)"></router-outlet>
</div>
</div>

2
ui-ngx/src/app/modules/home/menu/side-menu.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<ul fxFlex fxLayout="column" fxLayoutAlign="start stretch" class="tb-side-menu">
<ul class="tb-side-menu flex flex-col justify-start items-stretch">
<li *ngFor="let section of menuSections$ | async; trackBy: trackByMenuSection" [ngSwitch]="section.type === 'link'">
<tb-menu-link *ngSwitchCase="true" [section]="section"></tb-menu-link>
<tb-menu-toggle *ngSwitchCase="false" [section]="section"></tb-menu-toggle>

2
ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.html

@ -70,7 +70,7 @@
</button>
</div>
<tb-toggle-select appearance="fill"
[disabled]="!svgContentFormControl.valid"
[disabled]="!readonly && !svgContentFormControl.valid"
fillHeight
extraPadding
primaryBackground

5
ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol-editor.component.ts

@ -110,6 +110,11 @@ export class ScadaSymbolEditorComponent implements OnInit, OnDestroy, AfterViewI
}
ngOnInit(): void {
if (this.readonly) {
this.svgContentFormControl.disable({emitEvent: false});
} else {
this.svgContentFormControl.enable({emitEvent: false});
}
this.svgContentFormControl.valueChanges.subscribe((svgContent) => {
if (this.svgContent !== svgContent) {
this.svgContent = svgContent;

9
ui-ngx/src/app/modules/login/pages/login/create-password.component.html

@ -15,8 +15,8 @@
limitations under the License.
-->
<div class="tb-create-password-content mat-app-background tb-dark" fxLayout="row" fxLayoutAlign="center center" style="width: 100%;">
<mat-card appearance="raised" fxFlex="initial" class="tb-create-password-card">
<div class="tb-create-password-content mat-app-background tb-dark flex flex-row justify-center items-center" style="width: 100%;">
<mat-card appearance="raised" class="tb-create-password-card flex-initial">
<mat-card-header>
<mat-card-title class="layout-padding">
<span translate class="mat-headline-5">login.create-password</span>
@ -28,7 +28,7 @@
<mat-card-content>
<form [formGroup]="createPassword" (ngSubmit)="onCreatePassword()">
<fieldset [disabled]="isLoading$ | async">
<div tb-toast fxLayout="column" class="layout-padding">
<div tb-toast class="layout-padding flex flex-col">
<span style="height: 50px;"></span>
<mat-form-field class="mat-block tb-appearance-transparent">
<mat-label translate>common.password</mat-label>
@ -42,8 +42,7 @@
<mat-icon class="material-icons" matPrefix>lock</mat-icon>
<tb-toggle-password matSuffix></tb-toggle-password>
</mat-form-field>
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap="16px" fxLayoutAlign="start center"
fxLayoutAlign.gt-xs="center start">
<div class="flex flex-col gap-4 justify-start items-center gt-xs:flex-row gt-xs:justify-center gt-xs:items-start">
<button mat-raised-button color="accent" type="submit" [disabled]="(isLoading$ | async)">
{{ 'login.create-password' | translate }}
</button>

4
ui-ngx/src/app/modules/login/pages/login/link-expired.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<div class="tb-expired-link-content mat-app-background tb-dark tb-flex row center align-center"
<div class="tb-expired-link-content mat-app-background tb-dark flex flex-row justify-center items-center"
style="width: 100%;">
<mat-card appearance="raised" class="tb-expired-link-card">
<mat-card-header style="justify-content: center">
@ -29,7 +29,7 @@
<mat-card-content style="padding: 24px 16px">
<div>{{ message | translate }}</div>
</mat-card-content>
<mat-card-actions class="tb-flex row center">
<mat-card-actions class="flex flex-row justify-center">
<button mat-raised-button color="accent"
[disabled]="(isLoading$ | async)"
(click)="navigateToLoginPage()">

14
ui-ngx/src/app/modules/login/pages/login/login.component.html

@ -15,20 +15,20 @@
limitations under the License.
-->
<div class="tb-login-content mat-app-background tb-dark" fxFlex fxLayoutAlign="center center">
<div class="tb-login-content mat-app-background tb-dark flex flex-1 items-center justify-center">
<mat-card appearance="raised" style="max-height: 80vh; overflow-y: auto;">
<mat-card-content>
<form class="tb-login-form" [formGroup]="loginFormGroup" (ngSubmit)="login()">
<fieldset fxLayout="column">
<div fxLayout="column" fxLayoutAlign="start center" style="padding: 15px 0;">
<fieldset class="flex flex-col">
<div class="flex flex-col items-center justify-start" style="padding: 15px 0;">
<tb-logo class="login-logo"></tb-logo>
</div>
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<span style="height: 4px;" *ngIf="!(isLoading$ | async)"></span>
<div tb-toast fxLayout="column" class="layout-padding">
<div tb-toast class="layout-padding flex flex-col">
<span style="height: 50px;"></span>
<div class="oauth-container tb-default" fxLayout="column" fxLayoutGap="16px" *ngIf="oauth2Clients?.length">
<div class="oauth-container tb-default flex flex-col gap-4" *ngIf="oauth2Clients?.length">
<ng-container *ngFor="let oauth2Client of oauth2Clients">
<a mat-raised-button class="login-with-button" href="{{ getOAuth2Uri(oauth2Client) }}">
<mat-icon class="icon" svgIcon="{{ oauth2Client.icon }}"></mat-icon>
@ -55,12 +55,12 @@
<tb-toggle-password matSuffix></tb-toggle-password>
<mat-icon matPrefix>lock</mat-icon>
</mat-form-field>
<div fxLayoutAlign="end center" class="forgot-password">
<div class="forgot-password flex items-center justify-end">
<button class="tb-reset-password" mat-button type="button" routerLink="/login/resetPasswordRequest">
{{ (passwordViolation ? 'login.reset-password' : 'login.forgot-password') | translate }}
</button>
</div>
<div fxLayout="column" class="tb-action-button">
<div class="tb-action-button flex flex-col">
<button mat-raised-button color="accent" [disabled]="(isLoading$ | async)"
type="submit">{{ 'login.login' | translate }}</button>
</div>

9
ui-ngx/src/app/modules/login/pages/login/reset-password-request.component.html

@ -15,9 +15,9 @@
limitations under the License.
-->
<div class="tb-request-password-reset-content mat-app-background tb-dark" fxLayout="row" fxLayoutAlign="center center"
<div class="tb-request-password-reset-content mat-app-background tb-dark flex flex-row items-center justify-center"
style="width: 100%;">
<mat-card appearance="raised" fxFlex="initial" class="tb-request-password-reset-card">
<mat-card appearance="raised" class="tb-request-password-reset-card flex flex-initial">
<mat-card-header>
<mat-card-title class="layout-padding">
<span translate class="mat-headline-5">login.request-password-reset</span>
@ -29,7 +29,7 @@
<mat-card-content>
<form [formGroup]="requestPasswordRequest" (ngSubmit)="sendResetPasswordLink()">
<fieldset [disabled]="isLoading$ | async">
<div tb-toast fxLayout="column" class="layout-padding">
<div tb-toast class="layout-padding flex flex-col">
<span style="height: 50px;"></span>
<mat-form-field class="mat-block tb-appearance-transparent" hideRequiredMarker>
<mat-label translate>login.email</mat-label>
@ -39,8 +39,7 @@
{{ 'user.invalid-email-format' | translate }}
</mat-error>
</mat-form-field>
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap="16px" fxLayoutAlign="start center"
fxLayoutAlign.gt-xs="center start">
<div class="flex flex-col gap-4 justify-start items-center gt-xs:flex-row gt-xs:justify-center gt-xs:items-start">
<button mat-raised-button color="accent" type="submit" [disabled]="(isLoading$ | async) || this.clicked">
{{ 'login.request-password-reset' | translate }}
</button>

9
ui-ngx/src/app/modules/login/pages/login/reset-password.component.html

@ -15,8 +15,8 @@
limitations under the License.
-->
<div class="tb-reset-password-content mat-app-background tb-dark" fxLayout="row" fxLayoutAlign="center center" style="width: 100%;">
<mat-card appearance="raised" fxFlex="initial" class="tb-reset-password-card">
<div class="tb-reset-password-content mat-app-background tb-dark flex flex-row justify-center items-center" style="width: 100%;">
<mat-card appearance="raised" class="tb-reset-password-card flex-initial">
<mat-card-header>
<mat-card-title class="layout-padding tb-card-title">
<span translate class="mat-headline-5 tb-card-title">login.password-reset</span>
@ -31,7 +31,7 @@
<mat-card-content>
<form [formGroup]="resetPassword" (ngSubmit)="onResetPassword()">
<fieldset [disabled]="isLoading$ | async">
<div tb-toast fxLayout="column" class="layout-padding">
<div tb-toast class="layout-padding flex flex-col">
<span style="height: 50px;"></span>
<mat-form-field class="mat-block tb-appearance-transparent">
<mat-label translate>login.new-password</mat-label>
@ -45,8 +45,7 @@
<mat-icon class="material-icons" matPrefix>lock</mat-icon>
<tb-toggle-password matSuffix></tb-toggle-password>
</mat-form-field>
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap="16px" fxLayoutAlign="start center"
fxLayoutAlign.gt-sm="center start">
<div class="flex flex-col gap-4 justify-start items-center gt-sm:flex-row gt-sm:justify-center gt-sm:items-start">
<button mat-raised-button color="accent" type="submit" [disabled]="(isLoading$ | async)">
{{ 'login.reset-password' | translate }}
</button>

24
ui-ngx/src/app/modules/login/pages/login/two-factor-auth-login.component.html

@ -15,11 +15,11 @@
limitations under the License.
-->
<div class="tb-two-factor-auth-login-content mat-app-background tb-dark" fxLayout="row" fxLayoutAlign="center center"
<div class="tb-two-factor-auth-login-content mat-app-background tb-dark flex flex-row justify-center items-center"
style="width: 100%;">
<mat-card appearance="raised" fxFlex="initial" class="tb-two-factor-auth-login-card" >
<mat-card appearance="raised" class="tb-two-factor-auth-login-card flex-initial">
<mat-card-header>
<mat-card-title class="mat-headline-5" fxLayout="row" fxLayoutAlign="start center">
<mat-card-title class="mat-headline-5 flex flex-row justify-start items-center">
<button mat-icon-button type="button" (click)="cancelLogin()">
<mat-icon>chevron_left</mat-icon>
</button>
@ -27,7 +27,7 @@
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="providers-container tb-default" fxLayout="column" fxLayoutGap="8px" *ngIf="!selectedProvider">
<div class="providers-container tb-default flex flex-col gap-2" *ngIf="!selectedProvider">
<p class="mat-body" translate>login.select-way-to-verify</p>
<ng-container *ngFor="let provider of allowProviders">
<button type="button" mat-stroked-button class="provider" (click)="selectProvider(provider)">
@ -38,10 +38,10 @@
</div>
<form [formGroup]="verificationForm" (ngSubmit)="sendVerificationCode()" *ngIf="selectedProvider">
<fieldset [disabled]="isLoading$ | async">
<div tb-toast fxLayout="column">
<div tb-toast class="flex flex-col">
<p class="mat-body">{{ providerDescription }}</p>
<div fxLayout="row" class="code-block" fxLayoutGap="8px">
<mat-form-field class="mat-block tb-appearance-transparent" fxFlex>
<div class="code-block flex flex-row gap-2">
<mat-form-field class="mat-block tb-appearance-transparent flex-1">
<input matInput formControlName="verificationCode"
required [maxlength]="maxLengthInput" type="text"
[attr.inputmode]="inputMode" [pattern]="pattern"
@ -69,19 +69,19 @@
{{ 'action.continue' | translate }}
</button>
<span style="height: 16px;"></span>
<div fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="8px" class="action-row">
<div *ngIf="showResendAction" fxFlex fxLayoutAlign="center center" class="action-resend">
<div class="action-row flex flex-row justify-between items-center gap-2">
<div *ngIf="showResendAction" class="action-resend flex flex-1 justify-center items-center">
<div *ngIf="countDownTime" class="timer">
{{ 'login.resend-code-wait' | translate : {time: countDownTime} }}
</div>
<button [fxShow]="!hideResendButton"
mat-button fxFlex
<button mat-button class="flex-1"
[class.!hidden]="hideResendButton"
(click)="sendCode($event)"
type="button">
{{ 'login.resend-code' | translate }}
</button>
</div>
<button mat-button fxFlex
<button mat-button class="flex-1"
type="button"
*ngIf="allowProviders.length > 1"
(click)="selectProvider(null)">

8
ui-ngx/src/app/shared/components/breadcrumb.component.html

@ -15,11 +15,11 @@
limitations under the License.
-->
<div fxFlex class="tb-breadcrumb" fxLayout="row">
<h1 fxFlex fxHide.gt-sm *ngIf="lastBreadcrumb$ | async; let breadcrumb">
<div class="tb-breadcrumb flex flex-1 flex-row">
<h1 class="flex-1 gt-sm:!hidden" *ngIf="lastBreadcrumb$ | async; let breadcrumb">
{{ breadcrumb.labelFunction ? breadcrumb.labelFunction() : (breadcrumb.customTranslate ? (breadcrumb.label | customTranslate) : (breadcrumb.label | translate)) }}
</h1>
<span fxHide.lt-md fxLayout="row" *ngFor="let breadcrumb of breadcrumbs$ | async; trackBy: trackByBreadcrumbs; last as isLast;" [ngSwitch]="isLast">
<span class="flex flex-row lt-md:!hidden" *ngFor="let breadcrumb of breadcrumbs$ | async; trackBy: trackByBreadcrumbs; last as isLast;" [ngSwitch]="isLast">
<a *ngSwitchCase="false" [routerLink]="breadcrumb.link" [queryParams]="breadcrumb.queryParams">
<ng-container
*ngTemplateOutlet="breadcrumbWithIcon;context:{breadcrumb: breadcrumb}">
@ -30,7 +30,7 @@
*ngTemplateOutlet="breadcrumbWithIcon;context:{breadcrumb: breadcrumb}">
</ng-container>
</span>
<span class="divider" [fxHide]="isLast"> > </span>
<span class="divider" [class.!hidden]="isLast"> > </span>
</span>
</div>
<ng-template #breadcrumbWithIcon let-breadcrumb="breadcrumb">

4
ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html

@ -26,8 +26,8 @@
[disabled]="!colorPickerControl.value">
{{ 'action.clear' | translate }}
</button>
<span fxFlex></span>
<div fxLayoutGap="8px">
<span class="flex-1"></span>
<div class="flex flex-row gap-2">
<button *ngIf="colorCancelButton"
mat-button
type="button"

14
ui-ngx/src/app/shared/components/css.component.html

@ -15,12 +15,12 @@
limitations under the License.
-->
<div class="tb-css" style="background: #fff;" [ngClass]="{'tb-disabled': disabled, 'fill-height': fillHeight}"
<div class="tb-css flex flex-col" style="background: #fff;" [class]="{'tb-disabled': disabled, 'fill-height': fillHeight}"
tb-fullscreen
[fullscreen]="fullscreen" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;" class="tb-css-toolbar">
<label class="tb-title no-padding" [ngClass]="{'tb-error': !disabled && (hasErrors || required && !modelValue), 'tb-required': !disabled && required}">{{ label }}</label>
<span fxFlex></span>
[fullscreen]="fullscreen">
<div style="height: 40px;" class="tb-css-toolbar flex flex-row justify-start items-center">
<label class="tb-title no-padding" [class]="{'tb-error': !disabled && (hasErrors || required && !modelValue), 'tb-required': !disabled && required}">{{ label }}</label>
<span class="flex-1"></span>
<button type='button' *ngIf="!disabled" mat-button class="tidy" (click)="beautifyCss()">
{{'js-func.tidy' | translate }}
</button>
@ -35,7 +35,7 @@
</div>
</fieldset>
</div>
<div id="tb-css-panel" class="tb-css-content-panel" fxLayout="column">
<div #cssEditor id="tb-css-input" [ngClass]="{'fill-height': fillHeight}"></div>
<div id="tb-css-panel" class="tb-css-content-panel flex flex-col">
<div #cssEditor id="tb-css-input" [class.fill-height]="fillHeight"></div>
</div>
</div>

2
ui-ngx/src/app/shared/components/dashboard-autocomplete.component.html

@ -30,7 +30,7 @@
(focusin)="onFocus()"
[required]="required"
[matAutocomplete]="dashboardAutocomplete"
[fxShow]="!useDashboardLink || !disabled || !selectDashboardFormGroup.get('dashboard').value">
[class.!hidden]="useDashboardLink && disabled && selectDashboardFormGroup.get('dashboard').value">
<a *ngIf="useDashboardLink && selectDashboardFormGroup.get('dashboard').value && disabled" aria-label="Open device profile" [routerLink]=dashboardURL>
{{ displayDashboardFn(selectDashboardFormGroup.get('dashboard').value) | customTranslate }}
</a>

2
ui-ngx/src/app/shared/components/dashboard-select-panel.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<div fxLayout="column" class="mat-content mat-padding">
<div class="mat-content mat-padding flex flex-col">
<mat-form-field>
<mat-label>{{'dashboard.select-dashboard' | translate}}</mat-label>
<mat-select matInput [(ngModel)]="dashboardId"

4
ui-ngx/src/app/shared/components/dashboard-select.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<mat-select fxHide.lt-lg
<mat-select class="lt-lg:!hidden"
[required]="required"
[disabled]="disabled"
[(ngModel)]="dashboardId"
@ -24,7 +24,7 @@
{{dashboard.title}}
</mat-option>
</mat-select>
<section fxHide.gt-md class="tb-dashboard-select">
<section class="tb-dashboard-select gt-md:!hidden">
<button mat-icon-button
cdkOverlayOrigin #dashboardSelectPanelOrigin="cdkOverlayOrigin"
(click)="openDashboardSelectPanel()"

2
ui-ngx/src/app/shared/components/dialog/alert-dialog.component.html

@ -22,6 +22,6 @@
<ng-template #htmlMode>
<div mat-dialog-content [innerHTML]="data.message | safe:'html'"></div>
</ng-template>
<div mat-dialog-actions fxLayoutAlign="end center">
<div mat-dialog-actions class="flex justify-end items-center">
<button mat-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>{{data.ok}}</button>
</div>

2
ui-ngx/src/app/shared/components/dialog/confirm-dialog.component.html

@ -17,7 +17,7 @@
-->
<h2 mat-dialog-title>{{data.title}}</h2>
<div mat-dialog-content [innerHTML]="data.message | safe: 'html'"></div>
<div mat-dialog-actions fxLayoutAlign="end center">
<div mat-dialog-actions class="flex justify-end items-center">
<button mat-button color="primary" [mat-dialog-close]="false">{{data.cancel}}</button>
<button mat-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>{{data.ok}}</button>
</div>

4
ui-ngx/src/app/shared/components/dialog/entity-conflict-dialog/entity-conflict-dialog.component.html

@ -19,7 +19,7 @@
<h2 class="main-label">
{{ data.message }}
</h2>
<span fxFlex></span>
<span class="flex-1"></span>
<button mat-icon-button
(click)="onCancel()"
type="button">
@ -36,7 +36,7 @@
<span>{{ 'entity.version-conflict.message' | translate }}</span>
</div>
</div>
<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
<div mat-dialog-actions class="flex flex-row justify-end items-center">
<button mat-button color="primary"
type="button"
(click)="onDiscard()"

2
ui-ngx/src/app/shared/components/dialog/error-alert-dialog.component.html

@ -25,6 +25,6 @@
<small class="error-details-content" [innerHTML]="errorDetails"></small>
</mat-expansion-panel>
</div>
<div mat-dialog-actions fxLayoutAlign="end center">
<div mat-dialog-actions class="flex justify-end items-center">
<button mat-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>{{data.ok}}</button>
</div>

8
ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html

@ -16,9 +16,9 @@
-->
<form [formGroup]="jsonFormGroup" (ngSubmit)="add()" style="min-width: 400px;">
<mat-toolbar fxLayout="row" color="primary">
<mat-toolbar class="flex flex-row" color="primary">
<h2>{{ title }}</h2>
<span fxFlex></span>
<span class="flex-1"></span>
<button mat-icon-button
(click)="cancel()"
type="button">
@ -38,8 +38,8 @@
</tb-json-object-edit>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
<span fxFlex></span>
<div mat-dialog-actions class="flex flex-row justify-end items-center">
<span class="flex-1"></span>
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"

20
ui-ngx/src/app/shared/components/dialog/node-script-test-dialog.component.html

@ -17,16 +17,16 @@
-->
<form class="tb-node-script-test-dialog"
[formGroup]="nodeScriptTestFormGroup" (ngSubmit)="save()">
<mat-toolbar fxLayout="row" color="primary">
<mat-toolbar class="flex flex-row" color="primary">
<h2>{{ 'rulenode.test-script-function' | translate }} ({{ (scriptLang === scriptLanguage.JS ? 'rulenode.script-lang-java-script' : 'rulenode.script-lang-tbel') | translate }})</h2>
<span fxFlex></span>
<span class="flex-1"></span>
<button mat-icon-button
(click)="cancel()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
</button>
</mat-toolbar>
<div mat-dialog-content fxFlex style="position: relative;">
<div mat-dialog-content class="flex-1" style="position: relative;">
<div class="tb-absolute-fill">
<div #topPanel class="tb-split tb-split-vertical">
<div #topLeftPanel class="tb-split tb-content">
@ -34,8 +34,8 @@
<div class="tb-editor-area-title-panel">
<label translate>rulenode.message</label>
</div>
<div formGroupName="payload" fxLayout="column" style="height: 100%;">
<div fxLayout="row">
<div formGroupName="payload" class="flex flex-col" style="height: 100%;">
<div class="flex flex-row">
<tb-message-type-autocomplete
style="margin-bottom: 0; min-width: 300px;"
formControlName="msgType"
@ -44,7 +44,7 @@
</div>
<tb-json-content
#payloadContent
fxFlex
class="flex-1"
formControlName="msg"
label="{{ 'rulenode.message' | translate }}"
[contentType]="contentTypes.JSON"
@ -70,7 +70,7 @@
<div #bottomPanel class="tb-split tb-split-vertical">
<div #bottomLeftPanel class="tb-split tb-content">
<div class="tb-resize-container">
<div class="tb-editor-area-title-panel tb-js-function" [ngClass]="{'tb-js-function-help': data.helpId}">
<div class="tb-editor-area-title-panel tb-js-function" [class.tb-js-function-help]="data.helpId">
<label>{{ functionTitle }}</label>
</div>
<tb-js-func
@ -92,7 +92,7 @@
<label translate>rulenode.output</label>
</div>
<tb-json-content
fxFlex
class="flex-1"
formControlName="output"
label="{{ 'rulenode.output' | translate }}"
[contentType]="contentTypes.JSON"
@ -105,14 +105,14 @@
</div>
</div>
</div>
<div mat-dialog-actions fxLayout="row">
<div mat-dialog-actions class="flex flex-row">
<button mat-button mat-raised-button color="primary"
type="button"
(click)="test()"
[disabled]="(isLoading$ | async) || nodeScriptTestFormGroup.invalid">
{{ 'rulenode.test' | translate }}
</button>
<span fxFlex></span>
<span class="flex-1"></span>
<button mat-button color="primary"
type="button"
cdkFocusInitial

2
ui-ngx/src/app/shared/components/dialog/todo-dialog.component.html

@ -19,6 +19,6 @@
<div mat-dialog-content>
<h1>COMING SOON!</h1>
</div>
<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
<div mat-dialog-actions class="flex flex-row justify-end items-center">
<button mat-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>Ok</button>
</div>

2
ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.html

@ -23,7 +23,7 @@
(focusin)="onFocus()"
[required]="required"
[matAutocomplete]="entityAutocomplete"
[fxShow]="!disabled || !selectEntityFormGroup.get('entity').value">
[class.!hidden]="disabled && selectEntityFormGroup.get('entity').value">
<a *ngIf="selectEntityFormGroup.get('entity').value && disabled" aria-label="Open device profile" [routerLink]=entityURL>
{{ displayEntityFn(selectEntityFormGroup.get('entity').value) }}
</a>

6
ui-ngx/src/app/shared/components/entity/entity-list-select.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<div fxLayout="row" class="tb-entity-list-select" [formGroup]="entityListSelectFormGroup">
<div class="tb-entity-list-select flex flex-row" [formGroup]="entityListSelectFormGroup">
<tb-entity-type-select
style="min-width: 100px; padding-right: 8px;"
*ngIf="displayEntityTypeSelect"
@ -26,8 +26,8 @@
formControlName="entityType">
</tb-entity-type-select>
<tb-entity-list
[ngClass]="{'tb-not-empty': this.modelValue.ids?.length > 0}"
fxFlex
class="flex-1"
[class.tb-not-empty]="modelValue.ids?.length > 0"
*ngIf="modelValue.entityType"
[required]="required"
[entityType]="modelValue.entityType"

2
ui-ngx/src/app/shared/components/entity/entity-subtype-select.component.html

@ -17,7 +17,7 @@
-->
<mat-form-field [formGroup]="subTypeFormGroup" class="mat-block" subscriptSizing="{{ subscriptSizing }}">
<mat-label *ngIf="showLabel">{{ entitySubtypeTitle | translate }}</mat-label>
<mat-select [fxShow]="subTypesLoaded" class="tb-entity-subtype-select" formControlName="subType">
<mat-select [class.!hidden]="!subTypesLoaded" class="tb-entity-subtype-select" formControlName="subType">
<mat-option *ngFor="let subType of subTypesOptions | async" [value]="subType">
{{ displaySubTypeFn(subType) }}
</mat-option>

2
ui-ngx/src/app/shared/components/footer-fab-buttons.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<section fxLayout="row" class="layout-wrap tb-footer-fab-buttons" [ngClass]="{'relative-buttons': relative}">
<section class="tb-footer-fab-buttons flex flex-row flex-wrap" [class.relative-buttons]="relative">
<div class="fab-container">
<button [disabled]="isLoading$ | async"
mat-fab class="fab-toggler tb-btn-footer"

5
ui-ngx/src/app/shared/components/grid/scroll-grid.component.html

@ -42,13 +42,12 @@
<ng-container *ngTemplateOutlet="noData"></ng-container>
</ng-template>
<ng-template #defaultLoadingCell>
<div fxLayout="column" fxLayoutAlign="center center" [style]="{minHeight: itemSize + 'px'}">
<div class="flex flex-col justify-center items-center" [style]="{minHeight: itemSize + 'px'}">
<mat-spinner color="accent" strokeWidth="5"></mat-spinner>
</div>
</ng-template>
<ng-template #defaultDataLoading>
<div fxLayout="column"
fxLayoutAlign="center center" class="tb-absolute-fill">
<div class="tb-absolute-fill flex flex-col justify-center items-center">
<mat-spinner color="accent" strokeWidth="5"></mat-spinner>
</div>
</ng-template>

14
ui-ngx/src/app/shared/components/html.component.html

@ -15,12 +15,12 @@
limitations under the License.
-->
<div class="tb-html" style="background: #fff;" [ngClass]="{'tb-disabled': disabled, 'fill-height': fillHeight}"
<div class="tb-html flex flex-col" style="background: #fff;" [class]="{'tb-disabled': disabled, 'fill-height': fillHeight}"
tb-fullscreen
[fullscreen]="fullscreen" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center" style="min-height: 40px;" class="tb-html-toolbar">
<label class="tb-title no-padding" [ngClass]="{'tb-error': !disabled && (hasErrors || required && !modelValue), 'tb-required': !disabled && required}">{{ label }}</label>
<span fxFlex></span>
[fullscreen]="fullscreen">
<div style="min-height: 40px;" class="tb-html-toolbar flex flex-row justify-start items-center">
<label class="tb-title no-padding" [class]="{'tb-error': !disabled && (hasErrors || required && !modelValue), 'tb-required': !disabled && required}">{{ label }}</label>
<span class="flex-1"></span>
<button type='button' *ngIf="!disabled" mat-button class="tidy" (click)="beautifyHtml()">
{{'js-func.tidy' | translate }}
</button>
@ -35,7 +35,7 @@
</div>
</fieldset>
</div>
<div id="tb-html-panel" class="tb-html-content-panel" fxLayout="column">
<div #htmlEditor id="tb-html-input" [ngStyle]="fillHeight ? {} : {minHeight: minHeight}" [ngClass]="{'fill-height': fillHeight}"></div>
<div id="tb-html-panel" class="tb-html-content-panel flex flex-col">
<div #htmlEditor id="tb-html-input" [style]="fillHeight ? {} : {minHeight: minHeight}" [class.fill-height]="fillHeight"></div>
</div>
</div>

7
ui-ngx/src/app/shared/components/image/embed-image-dialog.component.html

@ -17,7 +17,7 @@
-->
<mat-toolbar color="primary">
<h2>{{ 'image.embed-image' | translate }}</h2>
<span fxFlex></span>
<span class="flex-1"></span>
<button mat-icon-button
(click)="cancel()"
type="button">
@ -30,12 +30,11 @@
<div mat-dialog-content>
<div class="tb-form-panel stroked tb-slide-toggle" *ngIf="!readonly || image.public">
<mat-expansion-panel class="tb-settings" [expanded]="image.public" disabled>
<mat-expansion-panel-header fxLayout="row wrap">
<mat-expansion-panel-header class="flex flex-row flex-wrap">
<mat-panel-title>
<div *ngIf="!readonly" tb-hint-tooltip-icon="{{ 'image.embed-to-html-hint' | translate }}"
class="tb-form-row no-border no-padding">
<mat-slide-toggle class="mat-slide" [formControl]="publicStatusControl" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
<mat-slide-toggle class="mat-slide flex justify-center items-stretch" [formControl]="publicStatusControl" (click)="$event.stopPropagation()">
<div class="tb-form-panel-title">{{ 'image.embed-to-html' | translate }}</div>
</mat-slide-toggle>
</div>

2
ui-ngx/src/app/shared/components/image/image-dialog.component.html

@ -18,7 +18,7 @@
<form class="tb-image-dialog" [formGroup]="imageFormGroup">
<mat-toolbar color="primary">
<h2>{{ (readonly ? 'image.image-details' : 'image.edit-image') | translate }}</h2>
<span fxFlex></span>
<span class="flex-1"></span>
<button mat-icon-button
(click)="cancel()"
type="button">

94
ui-ngx/src/app/shared/components/image/image-gallery.component.html

@ -15,21 +15,19 @@
limitations under the License.
-->
<div class="tb-images tb-absolute-fill" [ngClass]="{'tb-dialog-mode': dialogMode, 'mat-padding': !dialogMode}">
<div fxFlex fxLayout="column" class="tb-images-content" [ngClass]="{'tb-outlined-border': pageMode}">
<mat-toolbar class="mat-mdc-table-toolbar"
fxLayout.lt-lg="column" fxLayoutAlign.lt-lg="start stretch"
[fxShow]="!textSearchMode && (mode === 'grid' || dataSource?.selection.isEmpty())" [ngClass.lt-lg]="{'multi-row': !isSysAdmin}">
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<div class="tb-images tb-absolute-fill" [class.tb-dialog-mode]="dialogMode" [class.mat-padding]="!dialogMode">
<div class="tb-images-content flex flex-1 flex-col" [class.tb-outlined-border]="pageMode">
<mat-toolbar class="mat-mdc-table-toolbar lt-lg:flex lt-lg:flex-col lt-lg:justify-start lt-lg:items-stretch"
[class.!hidden]="textSearchMode || !(mode === 'grid' || dataSource?.selection.isEmpty())"
[class.multi-row]="!isSysAdmin">
<div class="flex flex-1 flex-row justify-start items-center">
<div class="mat-toolbar-tools">
<div fxHide fxShow.gt-sm class="tb-images-title">
<div class="tb-images-title lt-md:!hidden">
<div tbTruncateWithTooltip>{{ (isScada ? 'scada.symbols' : 'image.gallery') | translate }}</div>
<div *ngIf="isScada" tb-help="scada"></div>
</div>
<div class="tb-images-view-type-toolbar"
fxLayout="row"
fxLayoutAlign="start center">
<div class="tb-toolbar-button" [ngClass]="{'tb-selected' : mode === 'list'}">
<div class="tb-images-view-type-toolbar flex flex-row justify-start items-center">
<div class="tb-toolbar-button" [class.tb-selected]="mode === 'list'">
<button mat-icon-button
(click)="setMode('list')"
matTooltip="{{'image.list-mode' | translate }}"
@ -37,7 +35,7 @@
<mat-icon>view_list</mat-icon>
</button>
</div>
<div class="tb-toolbar-button" [ngClass]="{'tb-selected' : mode === 'grid'}">
<div class="tb-toolbar-button" [class.tb-selected]="mode === 'grid'">
<button mat-icon-button
(click)="setMode('grid');"
matTooltip="{{'image.grid-mode' | translate }}"
@ -47,13 +45,13 @@
</div>
</div>
<mat-slide-toggle *ngIf="!isSysAdmin"
fxHide fxShow.gt-md
class="lt-lg:!hidden"
[ngModel]="includeSystemImages"
(ngModelChange)="includeSystemImagesChanged($event)">{{ (isScada ? 'scada.include-system-symbols' : 'image.include-system-images') | translate }}</mat-slide-toggle>
</div>
<section fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap.gt-md="16px">
<span fxFlex></span>
<section fxLayout="row" fxLayoutAlign="start center">
<section class="flex flex-1 flex-row justify-start items-center gt-md:gap-4">
<span class="flex-1"></span>
<section class="flex flex-row justify-start items-center">
<button [disabled]="isLoading$ | async"
mat-icon-button
(click)="enterFilterMode()"
@ -75,7 +73,8 @@
matTooltipPosition="above">
<tb-icon>mdi:file-import</tb-icon>
</button>
<button [fxHide]="!(dialogMode && isScada)" fxShow.lt-lg
<button [class.!hidden]="dialogMode && isScada"
class="gt-md:!hidden"
[disabled]="isLoading$ | async"
mat-icon-button
color="primary"
@ -85,7 +84,8 @@
<mat-icon>add</mat-icon>
</button>
</section>
<button fxHide [fxShow.gt-md]="!(dialogMode && isScada)"
<button [class.!hidden]="dialogMode && isScada"
class="lt-lg:!hidden"
[disabled]="isLoading$ | async"
mat-flat-button
color="primary"
@ -94,18 +94,18 @@
</button>
</section>
</div>
<mat-slide-toggle *ngIf="!isSysAdmin" fxHide fxShow.lt-lg
<mat-slide-toggle *ngIf="!isSysAdmin" class="gt-md:!hidden"
[ngModel]="includeSystemImages"
(ngModelChange)="includeSystemImagesChanged($event)">{{ (isScada ? 'scada.include-system-symbols' : 'image.include-system-images') | translate }}</mat-slide-toggle>
</mat-toolbar>
<mat-toolbar class="mat-mdc-table-toolbar" [fxShow]="textSearchMode && (mode === 'grid' || dataSource?.selection.isEmpty())">
<mat-toolbar class="mat-mdc-table-toolbar" [class.!hidden]="!textSearchMode || !(mode === 'grid' || dataSource?.selection.isEmpty())">
<div class="mat-toolbar-tools">
<button mat-icon-button
matTooltip="{{ (isScada ? 'scada.search' : 'image.search' ) | translate }}"
matTooltipPosition="above">
<mat-icon>search</mat-icon>
</button>
<mat-form-field fxFlex>
<mat-form-field class="flex-1">
<mat-label>&nbsp;</mat-label>
<input #searchInput matInput
[formControl]="textSearch"
@ -118,12 +118,12 @@
</button>
</div>
</mat-toolbar>
<mat-toolbar class="mat-mdc-table-toolbar" color="primary" [fxShow]="mode === 'list' && !dataSource?.selection.isEmpty()">
<mat-toolbar class="mat-mdc-table-toolbar" color="primary" [class.!hidden]="mode !== 'list' || dataSource?.selection.isEmpty()">
<div class="mat-toolbar-tools">
<span>
{{ translate.get((isScada ? 'scada.selected-symbols' : 'image.selected-images' ), {count: dataSource?.selection.selected.length}) | async }}
</span>
<span fxFlex></span>
<span class="flex-1"></span>
<button mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ 'action.delete' | translate }}"
matTooltipPosition="above"
@ -132,8 +132,8 @@
</button>
</div>
</mat-toolbar>
<div fxFlex *ngIf="mode === 'list'" fxLayout="column">
<div fxFlex class="table-container">
<div *ngIf="mode === 'list'" class="flex flex-1 flex-col">
<div class="table-container flex-1">
<table mat-table [dataSource]="dataSource" [trackBy]="trackByEntity"
matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear>
<ng-container matColumnDef="select" sticky>
@ -145,7 +145,7 @@
</mat-header-cell>
<mat-cell *matCellDef="let image">
<mat-checkbox (click)="$event.stopPropagation()"
[fxShow]="deleteEnabled(image)"
[class.!hidden]="!deleteEnabled(image)"
(change)="$event ? dataSource.selection.toggle(image) : null"
[checked]="dataSource.selection.isSelected(image)">
</mat-checkbox>
@ -190,10 +190,22 @@
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<mat-header-cell *matHeaderCellDef [ngStyle.gt-md]="{ minWidth: actionColumnWidth, maxWidth: actionColumnWidth, width: actionColumnWidth }">
<mat-header-cell *matHeaderCellDef
[class.gt-md:min-w-60]="!isScada"
[class.gt-md:max-w-60]="!isScada"
[class.gt-md:w-60]="!isScada"
[class.gt-md:min-w-48]="isScada"
[class.gt-md:max-w-48]="isScada"
[class.gt-md:w-48]="isScada">
</mat-header-cell>
<mat-cell *matCellDef="let image" [ngStyle.gt-md]="{ minWidth: actionColumnWidth, maxWidth: actionColumnWidth, width: actionColumnWidth }">
<div fxHide fxShow.gt-md fxFlex fxLayout="row" fxLayoutAlign="end">
<mat-cell *matCellDef="let image"
[class.gt-md:min-w-60]="!isScada"
[class.gt-md:max-w-60]="!isScada"
[class.gt-md:w-60]="!isScada"
[class.gt-md:min-w-48]="isScada"
[class.gt-md:max-w-48]="isScada"
[class.gt-md:w-48]="isScada">
<div class="lt-lg:!hidden flex flex-1 flex-row justify-end items-stretch">
<button mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ (isScada ? 'scada.download-symbol' : 'image.download-image' ) | translate }}"
matTooltipPosition="above"
@ -225,7 +237,7 @@
<mat-icon>delete</mat-icon>
</button>
</div>
<div fxHide fxShow.lt-lg>
<div class="gt-md:!hidden">
<button mat-icon-button
(click)="$event.stopPropagation()"
[matMenuTriggerFor]="cellActionsMenu">
@ -258,7 +270,7 @@
</button>
<button mat-menu-item
[disabled]="isLoading$ | async"
[fxShow]="deleteEnabled(image)"
[class.!hidden]="!deleteEnabled(image)"
(click)="deleteImage($event, image)">
<mat-icon>delete</mat-icon>
<span>{{ (isScada ? 'scada.delete-symbol' : 'image.delete-image' ) | translate }}</span>
@ -275,18 +287,17 @@
(click)="selectImage($event, image)">{{ 'action.select' | translate }}</button>
</mat-cell>
</ng-container>
<mat-header-row [ngClass]="{'mat-row-select': true}" *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
<mat-row [fxShow]="!dataSource.dataLoading"
[ngClass]="{'mat-row-select': true,
'mat-selected': dataSource.selection.isSelected(image)}"
<mat-header-row class="mat-row-select" *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
<mat-row class="mat-row-select"
[class.!hidden]="dataSource.dataLoading"
[class.mat-selected]="dataSource.selection.isSelected(image)"
*matRowDef="let image; columns: displayedColumns;" (click)="rowClick($event, image)"></mat-row>
</table>
<ng-container *ngIf="(dataSource.isEmpty() | async) && !dataSource.dataLoading">
<ng-container *ngTemplateOutlet="noImages"></ng-container>
</ng-container>
<span [fxShow]="dataSource.dataLoading"
fxLayoutAlign="center center"
class="no-data-found">{{ 'common.loading' | translate }}</span>
<span [class.!hidden]="!dataSource.dataLoading"
class="no-data-found flex justify-center items-center">{{ 'common.loading' | translate }}</span>
</div>
<mat-divider></mat-divider>
<mat-paginator [length]="dataSource.total() | async"
@ -296,8 +307,8 @@
[hidePageSize]="hidePageSize"
showFirstLastButtons></mat-paginator>
</div>
<div *ngIf="mode === 'grid'" fxFlex [ngClass]="{'mat-padding': !dialogMode}" fxLayout="column">
<tb-scroll-grid fxFlex
<div *ngIf="mode === 'grid'" class="flex flex-1 flex-col" [class.mat-padding]="!dialogMode">
<tb-scroll-grid class="flex-1"
[columns]="gridColumns"
[itemSize]="gridImagesItemSizeStrategy"
[fetchFunction]="gridImagesFetchFunction"
@ -311,8 +322,7 @@
</div>
</div>
<ng-template #loadingImages>
<div fxLayout="column"
fxLayoutAlign="center center" class="tb-absolute-fill">
<div class="tb-absolute-fill flex flex-col justify-center items-center">
<span>
{{ 'common.loading' | translate }}
</span>

14
ui-ngx/src/app/shared/components/image/image-gallery.component.scss

@ -42,12 +42,14 @@ $tb-button-selected-color: rgb(255, 110, 64) !default;
.mat-mdc-table-toolbar {
&.multi-row {
&.mat-toolbar-single-row {
height: 112px;
}
.mat-mdc-slide-toggle {
display: flex;
min-height: 48px;
@media #{$mat-lt-lg} {
&.mat-toolbar-single-row {
height: 112px;
}
.mat-mdc-slide-toggle {
display: flex;
min-height: 48px;
}
}
}
}

5
ui-ngx/src/app/shared/components/image/image-gallery.component.ts

@ -174,8 +174,6 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe
authUser = getCurrentAuthUser(this.store);
actionColumnWidth = '240px';
get isScada() {
return this.imageSubType === ResourceSubType.SCADA_SYMBOL;
}
@ -245,9 +243,6 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe
this.dataSource = new ImagesDatasource(this.imageService, null,
entity => this.deleteEnabled(entity));
}
if (this.isScada) {
this.actionColumnWidth = '192px';
}
}
ngOnDestroy(): void {

8
ui-ngx/src/app/shared/components/image/images-in-use-dialog.component.html

@ -63,15 +63,15 @@
(click)="toggleShowReferences($event, image, showReferencesButton)">{{ 'image.references' | translate }}</button>
</mat-cell>
</ng-container>
<mat-header-row [ngClass]="{'mat-row-select': true}" *matHeaderRowDef="['select', 'preview', 'title', 'references']; sticky: true"></mat-header-row>
<mat-row [ngClass]="{'mat-row-select': true,
'mat-selected': dataSource.selection.isSelected(image)}"
<mat-header-row class="mat-row-select" *matHeaderRowDef="['select', 'preview', 'title', 'references']; sticky: true"></mat-header-row>
<mat-row class="mat-row-select"
[class.mat-selected]="dataSource.selection.isSelected(image)"
*matRowDef="let image; columns: ['select', 'preview', 'title', 'references'];"></mat-row>
</table>
</div>
</ng-container>
</div>
<div mat-dialog-actions fxLayoutAlign="end center">
<div mat-dialog-actions class="flex justify-end items-center">
<button mat-button color="primary" (click)="cancel()">{{'action.cancel' | translate}}</button>
<button mat-raised-button color="accent" (click)="delete()" [disabled]="data.multiple && dataSource.selection.isEmpty()"
cdkFocusInitial>{{ (data.multiple ? 'action.delete-selected' : 'action.delete-anyway') | translate}}</button>

14
ui-ngx/src/app/shared/components/image/multiple-gallery-image-input.component.html

@ -16,10 +16,10 @@
-->
<div class="tb-container">
<label class="tb-title" *ngIf="label" [ngClass]="{'tb-error': !disabled && (required && !imageUrls.length), 'tb-required': !disabled && required}">{{label}}</label>
<div class="images-container" dndDropzone [dndHorizontal]="true" dndEffectAllowed="move"
[dndDisableIf]="disabled" (dndDrop)="imageDrop($event)"
fxLayout="row" fxLayoutGap="8px" [ngClass]="{'no-images': !imageUrls.length}">
<label class="tb-title" *ngIf="label" [class]="{'tb-error': !disabled && (required && !imageUrls.length), 'tb-required': !disabled && required}">{{label}}</label>
<div class="images-container flex flex-row gap-2" dndDropzone [dndHorizontal]="true" dndEffectAllowed="move"
[class.no-images]="!imageUrls.length"
[dndDisableIf]="disabled" (dndDrop)="imageDrop($event)">
<div dndPlaceholderRef class="image-card image-dnd-placeholder"></div>
<div *ngFor="let imageUrl of imageUrls; let $index = index;"
(dndStart)="imageDragStart($index)"
@ -27,10 +27,10 @@
[dndDraggable]="imageUrl"
[dndDisableIf]="disabled"
dndEffectAllowed="move"
[ngClass]="{'image-dragging': dragIndex === $index}"
class="image-card" fxLayout="column">
[class.image-dragging]="dragIndex === $index"
class="image-card flex flex-col">
<span class="image-title">{{ 'image-input.images' | translate }} [{{ $index }}]</span>
<div class="image-content-container" fxLayout="row">
<div class="image-content-container flex flex-row">
<div dndHandle *ngIf="!disabled" class="tb-image-action-container tb-drag-handle">
<mat-icon color="primary">drag_indicator</mat-icon>
</div>

4
ui-ngx/src/app/shared/components/image/upload-image-dialog.component.html

@ -18,7 +18,7 @@
<form [formGroup]="uploadImageFormGroup" (ngSubmit)="upload()" style="width: 560px;">
<mat-toolbar color="primary">
<h2>{{ ( uploadImage ? (isScada ? 'scada.upload-symbol' : 'image.upload-image') : (isScada ? 'scada.update-symbol' : 'image.update-image') ) | translate }}</h2>
<span fxFlex></span>
<span class="flex-1"></span>
<button mat-icon-button
(click)="cancel()"
type="button">
@ -50,7 +50,7 @@
</mat-form-field>
</fieldset>
</div>
<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
<div mat-dialog-actions class="flex flex-row justify-end items-center">
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"

18
ui-ngx/src/app/shared/components/js-func.component.html

@ -15,15 +15,15 @@
limitations under the License.
-->
<div class="tb-js-func" style="background: #fff;" [ngClass]="{'tb-disabled': disabled, 'fill-height': fillHeight, 'tb-hide-brackets': hideBrackets}"
<div class="tb-js-func flex flex-col" style="background: #fff;" [class]="{'tb-disabled': disabled, 'fill-height': fillHeight, 'tb-hide-brackets': hideBrackets}"
tb-fullscreen
[fullscreen]="fullscreen" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center" style="min-height: 40px;" class="tb-js-func-toolbar">
[fullscreen]="fullscreen">
<div style="min-height: 40px;" class="tb-js-func-toolbar flex flex-row justify-start items-center">
<label class="tb-title no-padding"
[ngClass]="{'tb-error': !disabled && (hasErrors || !functionValid || required && !modelValue), 'tb-required': !disabled && required}">
[class]="{'tb-error': !disabled && (hasErrors || !functionValid || required && !modelValue), 'tb-required': !disabled && required}">
{{ functionLabel }}
</label>
<span fxFlex></span>
<span class="flex-1"></span>
<ng-content select="[toolbarPrefixButton]"></ng-content>
<button type='button' *ngIf="!disabled" mat-button class="tidy" (click)="beautifyJs()">
{{'js-func.tidy' | translate }}
@ -41,10 +41,10 @@
</div>
</fieldset>
</div>
<div id="tb-javascript-panel" class="tb-js-func-panel" fxLayout="column" tb-toast toastTarget="{{toastTargetId}}">
<div #javascriptEditor id="tb-javascript-input" [ngStyle]="fillHeight ? {} : {minHeight: minHeight}" [ngClass]="{'fill-height': fillHeight}"></div>
<div id="tb-javascript-panel" class="tb-js-func-panel flex flex-col" tb-toast toastTarget="{{toastTargetId}}">
<div #javascriptEditor id="tb-javascript-input" [style]="fillHeight ? {} : {minHeight: minHeight}" [class.fill-height]="fillHeight"></div>
</div>
<div *ngIf="!hideBrackets" fxLayout="row" fxLayoutAlign="start center" style="height: 40px;">
<label class="tb-title no-padding" [ngClass]="{'tb-error': hasErrors || !functionValid || required && !modelValue}">&#125;</label>
<div *ngIf="!hideBrackets" class="flex flex-row justify-start items-center" style="height: 40px;">
<label class="tb-title no-padding" [class]="{'tb-error': hasErrors || !functionValid || required && !modelValue}">&#125;</label>
</div>
</div>

14
ui-ngx/src/app/shared/components/json-content.component.html

@ -15,12 +15,12 @@
limitations under the License.
-->
<div class="tb-json-content" style="background: #fff;" [ngClass]="{'fill-height': fillHeight}"
<div class="tb-json-content flex flex-col" style="background: #fff;" [class]="{'fill-height': fillHeight}"
tb-fullscreen
[fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;" class="tb-json-content-toolbar" *ngIf="!hideToolbar">
<label class="tb-title no-padding" [ngClass]="{'tb-error': !disabled && (!contentValid || required && !contentBody), 'tb-required': !disabled && required}">{{ label }}</label>
<span fxFlex></span>
[fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()">
<div style="height: 40px;" class="tb-json-content-toolbar flex flex-row justify-start items-center" *ngIf="!hideToolbar">
<label class="tb-title no-padding" [class]="{'tb-error': !disabled && (!contentValid || required && !contentBody), 'tb-required': !disabled && required}">{{ label }}</label>
<span class="flex-1"></span>
<button type="button"
mat-button *ngIf="!readonly && !disabled" class="tidy" (click)="beautifyJSON()">
{{'js-func.tidy' | translate }}
@ -41,7 +41,7 @@
</fieldset>
</div>
<div id="tb-json-panel" tb-toast toastTarget="{{toastTargetId}}"
class="tb-json-content-panel" fxLayout="column">
<div #jsonEditor id="tb-json-input" [ngStyle]="editorStyle" [ngClass]="{'fill-height': fillHeight}"></div>
class="tb-json-content-panel flex flex-col">
<div #jsonEditor id="tb-json-input" [style]="editorStyle" [class.fill-height]="fillHeight"></div>
</div>
</div>

18
ui-ngx/src/app/shared/components/json-object-edit.component.html

@ -15,15 +15,15 @@
limitations under the License.
-->
<div style="background: #fff;" [ngClass]="{'fill-height': fillHeight}"
<div class="flex flex-col" style="background: #fff;" [class.fill-height]="fillHeight"
tb-fullscreen
[fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center" class="tb-json-object-toolbar">
[fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()">
<div class="tb-json-object-toolbar flex flex-row justify-start items-center">
<label class="tb-title no-padding"
[ngClass]="{'tb-required': jsonRequired,
'tb-readonly': readonly,
'tb-error': !objectValid}">{{ label }}</label>
<span fxFlex></span>
[class]="{'tb-required': jsonRequired,
'tb-readonly': readonly,
'tb-error': !objectValid}">{{ label }}</label>
<span class="flex-1"></span>
<button type="button"
mat-button *ngIf="!readonly && !disabled" class="tidy" (click)="beautifyJSON()">
{{'js-func.tidy' | translate }}
@ -39,7 +39,7 @@
</button>
</div>
<div id="tb-json-panel" tb-toast toastTarget="{{toastTargetId}}"
class="tb-json-object-panel" fxLayout="column">
<div #jsonEditor id="tb-json-input" [ngStyle]="editorStyle" [ngClass]="{'fill-height': fillHeight}"></div>
class="tb-json-object-panel flex flex-col">
<div #jsonEditor id="tb-json-input" [style]="editorStyle" [class.fill-height]="fillHeight"></div>
</div>
</div>

6
ui-ngx/src/app/shared/components/json-object-view.component.html

@ -15,8 +15,8 @@
limitations under the License.
-->
<div style="background: #fff;" [ngClass]="{'fill-height': fillHeight}">
<div style="background: #fff;" [class.fill-height]="fillHeight">
<label class="tb-title no-padding" *ngIf="label">{{ label }}</label>
<span fxFlex></span>
<div #jsonViewer id="tb-json-view" [ngClass]="{'fill-height': fillHeight}"></div>
<span class="flex-1"></span>
<div #jsonViewer id="tb-json-view" [class.fill-height]="fillHeight"></div>
</div>

20
ui-ngx/src/app/shared/components/kv-map.component.html

@ -15,21 +15,21 @@
limitations under the License.
-->
<section fxLayout="column" class="tb-kv-map" [formGroup]="kvListFormGroup">
<section class="tb-kv-map flex flex-col" [formGroup]="kvListFormGroup">
<label translate class="tb-title">{{ titleText }}</label>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"
<div class="flex flex-row justify-start items-center gap-2"
formArrayName="keyVals"
*ngFor="let keyValControl of keyValsFormArray().controls; let $index = index">
<mat-form-field fxFlex class="mat-block" subscriptSizing="{{ subscriptSizing }}">
<mat-form-field class="mat-block flex-1" subscriptSizing="{{ subscriptSizing }}">
<input [formControl]="keyValControl.get('key')" matInput required
placeholder="{{ (keyPlaceholderText ? keyPlaceholderText : 'key-val.key') | translate }}"/>
</mat-form-field>
<mat-form-field fxFlex class="mat-block" subscriptSizing="{{ subscriptSizing }}">
<mat-form-field class="mat-block flex-1" subscriptSizing="{{ subscriptSizing }}">
<input [formControl]="keyValControl.get('value')" matInput required
placeholder="{{ (valuePlaceholderText ? valuePlaceholderText : 'key-val.value') | translate }}"/>
</mat-form-field>
<button mat-icon-button color="primary"
[fxShow]="!disabled"
[class.!hidden]="disabled"
type="button"
(click)="removeKeyVal($index)"
[disabled]="isLoading$ | async"
@ -38,12 +38,14 @@
<mat-icon>close</mat-icon>
</button>
</div>
<span [fxShow]="!keyValsFormArray().length"
fxLayoutAlign="center center" [ngClass]="{'disabled': disabled}"
class="no-data-found" translate>{{noDataText ? noDataText : 'key-val.no-data'}}</span>
<span [class]="{
'disabled': disabled,
'!hidden': keyValsFormArray().length
}"
class="no-data-found flex justify-center items-center" translate>{{noDataText ? noDataText : 'key-val.no-data'}}</span>
<div style="margin-top: 8px;">
<button mat-button mat-raised-button color="primary"
[fxShow]="!disabled"
[class.!hidden]="disabled"
[disabled]="isLoading$ | async"
(click)="addKeyVal()"
type="button"

4
ui-ngx/src/app/shared/components/logo.component.html

@ -15,5 +15,5 @@
limitations under the License.
-->
<img (click)="gotoThingsboard()" fxFlex [src]="logo"
aria-label="logo" class="tb-logo-title"/>
<img (click)="gotoThingsboard()" [src]="logo"
aria-label="logo" class="tb-logo-title flex-1"/>

18
ui-ngx/src/app/shared/components/markdown-editor.component.html

@ -15,15 +15,15 @@
limitations under the License.
-->
<div class="markdown-content" [ngClass]="{'tb-edit-mode': !readonly}"
<div class="markdown-content" [class.tb-edit-mode]="!readonly"
tb-fullscreen [fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()">
<div fxLayout="row" fxLayoutAlign="start center" style="min-height: 40px;" class="markdown-editor-toolbar">
<label class="tb-title no-padding" [ngClass]="{'tb-error': !disabled && required && !markdownValue, 'tb-required': !disabled && required}">{{ label }}</label>
<span fxFlex></span>
<button [fxShow]="!editorMode"
<div style="min-height: 40px;" class="markdown-editor-toolbar flex flex-row justify-start items-center">
<label class="tb-title no-padding" [class]="{'tb-error': !disabled && required && !markdownValue, 'tb-required': !disabled && required}">{{ label }}</label>
<span class="flex-1"></span>
<button [class.!hidden]="editorMode"
type="button"
mat-button (click)="toggleEditMode()">{{ 'markdown.edit' | translate }}</button>
<button [fxShow]="editorMode"
<button [class.!hidden]="!editorMode"
type="button"
mat-button (click)="toggleEditMode()">{{ 'markdown.preview' | translate }}</button>
<div *ngIf = "helpId" [tb-help-popup]="helpId"></div>
@ -38,9 +38,9 @@
</div>
</fieldset>
</div>
<div [fxShow]="!readonly && !disabled" class="markdown-content-editor">
<div [fxShow]="editorMode" #markdownEditor class="tb-markdown-editor"></div>
<div [fxShow]="!editorMode" class="tb-markdown-view-container">
<div [class.!hidden]="readonly || disabled" class="markdown-content-editor">
<div [class.!hidden]="!editorMode" #markdownEditor class="tb-markdown-editor"></div>
<div [class.!hidden]="editorMode" class="tb-markdown-view-container">
<tb-markdown [data]="renderValue" lineNumbers fallbackToPlainMarkdown></tb-markdown>
</div>
</div>

2
ui-ngx/src/app/shared/components/markdown.component.html

@ -22,5 +22,5 @@
background: #efefef;">
{{error}}
</div>
<div #fallbackElement [fxShow]="usePlainMarkdown || (error && fallbackToPlainMarkdown)" class="tb-markdown-view" [ngClass]="markdownClass" [ngStyle]="style">
<div #fallbackElement [class.!hidden]="!usePlainMarkdown && !(error && fallbackToPlainMarkdown)" class="tb-markdown-view" [class]="markdownClass" [style]="style">
</div>

6
ui-ngx/src/app/shared/components/material-icon-select.component.html

@ -15,9 +15,9 @@
limitations under the License.
-->
<div *ngIf="!asBoxInput; else boxInput" fxLayout="row" [formGroup]="materialIconFormGroup">
<tb-icon class="icon-value" [ngStyle]="color ? { color: color } : {}" (click)="openIconDialog()">{{materialIconFormGroup.get('icon').value}}</tb-icon>
<mat-form-field fxFlex>
<div *ngIf="!asBoxInput; else boxInput" class="flex flex-row" [formGroup]="materialIconFormGroup">
<tb-icon class="icon-value" [style]="color ? { color: color } : {}" (click)="openIconDialog()">{{materialIconFormGroup.get('icon').value}}</tb-icon>
<mat-form-field class="flex-1">
<mat-label>{{ label }}</mat-label>
<input [required]="required" matInput formControlName="icon" (mousedown)="openIconDialog()">
<button *ngIf="iconClearButton"

10
ui-ngx/src/app/shared/components/material-icons.component.html

@ -27,8 +27,10 @@
<mat-icon class="material-icons">close</mat-icon>
</button>
</mat-form-field>
<cdk-virtual-scroll-viewport [fxShow]="!notFound" #iconsPanel
[itemSize]="iconsRowHeight" class="tb-material-icons-viewport" [ngStyle]="{width: iconsPanelWidth, height: iconsPanelHeight}">
<cdk-virtual-scroll-viewport [class.!hidden]="notFound" #iconsPanel
[itemSize]="iconsRowHeight" class="tb-material-icons-viewport"
[style.width]="iconsPanelWidth"
[style.height]="iconsPanelHeight">
<div *cdkVirtualFor="let iconRow of iconRows$ | async" class="tb-material-icons-row">
<ng-container *ngFor="let icon of iconRow">
<button *ngIf="icon.name === selectedIcon"
@ -54,7 +56,7 @@
</div>
</cdk-virtual-scroll-viewport>
<ng-container *ngIf="notFound">
<div class="tb-no-data-available" [ngStyle]="{width: iconsPanelWidth}">
<div class="tb-no-data-available" [style.width]="iconsPanelWidth">
<div class="tb-no-data-bg"></div>
<div class="tb-no-data-text">{{ 'icon.no-icons-found' | translate:{iconSearch: searchIconControl.value} }}</div>
</div>
@ -68,7 +70,7 @@
[disabled]="!selectedIcon">
{{ 'action.clear' | translate }}
</button>
<span fxFlex></span>
<span class="flex-1"></span>
<button *ngIf="!showAllSubject.value" class="tb-material-icons-show-more" mat-button color="primary" (click)="showAllSubject.next(true)">
{{ 'action.show-more' | translate }}
</button>

12
ui-ngx/src/app/shared/components/multiple-image-input.component.html

@ -16,13 +16,13 @@
-->
<div class="tb-container">
<label class="tb-title" *ngIf="label" [ngClass]="{'tb-error': !disabled && (required && !safeImageUrls.length), 'tb-required': !disabled && required}">{{label}}</label>
<label class="tb-title" *ngIf="label" [class]="{'tb-error': !disabled && (required && !safeImageUrls.length), 'tb-required': !disabled && required}">{{label}}</label>
<ng-container #flow="flow"
[flowConfig]="{allowDuplicateUploads: true}">
<div class="tb-image-select-container" #flowDrop="flowDrop" flowDrop [flow]="flow.flowJs">
<div class="images-container" dndDropzone [dndHorizontal]="true" dndEffectAllowed="move"
<div class="images-container flex flex-row gap-2" dndDropzone [dndHorizontal]="true" dndEffectAllowed="move"
[dndDisableIf]="disabled" (dndDrop)="imageDrop($event)"
fxLayout="row" fxLayoutGap="8px" [ngClass]="{'no-images': !safeImageUrls.length}">
[class.no-images]="!safeImageUrls.length">
<div dndPlaceholderRef class="image-card image-dnd-placeholder"></div>
<div *ngFor="let safeImageUrl of safeImageUrls; let $index = index;"
(dndStart)="imageDragStart($index)"
@ -30,10 +30,10 @@
[dndDraggable]="safeImageUrl"
[dndDisableIf]="disabled"
dndEffectAllowed="move"
[ngClass]="{'image-dragging': dragIndex === $index}"
class="image-card" fxLayout="column">
[class.image-dragging]="dragIndex === $index"
class="image-card flex flex-col">
<span class="image-title">{{ 'image-input.images' | translate }} [{{ $index }}]</span>
<div class="image-content-container" fxLayout="row">
<div class="image-content-container flex flex-row">
<div dndHandle *ngIf="!disabled" class="tb-image-action-container tb-drag-handle">
<mat-icon color="primary">drag_indicator</mat-icon>
</div>

16
ui-ngx/src/app/shared/components/notification/notification.component.html

@ -15,19 +15,19 @@
limitations under the License.
-->
<section fxLayout="row" fxLayoutAlign="space-between start" class="notification"
[ngStyle]="{borderColor: notificationColor(), backgroundColor: notificationBackgroundColor()}">
<section class="notification flex flex-row justify-between items-start"
[style]="{borderColor: notificationColor(), backgroundColor: notificationBackgroundColor()}">
<div *ngIf="showIcon; else defaultIcon">
<tb-icon class="icon" [ngStyle]="{color: notification.additionalConfig.icon.color}">
<tb-icon class="icon" [style.color]="notification.additionalConfig.icon.color">
{{ notification.additionalConfig.icon.icon }}
</tb-icon>
</div>
<ng-template #defaultIcon>
<tb-icon class="icon" *ngIf="notificationTypeIcons.get(notification.type)" [ngStyle]="notificationIconColor()">
<tb-icon class="icon" *ngIf="notificationTypeIcons.get(notification.type)" [style]="notificationIconColor()">
{{ notificationTypeIcons.get(notification.type) }}
</tb-icon>
</ng-template>
<div class="content" fxFlex>
<div class="content flex-1">
<div class="title" [innerHTML]="(title | safe: 'html' )"></div>
<div class="message" [innerHTML]="(message | safe: 'html' )"></div>
<button *ngIf="showButton" mat-stroked-button class="button" color="primary"
@ -35,15 +35,15 @@
{{ buttonLabel }}
</button>
</div>
<div class="description" fxLayout="column" fxLayoutAlign="start end">
<div class="description flex flex-col justify-start items-end">
<span class="time">{{ notification.createdTime ?? currentDate | dateAgo }}</span>
<button mat-icon-button (click)="markRead($event)" *ngIf="!hideMarkAsReadButton"
matTooltip="{{ 'notification.mark-as-read' | translate }}" matTooltipPosition="above">
<mat-icon>check_circle_outline</mat-icon>
</button>
<div class="alarm-severity" *ngIf="notification.type === notificationType.ALARM && !notification.info.cleared"
[ngStyle]="{backgroundColor: alarmColorSeverity(0.06)}">
<span [ngStyle]="notificationIconColor()" class="severity">
[style.background-color]="alarmColorSeverity(0.06)">
<span [style]="notificationIconColor()" class="severity">
{{alarmSeverityTranslations.get(notification.info.alarmSeverity) | translate}}
</span>
</div>

2
ui-ngx/src/app/shared/components/ota-package/ota-package-autocomplete.component.html

@ -24,7 +24,7 @@
[required]="required"
[matAutocomplete]="packageAutocomplete"
[matAutocompleteDisabled]="disabled"
[fxShow]="!showDetailsPageLink || !usePackageLink || !disabled || !otaPackageFormGroup.get('packageId').value">
[class.!hidden]="showDetailsPageLink && usePackageLink && disabled && otaPackageFormGroup.get('packageId').value">
<a *ngIf="showDetailsPageLink && usePackageLink && otaPackageFormGroup.get('packageId').value && disabled"
aria-label="Open ota package" [routerLink]=packageURL>
{{ displayPackageFn(otaPackageFormGroup.get('packageId').value) }}

12
ui-ngx/src/app/shared/components/protobuf-content.component.html

@ -15,12 +15,12 @@
limitations under the License.
-->
<div style="background: #fff;" [ngClass]="{'fill-height': fillHeight}"
<div class="flex flex-col" style="background: #fff;" [class.fill-height]="fillHeight"
tb-fullscreen
[fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;" class="tb-protobuf-content-toolbar">
[fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()">
<div style="height: 40px;" class="tb-protobuf-content-toolbar flex flex-row justify-start items-center">
<label class="tb-title no-padding">{{ label }}</label>
<span fxFlex></span>
<span class="flex-1"></span>
<button type="button"
mat-button *ngIf="!readonly && !disabled" class="tidy" (click)="beautifyProtobuf()">
{{'js-func.tidy' | translate }}
@ -37,7 +37,7 @@
</fieldset>
</div>
<div id="tb-protobuf-panel" tb-toast toastTarget="{{toastTargetId}}"
class="tb-protobuf-content-panel" fxLayout="column">
<div #protobufEditor id="tb-protobuf-input" [ngStyle]="editorStyle" [ngClass]="{'fill-height': fillHeight}"></div>
class="tb-protobuf-content-panel flex flex-col">
<div #protobufEditor id="tb-protobuf-input" [style]="editorStyle" [class.fill-height]="fillHeight"></div>
</div>
</div>

6
ui-ngx/src/app/shared/components/script-lang.component.html

@ -15,12 +15,12 @@
limitations under the License.
-->
<div [formGroup]="scriptLangFormGroup" fxLayout="row" fxLayoutAlign="center">
<div [formGroup]="scriptLangFormGroup" class="flex flex-row justify-center items-stretch">
<mat-button-toggle-group class="tb-script-lang-toggle-group"
formControlName="scriptLang"
aria-label="Script language">
<mat-button-toggle fxFlex value="{{ scriptLanguage.TBEL }}">{{ 'rulenode.script-lang-tbel' | translate }}</mat-button-toggle>
<mat-button-toggle fxFlex value="{{ scriptLanguage.JS }}">
<mat-button-toggle class="flex-1" value="{{ scriptLanguage.TBEL }}">{{ 'rulenode.script-lang-tbel' | translate }}</mat-button-toggle>
<mat-button-toggle class="flex-1" value="{{ scriptLanguage.JS }}">
{{ 'rulenode.script-lang-java-script' | translate }}
</mat-button-toggle>
</mat-button-toggle-group>

27
ui-ngx/src/app/shared/components/snack-bar-component.html

@ -15,28 +15,25 @@
limitations under the License.
-->
<div fxLayout="row" fxLayoutAlign="start center"
<div class="flex flex-row justify-start items-center"
[@showHideAnimation]="{value: animationState, params: animationParams}"
(@showHideAnimation.done)="onHideFinished($event)"
[ngClass]="{
'tb-toast': !notification.modern,
'tb-modern-toast': notification.modern,
'error-toast': notification.type === 'error',
'warn-toast': notification.type === 'warn',
'success-toast': notification.type === 'success',
'info-toast': notification.type === 'info'
}">
[class.tb-toast]="!notification.modern"
[class.tb-modern-toast]="notification.modern"
[class.error-toast]="notification.type === 'error'"
[class.warn-toast]="notification.type === 'warn'"
[class.success-toast]="notification.type === 'success'"
[class.info-toast]="notification.type === 'info'">
<ng-container *ngIf="!notification.modern; else modern">
<div class="toast-text" [innerHTML]="notification.message | safe: 'html'"></div>
<button #actionButton type="button" mat-button (click)="action($event)">{{ 'action.close' | translate }}</button>
</ng-container>
<ng-template #modern>
<div class="tb-modern-toast-panel" [ngClass]="{
'error-toast': notification.type === 'error',
'warn-toast': notification.type === 'warn',
'success-toast': notification.type === 'success',
'info-toast': notification.type === 'info'
}">
<div class="tb-modern-toast-panel"
[class.error-toast]="notification.type === 'error'"
[class.warn-toast]="notification.type === 'warn'"
[class.success-toast]="notification.type === 'success'"
[class.info-toast]="notification.type === 'info'">
<div class="toast-text" [innerHTML]="notification.message | safe: 'html'"></div>
<button #actionButton class="tb-mat-20" mat-icon-button (click)="action($event)"><mat-icon>close</mat-icon></button>
</div>

3
ui-ngx/src/app/shared/components/socialshare-panel.component.html

@ -15,7 +15,8 @@
limitations under the License.
-->
<div fxLayout="row" fxLayoutGap="12px" [fxHide]="isShareLinkLocal()">
<div class="flex flex-row gap-3"
[class.!hidden]="isShareLinkLocal()">
<button mat-mini-fab color="primary"
shareButton="facebook"
title="{{ shareTitle }}"

2
ui-ngx/src/app/shared/components/string-autocomplete.component.html

@ -45,7 +45,7 @@
class="tb-autocomplete tb-options-input-autocomplete"
panelWidth="fit-content">
<mat-option *ngFor="let option of filteredOptions$ | async" [value]="option">
<span class="tb-option-name" fxFlex [innerHTML]="option | highlight:searchText:true:'ig'"></span>
<span class="tb-option-name flex-1" [innerHTML]="option | highlight:searchText:true:'ig'"></span>
</mat-option>
</mat-autocomplete>
</mat-form-field>

2
ui-ngx/src/app/shared/components/string-items-list.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<mat-form-field [formGroup]="stringItemsForm" fxFlex class="mat-block"
<mat-form-field [formGroup]="stringItemsForm" class="mat-block flex-1"
[floatLabel]="floatLabel"
[appearance]="appearance"
[subscriptSizing]="subscriptSizing">

14
ui-ngx/src/app/shared/components/svg-xml.component.html

@ -15,12 +15,12 @@
limitations under the License.
-->
<div class="tb-svg-xml" style="background: #fff;" [ngClass]="{'tb-disabled': disabled, 'fill-height': fillHeight, 'no-label': noLabel}"
<div class="tb-svg-xml flex flex-col" style="background: #fff;" [class]="{'tb-disabled': disabled, 'fill-height': fillHeight, 'no-label': noLabel}"
tb-fullscreen
[fullscreen]="fullscreen" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center" style="min-height: 40px;" class="tb-svg-xml-toolbar">
<label *ngIf="!noLabel" class="tb-title no-padding" [ngClass]="{'tb-error': !disabled && (hasErrors || required && !modelValue), 'tb-required': !disabled && required}">{{ label }}</label>
<span fxFlex></span>
[fullscreen]="fullscreen">
<div style="min-height: 40px;" class="tb-svg-xml-toolbar flex flex-row justify-start items-center">
<label *ngIf="!noLabel" class="tb-title no-padding" [class]="{'tb-error': !disabled && (hasErrors || required && !modelValue), 'tb-required': !disabled && required}">{{ label }}</label>
<span class="flex-1"></span>
<fieldset style="width: initial">
<div matTooltip="{{(fullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
matTooltipPosition="above"
@ -32,7 +32,7 @@
</div>
</fieldset>
</div>
<div id="tb-svg-xml-panel" class="tb-svg-xml-content-panel" fxLayout="column">
<div #svgXmlEditor id="tb-svg-xml-input" [ngStyle]="fillHeight ? {} : {minHeight: minHeight}" [ngClass]="{'fill-height': fillHeight}"></div>
<div id="tb-svg-xml-panel" class="tb-svg-xml-content-panel flex flex-col">
<div #svgXmlEditor id="tb-svg-xml-input" [style]="fillHeight ? {} : {minHeight: minHeight}" [class.fill-height]="fillHeight"></div>
</div>
</div>

4
ui-ngx/src/app/shared/components/time/datapoints-limit.component.html

@ -15,8 +15,8 @@
limitations under the License.
-->
<div [formGroup]="datapointsLimitFormGroup" class="limit-slider-container" fxLayout="row" fxLayoutAlign="start center">
<mat-slider fxFlex
<div [formGroup]="datapointsLimitFormGroup" class="limit-slider-container flex flex-row justify-start items-center">
<mat-slider class="flex-1"
min="{{minDatapointsLimit()}}"
max="{{maxDatapointsLimit()}}">
<input matSliderThumb formControlName="limit" [value]="datapointsLimitFormGroup.get('limit').value"/>

2
ui-ngx/src/app/shared/components/time/datetime.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<section fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="16px">
<section class="flex flex-row justify-start items-start gap-4">
<mat-form-field>
<mat-label *ngIf="showLabel">{{ dateText | translate }}</mat-label>
<mat-datetimepicker-toggle [for]="datePicker" matPrefix></mat-datetimepicker-toggle>

4
ui-ngx/src/app/shared/components/time/quick-time-interval.component.html

@ -15,8 +15,8 @@
limitations under the License.
-->
<section class="interval-section" fxLayout="row" fxFlex>
<mat-form-field fxFlex [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<section class="interval-section flex-1 flex flex-row">
<mat-form-field class="flex-1" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label *ngIf="displayLabel" translate>timewindow.interval</mat-label>
<mat-select [disabled]="disabled" [(ngModel)]="modelValue" (ngModelChange)="onIntervalChange()">
<mat-option *ngFor="let interval of intervals" [value]="interval">

4
ui-ngx/src/app/shared/components/time/timeinterval.component.html

@ -18,7 +18,7 @@
<section class="tb-form-panel no-border no-padding" [formGroup]="timeintervalFormGroup">
<section class="tb-form-row column-xs no-border no-padding tb-standard-fields">
<ng-content></ng-content>
<mat-form-field fxFlex class="flex" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-form-field class="flex flex-1" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label *ngIf="predefinedName" translate>{{ predefinedName }}</mat-label>
<mat-select formControlName="interval">
<mat-option *ngFor="let interval of intervals" [value]="interval.value">
@ -29,7 +29,7 @@
</section>
<section class="tb-form-row column-xs no-border no-padding tb-standard-fields advanced-input"
formGroupName="customInterval"
[fxShow]="advanced">
[class.!hidden]="!advanced">
<div class="tb-flex">
<mat-form-field class="number-input flex" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label translate>timeinterval.days</mat-label>

4
ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.html

@ -18,7 +18,7 @@
<form [formGroup]="timewindowForm" mat-dialog-content class="tb-timewindow-form">
<mat-toolbar color="primary">
<h2>{{ 'timewindow.timewindow-settings' | translate }}</h2>
<span fxFlex></span>
<span class="flex-1"></span>
<!-- <div tb-help="#"></div>-->
<button mat-icon-button
(click)="cancel()"
@ -195,7 +195,7 @@
</div>
</section>
<section class="tb-form-panel" [fxShow]="timewindowForm.get('aggregation.type').value !== aggregationTypes.NONE">
<section class="tb-form-panel" [class.!hidden]="timewindowForm.get('aggregation.type').value === aggregationTypes.NONE">
<div class="tb-form-panel-title">{{ 'aggregation.group-interval' | translate }}</div>
<ng-container *ngIf="timewindowForm.get('selectedTab').value === timewindowTypes.REALTIME">

10
ui-ngx/src/app/shared/components/time/timewindow-panel.component.html

@ -31,7 +31,8 @@
<ng-container *ngIf="timewindowForm.get('selectedTab').value === timewindowTypes.REALTIME">
<section class="tb-form-panel stroked" *ngIf="realtimeIntervalSelectionAvailable; else timezoneSelectionPanel">
<div class="tb-flex space-between"
[ngClass]="{'align-end': realtimeTypeSelectionAvailable, 'align-center': !realtimeTypeSelectionAvailable }">
[class.align-end]="realtimeTypeSelectionAvailable"
[class.align-center]="!realtimeTypeSelectionAvailable">
<div class="tb-flex-xs column">
<div class="tb-form-panel-title">{{ 'timewindow.timewindow' | translate }}</div>
<ng-container formGroupName="realtime" *ngIf="realtimeTypeSelectionAvailable">
@ -72,7 +73,8 @@
<ng-container *ngIf="timewindowForm.get('selectedTab').value === timewindowTypes.HISTORY">
<section class="tb-form-panel stroked" *ngIf="historyIntervalSelectionAvailable; else timezoneSelectionPanel">
<div class="tb-flex space-between"
[ngClass]="{'align-end': historyTypeSelectionAvailable, 'align-center': !historyTypeSelectionAvailable }">
[class.align-end]="historyTypeSelectionAvailable"
[class.align-center]="!historyTypeSelectionAvailable">
<div class="tb-flex-xs column">
<div class="tb-form-panel-title">{{ 'timewindow.timewindow' | translate }}</div>
<ng-container formGroupName="history" *ngIf="historyTypeSelectionAvailable">
@ -143,8 +145,8 @@
</section>
</ng-container>
<section class="tb-form-row column-xs same-padding" [fxShow]="(isEdit || !timewindow.hideAggInterval)
&& timewindowForm.get('aggregation.type').value !== aggregationTypes.NONE">
<section class="tb-form-row column-xs same-padding" [class.!hidden]="!(isEdit || !timewindow.hideAggInterval)
|| timewindowForm.get('aggregation.type').value === aggregationTypes.NONE">
<ng-container formGroupName="realtime" *ngIf="timewindowForm.get('selectedTab').value === timewindowTypes.REALTIME">
<tb-timeinterval
formControlName="interval"

4
ui-ngx/src/app/shared/components/time/timewindow.component.html

@ -49,8 +49,8 @@
(click)="toggleTimewindow($event)">
<tb-icon *ngIf="computedTimewindowStyle.showIcon && computedTimewindowStyle.iconPosition === 'left'"
[style]="timewindowIconStyle">{{ computedTimewindowStyle.icon }}</tb-icon>
<div class="tb-timewindow-label" [fxHide]="hideLabel">
{{innerValue?.displayValue}} <span [fxShow]="innerValue?.displayTimezoneAbbr !== ''">| <span class="timezone-abbr">{{innerValue?.displayTimezoneAbbr}}</span></span>
<div class="tb-timewindow-label" [class.!hidden]="hideLabel">
{{innerValue?.displayValue}} <span [class.!hidden]="!(innerValue?.displayTimezoneAbbr !== '')">| <span class="timezone-abbr">{{innerValue?.displayTimezoneAbbr}}</span></span>
</div>
<tb-icon *ngIf="computedTimewindowStyle.showIcon && computedTimewindowStyle.iconPosition === 'right'"
[style]="timewindowIconStyle">{{ computedTimewindowStyle.icon }}</tb-icon>

2
ui-ngx/src/app/shared/components/time/timezone-select.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<mat-form-field [formGroup]="selectTimezoneFormGroup" fxFlex class="flex mat-block"
<mat-form-field [formGroup]="selectTimezoneFormGroup" class="flex flex-1 mat-block"
[subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label *ngIf="displayLabel" translate>timezone.timezone</mat-label>
<input matInput type="text" placeholder="{{ 'timezone.select-timezone' | translate }}"

2
ui-ngx/src/app/shared/components/time/timezone.component.html

@ -48,7 +48,7 @@
[matTooltip]="tooltipValue()"
[matTooltipPosition]="tooltipPosition"
(click)="toggleTimezone($event)">
<div class="tb-timezone-label" [fxHide]="hideLabel">
<div class="tb-timezone-label" [class.!hidden]="hideLabel">
{{displayValue()}}
</div>
</section>

4
ui-ngx/src/app/shared/components/unit-input.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<mat-form-field fxFlex appearance="outline" class="tb-inline-field tb-suffix-show-on-hover" subscriptSizing="dynamic" style="width: 100%;">
<mat-form-field appearance="outline" class="tb-inline-field tb-suffix-show-on-hover flex-1" subscriptSizing="dynamic" style="width: 100%;">
<input matInput #unitInput [formControl]="unitsFormControl"
placeholder="{{ 'widget-config.set' | translate }}"
(focusin)="onFocus()"
@ -40,7 +40,7 @@
panelWidth="fit-content"
[displayWith]="displayUnitFn">
<mat-option *ngFor="let unit of filteredUnits | async" [value]="unit">
<span class="tb-unit-name" fxFlex [innerHTML]="unit.name | highlight:searchText:true:'ig'"></span>
<span class="tb-unit-name flex-1" [innerHTML]="unit.name | highlight:searchText:true:'ig'"></span>
<span class="tb-unit-symbol" [innerHTML]="unit.symbol | highlight:searchText:true:'ig'"></span>
</mat-option>
</mat-autocomplete>

6
ui-ngx/src/app/shared/components/user-menu.component.html

@ -15,10 +15,10 @@
limitations under the License.
-->
<section fxLayout="row">
<div fxHide.lt-lg *ngIf="displayUserInfo" class="tb-user-info" fxLayout="row">
<section class="flex flex-row">
<div *ngIf="displayUserInfo" class="tb-user-info flex flex-row lt-lg:!hidden">
<mat-icon class="material-icons tb-mini-avatar">account_circle</mat-icon>
<div fxLayout="column" fxLayoutAlign="center">
<div class="flex flex-col justify-center items-stretch">
<span *ngIf="userDisplayName$ | async; let userDisplayName" class="tb-user-display-name">{{ userDisplayName }}</span>
<span *ngIf="authorityName$ | async; let authorityName" class="tb-user-authority">{{ authorityName | translate }}</span>
</div>

14
ui-ngx/src/app/shared/components/value-input.component.html

@ -16,7 +16,7 @@
-->
<form #inputForm="ngForm">
<section [fxLayout]="computedLayout" fxLayoutGap="8px">
<section class="flex gap-2" [class]="computedLayout === 'row' ? 'flex-row' : 'flex-col'">
<mat-form-field *ngIf="showValueType" appearance="outline" subscriptSizing="dynamic" class="tb-value-type tb-inline-field" [class]="computedLayout">
<mat-select [disabled]="disabled" name="valueType" [(ngModel)]="valueType" (ngModelChange)="onValueTypeChanged()">
<mat-select-trigger>
@ -31,7 +31,7 @@
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="valueType === valueTypeEnum.STRING" fxFlex appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute">
<mat-form-field *ngIf="valueType === valueTypeEnum.STRING" appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute flex-1">
<input [disabled]="disabled" matInput required name="value" #value="ngModel" [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()"
placeholder="{{ 'value.string-value' | translate }}*"/>
<mat-icon matSuffix
@ -43,7 +43,7 @@
warning
</mat-icon>
</mat-form-field>
<mat-form-field *ngIf="valueType === valueTypeEnum.INTEGER" fxFlex appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute number">
<mat-form-field *ngIf="valueType === valueTypeEnum.INTEGER" appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute number flex-1">
<input [disabled]="disabled" matInput required name="value" type="number" step="1" pattern="^-?[0-9]+$" #value="ngModel" [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()"
placeholder="{{ 'value.integer-value' | translate }}*"/>
<mat-icon matSuffix
@ -56,7 +56,7 @@
warning
</mat-icon>
</mat-form-field>
<mat-form-field *ngIf="valueType === valueTypeEnum.DOUBLE" fxFlex appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute number">
<mat-form-field *ngIf="valueType === valueTypeEnum.DOUBLE" appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute number flex-1">
<input [disabled]="disabled" matInput required name="value" type="number" step="any" #value="ngModel" [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()"
placeholder="{{ 'value.double-value' | translate }}*"/>
<mat-icon matSuffix
@ -68,13 +68,13 @@
warning
</mat-icon>
</mat-form-field>
<mat-chip-listbox *ngIf="valueType === valueTypeEnum.BOOLEAN" fxFlex class="tb-boolean-input center-stretch"
<mat-chip-listbox *ngIf="valueType === valueTypeEnum.BOOLEAN" class="tb-boolean-input center-stretch flex-1"
[disabled]="disabled" name="value" #value="ngModel" [(ngModel)]="modelValue" (ngModelChange)="onValueChanged()">
<mat-chip-option [selectable]="!modelValue" [value]="true">{{ trueLabel }}</mat-chip-option>
<mat-chip-option [selectable]="modelValue" [value]="false">{{ falseLabel }}</mat-chip-option>
</mat-chip-listbox>
<div *ngIf="valueType === valueTypeEnum.JSON" fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute">
<div *ngIf="valueType === valueTypeEnum.JSON" class="flex flex-1 flex-row justify-start items-center gap-2">
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="tb-inline-field flex tb-suffix-absolute flex-1">
<input [disabled]="disabled" matInput tb-json-to-string required name="value" #value="ngModel"
[(ngModel)]="modelValue" (ngModelChange)="onValueChanged()" placeholder="{{ 'value.json-value' | translate }}*"/>
<mat-icon matSuffix

2
ui-ngx/src/app/shared/components/widgets-bundle-search.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<div class="input-wrapper" [ngClass]="{'focus': focus}" fxLayoutAlign="start center" fxLayoutGap="16px">
<div class="input-wrapper flex justify-start items-center gap-4" [class.focus]="focus">
<mat-icon>search</mat-icon>
<input type="text"
[(ngModel)]="searchText"

78
ui-ngx/src/styles.scss

@ -23,6 +23,10 @@
@import './scss/mixins';
@import './scss/fonts';
@tailwind base;
@tailwind components;
@tailwind utilities;
body, html {
height: 100%;
min-height: 100%;
@ -58,6 +62,10 @@ tb-root {
* TYPE DEFAULTS
***************/
*, ::before, ::after {
border-style: none;
}
body,
button,
html,
@ -70,7 +78,7 @@ th {
font-size: 16px;
}
body {
body, button {
line-height: normal;
}
@ -314,40 +322,6 @@ pre.tb-highlight {
z-index: 0;
}
mat-label {
&.tb-title {
font-size: 13px;
font-weight: 400;
color: #666;
pointer-events: none;
&.no-padding {
padding-bottom: 0;
}
&.tb-required::after {
font-size: 13px;
color: rgba(0, 0, 0, .54);
vertical-align: top;
content: " *";
}
&.tb-error {
color: rgb(221, 44, 0);
&.tb-required::after {
color: rgb(221, 44, 0);
}
}
}
}
mat-icon {
&.tb-error {
color: rgb(221, 44, 0);
}
}
.tb-error-messages {
height: 24px; //30px
margin-top: -6px;
@ -518,6 +492,40 @@ mat-icon {
letter-spacing: .01em;
}
mat-label {
&.tb-title {
font-size: 13px;
font-weight: 400;
color: #666;
pointer-events: none;
&.no-padding {
padding-bottom: 0;
}
&.tb-required::after {
font-size: 13px;
color: rgba(0, 0, 0, .54);
vertical-align: top;
content: " *";
}
&.tb-error {
color: rgb(221, 44, 0);
&.tb-required::after {
color: rgb(221, 44, 0);
}
}
}
}
mat-icon {
&.tb-error {
color: rgb(221, 44, 0);
}
}
.mat-mdc-tooltip {
white-space: pre-line;
}

67
ui-ngx/tailwind.config.js

@ -0,0 +1,67 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
important: ".tb-default",
content: [
"./src/**/*.{html,ts}",
],
theme: {
screens: {
'xs': {
max: '599px'
},
'sm': {
min: '600px',
max: '959px'
},
'md': {
min: '960px',
max: '1279px'
},
'md-lg': {
min: '960px',
max: '1819px'
},
'lg': {
min: '1280px',
max: '1919px'
},
'xl': {
min: '1920px',
max: '5000px'
},
'lt-sm': {
max: '599px'
},
'lt-md': {
max: '959px'
},
'lt-lg': {
max: '1279px'
},
'lt-xl': {
max: '1919px'
},
'gt-xs': {
min: '600px'
},
'gt-sm': {
min: '960px'
},
'gt-md': {
min: '1280px'
},
'gt-xmd': {
min: '1600px'
},
'gt-lg': {
min: '1920px'
},
'gt-xl': {
min: '1920px'
}
},
extend: {},
},
plugins: [],
}

189
ui-ngx/yarn.lock

@ -2,6 +2,11 @@
# yarn lockfile v1
"@alloc/quick-lru@^5.2.0":
version "5.2.0"
resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
"@ampproject/remapping@2.3.0", "@ampproject/remapping@^2.2.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4"
@ -2094,7 +2099,7 @@
resolved "https://registry.yarnpkg.com/@jcubic/lily/-/lily-0.3.0.tgz#00b229aab69fe094a57fd37f27d32dd4f380c1d1"
integrity sha512-4z6p4jLGSthc8gQ7wu4nHfGYn/IgCKFr+7hjuf80VdXUs7sm029mZGGDpS8sb29PVZWUBvMMTBCVGFhH2nN4Vw==
"@jridgewell/gen-mapping@^0.3.5":
"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5":
version "0.3.5"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
@ -3877,6 +3882,11 @@ ansidec@^0.3.4:
resolved "https://registry.yarnpkg.com/ansidec/-/ansidec-0.3.4.tgz#e12d267d6b1f122d2da5b98fe0de1f98d14ac62b"
integrity sha512-Ydgbey4zqUmmNN2i2OVeVHXig3PxHRbok2X6B2Sogmb92JzZUFfTL806dT7os6tBL1peXItfeFt76CP3zsoXUg==
any-promise@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
anymatch@~3.1.2:
version "3.1.3"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
@ -3895,6 +3905,11 @@ arg@^4.1.0:
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
arg@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
argparse@^1.0.9:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@ -4017,7 +4032,7 @@ attr-accept@^2.2.2:
resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b"
integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==
autoprefixer@10.4.20:
autoprefixer@10.4.20, autoprefixer@^10.4.20:
version "10.4.20"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.20.tgz#5caec14d43976ef42e32dcb4bd62878e96be5b3b"
integrity sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==
@ -4253,6 +4268,11 @@ callsites@^3.0.0:
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
camelcase-css@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
camelcase@^5.0.0:
version "5.3.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
@ -4309,7 +4329,7 @@ chevrotain@~11.0.3:
"@chevrotain/utils" "11.0.3"
lodash-es "4.17.21"
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.6.0:
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.5.3, chokidar@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
@ -4498,6 +4518,11 @@ commander@^2.20.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commander@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
commander@^8.3.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
@ -5233,6 +5258,11 @@ detect-node@^2.0.4:
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
didyoumean@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
diff-match-patch@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37"
@ -5256,6 +5286,11 @@ directory-tree@^3.5.2:
command-line-args "^5.2.0"
command-line-usage "^6.1.1"
dlv@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
dns-packet@^5.2.2:
version "5.6.1"
resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.1.tgz#ae888ad425a9d1478a0674256ab866de1012cf2f"
@ -5905,7 +5940,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-glob@3.3.2, fast-glob@^3.3.2:
fast-glob@3.3.2, fast-glob@^3.3.0, fast-glob@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
@ -6958,7 +6993,7 @@ jest-worker@^27.4.5:
merge-stream "^2.0.0"
supports-color "^8.0.0"
jiti@^1.20.0:
jiti@^1.20.0, jiti@^1.21.0:
version "1.21.6"
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268"
integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==
@ -7368,6 +7403,16 @@ lie@~3.3.0:
dependencies:
immediate "~3.0.5"
lilconfig@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
lilconfig@^3.0.0:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb"
integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
@ -7871,6 +7916,15 @@ mute-stream@^1.0.0:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e"
integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==
mz@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
dependencies:
any-promise "^1.0.0"
object-assign "^4.0.1"
thenify-all "^1.0.0"
nanoid@^3.3.7:
version "3.3.7"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
@ -8149,11 +8203,16 @@ nth-check@^2.0.1:
dependencies:
boolbase "^1.0.0"
object-assign@^4.1.1:
object-assign@^4.0.1, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
object-hash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
object-inspect@^1.13.1:
version "1.13.2"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff"
@ -8553,11 +8612,21 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pify@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
pify@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
pirates@^4.0.1:
version "4.0.6"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==
piscina@4.6.1:
version "4.6.1"
resolved "https://registry.yarnpkg.com/piscina/-/piscina-4.6.1.tgz#4de673b0ff84bf641b31b07b3348669383b51c9a"
@ -8612,6 +8681,30 @@ possible-typed-array-names@^1.0.0:
resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==
postcss-import@^15.1.0:
version "15.1.0"
resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70"
integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==
dependencies:
postcss-value-parser "^4.0.0"
read-cache "^1.0.0"
resolve "^1.1.7"
postcss-js@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2"
integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
dependencies:
camelcase-css "^2.0.1"
postcss-load-config@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3"
integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==
dependencies:
lilconfig "^3.0.0"
yaml "^2.3.4"
postcss-loader@8.1.1:
version "8.1.1"
resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-8.1.1.tgz#2822589e7522927344954acb55bbf26e8b195dfe"
@ -8654,7 +8747,14 @@ postcss-modules-values@^4.0.0:
dependencies:
icss-utils "^5.0.0"
postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
postcss-nested@^6.0.1:
version "6.2.0"
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131"
integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==
dependencies:
postcss-selector-parser "^6.1.1"
postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.1.1:
version "6.1.2"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de"
integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==
@ -8662,7 +8762,7 @@ postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
@ -8676,7 +8776,7 @@ postcss@8.4.41:
picocolors "^1.0.1"
source-map-js "^1.2.0"
postcss@^8.2.14, postcss@^8.4.23, postcss@^8.4.33, postcss@^8.4.43:
postcss@^8.2.14, postcss@^8.4.23, postcss@^8.4.33, postcss@^8.4.43, postcss@^8.4.47:
version "8.4.47"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365"
integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==
@ -8952,6 +9052,13 @@ reactcss@^1.2.3:
dependencies:
lodash "^4.0.1"
read-cache@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
dependencies:
pify "^2.3.0"
readable-stream@^2.0.1, readable-stream@~2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
@ -9095,7 +9202,7 @@ resolve-url-loader@5.0.0:
postcss "^8.2.14"
source-map "0.6.1"
resolve@1.22.8, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.4:
resolve@1.22.8, resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.2, resolve@^1.22.4:
version "1.22.8"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
@ -9849,6 +9956,19 @@ stylis@^4.3.1:
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.4.tgz#ca5c6c4a35c4784e4e93a2a24dc4e9fa075250a4"
integrity sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==
sucrase@^3.32.0:
version "3.35.0"
resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263"
integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==
dependencies:
"@jridgewell/gen-mapping" "^0.3.2"
commander "^4.0.0"
glob "^10.3.10"
lines-and-columns "^1.1.6"
mz "^2.7.0"
pirates "^4.0.1"
ts-interface-checker "^0.1.9"
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@ -9903,6 +10023,34 @@ table-layout@^1.0.2:
typical "^5.2.0"
wordwrapjs "^4.0.0"
tailwindcss@^3.4.13:
version "3.4.13"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.13.tgz#3d11e5510660f99df4f1bfb2d78434666cb8f831"
integrity sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw==
dependencies:
"@alloc/quick-lru" "^5.2.0"
arg "^5.0.2"
chokidar "^3.5.3"
didyoumean "^1.2.2"
dlv "^1.1.3"
fast-glob "^3.3.0"
glob-parent "^6.0.2"
is-glob "^4.0.3"
jiti "^1.21.0"
lilconfig "^2.1.0"
micromatch "^4.0.5"
normalize-path "^3.0.0"
object-hash "^3.0.0"
picocolors "^1.0.0"
postcss "^8.4.23"
postcss-import "^15.1.0"
postcss-js "^4.0.1"
postcss-load-config "^4.0.1"
postcss-nested "^6.0.1"
postcss-selector-parser "^6.0.11"
resolve "^1.22.2"
sucrase "^3.32.0"
tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
@ -9963,6 +10111,20 @@ text-table@^0.2.0:
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
thenify-all@^1.0.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==
dependencies:
thenify ">= 3.1.0 < 4"
"thenify@>= 3.1.0 < 4":
version "3.3.1"
resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
dependencies:
any-promise "^1.0.0"
thingies@^1.20.0:
version "1.21.0"
resolved "https://registry.yarnpkg.com/thingies/-/thingies-1.21.0.tgz#e80fbe58fd6fdaaab8fad9b67bd0a5c943c445c1"
@ -10047,6 +10209,11 @@ ts-dedent@^2.2.0:
resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5"
integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==
ts-interface-checker@^0.1.9:
version "0.1.13"
resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
ts-node@^10.0.0, ts-node@^10.9.2:
version "10.9.2"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f"
@ -10725,7 +10892,7 @@ yaml@^1.10.0:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yaml@^2.2.2:
yaml@^2.2.2, yaml@^2.3.4:
version "2.5.1"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130"
integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==

Loading…
Cancel
Save