Pull request #145: File attributes CSV import
Merge in RED/ui from file-attributes-csv-import to master * commit 'a369866e8c55c3607a93c447f2ad62222aac4666': Rebase fix Remove selected Fixed some virtual scroll issues Renamed left-container to content-container Change file attribute name Save attributes and base config Column preview on hover
This commit is contained in:
commit
f1ce38e408
@ -6,7 +6,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="header-item">
|
||||
<span class="all-caps-label">
|
||||
{{ 'downloads-list.table-header.title' | translate: { length: fileDownloadService.downloads.length } }}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: 100vw;
|
||||
|
||||
cdk-virtual-scroll-viewport {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<section class="red-content-inner">
|
||||
<div class="left-container full-height">
|
||||
<div class="content-container full-height">
|
||||
<div class="overlay-shadow"></div>
|
||||
<div class="dialog">
|
||||
<div class="dialog-header">
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
@import '../../../assets/styles/red-mixins';
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
background-color: $grey-2;
|
||||
justify-content: center;
|
||||
@include scroll-bar;
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="header-item">
|
||||
<span class="all-caps-label">
|
||||
{{ 'audit-screen.table-header.title' | translate: { length: logs?.totalHits || 0 } }}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: 100vw;
|
||||
|
||||
.header-item {
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="header-item">
|
||||
<span class="all-caps-label">
|
||||
{{ 'default-colors-screen.table-header.title' | translate: { length: colors.length } }}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: 100vw;
|
||||
|
||||
cdk-virtual-scroll-viewport {
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-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>
|
||||
|
||||
@ -21,7 +21,7 @@ redaction-table-col-name::ng-deep {
|
||||
}
|
||||
}
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: calc(100vw - 353px);
|
||||
|
||||
cdk-virtual-scroll-viewport {
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="actions-bar">
|
||||
<div class="red-input-group w-450 mr-32">
|
||||
<input
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: calc(100vw - 353px);
|
||||
padding: 15px;
|
||||
@include inset-shadow;
|
||||
@ -130,8 +130,3 @@
|
||||
color: $grey-7;
|
||||
}
|
||||
}
|
||||
|
||||
.w-200 {
|
||||
width: 200px;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="left-container-content">
|
||||
<div class="content-container">
|
||||
<div class="content-container-content">
|
||||
<form [formGroup]="digitalSignatureForm" (keyup)="formChanged()" autocomplete="off" *ngIf="digitalSignatureForm">
|
||||
<input #fileInput (change)="fileChanged($event, fileInput)" hidden class="file-upload-input" type="file" />
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
@import '../../../../../assets/styles/red-mixins';
|
||||
@import '../../../../../assets/styles/red-variables';
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: 100vw;
|
||||
@include inset-shadow;
|
||||
|
||||
.left-container-content {
|
||||
.content-container-content {
|
||||
margin: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,59 +4,79 @@
|
||||
<div class="dialog-content">
|
||||
<div class="sub-header">
|
||||
<div class="left">
|
||||
<div class="info">
|
||||
{{ csvFile.name }}
|
||||
</div>
|
||||
<div class="info"><span translate="file-attributes-csv-import.file"> </span> {{ csvFile.name }}</div>
|
||||
<div class="large-label">
|
||||
{{ 'file-attributes-csv-import.total-rows' | translate: { rows: parseResult?.data?.length } }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="red-input-group required w-250">
|
||||
<mat-form-field floatLabel="always">
|
||||
<mat-label>{{ 'file-attributes-csv-import.key-column' | translate }}</mat-label>
|
||||
<mat-select>
|
||||
<mat-option *ngFor="let field of parseResult?.meta?.fields" [value]="field">
|
||||
{{ field }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<form [formGroup]="baseConfigForm">
|
||||
<div class="red-input-group required w-250">
|
||||
<mat-form-field floatLabel="always">
|
||||
<mat-label>{{ 'file-attributes-csv-import.key-column' | translate }}</mat-label>
|
||||
<mat-select formControlName="filenameMappingColumnHeaderName">
|
||||
<mat-option *ngFor="let field of parseResult?.meta?.fields" [value]="field">
|
||||
{{ field }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="red-input-group required w-110">
|
||||
<label translate="file-attributes-csv-import.delimiter"></label>
|
||||
<input
|
||||
[(ngModel)]="delimiter"
|
||||
name="delimiter"
|
||||
type="text"
|
||||
[placeholder]="'file-attributes-csv-import.delimiter-placeholder' | translate"
|
||||
/>
|
||||
</div>
|
||||
<div class="red-input-group required w-110">
|
||||
<label translate="file-attributes-csv-import.delimiter"></label>
|
||||
<input
|
||||
formControlName="delimiter"
|
||||
name="delimiter"
|
||||
type="text"
|
||||
[placeholder]="'file-attributes-csv-import.delimiter-placeholder' | translate"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="red-input-group required w-160">
|
||||
<label translate="file-attributes-csv-import.encoding"></label>
|
||||
<input [(ngModel)]="encoding" name="encoding" type="text" [placeholder]="'file-attributes-csv-import.encoding-placeholder' | translate" />
|
||||
</div>
|
||||
<div class="red-input-group required w-160">
|
||||
<label translate="file-attributes-csv-import.encoding"></label>
|
||||
<input
|
||||
formControlName="encoding"
|
||||
name="encoding"
|
||||
type="text"
|
||||
[placeholder]="'file-attributes-csv-import.encoding-placeholder' | translate"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="csv-part">
|
||||
<div class="left">
|
||||
<div class="csv-part-header">
|
||||
<div class="all-caps-label">
|
||||
{{ 'file-attributes-csv-import.available' | translate: { value: parseResult?.meta?.fields.length } }}
|
||||
<div>
|
||||
<span class="all-caps-label">{{
|
||||
'file-attributes-csv-import.available' | translate: { value: parseResult?.meta?.fields.length }
|
||||
}}</span>
|
||||
<span class="all-caps-label">{{ 'file-attributes-csv-import.selected' | translate: { value: activeFields.length } }}</span>
|
||||
</div>
|
||||
<div class="all-caps-label">
|
||||
{{ 'file-attributes-csv-import.selected' | translate: { value: selectedFields.length } }}
|
||||
<div class="quick-activation">
|
||||
<span class="all-caps-label primary pointer" (click)="activateAll()" translate="file-attributes-csv-import.quick-activation.all"></span>
|
||||
<span
|
||||
class="all-caps-label primary pointer"
|
||||
(click)="deactivateAll()"
|
||||
translate="file-attributes-csv-import.quick-activation.none"
|
||||
></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="csv-header-pill-content">
|
||||
<div class="csv-header-pill" *ngFor="let field of parseResult?.meta?.fields">
|
||||
<div
|
||||
class="csv-header-pill"
|
||||
*ngFor="let field of parseResult?.fields"
|
||||
(mouseenter)="hoveredColumn = field.csvColumn"
|
||||
(mouseleave)="hoveredColumn = undefined"
|
||||
(click)="toggleFieldActive(field)"
|
||||
[class.selected]="isActive(field)"
|
||||
>
|
||||
<div class="name">
|
||||
{{ field }}
|
||||
{{ field.csvColumn }}
|
||||
</div>
|
||||
<div class="secondary">
|
||||
<div class="entry-count small-label">{{ getEntries(field) }} entries</div>
|
||||
<div class="sample small-label">Sample: {{ getSample(field) }}</div>
|
||||
<div class="entry-count small-label">{{ getEntries(field.csvColumn) }} entries</div>
|
||||
<div class="sample small-label">Sample: {{ getSample(field.csvColumn) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -67,22 +87,161 @@
|
||||
{{ 'file-attributes-csv-import.csv-column' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="csv-part-content">
|
||||
<div class="no-hovered-column" *ngIf="!hoveredColumn" translate="file-attributes-csv-import.no-hovered-column"></div>
|
||||
<ng-container *ngFor="let row of parseResult?.data || []">
|
||||
<div *ngIf="row[hoveredColumn]">
|
||||
{{ row[hoveredColumn] }}
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="csv-part-header"></div>
|
||||
<!-- {{ parseResult | json }}-->
|
||||
<div class="content-container">
|
||||
<div class="header-item">
|
||||
<div class="select-all-container">
|
||||
<div
|
||||
(click)="toggleSelectAll()"
|
||||
[class.active]="areAllFieldsSelected"
|
||||
class="select-oval always-visible"
|
||||
*ngIf="!areAllFieldsSelected && !areSomeFieldsSelected"
|
||||
></div>
|
||||
<mat-icon
|
||||
*ngIf="areAllFieldsSelected"
|
||||
(click)="toggleSelectAll()"
|
||||
class="selection-icon active"
|
||||
svgIcon="red:radio-selected"
|
||||
></mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="areSomeFieldsSelected && !areAllFieldsSelected"
|
||||
(click)="toggleSelectAll()"
|
||||
class="selection-icon"
|
||||
svgIcon="red:radio-indeterminate"
|
||||
></mat-icon>
|
||||
</div>
|
||||
<span class="all-caps-label">
|
||||
{{ 'file-attributes-csv-import.table-header.title' | translate: { length: activeFields.length } }}
|
||||
</span>
|
||||
|
||||
<ng-container *ngIf="areSomeFieldsSelected">
|
||||
<redaction-circle-button
|
||||
(action)="deactivateSelection()"
|
||||
tooltip="file-attributes-csv-import.table-header.actions.remove-selected"
|
||||
type="dark-bg"
|
||||
icon="red:trash"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<div class="select-oval-placeholder"></div>
|
||||
|
||||
<redaction-table-col-name label="file-attributes-csv-import.table-col-names.name" class="name"></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name label="file-attributes-csv-import.table-col-names.type"></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name
|
||||
label="file-attributes-csv-import.table-col-names.read-only"
|
||||
class="flex-center"
|
||||
icon="red:read-only"
|
||||
></redaction-table-col-name>
|
||||
|
||||
<redaction-table-col-name
|
||||
label="file-attributes-csv-import.table-col-names.display"
|
||||
class="flex-center"
|
||||
icon="red:visibility"
|
||||
></redaction-table-col-name>
|
||||
|
||||
<div></div>
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
</div>
|
||||
|
||||
<cdk-virtual-scroll-viewport [itemSize]="50" redactionHasScrollbar>
|
||||
<!-- Table lines -->
|
||||
<div
|
||||
class="table-item"
|
||||
*cdkVirtualFor="let field of activeFields"
|
||||
(mouseenter)="hoveredColumn = field.csvColumn"
|
||||
(mouseleave)="hoveredColumn = undefined"
|
||||
>
|
||||
<div class="pr-0" (click)="toggleFieldSelected(field.csvColumn)">
|
||||
<div *ngIf="!isFieldSelected(field.csvColumn)" class="select-oval"></div>
|
||||
<mat-icon class="selection-icon active" *ngIf="isFieldSelected(field.csvColumn)" svgIcon="red:radio-selected"></mat-icon>
|
||||
</div>
|
||||
<div class="name" [class.editing]="field.editingName">
|
||||
<div *ngIf="!field.editingName">
|
||||
{{ field.name }}
|
||||
</div>
|
||||
<form (submit)="field.editingName = false; field.name = field.temporaryName" *ngIf="field.editingName">
|
||||
<div class="red-input-group w-200">
|
||||
<input name="name" [(ngModel)]="field.temporaryName" />
|
||||
</div>
|
||||
</form>
|
||||
<redaction-circle-button
|
||||
class="edit-name-button"
|
||||
*ngIf="!field.editingName"
|
||||
(action)="field.editingName = true"
|
||||
tooltip="file-attributes-csv-import.action.edit-name"
|
||||
type="dark-bg"
|
||||
icon="red:edit"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
<ng-container *ngIf="field.editingName">
|
||||
<redaction-circle-button
|
||||
(action)="field.editingName = false; field.name = field.temporaryName"
|
||||
tooltip="file-attributes-csv-import.action.save-name"
|
||||
type="dark-bg"
|
||||
icon="red:check-alt"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
<redaction-circle-button
|
||||
(action)="field.editingName = false; field.temporaryName = field.name"
|
||||
tooltip="file-attributes-csv-import.action.cancel-edit-name"
|
||||
type="dark-bg"
|
||||
icon="red:close"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div>
|
||||
<div class="red-input-group">
|
||||
<mat-form-field class="no-label">
|
||||
<mat-select [(ngModel)]="field.type">
|
||||
<mat-option *ngFor="let type of ['Text', 'Number', 'Date']" [value]="type">
|
||||
{{ 'file-attributes-csv-import.types.' + type | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center">
|
||||
<mat-slide-toggle [(ngModel)]="field.readonly" color="primary"></mat-slide-toggle>
|
||||
</div>
|
||||
<div class="center"><mat-slide-toggle [(ngModel)]="field.display" color="primary"></mat-slide-toggle></div>
|
||||
<div class="actions-container">
|
||||
<div class="action-buttons">
|
||||
<redaction-circle-button
|
||||
(action)="toggleFieldActive(field)"
|
||||
tooltip="file-attributes-csv-import.action.remove"
|
||||
type="dark-bg"
|
||||
icon="red:trash"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
</div>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button color="primary" mat-flat-button>
|
||||
<button color="primary" mat-flat-button (click)="save()" [disabled]="baseConfigForm.invalid">
|
||||
{{ 'file-attributes-csv-import.save' | translate }}
|
||||
</button>
|
||||
|
||||
<button mat-flat-button>
|
||||
{{ 'file-attributes-csv-import.cancel' | translate }}
|
||||
</button>
|
||||
<div class="all-caps-label cancel" (click)="dialogRef.close()">{{ 'file-attributes-csv-import.cancel' | translate }}</div>
|
||||
</div>
|
||||
|
||||
<redaction-circle-button icon="red:close" mat-dialog-close class="dialog-close"></redaction-circle-button>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
@import '../../../../../assets/styles/red-variables';
|
||||
@import '../../../../../assets/styles/red-mixins';
|
||||
|
||||
.sub-header {
|
||||
display: flex;
|
||||
@ -6,100 +7,223 @@
|
||||
margin-bottom: 25px;
|
||||
|
||||
.left {
|
||||
width: 375px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding-left: 32px;
|
||||
min-width: 376px;
|
||||
box-sizing: border-box;
|
||||
border-right: 1px solid $separator;
|
||||
|
||||
.info {
|
||||
margin-bottom: 8px;
|
||||
|
||||
> span {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.large-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
.right > form {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-left: 16px;
|
||||
|
||||
.red-input-group {
|
||||
margin-left: 8px;
|
||||
margin-right: 8px;
|
||||
height: 60px;
|
||||
margin: 0 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
padding-bottom: 0;
|
||||
padding: 24px 0 0;
|
||||
}
|
||||
|
||||
.csv-part {
|
||||
margin-left: -32px;
|
||||
margin-right: -32px;
|
||||
display: flex;
|
||||
max-height: calc(90vh - 251px);
|
||||
|
||||
.csv-part-header {
|
||||
height: 50px;
|
||||
box-sizing: border-box;
|
||||
background: $white;
|
||||
border-top: 1px solid $grey-4;
|
||||
border-bottom: 1px solid $grey-4;
|
||||
border-top: 1px solid $separator;
|
||||
border-bottom: 1px solid $separator;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
justify-content: space-between;
|
||||
padding: 0 16px;
|
||||
|
||||
> :not(.quick-activation) > *:not(:last-child)::after {
|
||||
content: '-';
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
.quick-activation > :not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.left {
|
||||
.csv-part-content {
|
||||
overflow: auto;
|
||||
@include no-scroll-bar;
|
||||
height: calc(100% - 51px);
|
||||
font-size: 12px;
|
||||
|
||||
.no-hovered-column {
|
||||
height: 100%;
|
||||
margin: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
color: $grey-7;
|
||||
line-height: 15px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
> *:not(.no-hovered-column) {
|
||||
height: 30px;
|
||||
border-bottom: 1px solid $separator;
|
||||
display: flex;
|
||||
padding: 0 16px;
|
||||
align-items: center;
|
||||
@include line-clamp(1);
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
> .left {
|
||||
width: 375px;
|
||||
background: $grey-2;
|
||||
|
||||
.csv-header-pill-content {
|
||||
overflow: auto;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
padding: 4px 10px;
|
||||
background: $grey-2;
|
||||
height: calc(100% - 65px);
|
||||
height: calc(100% - 58px);
|
||||
@include no-scroll-bar;
|
||||
|
||||
.csv-header-pill {
|
||||
height: 32px;
|
||||
width: 325px;
|
||||
margin: 3px 10px;
|
||||
min-height: 32px;
|
||||
margin: 6px auto;
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
background: $white;
|
||||
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.name {
|
||||
}
|
||||
.secondary {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 2px;
|
||||
|
||||
.entry-count {
|
||||
white-space: nowrap;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.sample {
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@include line-clamp(1);
|
||||
}
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: $primary;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
border-right: 1px solid $grey-4;
|
||||
border-right: 1px solid $separator;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 149px;
|
||||
> .center {
|
||||
width: 150px;
|
||||
min-width: 150px;
|
||||
background: $grey-2;
|
||||
border-right: 1px solid $grey-4;
|
||||
border-right: 1px solid $separator;
|
||||
}
|
||||
|
||||
.right {
|
||||
overflow: auto;
|
||||
max-width: calc(90vw - 525px);
|
||||
flex: 1 1 auto;
|
||||
> .content-container {
|
||||
width: 100%;
|
||||
|
||||
redaction-table-col-name::ng-deep {
|
||||
> div {
|
||||
padding: 0 13px 0 10px !important;
|
||||
|
||||
&.name {
|
||||
padding-left: 22px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-item {
|
||||
padding: 0 24px 0 10px;
|
||||
box-shadow: none;
|
||||
border-top: 1px solid $separator;
|
||||
|
||||
.all-caps-label {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
cdk-virtual-scroll-viewport {
|
||||
height: calc(100% - 80px);
|
||||
|
||||
::ng-deep.cdk-virtual-scroll-content-wrapper {
|
||||
grid-template-columns: auto 2fr 150px auto auto auto 11px;
|
||||
|
||||
.table-item {
|
||||
> div {
|
||||
height: 50px;
|
||||
|
||||
&:not(.scrollbar-placeholder) {
|
||||
padding-left: 10px;
|
||||
|
||||
&.center {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
&.name {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
&:not(.editing) {
|
||||
padding-left: 22px;
|
||||
}
|
||||
|
||||
.edit-name-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
redaction-circle-button:first-of-type {
|
||||
margin-left: 7px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .name .edit-name-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.has-scrollbar:hover {
|
||||
::ng-deep.cdk-virtual-scroll-content-wrapper {
|
||||
grid-template-columns: auto 2fr 150px auto auto auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,26 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { AppStateService } from '../../../../state/app-state.service';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import * as Papa from 'papaparse';
|
||||
import { FileAttributeConfig, FileAttributesConfig, FileAttributesControllerService } from '@redaction/red-ui-http';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
|
||||
enum FieldType {
|
||||
Text = 'Text',
|
||||
Number = 'Number',
|
||||
Date = 'Date'
|
||||
}
|
||||
|
||||
interface Field {
|
||||
csvColumn: string;
|
||||
name: string;
|
||||
type: FieldType;
|
||||
readonly: boolean;
|
||||
display: boolean;
|
||||
editingName?: boolean;
|
||||
temporaryName?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-file-attributes-csv-import-dialog',
|
||||
@ -12,48 +30,65 @@ import * as Papa from 'papaparse';
|
||||
export class FileAttributesCsvImportDialogComponent implements OnInit {
|
||||
public csvFile: File;
|
||||
public ruleSetId: string;
|
||||
public parseResult: any;
|
||||
public encoding = 'UTF-8';
|
||||
public delimiter: string = undefined;
|
||||
public parseResult: { data: any[]; errors: any[]; meta: any; fields: Field[] };
|
||||
public hoveredColumn: string;
|
||||
public activeFields: Field[] = [];
|
||||
public selectedFields: string[] = [];
|
||||
public baseConfigForm: FormGroup;
|
||||
|
||||
selectedFields: any[] = [];
|
||||
@ViewChild(CdkVirtualScrollViewport, { static: false }) cdkVirtualScrollViewport: CdkVirtualScrollViewport;
|
||||
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _fileAttributesControllerService: FileAttributesControllerService,
|
||||
public dialogRef: MatDialogRef<FileAttributesCsvImportDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: { csv: File; ruleSetId: string }
|
||||
) {
|
||||
this.csvFile = data.csv;
|
||||
this.ruleSetId = data.ruleSetId;
|
||||
|
||||
this.baseConfigForm = this._formBuilder.group({
|
||||
filenameMappingColumnHeaderName: [undefined, Validators.required],
|
||||
delimiter: [undefined, Validators.required],
|
||||
encoding: ['UTF-8', Validators.required]
|
||||
});
|
||||
|
||||
this._readFile();
|
||||
}
|
||||
|
||||
ngOnInit(): void {}
|
||||
ngOnInit(): void {
|
||||
setTimeout(() => {
|
||||
this.cdkVirtualScrollViewport.checkViewportSize();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
private _readFile() {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', async (event) => {
|
||||
const parsedCsv = <any>event.target.result;
|
||||
this.parseResult = Papa.parse(parsedCsv, { header: true, delimiter: this.delimiter });
|
||||
if (!this.delimiter) {
|
||||
this.delimiter = this.parseResult.meta.delimiter;
|
||||
this.parseResult = Papa.parse(parsedCsv, {
|
||||
header: true,
|
||||
delimiter: this.baseConfigForm.get('delimiter').value
|
||||
});
|
||||
if (!this.baseConfigForm.get('delimiter').value) {
|
||||
this.baseConfigForm.patchValue({ delimiter: this.parseResult.meta.delimiter });
|
||||
}
|
||||
this.parseResult.fields = this.parseResult.meta.fields.map((field) => this._buildAttribute(field));
|
||||
console.log(this.parseResult);
|
||||
});
|
||||
reader.readAsText(this.csvFile, this.encoding);
|
||||
reader.readAsText(this.csvFile, this.baseConfigForm.get('encoding').value);
|
||||
}
|
||||
|
||||
getSample(field: string) {
|
||||
return this.parseResult?.data ? this.parseResult?.data[0][field] : '';
|
||||
public getSample(csvColumn: string) {
|
||||
return this.parseResult?.data ? this.parseResult?.data[0][csvColumn] : '';
|
||||
}
|
||||
|
||||
getEntries(field: any) {
|
||||
public getEntries(csvColumn: string) {
|
||||
if (this.parseResult?.data) {
|
||||
let count = 0;
|
||||
for (const entry of this.parseResult.data) {
|
||||
if (entry[field]) {
|
||||
if (entry[csvColumn]) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@ -62,4 +97,100 @@ export class FileAttributesCsvImportDialogComponent implements OnInit {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public isActive(field: Field): boolean {
|
||||
return this.activeFields.indexOf(field) !== -1;
|
||||
}
|
||||
|
||||
public toggleFieldActive(field: Field) {
|
||||
if (!this.isActive(field)) {
|
||||
this.activeFields = [...this.activeFields, field];
|
||||
} else {
|
||||
this.activeFields.splice(this.activeFields.indexOf(field), 1);
|
||||
this.activeFields = [...this.activeFields];
|
||||
if (this.isFieldSelected(field.csvColumn)) {
|
||||
this.toggleFieldSelected(field.csvColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _buildAttribute(csvColumn: string): Field {
|
||||
const sample = this.getSample(csvColumn);
|
||||
const isNumber = sample && !isNaN(sample);
|
||||
return {
|
||||
csvColumn,
|
||||
name: csvColumn,
|
||||
temporaryName: csvColumn,
|
||||
type: isNumber ? FieldType.Number : FieldType.Text,
|
||||
readonly: false,
|
||||
display: true
|
||||
};
|
||||
}
|
||||
|
||||
public activateAll() {
|
||||
this.activeFields = [...this.parseResult.fields];
|
||||
}
|
||||
|
||||
public deactivateAll() {
|
||||
this.activeFields = [];
|
||||
this.selectedFields = [];
|
||||
}
|
||||
|
||||
public toggleFieldSelected(field: string) {
|
||||
const idx = this.selectedFields.indexOf(field);
|
||||
if (idx === -1) {
|
||||
this.selectedFields.push(field);
|
||||
} else {
|
||||
this.selectedFields.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public toggleSelectAll() {
|
||||
if (this.areSomeFieldsSelected) {
|
||||
this.selectedFields = [];
|
||||
} else {
|
||||
this.selectedFields = this.activeFields.map((field) => field.csvColumn);
|
||||
}
|
||||
}
|
||||
|
||||
public get areAllFieldsSelected() {
|
||||
return this.activeFields.length !== 0 && this.selectedFields.length === this.activeFields.length;
|
||||
}
|
||||
|
||||
public get areSomeFieldsSelected() {
|
||||
return this.selectedFields.length > 0;
|
||||
}
|
||||
|
||||
public isFieldSelected(field: string) {
|
||||
return this.selectedFields.indexOf(field) !== -1;
|
||||
}
|
||||
|
||||
public deactivateSelection() {
|
||||
this.activeFields = [...this.activeFields.filter((field) => !this.isFieldSelected(field.csvColumn))];
|
||||
this.selectedFields = [];
|
||||
}
|
||||
|
||||
public async save() {
|
||||
const promises: Promise<FileAttributeConfig | FileAttributesConfig>[] = [
|
||||
this._fileAttributesControllerService.addOrUpdateFileAttributesBaseConfig(this.baseConfigForm.getRawValue(), this.ruleSetId).toPromise()
|
||||
];
|
||||
|
||||
for (const field of this.activeFields) {
|
||||
promises.push(
|
||||
this._fileAttributesControllerService
|
||||
.setFileAttributesConfiguration(
|
||||
{
|
||||
csvColumnHeader: field.csvColumn,
|
||||
editable: !field.readonly,
|
||||
label: field.name,
|
||||
visible: field.display
|
||||
},
|
||||
this.ruleSetId
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
}
|
||||
await Promise.all(promises);
|
||||
this.dialogRef.close(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="header-item">
|
||||
<div class="select-all-container">
|
||||
<div
|
||||
@ -39,23 +39,22 @@
|
||||
|
||||
<div class="attributes-actions-container">
|
||||
<redaction-search-input [form]="searchForm" [placeholder]="'file-attributes-listing.search'"></redaction-search-input>
|
||||
<div class="actions">
|
||||
<input #fileInput (change)="importCSV($event.target['files'])" class="csv-input" type="file" accept=".csv" />
|
||||
<input #fileInput (change)="importCSV($event.target['files'])" class="csv-input" type="file" accept=".csv" />
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="fileInput.click()"
|
||||
tooltip="file-attributes-listing.upload-csv"
|
||||
tooltipPosition="above"
|
||||
icon="red:upload"
|
||||
></redaction-circle-button>
|
||||
<redaction-circle-button
|
||||
(action)="fileInput.click()"
|
||||
tooltip="file-attributes-listing.upload-csv"
|
||||
tooltipPosition="above"
|
||||
icon="red:upload"
|
||||
type="dark-bg"
|
||||
></redaction-circle-button>
|
||||
|
||||
<redaction-icon-button
|
||||
icon="red:plus"
|
||||
(action)="openAddEditAttributeDialog($event)"
|
||||
text="file-attributes-listing.add-new"
|
||||
type="primary"
|
||||
></redaction-icon-button>
|
||||
</div>
|
||||
<redaction-icon-button
|
||||
icon="red:plus"
|
||||
(action)="openAddEditAttributeDialog($event)"
|
||||
text="file-attributes-listing.add-new"
|
||||
type="primary"
|
||||
></redaction-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ redaction-table-col-name::ng-deep {
|
||||
}
|
||||
}
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: 100vw;
|
||||
|
||||
.header-item {
|
||||
@ -23,7 +23,7 @@ redaction-table-col-name::ng-deep {
|
||||
justify-content: flex-end;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 16px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { PermissionsService } from '../../../../services/permissions.service';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { FileAttributeConfig, FileAttributesControllerService } from '@redaction/red-ui-http';
|
||||
@ -20,6 +20,8 @@ export class FileAttributesListingScreenComponent implements OnInit {
|
||||
public selectedFileAttributeIds: string[] = [];
|
||||
public viewReady = false;
|
||||
|
||||
@ViewChild('fileInput') private _fileInput: ElementRef;
|
||||
|
||||
constructor(
|
||||
public readonly permissionsService: PermissionsService,
|
||||
public readonly _sortingService: SortingService,
|
||||
@ -118,8 +120,9 @@ export class FileAttributesListingScreenComponent implements OnInit {
|
||||
return this.selectedFileAttributeIds.indexOf(attribute.id) !== -1;
|
||||
}
|
||||
|
||||
importCSV(files: FileList | File[]) {
|
||||
public importCSV(files: FileList | File[]) {
|
||||
const csvFile = files[0];
|
||||
this._fileInput.nativeElement.value = null;
|
||||
|
||||
this._dialogService.openImportFileAttributeCSVDialog(csvFile, this._appStateService.activeRuleSetId, async () => {
|
||||
await this._loadData();
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="grid-container">
|
||||
<div class="row">
|
||||
<div translate="license-info-screen.backend-version"></div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import '../../../../../assets/styles/red-mixins';
|
||||
@import '../../../../../assets/styles/red-variables';
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: 100vw;
|
||||
@include inset-shadow;
|
||||
overflow: auto;
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="header-item">
|
||||
<div class="select-all-container">
|
||||
<div
|
||||
|
||||
@ -11,7 +11,7 @@ redaction-table-col-name::ng-deep {
|
||||
}
|
||||
}
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: 100vw;
|
||||
|
||||
cdk-virtual-scroll-viewport {
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="overlay-shadow"></div>
|
||||
<div class="dialog">
|
||||
<div class="dialog-header">
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import '../../../../../assets/styles/red-variables';
|
||||
@import '../../../../../assets/styles/red-mixins';
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: 100vw;
|
||||
background-color: $grey-2;
|
||||
display: flex;
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container" [class.extended]="collapsedDetails">
|
||||
<div class="content-container" [class.extended]="collapsedDetails">
|
||||
<div class="header-item">
|
||||
<div class="select-all-container">
|
||||
<div
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: calc(100vw - 353px);
|
||||
|
||||
.header-item {
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="overlay-shadow"></div>
|
||||
<div #viewer class="viewer"></div>
|
||||
<div class="changes-box" *ngIf="changed && permissionsService.isAdmin()">
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: calc(100vw - 353px);
|
||||
|
||||
.viewer {
|
||||
@ -94,11 +94,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.w-150 {
|
||||
max-width: 150px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.mb-5 {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
@ -127,8 +127,7 @@ export class AdminDialogService {
|
||||
public openImportFileAttributeCSVDialog(csv: File, ruleSetId: string, cb?: Function): MatDialogRef<FileAttributesCsvImportDialogComponent> {
|
||||
const ref = this._dialog.open(FileAttributesCsvImportDialogComponent, {
|
||||
...largeDialogConfig,
|
||||
data: { csv, ruleSetId },
|
||||
autoFocus: true
|
||||
data: { csv, ruleSetId }
|
||||
});
|
||||
|
||||
ref.afterClosed().subscribe((result) => {
|
||||
|
||||
@ -30,27 +30,25 @@
|
||||
</div>
|
||||
|
||||
<div class="page-title">
|
||||
<span *ngIf="!permissionsService.canPerformAnnotationActions()" class="pill"
|
||||
translate="readonly-pill"></span>
|
||||
<span *ngIf="!permissionsService.canPerformAnnotationActions()" class="pill" translate="readonly-pill"></span>
|
||||
</div>
|
||||
|
||||
<div *ngIf="viewReady" class="flex-1 actions-container">
|
||||
<ng-container *ngIf="!appStateService.activeFile.isExcluded">
|
||||
<redaction-status-bar
|
||||
[config]="[
|
||||
{
|
||||
length: 1,
|
||||
color: appStateService.activeFile.status
|
||||
}
|
||||
]"
|
||||
{
|
||||
length: 1,
|
||||
color: appStateService.activeFile.status
|
||||
}
|
||||
]"
|
||||
[small]="true"
|
||||
>
|
||||
</redaction-status-bar>
|
||||
<div class="all-caps-label mr-16 ml-8">
|
||||
{{ appStateService.activeFile.status | translate }}
|
||||
<span
|
||||
*ngIf="appStateService.activeFile.status === 'UNDER_REVIEW' || appStateService.activeFile.status === 'UNDER_APPROVAL'"
|
||||
>{{ 'by' | translate }}:</span
|
||||
<span *ngIf="appStateService.activeFile.status === 'UNDER_REVIEW' || appStateService.activeFile.status === 'UNDER_APPROVAL'"
|
||||
>{{ 'by' | translate }}:</span
|
||||
>
|
||||
</div>
|
||||
|
||||
@ -62,7 +60,9 @@
|
||||
></redaction-initials-avatar>
|
||||
<div
|
||||
(click)="editingReviewer = true"
|
||||
*ngIf="!editingReviewer && !appStateService.activeFile.currentReviewer && permissionsService.canAssignReviewer(appStateService.activeFile)"
|
||||
*ngIf="
|
||||
!editingReviewer && !appStateService.activeFile.currentReviewer && permissionsService.canAssignReviewer(appStateService.activeFile)
|
||||
"
|
||||
class="assign-reviewer pointer"
|
||||
translate="file-preview.assign-reviewer"
|
||||
></div>
|
||||
@ -190,7 +190,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="overlay-shadow"></div>
|
||||
<redaction-pdf-viewer
|
||||
(keyUp)="handleKeyEvent($event)"
|
||||
@ -208,10 +208,7 @@
|
||||
</div>
|
||||
|
||||
<div class="right-container">
|
||||
<redaction-disabled-for-redaction
|
||||
*ngIf="viewReady && appStateService.activeFile.isExcluded"
|
||||
>
|
||||
</redaction-disabled-for-redaction>
|
||||
<redaction-disabled-for-redaction *ngIf="viewReady && appStateService.activeFile.isExcluded"> </redaction-disabled-for-redaction>
|
||||
|
||||
<redaction-document-info
|
||||
*ngIf="viewReady && viewDocumentInfo"
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
min-width: fit-content;
|
||||
}
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
position: relative;
|
||||
width: calc(100vw - 350px);
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container">
|
||||
<div class="content-container">
|
||||
<div class="header-item">
|
||||
<span class="all-caps-label">
|
||||
{{ 'project-listing.table-header.title' | translate: { length: displayedProjects.length || 0 } }}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
@import '../../../../../assets/styles/red-mixins';
|
||||
@import '../../../../../assets/styles/red-variables';
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
cdk-virtual-scroll-viewport {
|
||||
::ng-deep.cdk-virtual-scroll-content-wrapper {
|
||||
grid-template-columns: 2fr 1fr 1fr auto 11px;
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="red-content-inner">
|
||||
<div class="left-container" [class.extended]="collapsedDetails">
|
||||
<div class="content-container" [class.extended]="collapsedDetails">
|
||||
<div *ngIf="!appStateService.activeProject?.hasFiles" class="empty-state">
|
||||
<mat-icon svgIcon="red:document"></mat-icon>
|
||||
<div class="heading-l" translate="project-overview.no-data.title"></div>
|
||||
@ -175,7 +175,7 @@
|
||||
[class.pointer]="permissionsService.canOpenFile(fileStatus)"
|
||||
[routerLink]="fileLink(fileStatus)"
|
||||
class="table-item"
|
||||
[class.disabled]='fileStatus.isExcluded'
|
||||
[class.disabled]="fileStatus.isExcluded"
|
||||
>
|
||||
<div class="pr-0" (click)="toggleFileSelected($event, fileStatus)">
|
||||
<div *ngIf="!isFileSelected(fileStatus)" class="select-oval"></div>
|
||||
|
||||
@ -72,7 +72,7 @@ cdk-virtual-scroll-viewport {
|
||||
}
|
||||
}
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
width: calc(100vw - 375px);
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div [matTooltipClass]="tooltipClass" [matTooltipPosition]="tooltipPosition" [matTooltip]="tooltip | translate">
|
||||
<div #matTooltip="matTooltip" [matTooltipClass]="tooltipClass" [matTooltipPosition]="tooltipPosition" [matTooltip]="tooltip | translate">
|
||||
<button
|
||||
(click)="performAction($event)"
|
||||
(click)="matTooltip.hide(0); performAction($event)"
|
||||
[class.dark-bg]="type === 'dark-bg'"
|
||||
[class.primary]="type === 'primary'"
|
||||
[class.warn]="type === 'warn'"
|
||||
|
||||
@ -23,7 +23,10 @@ export class CircleButtonComponent implements OnInit {
|
||||
|
||||
performAction($event: any) {
|
||||
if (!this.disabled) {
|
||||
this.action.emit($event);
|
||||
// Timeout to allow tooltip to disappear first
|
||||
setTimeout(() => {
|
||||
this.action.emit($event);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<div (click)="withSort && toggleSort.emit(column)" [class.pointer]="withSort" [ngClass]="class">
|
||||
<mat-icon *ngIf="!!icon" [svgIcon]="icon"></mat-icon>
|
||||
<span [translate]="label" class="all-caps-label"></span>
|
||||
<div class="sort-arrows-container" *ngIf="withSort" [class.force-display]="activeSortingOption.column === column">
|
||||
<mat-icon *ngIf="activeSortingOption?.order === 'asc'" svgIcon="red:sort-asc"></mat-icon>
|
||||
|
||||
@ -11,6 +11,13 @@
|
||||
width: 100%;
|
||||
line-height: 11px;
|
||||
padding: 0 24px;
|
||||
|
||||
> mat-icon {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 6px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-end {
|
||||
|
||||
@ -12,6 +12,7 @@ export class TableColNameComponent implements OnInit {
|
||||
@Input() public label: string;
|
||||
@Input() public withSort = false;
|
||||
@Input() public class: string;
|
||||
@Input() public icon: string;
|
||||
@Output() public toggleSort = new EventEmitter<string>();
|
||||
|
||||
constructor() {}
|
||||
|
||||
@ -755,7 +755,8 @@
|
||||
"action": {
|
||||
"edit": "Edit attribute",
|
||||
"delete": "Delete attribute"
|
||||
}
|
||||
},
|
||||
"upload-csv": "Upload File Attributes Configuration"
|
||||
},
|
||||
"confirm-delete-file-attribute": {
|
||||
"title": "Delete {{name}}",
|
||||
@ -1118,6 +1119,35 @@
|
||||
"total-rows": "{{rows}} rows in total",
|
||||
"available": "{{value}} available",
|
||||
"selected": "{{value}} selected",
|
||||
"csv-column": "CSV Column"
|
||||
"csv-column": "CSV Column",
|
||||
"no-hovered-column": "Preview CSV column by hovering the entry.",
|
||||
"table-header": {
|
||||
"title": "{{length}} file attributes",
|
||||
"actions": {
|
||||
"remove-selected": "Remove Selected"
|
||||
}
|
||||
},
|
||||
"file": "File:",
|
||||
"table-col-names": {
|
||||
"name": "Name",
|
||||
"type": "Type",
|
||||
"read-only": "Read-Only",
|
||||
"display": "Display"
|
||||
},
|
||||
"quick-activation": {
|
||||
"all": "All",
|
||||
"none": "None"
|
||||
},
|
||||
"types": {
|
||||
"Text": "Free Text",
|
||||
"Number": "Number",
|
||||
"Date": "Date"
|
||||
},
|
||||
"action": {
|
||||
"edit-name": "Edit Name",
|
||||
"save-name": "Save",
|
||||
"cancel-edit-name": "Cancel",
|
||||
"remove": "Remove"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +55,8 @@ form {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mat-form-field-wrapper {
|
||||
.mat-form-field-wrapper,
|
||||
.mat-form-field-infix {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
@ -221,11 +222,21 @@ form {
|
||||
max-width: 110px;
|
||||
}
|
||||
|
||||
&.w-150 {
|
||||
max-width: 150px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
&.w-160 {
|
||||
width: 160px;
|
||||
max-width: 160px;
|
||||
}
|
||||
|
||||
&.w-200 {
|
||||
width: 200px;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
&.w-250 {
|
||||
width: 250px;
|
||||
max-width: 250px;
|
||||
|
||||
@ -80,7 +80,7 @@ body {
|
||||
z-index: 1;
|
||||
transition: height ease-in-out 0.2s;
|
||||
|
||||
.left-container {
|
||||
.content-container {
|
||||
.overlay-shadow {
|
||||
@include inset-shadow;
|
||||
position: fixed;
|
||||
|
||||
@ -91,6 +91,11 @@ cdk-virtual-scroll-viewport {
|
||||
}
|
||||
}
|
||||
|
||||
input,
|
||||
mat-select {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
> div {
|
||||
background-color: #f9fafb;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user