Pull request #77: Project templates
Merge in RED/ui from project-templates to master * commit 'd6d54b3740ce59b4cc5a97543ec6298dd826a39b': Added project templates
This commit is contained in:
commit
4166bdb9cb
@ -98,6 +98,10 @@ import { HtmlDebugScreenComponent } from './screens/html-debug-screen/html-debug
|
||||
import { ReportDownloadBtnComponent } from './components/buttons/report-download-btn/report-download-btn.component';
|
||||
import { ProjectListingActionsComponent } from './screens/project-listing-screen/project-listing-actions/project-listing-actions.component';
|
||||
import { HasScrollbarDirective } from './utils/has-scrollbar.directive';
|
||||
import { ProjectTemplatesListingScreenComponent } from './screens/admin/project-templates-listing-screen/project-templates-listing-screen.component';
|
||||
import { AddEditProjectTemplateDialogComponent } from './screens/admin/project-templates-listing-screen/add-edit-project-template-dialog/add-edit-project-template-dialog.component';
|
||||
import { ProjectTemplateActionsComponent } from './components/project-template-actions/project-template-actions.component';
|
||||
import { ProjectTemplateViewSwitchComponent } from './components/project-template-view-switch/project-template-view-switch.component';
|
||||
import { MatSliderModule } from '@angular/material/slider';
|
||||
import { PendingChangesGuard } from './utils/can-deactivate.guard';
|
||||
|
||||
@ -168,23 +172,56 @@ const routes = [
|
||||
{
|
||||
path: 'admin',
|
||||
children: [
|
||||
{ path: '', redirectTo: 'dictionaries', pathMatch: 'full' },
|
||||
{ path: '', redirectTo: 'project-templates', pathMatch: 'full' },
|
||||
{
|
||||
path: 'dictionaries',
|
||||
component: DictionaryListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'dictionaries/:type',
|
||||
component: DictionaryOverviewScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
}
|
||||
path: 'project-templates',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: ProjectTemplatesListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
}
|
||||
},
|
||||
{
|
||||
path: ':templateId',
|
||||
children: [
|
||||
{
|
||||
path: 'dictionaries',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: DictionaryListingScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
}
|
||||
},
|
||||
{
|
||||
path: ':type',
|
||||
component: DictionaryOverviewScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'rules',
|
||||
component: RulesScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
}
|
||||
},
|
||||
{ path: '', redirectTo: 'dictionaries', pathMatch: 'full' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'users',
|
||||
@ -194,15 +231,6 @@ const routes = [
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'rules',
|
||||
component: RulesScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'watermark',
|
||||
component: WatermarkScreenComponent,
|
||||
@ -285,6 +313,8 @@ const matImports = [
|
||||
CircleButtonComponent,
|
||||
ChevronButtonComponent,
|
||||
DictionaryListingScreenComponent,
|
||||
ProjectTemplatesListingScreenComponent,
|
||||
AddEditProjectTemplateDialogComponent,
|
||||
SyncWidthDirective,
|
||||
HasScrollbarDirective,
|
||||
AddEditDictionaryDialogComponent,
|
||||
@ -298,7 +328,9 @@ const matImports = [
|
||||
PdfViewerScreenComponent,
|
||||
HtmlDebugScreenComponent,
|
||||
ReportDownloadBtnComponent,
|
||||
ProjectListingActionsComponent
|
||||
ProjectListingActionsComponent,
|
||||
ProjectTemplateActionsComponent,
|
||||
ProjectTemplateViewSwitchComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@ -351,7 +383,10 @@ const matImports = [
|
||||
provide: MAT_DATE_FORMATS,
|
||||
useValue: {
|
||||
display: {
|
||||
dateInput: 'DD/MM/YY'
|
||||
dateInput: 'DD/MM/YY',
|
||||
monthYearLabel: 'YYYY',
|
||||
dateA11yLabel: 'LL',
|
||||
monthYearA11yLabel: 'YYYY'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
.file-actions {
|
||||
display: flex;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
.actions {
|
||||
display: flex;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,44 +1,46 @@
|
||||
<div class="menu flex-2 visible-lg breadcrumbs-container">
|
||||
<a
|
||||
class="breadcrumb"
|
||||
routerLink="/ui/admin/dictionaries"
|
||||
translate="dictionaries"
|
||||
routerLinkActive="active"
|
||||
[routerLink]="'/ui/admin/project-templates'"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
*ngIf="screen === 'dictionaries' || root"
|
||||
routerLinkActive="active"
|
||||
translate="project-templates"
|
||||
*ngIf="root || !!projectTemplate"
|
||||
></a>
|
||||
|
||||
<a
|
||||
class="ml-32 breadcrumb"
|
||||
[routerLink]="'/ui/admin/rules'"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
routerLinkActive="active"
|
||||
translate="rule-editor"
|
||||
*ngIf="(screen === 'rules' || root) && userPreferenceService.areDevFeaturesEnabled"
|
||||
></a>
|
||||
|
||||
<a
|
||||
class="ml-32 breadcrumb"
|
||||
class="breadcrumb"
|
||||
[routerLink]="'/ui/admin/users'"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
routerLinkActive="active"
|
||||
translate="user-management"
|
||||
*ngIf="(screen === 'users' || root) && userPreferenceService.areDevFeaturesEnabled"
|
||||
*ngIf="root && userPreferenceService.areDevFeaturesEnabled"
|
||||
></a>
|
||||
|
||||
<a
|
||||
class="ml-32 breadcrumb"
|
||||
class="breadcrumb"
|
||||
[routerLink]="'/ui/admin/watermark'"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
routerLinkActive="active"
|
||||
translate="watermark"
|
||||
*ngIf="(screen === 'watermark' || root) && permissionService.isAdmin()"
|
||||
*ngIf="root && permissionService.isAdmin()"
|
||||
></a>
|
||||
|
||||
<ng-container *ngIf="projectTemplate">
|
||||
<mat-icon svgIcon="red:arrow-right"></mat-icon>
|
||||
<a class="breadcrumb ml-0" [routerLink]="'/ui/admin/project-templates/' + projectTemplate.id" [class.active]="!dictionary">
|
||||
{{ projectTemplate.name }}
|
||||
</a>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="dictionary">
|
||||
<mat-icon svgIcon="red:arrow-right"></mat-icon>
|
||||
<a class="breadcrumb" [routerLink]="'/ui/admin/dictionaries/' + dictionary.type" routerLinkActive="active">
|
||||
{{ dictionary.type | humanize }}
|
||||
<a
|
||||
class="breadcrumb ml-0"
|
||||
[routerLink]="'/ui/admin/project-templates/' + projectTemplate.id + '/dictionaries/' + dictionary.type"
|
||||
routerLinkActive="active"
|
||||
>
|
||||
{{ dictionary.label }}
|
||||
</a>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
.ml-32 {
|
||||
.breadcrumb:not(:first-child):not(.ml-0) {
|
||||
margin-left: 32px;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { TypeValue } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '../../state/app-state.service';
|
||||
import { AppStateService, ProjectTemplate } from '../../state/app-state.service';
|
||||
import { UserPreferenceService } from '../../common/service/user-preference.service';
|
||||
import { PermissionsService } from '../../common/service/permissions.service';
|
||||
|
||||
@ -12,24 +12,25 @@ import { PermissionsService } from '../../common/service/permissions.service';
|
||||
})
|
||||
export class AdminBreadcrumbsComponent implements OnInit {
|
||||
public dictionary: TypeValue;
|
||||
public root: boolean;
|
||||
public screen: string;
|
||||
public projectTemplate: ProjectTemplate;
|
||||
@Input()
|
||||
public root = false;
|
||||
|
||||
constructor(
|
||||
public readonly userPreferenceService: UserPreferenceService,
|
||||
public readonly permissionService: PermissionsService,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
private readonly _appStateService: AppStateService
|
||||
) {
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this._activatedRoute.params.subscribe((params) => {
|
||||
const url = this._activatedRoute.snapshot.url;
|
||||
this.root = url.length === 1;
|
||||
this.screen = url[0].path;
|
||||
if (this.screen === 'dictionaries' && url.length === 2) {
|
||||
this.dictionary = this._appStateService.dictionaryData[params.type];
|
||||
if (params.templateId) {
|
||||
this.projectTemplate = this._appStateService.getProjectTemplateById(params.templateId);
|
||||
}
|
||||
if (params.type) {
|
||||
this.dictionary = this._appStateService.getDictionaryTypeValue(params.type);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {}
|
||||
}
|
||||
|
||||
@ -5,14 +5,14 @@
|
||||
flex-direction: column;
|
||||
margin-top: 10px;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.comment {
|
||||
display: flex;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
@ -61,7 +61,7 @@
|
||||
.actions-container {
|
||||
margin-left: 26px;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
<div class="action-buttons">
|
||||
<redaction-circle-button
|
||||
(action)="openDeleteTemplateDialog($event, template)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
tooltip="project-templates-listing.action.delete"
|
||||
type="dark-bg"
|
||||
icon="red:trash"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="openEditTemplateDialog($event, template)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
tooltip="project-templates-listing.action.edit"
|
||||
type="dark-bg"
|
||||
icon="red:edit"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
</div>
|
||||
@ -0,0 +1,7 @@
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
|
||||
redaction-circle-button:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { ProjectTemplate } from '../../state/app-state.service';
|
||||
import { DialogService } from '../../dialogs/dialog.service';
|
||||
import { PermissionsService } from '../../common/service/permissions.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-project-template-actions',
|
||||
templateUrl: './project-template-actions.component.html',
|
||||
styleUrls: ['./project-template-actions.component.scss']
|
||||
})
|
||||
export class ProjectTemplateActionsComponent implements OnInit {
|
||||
@Input() template: ProjectTemplate;
|
||||
@Output() loadTemplatesData = new EventEmitter<any>();
|
||||
|
||||
constructor(private readonly _dialogService: DialogService, public readonly permissionsService: PermissionsService) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
openAddEditTemplateDialog(template?: ProjectTemplate) {
|
||||
this._dialogService.openAddEditTemplateDialog(template, async (newTemplate) => {
|
||||
if (newTemplate) {
|
||||
this.loadTemplatesData.emit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openEditTemplateDialog($event: any, pt: ProjectTemplate) {
|
||||
$event.stopPropagation();
|
||||
this.openAddEditTemplateDialog(pt);
|
||||
}
|
||||
|
||||
openDeleteTemplateDialog($event: any, template: ProjectTemplate) {
|
||||
this._dialogService.openDeleteProjectTemplateDialog($event, template, async () => {
|
||||
this.loadTemplatesData.emit();
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
<div class="">
|
||||
<div class="red-input-group slider-row">
|
||||
<mat-button-toggle-group [value]="screen" (change)="switchView($event)" appearance="legacy">
|
||||
<mat-button-toggle [value]="'dictionaries'"> {{ 'dictionaries' | translate }}</mat-button-toggle>
|
||||
<mat-button-toggle [value]="'rules'"> {{ 'rule-editor' | translate }}</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,27 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-project-template-view-switch',
|
||||
templateUrl: './project-template-view-switch.component.html',
|
||||
styleUrls: ['./project-template-view-switch.component.scss']
|
||||
})
|
||||
export class ProjectTemplateViewSwitchComponent implements OnInit {
|
||||
@Input() public screen: 'rules' | 'dictionaries';
|
||||
|
||||
private readonly _projectTemplateId: string;
|
||||
|
||||
constructor(private readonly _actr: ActivatedRoute, private _router: Router) {
|
||||
this._projectTemplateId = this._actr.snapshot.params.templateId;
|
||||
}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
public switchView($event) {
|
||||
if ($event.value === 'dictionaries') {
|
||||
this._router.navigate(['ui/admin/project-templates/' + this._projectTemplateId + '/dictionaries']);
|
||||
} else {
|
||||
this._router.navigate(['ui/admin/project-templates/' + this._projectTemplateId + '/rules']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,7 @@
|
||||
align-items: center;
|
||||
|
||||
&:not(.column) {
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
@ -18,7 +18,7 @@
|
||||
&.column {
|
||||
flex-direction: column;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
@ -51,7 +51,7 @@
|
||||
border-radius: 4px;
|
||||
padding: 3px 8px;
|
||||
|
||||
&:not(last-child) {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import * as moment from 'moment';
|
||||
})
|
||||
export class AddEditProjectDialogComponent {
|
||||
public projectForm: FormGroup;
|
||||
public hasDueDate = true;
|
||||
public hasDueDate: boolean;
|
||||
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
|
||||
@ -4,7 +4,7 @@ import { DictionaryControllerService, FileManagementControllerService, FileStatu
|
||||
import { ConfirmationDialogComponent, ConfirmationDialogInput } from './confirmation-dialog/confirmation-dialog.component';
|
||||
import { NotificationService, NotificationType } from '../notification/notification.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { AppStateService } from '../state/app-state.service';
|
||||
import { AppStateService, ProjectTemplate } from '../state/app-state.service';
|
||||
import { AddEditProjectDialogComponent } from './add-edit-project-dialog/add-edit-project-dialog.component';
|
||||
import { AssignOwnerDialogComponent } from './assign-owner-dialog/assign-owner-dialog.component';
|
||||
import { ManualRedactionEntryWrapper } from '../screens/file/model/manual-redaction-entry.wrapper';
|
||||
@ -13,6 +13,7 @@ import { ManualAnnotationDialogComponent } from './manual-redaction-dialog/manua
|
||||
import { ManualAnnotationService } from '../screens/file/service/manual-annotation.service';
|
||||
import { ProjectWrapper } from '../state/model/project.wrapper';
|
||||
import { AddEditDictionaryDialogComponent } from '../screens/admin/dictionary-listing-screen/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component';
|
||||
import { AddEditProjectTemplateDialogComponent } from '../screens/admin/project-templates-listing-screen/add-edit-project-template-dialog/add-edit-project-template-dialog.component';
|
||||
import { DEFAULT_RUL_SET_UUID } from '../utils/rule-set-default';
|
||||
|
||||
const dialogConfig = {
|
||||
@ -174,6 +175,17 @@ export class DialogService {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public openDeleteProjectTemplateDialog($event: MouseEvent, projectTemplate: ProjectTemplate, cb?: Function): MatDialogRef<ConfirmationDialogComponent> {
|
||||
$event.stopPropagation();
|
||||
const ref = this._dialog.open(ConfirmationDialogComponent, dialogConfig);
|
||||
ref.afterClosed().subscribe(async (result) => {
|
||||
if (result) {
|
||||
if (cb) cb();
|
||||
}
|
||||
});
|
||||
return ref;
|
||||
}
|
||||
|
||||
public openDeleteProjectDialog($event: MouseEvent, project: ProjectWrapper, cb?: Function): MatDialogRef<ConfirmationDialogComponent> {
|
||||
$event.stopPropagation();
|
||||
const ref = this._dialog.open(ConfirmationDialogComponent, {
|
||||
@ -273,6 +285,22 @@ export class DialogService {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public openAddEditTemplateDialog(template: ProjectTemplate, cb?: Function): MatDialogRef<AddEditProjectTemplateDialogComponent> {
|
||||
const ref = this._dialog.open(AddEditProjectTemplateDialogComponent, {
|
||||
...dialogConfig,
|
||||
data: template,
|
||||
autoFocus: true
|
||||
});
|
||||
|
||||
ref.afterClosed().subscribe((result) => {
|
||||
if (result && cb) {
|
||||
cb(result);
|
||||
}
|
||||
});
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
openRemoveAnnotationModal($event: MouseEvent, annotation: AnnotationWrapper, callback: () => void) {
|
||||
$event?.stopPropagation();
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ export class IconsModule {
|
||||
'comment',
|
||||
'case-sensitive',
|
||||
'comment-fill',
|
||||
'dictionary',
|
||||
'document',
|
||||
'double-chevron-right',
|
||||
'download',
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
.first-row {
|
||||
display: flex;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
@ -12,18 +12,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.slider-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mat-button-toggle-checked {
|
||||
background: $primary;
|
||||
transition: background-color 0.25s ease;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.mb-14 {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
@ -2,130 +2,162 @@
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
|
||||
<form [formGroup]="searchForm">
|
||||
<div class="red-input-group">
|
||||
<input [placeholder]="'dictionary-listing.search' | translate" formControlName="query" name="query" type="text" class="with-icon mt-0" />
|
||||
<mat-icon class="icon-right" svgIcon="red:search"></mat-icon>
|
||||
</div>
|
||||
</form>
|
||||
<redaction-project-template-view-switch [screen]="'dictionaries'"></redaction-project-template-view-switch>
|
||||
|
||||
<div class="actions">
|
||||
<redaction-icon-button
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
icon="red:plus"
|
||||
(action)="openAddEditDictionaryDialog()"
|
||||
text="dictionary-listing.add-new"
|
||||
type="primary"
|
||||
></redaction-icon-button>
|
||||
<div class="flex-1 actions">
|
||||
<redaction-project-template-actions (loadTemplatesData)="loadProjectTemplatesData()" [template]="projectTemplate">
|
||||
</redaction-project-template-actions>
|
||||
|
||||
<redaction-circle-button
|
||||
class="ml-6"
|
||||
*ngIf="permissionsService.isUser()"
|
||||
[routerLink]="['/ui/projects/']"
|
||||
tooltip="common.close"
|
||||
tooltipPosition="before"
|
||||
icon="red:close"
|
||||
></redaction-circle-button>
|
||||
<redaction-circle-button [routerLink]="['../..']" tooltip="common.close" tooltipPosition="before" icon="red:close"></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="header-item">
|
||||
<div class="select-all-container">
|
||||
<div *ngIf="dictionaries.length === 0" class="empty-state">
|
||||
<mat-icon svgIcon="red:dictionary"></mat-icon>
|
||||
<div class="heading-l" translate="dictionary-listing.no-data.title"></div>
|
||||
<redaction-icon-button (action)="openAddEditDictionaryDialog()" icon="red:plus" text="dictionary-listing.no-data.action" type="primary">
|
||||
</redaction-icon-button>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="dictionaries.length > 0">
|
||||
<div class="header-item">
|
||||
<div class="select-all-container">
|
||||
<div
|
||||
(click)="toggleSelectAll()"
|
||||
[class.active]="areAllDictsSelected"
|
||||
class="select-oval always-visible"
|
||||
*ngIf="!areAllDictsSelected && !areSomeDictsSelected"
|
||||
></div>
|
||||
<mat-icon *ngIf="areAllDictsSelected" (click)="toggleSelectAll()" class="selection-icon active" svgIcon="red:radio-selected"></mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="areSomeDictsSelected && !areAllDictsSelected"
|
||||
(click)="toggleSelectAll()"
|
||||
class="selection-icon"
|
||||
svgIcon="red:radio-indeterminate"
|
||||
></mat-icon>
|
||||
</div>
|
||||
|
||||
<span class="all-caps-label">
|
||||
{{ 'dictionary-listing.table-header.title' | translate: { length: displayedDictionaries.length } }}
|
||||
</span>
|
||||
|
||||
<div class="dictionary-actions-container">
|
||||
<form [formGroup]="searchForm">
|
||||
<div class="red-input-group w-250">
|
||||
<input
|
||||
[placeholder]="'dictionary-listing.search' | translate"
|
||||
formControlName="query"
|
||||
name="query"
|
||||
type="text"
|
||||
class="with-icon mt-0"
|
||||
/>
|
||||
<mat-icon class="icon-right" svgIcon="red:search"></mat-icon>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="actions">
|
||||
<redaction-icon-button
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
icon="red:plus"
|
||||
(action)="openAddEditDictionaryDialog()"
|
||||
text="dictionary-listing.add-new"
|
||||
type="primary"
|
||||
></redaction-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<div class="select-oval-placeholder placeholder-bottom-border"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
label="dictionary-listing.table-col-names.type"
|
||||
column="label"
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name
|
||||
label="dictionary-listing.table-col-names.order-of-importance"
|
||||
column="rank"
|
||||
class="flex-center"
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name label="dictionary-listing.table-col-names.hint-redaction" class="flex-center"></redaction-table-col-name>
|
||||
<div class="placeholder-bottom-border"></div>
|
||||
<div class="placeholder-bottom-border scrollbar-placeholder"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid-container" redactionHasScrollbar>
|
||||
<!-- Table lines -->
|
||||
<div
|
||||
(click)="toggleSelectAll()"
|
||||
[class.active]="areAllDictsSelected"
|
||||
class="select-oval always-visible"
|
||||
*ngIf="!areAllDictsSelected && !areSomeDictsSelected"
|
||||
></div>
|
||||
<mat-icon *ngIf="areAllDictsSelected" (click)="toggleSelectAll()" class="selection-icon active" svgIcon="red:radio-selected"></mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="areSomeDictsSelected && !areAllDictsSelected"
|
||||
(click)="toggleSelectAll()"
|
||||
class="selection-icon"
|
||||
svgIcon="red:radio-indeterminate"
|
||||
></mat-icon>
|
||||
</div>
|
||||
class="table-item pointer"
|
||||
*ngFor="let dict of displayedDictionaries | sortBy: sortingOption.order:sortingOption.column"
|
||||
[routerLink]="[dict.type]"
|
||||
>
|
||||
<div class="pr-0" (click)="toggleDictSelected($event, dict)">
|
||||
<div *ngIf="!isDictSelected(dict)" class="select-oval"></div>
|
||||
<mat-icon class="selection-icon active" *ngIf="isDictSelected(dict)" svgIcon="red:radio-selected"></mat-icon>
|
||||
</div>
|
||||
|
||||
<span class="all-caps-label">
|
||||
{{ 'dictionary-listing.table-header.title' | translate: { length: displayedDictionaries.length } }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<div class="select-oval-placeholder placeholder-bottom-border"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
label="dictionary-listing.table-col-names.type"
|
||||
column="label"
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name label="dictionary-listing.table-col-names.hint-redaction" class="flex-center"></redaction-table-col-name>
|
||||
<div class="placeholder-bottom-border"></div>
|
||||
<div class="placeholder-bottom-border scrollbar-placeholder"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid-container" redactionHasScrollbar>
|
||||
<!-- Table lines -->
|
||||
<div
|
||||
class="table-item pointer"
|
||||
*ngFor="let dict of displayedDictionaries | sortBy: sortingOption.order:sortingOption.column"
|
||||
[routerLink]="['/ui/admin/dictionaries/' + dict.type]"
|
||||
>
|
||||
<div class="pr-0" (click)="toggleDictSelected($event, dict)">
|
||||
<div *ngIf="!isDictSelected(dict)" class="select-oval"></div>
|
||||
<mat-icon class="selection-icon active" *ngIf="isDictSelected(dict)" svgIcon="red:radio-selected"></mat-icon>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="color-square" [ngStyle]="{ 'background-color': dict.hexColor }"></div>
|
||||
<div class="dict-name">
|
||||
<div class="table-item-title heading">
|
||||
{{ dict.label }}
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||
{{ dict.entries?.length }}
|
||||
<div>
|
||||
<div class="color-square" [ngStyle]="{ 'background-color': dict.hexColor }"></div>
|
||||
<div class="dict-name">
|
||||
<div class="table-item-title heading">
|
||||
{{ dict.label }}
|
||||
</div>
|
||||
<div *ngIf="!dict.caseInsensitive">
|
||||
<mat-icon svgIcon="red:case-sensitive"></mat-icon>
|
||||
{{ 'dictionary-listing.case-sensitive' | translate }}
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||
{{ dict.entries?.length }}
|
||||
</div>
|
||||
<div *ngIf="!dict.caseInsensitive">
|
||||
<mat-icon svgIcon="red:case-sensitive"></mat-icon>
|
||||
{{ 'dictionary-listing.case-sensitive' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="analyzed">
|
||||
<redaction-annotation-icon [dictType]="dict" [type]="dict.hint ? 'circle' : 'square'"></redaction-annotation-icon>
|
||||
</div>
|
||||
|
||||
<div class="actions-container">
|
||||
<div class="action-buttons">
|
||||
<redaction-circle-button
|
||||
(action)="openDeleteDictionaryDialog($event, dict)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
tooltip="dictionary-listing.action.delete"
|
||||
type="dark-bg"
|
||||
icon="red:trash"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="openEditDictionaryDialog($event, dict)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
tooltip="dictionary-listing.action.edit"
|
||||
type="dark-bg"
|
||||
icon="red:edit"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
<div class="rank small-label">
|
||||
{{ dict.rank }}
|
||||
</div>
|
||||
|
||||
<div class="analyzed">
|
||||
<redaction-annotation-icon [dictType]="dict" [type]="dict.hint ? 'circle' : 'square'"></redaction-annotation-icon>
|
||||
</div>
|
||||
|
||||
<div class="actions-container">
|
||||
<div class="action-buttons">
|
||||
<redaction-circle-button
|
||||
(action)="openDeleteDictionaryDialog($event, dict)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
tooltip="dictionary-listing.action.delete"
|
||||
type="dark-bg"
|
||||
icon="red:trash"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="openEditDictionaryDialog($event, dict)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
tooltip="dictionary-listing.action.edit"
|
||||
type="dark-bg"
|
||||
icon="red:edit"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
</div>
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div class="right-container">
|
||||
|
||||
@ -2,7 +2,17 @@
|
||||
@import '../../../../assets/styles/red-mixins';
|
||||
|
||||
.header-item {
|
||||
padding: 0 24px 0 10px;
|
||||
padding: 0 16px 0 10px;
|
||||
|
||||
.dictionary-actions-container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: flex-end;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redaction-table-col-name::ng-deep {
|
||||
@ -15,10 +25,10 @@ redaction-table-col-name::ng-deep {
|
||||
width: calc(100vw - 353px);
|
||||
|
||||
.grid-container {
|
||||
grid-template-columns: auto 1fr 1fr 2fr 11px;
|
||||
grid-template-columns: auto 2fr 1fr 1fr 1fr 11px;
|
||||
|
||||
&.has-scrollbar:hover {
|
||||
grid-template-columns: auto 1fr 1fr 2fr;
|
||||
grid-template-columns: auto 2fr 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
.table-item {
|
||||
@ -29,7 +39,8 @@ redaction-table-col-name::ng-deep {
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
&.analyzed {
|
||||
&.analyzed,
|
||||
&.rank {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@ -71,10 +82,5 @@ redaction-table-col-name::ng-deep {
|
||||
|
||||
.page-header .actions {
|
||||
display: flex;
|
||||
width: calc(353px - 24px);
|
||||
justify-content: flex-end;
|
||||
|
||||
.ml-6 {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import { DoughnutChartConfig } from '../../../components/simple-doughnut-chart/s
|
||||
import { DictionaryControllerService, TypeValue } from '@redaction/red-ui-http';
|
||||
import { SortingOption, SortingService } from '../../../utils/sorting.service';
|
||||
import { DialogService } from '../../../dialogs/dialog.service';
|
||||
import { AppStateService } from '../../../state/app-state.service';
|
||||
import { AppStateService, ProjectTemplate } from '../../../state/app-state.service';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { forkJoin } from 'rxjs';
|
||||
import { PermissionsService } from '../../../common/service/permissions.service';
|
||||
@ -11,6 +11,7 @@ import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { debounce } from '../../../utils/debounce';
|
||||
import { UserPreferenceService } from '../../../common/service/user-preference.service';
|
||||
import { DEFAULT_RUL_SET_UUID } from '../../../utils/rule-set-default';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dictionary-listing-screen',
|
||||
@ -23,6 +24,7 @@ export class DictionaryListingScreenComponent implements OnInit {
|
||||
public displayedDictionaries: TypeValue[];
|
||||
public selectedDictKeys: string[] = [];
|
||||
public searchForm: FormGroup;
|
||||
public projectTemplate: ProjectTemplate;
|
||||
|
||||
constructor(
|
||||
private readonly _dialogService: DialogService,
|
||||
@ -30,6 +32,7 @@ export class DictionaryListingScreenComponent implements OnInit {
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _dictionaryControllerService: DictionaryControllerService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _actr: ActivatedRoute,
|
||||
public readonly permissionsService: PermissionsService
|
||||
) {
|
||||
this.searchForm = this._formBuilder.group({
|
||||
@ -37,6 +40,8 @@ export class DictionaryListingScreenComponent implements OnInit {
|
||||
});
|
||||
|
||||
this.searchForm.valueChanges.subscribe((value) => this._executeSearch(value));
|
||||
|
||||
this.projectTemplate = this._appStateService.getProjectTemplateById(this._actr.snapshot.params.templateId);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -141,4 +146,8 @@ export class DictionaryListingScreenComponent implements OnInit {
|
||||
this._loadDictionaryData();
|
||||
});
|
||||
}
|
||||
|
||||
public loadProjectTemplatesData(): void {
|
||||
console.log('load project templates data');
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
|
||||
<redaction-circle-button
|
||||
class="ml-6"
|
||||
[routerLink]="['/ui/admin/dictionaries/']"
|
||||
[routerLink]="['..']"
|
||||
tooltip="common.close"
|
||||
tooltipPosition="before"
|
||||
icon="red:close"
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
<section class="dialog">
|
||||
<div class="dialog-header heading-l">
|
||||
{{ (template ? 'add-edit-project-template.title.edit' : 'add-edit-project-template.title.new') | translate: { name: template?.name } }}
|
||||
</div>
|
||||
|
||||
<form (submit)="saveTemplate()" [formGroup]="templateForm">
|
||||
<div class="dialog-content">
|
||||
<div class="red-input-group required w-300">
|
||||
<label translate="add-edit-project-template.form.name"></label>
|
||||
<input formControlName="name" name="name" type="text" placeholder="{{ 'add-edit-project-template.form.name-placeholder' | translate }}" />
|
||||
</div>
|
||||
|
||||
<div class="red-input-group w-400">
|
||||
<label translate="add-edit-project-template.form.description"></label>
|
||||
<textarea
|
||||
formControlName="description"
|
||||
name="description"
|
||||
type="text"
|
||||
rows="4"
|
||||
placeholder="{{ 'add-edit-project-template.form.description-placeholder' | translate }}"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="valid-from">
|
||||
<mat-checkbox [checked]="hasValidFrom" (change)="hasValidFrom = !hasValidFrom" class="filter-menu-checkbox" color="primary">
|
||||
{{ 'project-listing.add-edit-dialog.form.due-date' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
<ng-container *ngIf="hasValidFrom">
|
||||
<div class="red-input-group datepicker-wrapper ml-16 mr-16">
|
||||
<input placeholder="dd/mm/yy" [matDatepicker]="fromPicker" formControlName="validFrom" />
|
||||
<mat-datepicker-toggle matSuffix [for]="fromPicker">
|
||||
<mat-icon matDatepickerToggleIcon svgIcon="red:calendar"></mat-icon>
|
||||
</mat-datepicker-toggle>
|
||||
<mat-datepicker #fromPicker></mat-datepicker>
|
||||
</div>
|
||||
|
||||
to
|
||||
|
||||
<div class="red-input-group datepicker-wrapper ml-16">
|
||||
<input placeholder="dd/mm/yy" [matDatepicker]="toPicker" formControlName="validTo" />
|
||||
<mat-datepicker-toggle matSuffix [for]="toPicker">
|
||||
<mat-icon matDatepickerToggleIcon svgIcon="red:calendar"></mat-icon>
|
||||
</mat-datepicker-toggle>
|
||||
<mat-datepicker #toPicker></mat-datepicker>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button [disabled]="templateForm.invalid || !changed" color="primary" mat-flat-button type="submit">
|
||||
{{ 'add-edit-project-template.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<redaction-circle-button icon="red:close" mat-dialog-close class="dialog-close"></redaction-circle-button>
|
||||
</section>
|
||||
@ -0,0 +1,19 @@
|
||||
.valid-from {
|
||||
margin-top: 16px;
|
||||
min-height: 34px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
mat-checkbox {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.mr-16 {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.ml-16 {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { AppStateService, ProjectTemplate } from '../../../../state/app-state.service';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import * as moment from 'moment';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-add-edit-project-template-dialog',
|
||||
templateUrl: './add-edit-project-template-dialog.component.html',
|
||||
styleUrls: ['./add-edit-project-template-dialog.component.scss']
|
||||
})
|
||||
export class AddEditProjectTemplateDialogComponent {
|
||||
public templateForm: FormGroup;
|
||||
public hasValidFrom: boolean;
|
||||
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
public dialogRef: MatDialogRef<AddEditProjectTemplateDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public template: ProjectTemplate
|
||||
) {
|
||||
this.templateForm = this._formBuilder.group({
|
||||
name: [this.template?.name, Validators.required],
|
||||
description: [this.template?.description],
|
||||
validFrom: [this.template?.validFrom],
|
||||
validTo: [this.template?.validTo]
|
||||
});
|
||||
this.hasValidFrom = !!this.template?.validFrom && !!this.template?.validTo;
|
||||
}
|
||||
|
||||
public get changed(): boolean {
|
||||
if (!this.template) return true;
|
||||
|
||||
for (const key of Object.keys(this.templateForm.getRawValue())) {
|
||||
if (key === 'validFrom' || key === 'validTo') {
|
||||
if (this.hasValidFrom !== (!!this.template.validFrom && !!this.template.validTo)) {
|
||||
return true;
|
||||
}
|
||||
if (this.hasValidFrom && !moment(this.template[key]).isSame(moment(this.templateForm.get(key).value))) {
|
||||
return true;
|
||||
}
|
||||
} else if (this.template[key] !== this.templateForm.get(key).value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async saveTemplate() {
|
||||
const template = this.templateForm.getRawValue();
|
||||
console.log({ template });
|
||||
this.dialogRef.close({ template });
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,142 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1" [root]="true"></redaction-admin-breadcrumbs>
|
||||
|
||||
<div class="actions">
|
||||
<form [formGroup]="searchForm">
|
||||
<div class="red-input-group w-250">
|
||||
<input
|
||||
[placeholder]="'project-templates-listing.search' | translate"
|
||||
formControlName="query"
|
||||
name="query"
|
||||
type="text"
|
||||
class="with-icon mt-0"
|
||||
/>
|
||||
<mat-icon class="icon-right" svgIcon="red:search"></mat-icon>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<redaction-icon-button
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
icon="red:plus"
|
||||
(action)="openAddTemplateDialog()"
|
||||
text="project-templates-listing.add-new"
|
||||
type="primary"
|
||||
></redaction-icon-button>
|
||||
|
||||
<redaction-circle-button
|
||||
class="ml-6"
|
||||
*ngIf="permissionsService.isUser()"
|
||||
[routerLink]="['/ui/projects/']"
|
||||
tooltip="common.close"
|
||||
tooltipPosition="before"
|
||||
icon="red:close"
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="header-item">
|
||||
<div class="select-all-container">
|
||||
<div
|
||||
(click)="toggleSelectAll()"
|
||||
[class.active]="areAllTemplatesSelected"
|
||||
class="select-oval always-visible"
|
||||
*ngIf="!areAllTemplatesSelected && !areSomeTemplatesSelected"
|
||||
></div>
|
||||
<mat-icon *ngIf="areAllTemplatesSelected" (click)="toggleSelectAll()" class="selection-icon active" svgIcon="red:radio-selected"></mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="areSomeTemplatesSelected && !areAllTemplatesSelected"
|
||||
(click)="toggleSelectAll()"
|
||||
class="selection-icon"
|
||||
svgIcon="red:radio-indeterminate"
|
||||
></mat-icon>
|
||||
</div>
|
||||
|
||||
<span class="all-caps-label">
|
||||
{{ 'project-templates-listing.table-header.title' | translate: { length: displayedTemplates.length } }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<div class="select-oval-placeholder placeholder-bottom-border"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
label="project-templates-listing.table-col-names.name"
|
||||
column="name"
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name label="project-templates-listing.table-col-names.created-by" class="flex-center"></redaction-table-col-name>
|
||||
<redaction-table-col-name
|
||||
label="project-templates-listing.table-col-names.created-on"
|
||||
class="flex-center"
|
||||
column="dateAdded"
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
></redaction-table-col-name>
|
||||
<redaction-table-col-name
|
||||
label="project-templates-listing.table-col-names.modified-on"
|
||||
class="flex-center"
|
||||
column="dateModified"
|
||||
(toggleSort)="toggleSort($event)"
|
||||
[activeSortingOption]="sortingOption"
|
||||
[withSort]="true"
|
||||
></redaction-table-col-name>
|
||||
<div class="placeholder-bottom-border scrollbar-placeholder"></div>
|
||||
</div>
|
||||
|
||||
<div class="grid-container" redactionHasScrollbar>
|
||||
<!-- Table lines -->
|
||||
<div
|
||||
class="table-item pointer"
|
||||
*ngFor="let template of displayedTemplates | sortBy: sortingOption.order:sortingOption.column"
|
||||
[routerLink]="[template.id, 'dictionaries']"
|
||||
>
|
||||
<div class="pr-0" (click)="toggleTemplateSelected($event, template)">
|
||||
<div *ngIf="!isTemplateSelected(template)" class="select-oval"></div>
|
||||
<mat-icon class="selection-icon active" *ngIf="isTemplateSelected(template)" svgIcon="red:radio-selected"></mat-icon>
|
||||
</div>
|
||||
|
||||
<div class="template-name">
|
||||
<div class="table-item-title heading">
|
||||
{{ template.name }}
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:dictionary"></mat-icon>
|
||||
{{ 'project-templates-listing.dictionaries' | translate: { length: 3 } }}
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||
{{ 'project-templates-listing.entries' | translate: { length: 300 } }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="created-by">
|
||||
<redaction-initials-avatar></redaction-initials-avatar>
|
||||
</div>
|
||||
<div class="created-on small-label">
|
||||
{{ template.dateAdded | date: 'd MMM. yyyy' }}
|
||||
</div>
|
||||
<div class="modified-on">
|
||||
<div class="small-label">
|
||||
{{ template.dateModified | date: 'd MMM. yyyy' }}
|
||||
</div>
|
||||
|
||||
<redaction-project-template-actions
|
||||
class="actions-container"
|
||||
(loadTemplatesData)="loadTemplatesData()"
|
||||
></redaction-project-template-actions>
|
||||
</div>
|
||||
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -0,0 +1,56 @@
|
||||
@import '../../../../assets/styles/red-variables';
|
||||
@import '../../../../assets/styles/red-mixins';
|
||||
|
||||
.header-item {
|
||||
padding: 0 24px 0 10px;
|
||||
}
|
||||
|
||||
redaction-table-col-name::ng-deep {
|
||||
> div {
|
||||
padding-left: 10px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.left-container {
|
||||
width: 100vw;
|
||||
|
||||
.grid-container {
|
||||
grid-template-columns: auto 1fr 1fr 1fr 1fr 11px;
|
||||
|
||||
&.has-scrollbar:hover {
|
||||
grid-template-columns: auto 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
.table-item {
|
||||
> div:not(.scrollbar-placeholder) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-left: 10px;
|
||||
align-items: center;
|
||||
|
||||
&.template-name {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.stats-subtitle {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.table-item-title {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&.created-by,
|
||||
&.created-on,
|
||||
&.modified-on {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-header .actions > *:not(:last-child) {
|
||||
margin-right: 16px;
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { SortingOption, SortingService } from '../../../utils/sorting.service';
|
||||
import { DialogService } from '../../../dialogs/dialog.service';
|
||||
import { AppStateService, ProjectTemplate } from '../../../state/app-state.service';
|
||||
import { PermissionsService } from '../../../common/service/permissions.service';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { debounce } from '../../../utils/debounce';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-project-templates-listing-screen',
|
||||
templateUrl: './project-templates-listing-screen.component.html',
|
||||
styleUrls: ['./project-templates-listing-screen.component.scss']
|
||||
})
|
||||
export class ProjectTemplatesListingScreenComponent implements OnInit {
|
||||
public templates: ProjectTemplate[];
|
||||
public displayedTemplates: ProjectTemplate[];
|
||||
public selectedTemplateIds: string[] = [];
|
||||
public searchForm: FormGroup;
|
||||
|
||||
constructor(
|
||||
private readonly _dialogService: DialogService,
|
||||
private readonly _sortingService: SortingService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _appStateService: AppStateService,
|
||||
public readonly permissionsService: PermissionsService
|
||||
) {
|
||||
this.searchForm = this._formBuilder.group({
|
||||
query: ['']
|
||||
});
|
||||
|
||||
this.searchForm.valueChanges.subscribe((value) => this._executeSearch(value));
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadTemplatesData();
|
||||
}
|
||||
|
||||
@debounce(200)
|
||||
private _executeSearch(value: { query: string }) {
|
||||
this.displayedTemplates = this.templates.filter((pt) => pt.name.toLowerCase().includes(value.query.toLowerCase()));
|
||||
}
|
||||
|
||||
public loadTemplatesData() {
|
||||
this._appStateService.reset();
|
||||
this.templates = this._appStateService.projectTemplates;
|
||||
this.displayedTemplates = [...this.templates];
|
||||
}
|
||||
|
||||
public get sortingOption(): SortingOption {
|
||||
return this._sortingService.getSortingOption('project-templates-listing');
|
||||
}
|
||||
|
||||
public toggleSort($event) {
|
||||
this._sortingService.toggleSort('project-templates-listing', $event);
|
||||
}
|
||||
|
||||
toggleTemplateSelected($event: MouseEvent, template: ProjectTemplate) {
|
||||
$event.stopPropagation();
|
||||
const idx = this.selectedTemplateIds.indexOf(template.id);
|
||||
if (idx === -1) {
|
||||
this.selectedTemplateIds.push(template.id);
|
||||
} else {
|
||||
this.selectedTemplateIds.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public toggleSelectAll() {
|
||||
if (this.areSomeTemplatesSelected) {
|
||||
this.selectedTemplateIds = [];
|
||||
} else {
|
||||
this.selectedTemplateIds = this.displayedTemplates.map((pt) => pt.id);
|
||||
}
|
||||
}
|
||||
|
||||
public get areAllTemplatesSelected() {
|
||||
return this.displayedTemplates.length !== 0 && this.selectedTemplateIds.length === this.displayedTemplates.length;
|
||||
}
|
||||
|
||||
public get areSomeTemplatesSelected() {
|
||||
return this.selectedTemplateIds.length > 0;
|
||||
}
|
||||
|
||||
public isTemplateSelected(pt: ProjectTemplate) {
|
||||
return this.selectedTemplateIds.indexOf(pt.id) !== -1;
|
||||
}
|
||||
|
||||
openAddTemplateDialog() {
|
||||
this._dialogService.openAddEditTemplateDialog(null, async (newTemplate) => {
|
||||
if (newTemplate) {
|
||||
this.loadTemplatesData();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,34 +1,43 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs></redaction-admin-breadcrumbs>
|
||||
<div class="actions">
|
||||
<redaction-circle-button
|
||||
(action)="download()"
|
||||
tooltip="rules-screen.action.download"
|
||||
tooltipPosition="below"
|
||||
icon="red:download"
|
||||
></redaction-circle-button>
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="fileInput.click()"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
tooltip="rules-screen.action.upload"
|
||||
tooltipPosition="below"
|
||||
icon="red:upload"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
<redaction-project-template-view-switch [screen]="'rules'"></redaction-project-template-view-switch>
|
||||
|
||||
<input #fileInput (change)="upload($event)" hidden class="file-upload-input" type="file" accept="text/plain" />
|
||||
<div class="flex-1 actions">
|
||||
<redaction-project-template-actions (loadTemplatesData)="loadProjectTemplatesData()" [template]="projectTemplate">
|
||||
</redaction-project-template-actions>
|
||||
|
||||
<redaction-circle-button
|
||||
class="ml-6"
|
||||
*ngIf="permissionsService.isUser()"
|
||||
[routerLink]="['/ui/projects/']"
|
||||
tooltip="common.close"
|
||||
tooltipPosition="before"
|
||||
icon="red:close"
|
||||
></redaction-circle-button>
|
||||
<redaction-circle-button [routerLink]="['../..']" tooltip="common.close" tooltipPosition="before" icon="red:close"></redaction-circle-button>
|
||||
</div>
|
||||
<!-- <div class="actions">-->
|
||||
<!-- <redaction-circle-button-->
|
||||
<!-- (action)="download()"-->
|
||||
<!-- tooltip="rules-screen.action.download"-->
|
||||
<!-- tooltipPosition="below"-->
|
||||
<!-- icon="red:download"-->
|
||||
<!-- ></redaction-circle-button>-->
|
||||
|
||||
<!-- <redaction-circle-button-->
|
||||
<!-- (action)="fileInput.click()"-->
|
||||
<!-- *ngIf="permissionsService.isAdmin()"-->
|
||||
<!-- tooltip="rules-screen.action.upload"-->
|
||||
<!-- tooltipPosition="below"-->
|
||||
<!-- icon="red:upload"-->
|
||||
<!-- >-->
|
||||
<!-- </redaction-circle-button>-->
|
||||
|
||||
<!-- <input #fileInput (change)="upload($event)" hidden class="file-upload-input" type="file" accept="text/plain" />-->
|
||||
|
||||
<!-- <redaction-circle-button-->
|
||||
<!-- class="ml-6"-->
|
||||
<!-- *ngIf="permissionsService.isUser()"-->
|
||||
<!-- [routerLink]="['/ui/projects/']"-->
|
||||
<!-- tooltip="common.close"-->
|
||||
<!-- tooltipPosition="before"-->
|
||||
<!-- icon="red:close"-->
|
||||
<!-- ></redaction-circle-button>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
|
||||
@ -9,3 +9,8 @@
|
||||
.changes-box {
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
.page-header .actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { saveAs } from 'file-saver';
|
||||
import { DEFAULT_RUL_SET_UUID } from '../../../utils/rule-set-default';
|
||||
import { ComponentHasChanges } from '../../../utils/can-deactivate.guard';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AppStateService, ProjectTemplate } from '../../../state/app-state.service';
|
||||
|
||||
declare var ace;
|
||||
|
||||
@ -24,6 +26,7 @@ export class RulesScreenComponent extends ComponentHasChanges {
|
||||
public currentLines: string[] = [];
|
||||
public changedLines: number[] = [];
|
||||
public activeEditMarkers: any[] = [];
|
||||
public projectTemplate: ProjectTemplate;
|
||||
|
||||
@ViewChild('editorComponent', { static: true })
|
||||
editorComponent: AceEditorComponent;
|
||||
@ -34,11 +37,14 @@ export class RulesScreenComponent extends ComponentHasChanges {
|
||||
constructor(
|
||||
public readonly permissionsService: PermissionsService,
|
||||
private readonly _rulesControllerService: RulesControllerService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _notificationService: NotificationService,
|
||||
protected readonly _translateService: TranslateService
|
||||
protected readonly _translateService: TranslateService,
|
||||
private readonly _actr: ActivatedRoute
|
||||
) {
|
||||
super(_translateService);
|
||||
this._initialize();
|
||||
this.projectTemplate = this._appStateService.getProjectTemplateById(this._actr.snapshot.params.templateId);
|
||||
}
|
||||
|
||||
private _initialize() {
|
||||
@ -123,4 +129,8 @@ export class RulesScreenComponent extends ComponentHasChanges {
|
||||
fileReader.readAsText(file);
|
||||
}
|
||||
}
|
||||
|
||||
public loadProjectTemplatesData(): void {
|
||||
console.log('load project templates data');
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
<redaction-admin-breadcrumbs class="flex-1" [root]="true"></redaction-admin-breadcrumbs>
|
||||
|
||||
<form [formGroup]="searchForm">
|
||||
<div class="red-input-group">
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
<redaction-admin-breadcrumbs class="flex-1" [root]="true"></redaction-admin-breadcrumbs>
|
||||
|
||||
<div class="actions">
|
||||
<redaction-circle-button
|
||||
|
||||
@ -145,7 +145,7 @@
|
||||
display: flex;
|
||||
margin-left: 8px;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,18 @@ export interface AppState {
|
||||
ruleVersion?: number;
|
||||
}
|
||||
|
||||
export interface ProjectTemplate {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
dateAdded: string; // ( iso-string )
|
||||
dateModified: string; // ( iso-string)
|
||||
createdBy: string; // userId
|
||||
modifiedBy: string; // userid
|
||||
validFrom: string; // (iso-date )
|
||||
validTo: string; // ( iso-date)
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
@ -149,6 +161,37 @@ export class AppStateService {
|
||||
return this.getProjectById(projectId).files.find((file) => file.fileId === fileId);
|
||||
}
|
||||
|
||||
public get projectTemplates(): ProjectTemplate[] {
|
||||
return [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Most important sets',
|
||||
description: 'description',
|
||||
dateAdded: '2011-10-05T14:48:00.000Z',
|
||||
dateModified: '2011-10-05T14:48:00.000Z',
|
||||
createdBy: '2',
|
||||
modifiedBy: '2',
|
||||
validFrom: '2011-10-05T14:48:00.000Z',
|
||||
validTo: '2011-10-05T14:48:00.000Z'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Another rule set',
|
||||
description: 'description',
|
||||
dateAdded: '2012-10-05T14:48:00.000Z',
|
||||
dateModified: '2013-10-05T14:48:00.000Z',
|
||||
createdBy: '2',
|
||||
modifiedBy: '2',
|
||||
validFrom: '2011-10-05T14:48:00.000Z',
|
||||
validTo: '2011-10-05T14:48:00.000Z'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
public getProjectTemplateById(id: string): ProjectTemplate {
|
||||
return this.projectTemplates.find((pt) => pt.id === id);
|
||||
}
|
||||
|
||||
async loadAllProjects() {
|
||||
const projects = await this._projectControllerService.getProjects().toPromise();
|
||||
if (projects) {
|
||||
|
||||
@ -5,7 +5,7 @@ export class SortingOption {
|
||||
column: string;
|
||||
}
|
||||
|
||||
type Screen = 'project-listing' | 'project-overview' | 'dictionary-listing';
|
||||
type Screen = 'project-listing' | 'project-overview' | 'dictionary-listing' | 'project-templates-listing';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -14,7 +14,8 @@ export class SortingService {
|
||||
private _options: { [key: string]: SortingOption } = {
|
||||
'project-listing': { column: 'project.projectName', order: 'asc' },
|
||||
'project-overview': { column: 'filename', order: 'asc' },
|
||||
'dictionary-listing': { column: 'label', order: 'asc' }
|
||||
'dictionary-listing': { column: 'label', order: 'asc' },
|
||||
'project-templates-listing': { column: 'name', order: 'asc' }
|
||||
};
|
||||
|
||||
constructor() {}
|
||||
|
||||
@ -560,6 +560,20 @@
|
||||
},
|
||||
"save": "Save Dictionary"
|
||||
},
|
||||
"add-edit-project-template": {
|
||||
"title": {
|
||||
"edit": "Edit {{name}} Project Template",
|
||||
"new": "Create Project Template"
|
||||
},
|
||||
"form": {
|
||||
"name": "Project Template Name",
|
||||
"name-placeholder": "Enter Name",
|
||||
"description": "Description",
|
||||
"description-placeholder": "Enter Description",
|
||||
"valid-from": "Valid from"
|
||||
},
|
||||
"save": "Save Project Template"
|
||||
},
|
||||
"dictionary-overview": {
|
||||
"action": {
|
||||
"delete": "Delete Dictionary",
|
||||
@ -597,9 +611,34 @@
|
||||
},
|
||||
"table-col-names": {
|
||||
"type": "Type",
|
||||
"order-of-importance": "Order Of Importance",
|
||||
"hint-redaction": "Hint/Redaction"
|
||||
},
|
||||
"search": "Search..."
|
||||
"search": "Search...",
|
||||
"no-data": {
|
||||
"title": "There are no dictionaries yet.",
|
||||
"action": "New Dictionary"
|
||||
}
|
||||
},
|
||||
"project-templates": "Project Templates",
|
||||
"project-templates-listing": {
|
||||
"table-header": {
|
||||
"title": "{{length}} project templates"
|
||||
},
|
||||
"entries": "{{length}} entries",
|
||||
"dictionaries": "{{length}} dictionaries",
|
||||
"action": {
|
||||
"delete": "Delete Template",
|
||||
"edit": "Edit Template"
|
||||
},
|
||||
"add-new": "New Project Template",
|
||||
"search": "Search...",
|
||||
"table-col-names": {
|
||||
"name": "Name",
|
||||
"created-by": "Created by",
|
||||
"created-on": "Created on",
|
||||
"modified-on": "Modified on"
|
||||
}
|
||||
},
|
||||
"user-listing": {
|
||||
"table-header": {
|
||||
|
||||
16
apps/red-ui/src/assets/icons/general/dictionary.svg
Normal file
16
apps/red-ui/src/assets/icons/general/dictionary.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="10px" height="10px" viewBox="0 0 10 10" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>6C0B3F0C-53AF-4E50-8C71-BCE07198E584</title>
|
||||
<g id="Settings" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="01.0-Rule-Sets" transform="translate(-40.000000, -241.000000)">
|
||||
<rect x="0" y="0" width="1440" height="705"></rect>
|
||||
<rect id="Rectangle" x="0" y="193" width="1440" height="80"></rect>
|
||||
<g id="Group-16" transform="translate(40.000000, 239.000000)" fill="currentColor" fill-rule="nonzero" >
|
||||
<g id="status" transform="translate(0.000000, 2.000000)">
|
||||
<path d="M9.5,0 L9.5,10 L2,10 C1.15,10 0.5,9.35 0.5,8.5 L0.5,8.5 L0.5,1.5 C0.5,0.65 1.15,0 2,0 L2,0 L9.5,0 Z M2.5,1 L2,1 C1.7,1 1.5,1.2 1.5,1.5 L1.5,1.5 L1.5,8.5 C1.5,8.8 1.7,9 2,9 L2,9 L2.5,9 L2.5,1 Z M8.5,1 L3.5,1 L3.5,9 L8.5,9 L8.5,1 Z M7.5,2 L7.5,5 L4.5,5 L4.5,2 L7.5,2 Z M6.5,3 L5.5,3 L5.5,4 L6.5,4 L6.5,3 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group-20" transform="translate(0.000000, 163.000000)"></g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -5,7 +5,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
line-height: 34px;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&:not(last-child) {
|
||||
&:not(:last-child) {
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@
|
||||
box-shadow: 0 2px 6px 0 rgba(40, 50, 65, 0.3);
|
||||
z-index: 5000;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
box-sizing: border-box;
|
||||
@include inset-shadow;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,6 +73,18 @@ form {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.slider-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mat-button-toggle-checked {
|
||||
background: $primary;
|
||||
transition: background-color 0.25s ease;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
mat-select {
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
@ -284,7 +284,7 @@ body {
|
||||
height: calc(100vh - 61px);
|
||||
position: relative;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
align-items: center;
|
||||
box-shadow: none;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
margin-top: 24px;
|
||||
display: flex;
|
||||
|
||||
> *:not(last-child) {
|
||||
> *:not(:last-child) {
|
||||
margin-right: 24px;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user