merged with master
This commit is contained in:
parent
4f486aa4b4
commit
bbee5cadeb
@ -1,129 +1,144 @@
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {APP_INITIALIZER, NgModule} from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import {AppComponent} from './app.component';
|
||||
import {RouterModule} from '@angular/router';
|
||||
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||
import {ReactiveFormsModule} from "@angular/forms";
|
||||
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule} from "@angular/common/http";
|
||||
import {BaseScreenComponent} from './screens/base-screen/base-screen.component';
|
||||
import {ProjectListingScreenComponent} from './screens/project-listing-screen/project-listing-screen.component';
|
||||
import {ProjectOverviewScreenComponent} from './screens/project-overview-screen/project-overview-screen.component';
|
||||
import {MatToolbarModule} from "@angular/material/toolbar";
|
||||
import {ApiModule} from "@redaction/red-ui-http";
|
||||
import {ApiPathInterceptorService} from "./interceptor/api-path-interceptor.service";
|
||||
import {MatButtonModule} from "@angular/material/button";
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
|
||||
import {MatMenuModule} from "@angular/material/menu";
|
||||
import {languageInitializer} from "./i18n/language.initializer";
|
||||
import {LanguageService} from "./i18n/language.service";
|
||||
import {MatIconModule} from "@angular/material/icon";
|
||||
import {IconsModule} from "./icons/icons.module";
|
||||
import {AddEditProjectDialogComponent} from './screens/project-listing-screen/add-edit-project-dialog/add-edit-project-dialog.component';
|
||||
import {MatDialogModule} from '@angular/material/dialog';
|
||||
import {MatSnackBarModule} from "@angular/material/snack-bar";
|
||||
import {MatTooltipModule} from "@angular/material/tooltip";
|
||||
import {ConfirmationDialogComponent} from './common/confirmation-dialog/confirmation-dialog.component';
|
||||
import {FilePreviewScreenComponent} from './screens/file/file-preview-screen/file-preview-screen.component';
|
||||
import {PdfViewerComponent} from './screens/file/pdf-viewer/pdf-viewer.component';
|
||||
import {MatTabsModule} from "@angular/material/tabs";
|
||||
import {MatButtonToggleModule} from "@angular/material/button-toggle";
|
||||
import {NgpSortModule} from "ngp-sort-pipe";
|
||||
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||
import {MatSelectModule} from "@angular/material/select";
|
||||
import {NgxDropzoneModule} from "ngx-dropzone";
|
||||
import {MatSidenavModule} from "@angular/material/sidenav";
|
||||
import {FileDetailsDialogComponent} from './screens/file/file-preview-screen/file-details-dialog/file-details-dialog.component';
|
||||
import {ToastrModule} from "ngx-toastr";
|
||||
import {ServiceWorkerModule} from '@angular/service-worker';
|
||||
import {environment} from '../environments/environment';
|
||||
import {ProjectDetailsDialogComponent} from './screens/project-overview-screen/project-details-dialog/project-details-dialog.component';
|
||||
import {AuthModule} from "./auth/auth.module";
|
||||
import {AuthGuard} from "./auth/auth.guard";
|
||||
import {FileUploadModule} from "./upload/file-upload.module";
|
||||
import { AppComponent } from './app.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { BaseScreenComponent } from './screens/base-screen/base-screen.component';
|
||||
import { ProjectListingScreenComponent } from './screens/project-listing-screen/project-listing-screen.component';
|
||||
import { ProjectOverviewScreenComponent } from './screens/project-overview-screen/project-overview-screen.component';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { ApiModule } from '@redaction/red-ui-http';
|
||||
import { ApiPathInterceptorService } from './interceptor/api-path-interceptor.service';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { languageInitializer } from './i18n/language.initializer';
|
||||
import { LanguageService } from './i18n/language.service';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { IconsModule } from './icons/icons.module';
|
||||
import { AddEditProjectDialogComponent } from './screens/project-listing-screen/add-edit-project-dialog/add-edit-project-dialog.component';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { ConfirmationDialogComponent } from './common/confirmation-dialog/confirmation-dialog.component';
|
||||
import { FilePreviewScreenComponent } from './screens/file/file-preview-screen/file-preview-screen.component';
|
||||
import { PdfViewerComponent } from './screens/file/pdf-viewer/pdf-viewer.component';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { NgpSortModule } from 'ngp-sort-pipe';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { FileDetailsDialogComponent } from './screens/file/file-preview-screen/file-details-dialog/file-details-dialog.component';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
||||
import { environment } from '../environments/environment';
|
||||
import { ProjectDetailsDialogComponent } from './screens/project-overview-screen/project-details-dialog/project-details-dialog.component';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { AuthGuard } from './auth/auth.guard';
|
||||
import { FileUploadModule } from './upload/file-upload.module';
|
||||
import { FullPageLoadingIndicatorComponent } from './utils/full-page-loading-indicator/full-page-loading-indicator.component';
|
||||
import {MatProgressSpinnerModule} from "@angular/material/progress-spinner";
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { InitialsAvatarComponent } from './common/initials-avatar/initials-avatar.component';
|
||||
import { StatusBarComponent } from './components/status-bar/status-bar.component';
|
||||
|
||||
export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent, BaseScreenComponent, ProjectListingScreenComponent, ProjectOverviewScreenComponent, AddEditProjectDialogComponent, ConfirmationDialogComponent, FilePreviewScreenComponent, PdfViewerComponent, FileDetailsDialogComponent, ProjectDetailsDialogComponent, FullPageLoadingIndicatorComponent],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
ReactiveFormsModule,
|
||||
HttpClientModule,
|
||||
AuthModule,
|
||||
IconsModule,
|
||||
ApiModule,
|
||||
MatDialogModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
RouterModule.forRoot([
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'ui/projects',
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
path: 'ui',
|
||||
component: BaseScreenComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'projects',
|
||||
component: ProjectListingScreenComponent,
|
||||
canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'projects/:projectId',
|
||||
component: ProjectOverviewScreenComponent,
|
||||
canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'projects/:projectId/file/:fileId',
|
||||
component: FilePreviewScreenComponent,
|
||||
canActivate: [AuthGuard]
|
||||
}
|
||||
]
|
||||
}
|
||||
declarations: [
|
||||
AppComponent,
|
||||
BaseScreenComponent,
|
||||
ProjectListingScreenComponent,
|
||||
ProjectOverviewScreenComponent,
|
||||
AddEditProjectDialogComponent,
|
||||
ConfirmationDialogComponent,
|
||||
FilePreviewScreenComponent,
|
||||
PdfViewerComponent,
|
||||
FileDetailsDialogComponent,
|
||||
ProjectDetailsDialogComponent,
|
||||
FullPageLoadingIndicatorComponent,
|
||||
InitialsAvatarComponent,
|
||||
StatusBarComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
ReactiveFormsModule,
|
||||
HttpClientModule,
|
||||
AuthModule,
|
||||
IconsModule,
|
||||
ApiModule,
|
||||
MatDialogModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useFactory: HttpLoaderFactory,
|
||||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
RouterModule.forRoot([
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'ui/projects',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: 'ui',
|
||||
component: BaseScreenComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'projects',
|
||||
component: ProjectListingScreenComponent,
|
||||
canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'projects/:projectId',
|
||||
component: ProjectOverviewScreenComponent,
|
||||
canActivate: [AuthGuard]
|
||||
},
|
||||
{
|
||||
path: 'projects/:projectId/file/:fileId',
|
||||
component: FilePreviewScreenComponent,
|
||||
canActivate: [AuthGuard]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]),
|
||||
NgpSortModule,
|
||||
MatToolbarModule,
|
||||
MatButtonModule,
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatTooltipModule,
|
||||
MatSnackBarModule,
|
||||
MatTabsModule,
|
||||
MatButtonToggleModule,
|
||||
MatFormFieldModule,
|
||||
ToastrModule.forRoot(),
|
||||
MatSelectModule,
|
||||
MatSidenavModule,
|
||||
FileUploadModule,
|
||||
ServiceWorkerModule.register('ngsw-worker.js', {enabled: environment.production}),
|
||||
MatProgressSpinnerModule
|
||||
],
|
||||
providers: [ {
|
||||
]),
|
||||
NgpSortModule,
|
||||
MatToolbarModule,
|
||||
MatButtonModule,
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatTooltipModule,
|
||||
MatSnackBarModule,
|
||||
MatTabsModule,
|
||||
MatButtonToggleModule,
|
||||
MatFormFieldModule,
|
||||
ToastrModule.forRoot(),
|
||||
MatSelectModule,
|
||||
MatSidenavModule,
|
||||
FileUploadModule,
|
||||
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
|
||||
MatProgressSpinnerModule
|
||||
],
|
||||
providers: [{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
multi: true,
|
||||
useClass: ApiPathInterceptorService,
|
||||
useClass: ApiPathInterceptorService
|
||||
}, {
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
useFactory: languageInitializer,
|
||||
deps: [LanguageService]
|
||||
}],
|
||||
bootstrap: [AppComponent],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
<div class="flex-row">
|
||||
<div [className]="color + ' oval ' + size">{{initials}}</div>
|
||||
<div *ngIf="withName" class="clamp-2">{{username || ('initials-avatar.unassigned.label' | translate)}}</div>
|
||||
</div>
|
||||
@ -0,0 +1,11 @@
|
||||
@import "../../../assets/styles/red-variables";
|
||||
|
||||
* {
|
||||
font-size: 13px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-initials-avatar',
|
||||
templateUrl: './initials-avatar.component.html',
|
||||
styleUrls: ['./initials-avatar.component.scss']
|
||||
})
|
||||
export class InitialsAvatarComponent implements OnInit {
|
||||
@Input()
|
||||
public username: string;
|
||||
|
||||
@Input()
|
||||
public color: 'gray' | 'red' = 'gray';
|
||||
|
||||
@Input()
|
||||
public size: 'small' | 'large' = 'small';
|
||||
|
||||
@Input()
|
||||
public withName = false;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
public get initials(): string {
|
||||
if (!this.username) {
|
||||
return '?'
|
||||
}
|
||||
|
||||
return this.username
|
||||
.split(' ')
|
||||
.filter((value, idx) => idx < 2)
|
||||
.map((str) => str[0])
|
||||
.join('');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
<div class="rectangle-container">
|
||||
<div *ngFor="let rect of config" [className]="'section-wrapper flex-' + rect.length">
|
||||
<div *ngIf="rect.title" class="subtitle">{{ rect.title }}</div>
|
||||
<div [className]="'rectangle ' + rect.color "></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,49 @@
|
||||
@import '../../../assets/styles/red-variables';
|
||||
|
||||
.rectangle-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
.subtitle {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.section-wrapper:first-child {
|
||||
.rectangle {
|
||||
border-radius: 6px 0 0 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.section-wrapper:last-child {
|
||||
.rectangle {
|
||||
border-radius: 0 6px 6px 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
.rectangle {
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rectangle {
|
||||
height: 4px;
|
||||
|
||||
&.grey {
|
||||
background-color: $grey-4;
|
||||
}
|
||||
|
||||
&.yellow {
|
||||
background-color: $yellow-1;
|
||||
}
|
||||
|
||||
&.blue {
|
||||
background-color: $blue-1;
|
||||
}
|
||||
|
||||
&.green {
|
||||
background-color: $green-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-status-bar',
|
||||
templateUrl: './status-bar.component.html',
|
||||
styleUrls: ['./status-bar.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class StatusBarComponent implements OnInit {
|
||||
@Input()
|
||||
public config: {
|
||||
length: number,
|
||||
color: 'green' | 'blue' | 'red' | 'grey' | 'yellow',
|
||||
title?: string,
|
||||
}[] = [];
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
}
|
||||
@ -8,25 +8,31 @@
|
||||
<button mat-menu-item routerLink="/ui/projects"
|
||||
translate="top-bar.navigation-items.projects.label">
|
||||
</button>
|
||||
<button *ngIf="appStateService.activeProject" [routerLink]="'/ui/projects/'+appStateService.activeProject.projectId"
|
||||
<button *ngIf="appStateService.activeProject"
|
||||
[routerLink]="'/ui/projects/'+appStateService.activeProject.projectId"
|
||||
mat-menu-item>{{appStateService.activeProject.projectName}}</button>
|
||||
<button *ngIf="appStateService.activeFile" [routerLink]="'/ui/projects/'+appStateService.activeProject.projectId+'/file/'+appStateService.activeFile.fileId"
|
||||
<button *ngIf="appStateService.activeFile"
|
||||
[routerLink]="'/ui/projects/'+appStateService.activeProject.projectId+'/file/'+appStateService.activeFile.fileId"
|
||||
mat-menu-item>{{appStateService.activeFile.filename}}</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
<div class="menu left visible-lg">
|
||||
<button color="primary" mat-flat-button routerLink="/ui/projects"
|
||||
translate="top-bar.navigation-items.projects.label"></button>
|
||||
<a class="breadcrumb" routerLink="/ui/projects"
|
||||
translate="top-bar.navigation-items.projects.label"></a>
|
||||
<div *ngIf="appStateService.activeProject" class="breadcrumb">
|
||||
<mat-icon svgIcon="red:chevron-right"></mat-icon>
|
||||
</div>
|
||||
<button *ngIf="appStateService.activeProject" [routerLink]="'/ui/projects/'+appStateService.activeProject.projectId" color="accent"
|
||||
mat-flat-button>{{appStateService.activeProject.projectName}}</button>
|
||||
<a *ngIf="appStateService.activeProject" class="breadcrumb"
|
||||
[routerLink]="'/ui/projects/'+appStateService.activeProject.projectId">
|
||||
{{appStateService.activeProject.projectName}}
|
||||
</a>
|
||||
<div *ngIf="appStateService.activeFile" class="breadcrumb">
|
||||
<mat-icon svgIcon="red:chevron-right"></mat-icon>
|
||||
</div>
|
||||
<button *ngIf="appStateService.activeFile" [routerLink]="'/ui/projects/'+appStateService.activeProject.projectId+'/file/'+appStateService.activeFile.fileId" color="accent"
|
||||
mat-flat-button>{{appStateService.activeFile.filename}}</button>
|
||||
<a *ngIf="appStateService.activeFile" class="breadcrumb"
|
||||
[routerLink]="'/ui/projects/'+appStateService.activeProject.projectId+'/file/'+appStateService.activeFile.fileId">
|
||||
{{appStateService.activeFile.filename}}
|
||||
</a>
|
||||
</div>
|
||||
<div class="menu right">
|
||||
<button [matMenuTriggerFor]="menu" mat-button translate="top-bar.navigation-items.my-account.label"></button>
|
||||
@ -52,7 +58,5 @@
|
||||
<div class="divider"></div>
|
||||
</div>
|
||||
<div class="red-content">
|
||||
<div class="red-content-inner">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
|
||||
@ -1,35 +1,68 @@
|
||||
<section class="center-section" *ngIf="viewReady">
|
||||
|
||||
<div class="page-header">
|
||||
<div class="heading-xl" translate="projects.header.label"></div>
|
||||
<button (click)="openAddProjectDialog()" color="accent" mat-flat-button translate="projects.add-new.label"></button>
|
||||
<div class="filters flex-row">
|
||||
<span translate="filters.filter-by.label"></span>
|
||||
<div translate="filters.status.label"></div>
|
||||
<div translate="filters.people.label"></div>
|
||||
<div translate="filters.due-date.label"></div>
|
||||
<div translate="filters.project.label"></div>
|
||||
<div translate="filters.document.label"></div>
|
||||
</div>
|
||||
<button (click)="openAddProjectDialog()" color="warn" mat-flat-button translate="projects.add-new.label"></button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="appStateService.allProjects?.length === 0 " translate="projects.no-projects.label"></div>
|
||||
<div class="listing">
|
||||
<div *ngFor="let project of appStateService.allProjects" [routerLink]="'/ui/projects/'+project.projectId"
|
||||
class="list-entry clickable">
|
||||
<div class="list-entry-content">
|
||||
<div class="listing-title">
|
||||
{{project.projectName}}
|
||||
</div>
|
||||
<div class="listing-subtitle">
|
||||
{{project.description}}
|
||||
</div>
|
||||
<div class="listing-subtitle">
|
||||
{{project.date | date:'short'}}
|
||||
|
||||
<div class="flex red-content-inner">
|
||||
<div class="table-container">
|
||||
<div class="table-header">
|
||||
<span class="subheading">
|
||||
{{'projects.table-header.title.label'| translate:{ length: appStateService.allProjects?.length || 0 } }}
|
||||
</span>
|
||||
<div class="actions">
|
||||
<div translate="projects.table-header.bulk-select.label"></div>
|
||||
<div translate="projects.table-header.recent.label"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-entry-actions">
|
||||
<button (click)="editProject($event,project)" mat-icon-button
|
||||
[matTooltip]="'projects.edit.action.label'|translate">
|
||||
<mat-icon svgIcon="red:edit"></mat-icon>
|
||||
</button>
|
||||
<button (click)="deleteProject($event,project)" color="warn" mat-icon-button
|
||||
[matTooltip]="'projects.delete.action.label'|translate">
|
||||
<mat-icon svgIcon="red:delete"></mat-icon>
|
||||
</button>
|
||||
|
||||
<div class="table-content">
|
||||
<div *ngFor="let project of appStateService.allProjects"
|
||||
[routerLink]="'/ui/projects/'+project.projectId"
|
||||
class="table-item"
|
||||
>
|
||||
<div class="flex-2">
|
||||
<div class="table-item-title table-item-title--large">
|
||||
{{project.projectName}}
|
||||
</div>
|
||||
<div class="subtitle stats-subtitle">
|
||||
<div>12</div>
|
||||
<div>9</div>
|
||||
<div>25 Dec. 2020</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<redaction-initials-avatar username="Timo Bejan"
|
||||
withName="true"
|
||||
></redaction-initials-avatar>
|
||||
</div>
|
||||
<div class="stats-bar">
|
||||
<redaction-status-bar
|
||||
[config]="[{ color: 'yellow', length: 2}, { length: 1, color: 'green'}]"
|
||||
></redaction-status-bar>
|
||||
</div>
|
||||
|
||||
<div class="on-hover-wrapper">
|
||||
<div class="on-hover">
|
||||
<div>d</div>
|
||||
<div>s</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-fixed-container"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
@import "../../../assets/styles/red-mixins";
|
||||
|
||||
:host {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
.stats-subtitle {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.stats-bar {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
@ -5,66 +5,130 @@
|
||||
|
||||
|
||||
<div *ngIf="appStateService.activeProject" class="page-header">
|
||||
<div class="heading-xl clamp-1">{{appStateService.activeProject.projectName}}</div>
|
||||
<button (click)="fileInput.click()" color="accent" mat-flat-button
|
||||
translate="project-overview.upload-files.label"></button>
|
||||
<div class="filters flex-row">
|
||||
<span translate="filters.filter-by.label"></span>
|
||||
<div translate="filters.status.label"></div>
|
||||
<div translate="filters.people.label"></div>
|
||||
<div translate="filters.due-date.label"></div>
|
||||
<div translate="filters.document.label"></div>
|
||||
</div>
|
||||
<button (click)="fileInput.click()" color="warn" mat-flat-button
|
||||
translate="project-overview.upload-document.label"></button>
|
||||
<input #fileInput (change)="uploadFiles($event.target.files)" class="file-upload-input" multiple="true"
|
||||
type="file">
|
||||
</div>
|
||||
<div class="flex-row">
|
||||
<div class="heading-l clamp-2">{{appStateService.activeProject?.description}}</div>
|
||||
<mat-form-field *ngIf="appStateService.projectFiles && appStateService.projectFiles.length > 0">
|
||||
<mat-label>{{'project-overview.sorting.label' | translate}}</mat-label>
|
||||
<mat-select (valueChange)="sortingChanged($event)" [value]="sorting" color="primary">
|
||||
<mat-option *ngFor="let option of sortOptions" [value]="option.value">
|
||||
<mat-icon [svgIcon]="option.icon"></mat-icon>
|
||||
{{option.label | translate}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="break-20"></div>
|
||||
<div class="listing">
|
||||
<div *ngFor="let fileStatus of appStateService.projectFiles | sortBy: sorting.order:sorting.name; trackBy:fileId"
|
||||
[class.clickable]="fileStatus.status === 'PROCESSED'"
|
||||
[routerLink]="fileStatus.status === 'PROCESSED' ? ['/ui/projects/'+projectId+'/file/'+fileStatus.fileId] : []"
|
||||
class="list-entry xl">
|
||||
<div class="list-entry-content">
|
||||
<div class="listing-title one-line slim break-all">
|
||||
{{fileStatus.filename}}
|
||||
</div>
|
||||
<div class="listing-subtitle">
|
||||
{{'project-overview.file-listing.file-entry.status.label'| translate:fileStatus}}
|
||||
</div>
|
||||
<div class="listing-subtitle">
|
||||
{{'project-overview.file-listing.file-entry.number-of-pages.label'| translate:fileStatus}}
|
||||
</div>
|
||||
<div class="listing-subtitle">
|
||||
{{'project-overview.file-listing.file-entry.number-of-analyses.label'| translate:fileStatus}}
|
||||
</div>
|
||||
<div class="listing-subtitle">
|
||||
{{'project-overview.file-listing.file-entry.added.label'| translate:{added: fileStatus.added | date:'short'} }}
|
||||
</div>
|
||||
<div *ngIf="fileStatus.lastUpdated" class="listing-subtitle">
|
||||
{{'project-overview.file-listing.file-entry.last-updated.label'| translate:{lastUpdated: fileStatus.lastUpdated | date:'short'} }}
|
||||
|
||||
<div class="flex red-content-inner">
|
||||
<div class="table-container">
|
||||
<div class="table-header">
|
||||
<span class="subheading">
|
||||
{{'project-overview.table-header.title.label'| translate:{ length: appStateService.projectFiles?.length || 0 } }}
|
||||
</span>
|
||||
<div class="actions">
|
||||
<div translate="project-overview.table-header.bulk-select.label"></div>
|
||||
<div translate="project-overview.table-header.recent.label"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-entry-actions">
|
||||
<button (click)="deleteFile($event,fileStatus)" color="warn" mat-icon-button
|
||||
[matTooltip]="'project-overview.delete.action.label'|translate">
|
||||
<mat-icon svgIcon="red:delete"></mat-icon>
|
||||
</button>
|
||||
<button (click)="reanalyseFile($event,fileStatus)" color="primary" mat-icon-button
|
||||
[matTooltip]="'project-overview.reanalyse.action.label'|translate">
|
||||
<mat-icon svgIcon="red:refresh"></mat-icon>
|
||||
</button>
|
||||
|
||||
<div class="table-header">
|
||||
<redaction-status-bar [config]="[{ length: 2, color: 'yellow', title: 'text 1'}, { length: 1, color: 'green', title: 'text 2'}]"></redaction-status-bar>
|
||||
</div>
|
||||
|
||||
<div class="table-col-names">
|
||||
<div class="flex-3 subtitle min-width" translate="project-overview.table-col-names.name.label"></div>
|
||||
<div class="flex-2 subtitle min-width" translate="project-overview.table-col-names.added-on.label"></div>
|
||||
<div class="flex-1 subtitle min-width" translate="project-overview.table-col-names.added-by.label"></div>
|
||||
<div class="flex-1 subtitle min-width" translate="project-overview.table-col-names.assigned-to.label"></div>
|
||||
<div class="subtitle status-container" translate="project-overview.table-col-names.status.label"></div>
|
||||
</div>
|
||||
|
||||
<div class="table-item"
|
||||
*ngFor="let fileStatus of appStateService.projectFiles | sortBy: sorting.order:sorting.name; trackBy:fileId"
|
||||
[routerLink]="fileStatus.status === 'PROCESSED' ? ['/ui/projects/'+projectId+'/file/'+fileStatus.fileId] : []">
|
||||
<div class="flex-3 table-item-title min-width">
|
||||
{{ fileStatus.filename }}
|
||||
</div>
|
||||
|
||||
<div class="subtitle flex-2 min-width">
|
||||
{{ fileStatus.added | date:'d MMM. yyyy, hh:mm a' }}
|
||||
</div>
|
||||
|
||||
<div class="subtitle flex-1 min-width">
|
||||
Timo Bejan
|
||||
</div>
|
||||
|
||||
<div class="subtitle flex-1 min-width">
|
||||
<redaction-initials-avatar
|
||||
withName="true"
|
||||
></redaction-initials-avatar>
|
||||
</div>
|
||||
|
||||
<div class=" status-container">
|
||||
<div class="status-bar-wrapper">
|
||||
<redaction-status-bar
|
||||
[config]="[{ color: 'yellow', length: 1 }]"
|
||||
></redaction-status-bar>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="on-hover-wrapper">
|
||||
<div class="on-hover">
|
||||
<div>d</div>
|
||||
<div>s</div>
|
||||
<div>v</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project-details-container right-fixed-container">
|
||||
<div class="actions-row">
|
||||
<div>Edit</div>
|
||||
<div>Delete</div>
|
||||
<div>View</div>
|
||||
</div>
|
||||
|
||||
<div class="subtitle stats-subtitle mt-20">
|
||||
<div>
|
||||
{{ appStateService.projectFiles.length }}
|
||||
</div>
|
||||
<div>9</div>
|
||||
<div>
|
||||
{{ appStateService.activeProject.date | date:'d MMM. yyyy' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="heading-xl mt-20">
|
||||
{{ appStateService.activeProject.projectName }}
|
||||
</div>
|
||||
|
||||
<div class="owner flex-row mt-20">
|
||||
<redaction-initials-avatar username="Timo Bejan"
|
||||
size="large"
|
||||
withName="true"
|
||||
></redaction-initials-avatar>
|
||||
</div>
|
||||
|
||||
<div class="description mt-20">
|
||||
{{ appStateService.activeProject.description }}
|
||||
</div>
|
||||
|
||||
<div class="project-team mt-20">
|
||||
<div class="subheading" translate="project-overview.project-details.project-team.label"></div>
|
||||
<div class="flex mt-20">
|
||||
<div *ngFor="let username of ['S H', 'D O', 'E G', 'D V', 'J A', 'T H', 'P B']" class="member">
|
||||
<redaction-initials-avatar [username]="username" size="large"></redaction-initials-avatar>
|
||||
</div>
|
||||
<div class="member">
|
||||
<div class="oval large">+2</div>
|
||||
</div>
|
||||
<div class="member">
|
||||
<div class="oval red large">+</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<button (click)="showDetailsDialog($event)" aria-label="details" class="details-button" color="primary" mat-fab>
|
||||
<mat-icon svgIcon="red:info"></mat-icon>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<redaction-full-page-loading-indicator [displayed]="!viewReady"></redaction-full-page-loading-indicator>
|
||||
|
||||
@ -1,14 +1,45 @@
|
||||
|
||||
|
||||
|
||||
.listing {
|
||||
position: relative;
|
||||
height: calc(100vh - (61px + 80px + 70px + 80px));
|
||||
overflow: auto;
|
||||
}
|
||||
@import "../../../assets/styles/red-variables";
|
||||
|
||||
.file-upload-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.min-width {
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.status-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 40px;
|
||||
|
||||
.status-bar-wrapper {
|
||||
width: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-header redaction-status-bar {
|
||||
width: 100%;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.project-details-container {
|
||||
.actions-row {
|
||||
display: flex;
|
||||
|
||||
> div {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.project-team {
|
||||
.member:not(:last-child) {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
import {ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild} from '@angular/core';
|
||||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import {
|
||||
FileStatus,
|
||||
FileUploadControllerService,
|
||||
ProjectControllerService,
|
||||
ReanalysisControllerService,
|
||||
StatusControllerService
|
||||
} from "@redaction/red-ui-http";
|
||||
import {NotificationService, NotificationType} from "../../notification/notification.service";
|
||||
import {TranslateService} from "@ngx-translate/core";
|
||||
import {ConfirmationDialogComponent} from "../../common/confirmation-dialog/confirmation-dialog.component";
|
||||
import {MatDialog} from "@angular/material/dialog";
|
||||
import {AppStateService} from "../../state/app-state.service";
|
||||
import {ProjectDetailsDialogComponent} from "./project-details-dialog/project-details-dialog.component";
|
||||
import {FileDropOverlayService} from "../../upload/file-drop/service/file-drop-overlay.service";
|
||||
} from '@redaction/red-ui-http';
|
||||
import { NotificationService, NotificationType } from '../../notification/notification.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ConfirmationDialogComponent } from '../../common/confirmation-dialog/confirmation-dialog.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { AppStateService } from '../../state/app-state.service';
|
||||
import { ProjectDetailsDialogComponent } from './project-details-dialog/project-details-dialog.component';
|
||||
import { FileDropOverlayService } from '../../upload/file-drop/service/file-drop-overlay.service';
|
||||
|
||||
|
||||
@Component({
|
||||
@ -25,24 +25,26 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
|
||||
viewReady = false;
|
||||
|
||||
@ViewChild('dropzoneComponent', {static: true}) dropZoneComponent;
|
||||
@ViewChild('dropzoneComponent', { static: true }) dropZoneComponent;
|
||||
|
||||
dragActive = false;
|
||||
|
||||
sortOptions: any[] = [{
|
||||
value: {name: 'lastUpdated', order: 'desc'},
|
||||
value: { name: 'lastUpdated', order: 'desc' },
|
||||
label: 'project-overview.sorting.last-updated-desc.label',
|
||||
icon: 'red:sort-desc'
|
||||
}, {
|
||||
value: {name: 'lastUpdated', order: 'asc'},
|
||||
value: { name: 'lastUpdated', order: 'asc' },
|
||||
label: 'project-overview.sorting.last-updated-asc.label',
|
||||
icon: 'red:sort-asc'
|
||||
}, {
|
||||
value: {name: 'filename', order: 'desc'},
|
||||
value: { name: 'filename', order: 'desc' },
|
||||
label: 'project-overview.sorting.file-name-desc.label',
|
||||
icon: 'red:sort-desc'
|
||||
}, {
|
||||
value: {name: 'filename', order: 'asc'}, label: 'project-overview.sorting.file-name-asc.label', icon: 'red:sort-asc'
|
||||
value: { name: 'filename', order: 'asc' },
|
||||
label: 'project-overview.sorting.file-name-asc.label',
|
||||
icon: 'red:sort-asc'
|
||||
}];
|
||||
sorting: any = this.sortOptions[0].value;
|
||||
projectId: string;
|
||||
@ -78,7 +80,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
const dialogRef = this._dialog.open(ConfirmationDialogComponent, {
|
||||
width: '400px',
|
||||
maxWidth: '90vw',
|
||||
autoFocus: false,
|
||||
autoFocus: false
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
@ -116,7 +118,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
this._fileDropOverlayService.cleanupFileDropHandling();
|
||||
if (this._fileStatusInterval) {
|
||||
this._fileStatusInterval = null;
|
||||
clearInterval(this._fileStatusInterval)
|
||||
clearInterval(this._fileStatusInterval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +68,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"filters": {
|
||||
"filter-by": {
|
||||
"label": "Filter by:"
|
||||
},
|
||||
"status": {
|
||||
"label": "Status"
|
||||
},
|
||||
"people": {
|
||||
"label": "People"
|
||||
},
|
||||
"due-date": {
|
||||
"label": "Due Date"
|
||||
},
|
||||
"project": {
|
||||
"label": "Project"
|
||||
},
|
||||
"document": {
|
||||
"label": "Document"
|
||||
}
|
||||
},
|
||||
"projects": {
|
||||
"table-header": {
|
||||
"title": {
|
||||
"label": "{{length}} active projects"
|
||||
},
|
||||
"bulk-select": {
|
||||
"label": "Bulk select"
|
||||
},
|
||||
"recent": {
|
||||
"label": "Recent"
|
||||
}
|
||||
},
|
||||
"add-edit-dialog": {
|
||||
"header-new": {
|
||||
"label": "New Project"
|
||||
@ -146,6 +177,37 @@
|
||||
}
|
||||
},
|
||||
"project-overview": {
|
||||
"table-header": {
|
||||
"title": {
|
||||
"label": "{{length}} documents"
|
||||
},
|
||||
"bulk-select": {
|
||||
"label": "Bulk select"
|
||||
},
|
||||
"recent": {
|
||||
"label": "Recent"
|
||||
}
|
||||
},
|
||||
"table-col-names": {
|
||||
"name": {
|
||||
"label": "Name"
|
||||
},
|
||||
|
||||
"added-on": {
|
||||
"label": "Added on"
|
||||
},
|
||||
|
||||
"added-by": {
|
||||
"label": "Added by"
|
||||
},
|
||||
|
||||
"assigned-to": {
|
||||
"label": "Assigned to"
|
||||
},
|
||||
"status": {
|
||||
"label": "Status"
|
||||
}
|
||||
},
|
||||
"sorting": {
|
||||
"label": "Sorting",
|
||||
"last-updated-desc": {
|
||||
@ -196,14 +258,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"project-details": {
|
||||
"project-team": {
|
||||
"label": "Project team"
|
||||
}
|
||||
},
|
||||
"header": {
|
||||
"label": "Project Overview"
|
||||
},
|
||||
"upload-files": {
|
||||
"label": "Upload Files"
|
||||
"upload-document": {
|
||||
"label": "Upload Document"
|
||||
},
|
||||
"no-project": {
|
||||
"label": "Requested project: {{projectId}} does not exist! <a href='/ui/projects'>Back to Project Listing. <a/>"
|
||||
}
|
||||
},
|
||||
"initials-avatar": {
|
||||
"unassigned": {
|
||||
"label": "Unassigned"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
apps/red-ui/src/assets/styles/red-components.scss
Normal file
38
apps/red-ui/src/assets/styles/red-components.scss
Normal file
@ -0,0 +1,38 @@
|
||||
@import "red-variables";
|
||||
|
||||
.oval {
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
border-radius: 12px;
|
||||
font-size: 10px;
|
||||
border: 1px solid #E2E4E9;
|
||||
|
||||
&.large {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
border-radius: 16px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&.gray {
|
||||
background-color: $grey-4;
|
||||
border: none;
|
||||
}
|
||||
|
||||
&.red {
|
||||
background-color: $red-1;
|
||||
color: $white;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.stats-subtitle {
|
||||
display: flex;
|
||||
> div:not(:last-child) {
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,6 @@
|
||||
label {
|
||||
height: 14px;
|
||||
opacity: 0.6;
|
||||
color: $grey-1;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0;
|
||||
|
||||
@ -6,4 +6,5 @@
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@ -1,154 +1,81 @@
|
||||
@import "red-variables";
|
||||
@import "red-mixins";
|
||||
|
||||
@media only screen and (max-width: 720px) {
|
||||
.listing {
|
||||
.list-entry {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
font-family: 'Inter', sans-serif;
|
||||
color: $grey-1;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 20px;
|
||||
|
||||
&.slim {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
padding: 0 24px;
|
||||
height: 50px;
|
||||
box-shadow: 0 2px 4px 0 $grey-4;
|
||||
position: fixed;
|
||||
top: 61px;
|
||||
width: 100vw;
|
||||
box-sizing: border-box;
|
||||
background-color: $white;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
|
||||
.listing {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.list-entry {
|
||||
box-sizing: border-box;
|
||||
height: 122px;
|
||||
width: 310px;
|
||||
border: 1px solid $grey-1;
|
||||
border-radius: 2px;
|
||||
background-color: $white;
|
||||
padding: 20px 24px;
|
||||
margin-right: 22px;
|
||||
margin-bottom: 22px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
transition: background-color 0.35s ease-in-out;
|
||||
|
||||
&.xl {
|
||||
width: 100%;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-2;
|
||||
|
||||
.list-entry-actions {
|
||||
mat-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.clickable:hover {
|
||||
background-color: $grey-1;
|
||||
cursor: pointer;
|
||||
color: $white;
|
||||
|
||||
.list-entry-actions {
|
||||
button.mat-primary {
|
||||
mat-icon {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.listing-title, .listing-subtitle {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.list-entry-content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.list-entry-actions {
|
||||
width: 18px;
|
||||
margin-left: 22px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: -4px;
|
||||
|
||||
mat-icon {
|
||||
opacity: 0;
|
||||
transition: opacity 0.35s ease-in-out;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.listing-title {
|
||||
height: 44px;
|
||||
color: #283241;
|
||||
font-family: Inter, sans-serf, serif;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0;
|
||||
margin-bottom: 17px;
|
||||
line-height: 22px;
|
||||
@include line-clamp(2);
|
||||
transition: color 0.35s ease-in-out;
|
||||
|
||||
&.one-line {
|
||||
height: 22px;
|
||||
@include line-clamp(1);
|
||||
}
|
||||
|
||||
&.slim {
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
|
||||
&.break-all {
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.listing-subtitle {
|
||||
height: 12px;
|
||||
opacity: 0.7;
|
||||
color: #283241;
|
||||
font-family: Inconsolata, monospace, monospace;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0;
|
||||
line-height: 12px;
|
||||
@include line-clamp(1);
|
||||
transition: color 0.35s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.red-content-inner {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.right-fixed-container {
|
||||
border-left: 1px solid $grey-4;
|
||||
height: 100%;
|
||||
width: 330px;
|
||||
padding: 24px;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.filters {
|
||||
font-size: 13px;
|
||||
line-height: 14px;
|
||||
|
||||
> div {
|
||||
padding: 10px 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.flex-2 {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.flex-3 {
|
||||
flex: 3;
|
||||
}
|
||||
|
||||
.mt-20 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
height: calc(100vh - 61px - 50px);
|
||||
width: calc(100vw - 379px);
|
||||
}
|
||||
|
||||
.break-20 {
|
||||
height: 20px;
|
||||
background: transparent;
|
||||
@ -163,7 +90,6 @@ html, body {
|
||||
|
||||
.detail-row {
|
||||
opacity: 1;
|
||||
color: $grey-1;
|
||||
font-family: Inconsolata, monospace, monospace;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0;
|
||||
@ -171,13 +97,6 @@ html, body {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.center-section {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
|
||||
.red-top-bar {
|
||||
height: 61px;
|
||||
width: 100%;
|
||||
@ -189,8 +108,7 @@ html, body {
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-left: 60px;
|
||||
padding-right: 60px;
|
||||
padding: 0 24px;
|
||||
|
||||
.menu {
|
||||
display: flex;
|
||||
@ -199,15 +117,23 @@ html, body {
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
color: $yellow-1;
|
||||
text-decoration: none;
|
||||
color: $grey-1;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
font-weight: 600;
|
||||
@include line-clamp(1);
|
||||
max-width: 320px;
|
||||
|
||||
mat-icon {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
color: $red-1;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
@ -221,7 +147,6 @@ html, body {
|
||||
width: 100vw;
|
||||
height: calc(100vh - 61px);
|
||||
overflow: auto;
|
||||
|
||||
}
|
||||
|
||||
.hidden {
|
||||
|
||||
88
apps/red-ui/src/assets/styles/red-tables.scss
Normal file
88
apps/red-ui/src/assets/styles/red-tables.scss
Normal file
@ -0,0 +1,88 @@
|
||||
@import "red-variables";
|
||||
@import "red-mixins";
|
||||
|
||||
.table-header {
|
||||
background-color: rgba(226, 228, 233, 0.9);
|
||||
padding: 7px 24px 9px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
font-size: 13px;
|
||||
|
||||
div {
|
||||
padding: 10px 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-col-names {
|
||||
display: flex;
|
||||
text-transform: uppercase;
|
||||
|
||||
> div {
|
||||
padding: 8px 24px;
|
||||
font-weight: 600;
|
||||
border-bottom: 1px solid rgba(226, 228, 233, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.table-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 80px;
|
||||
border-bottom: 1px solid rgba(226, 228, 233, 0.9);
|
||||
|
||||
> div:not(.on-hover) {
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.table-item-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
line-height: 18px;
|
||||
@include line-clamp(1);
|
||||
}
|
||||
|
||||
.table-item-title--large {
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.on-hover-wrapper {
|
||||
width: 0;
|
||||
height: 0;
|
||||
padding: 0 !important;
|
||||
align-self: flex-start;
|
||||
|
||||
.on-hover {
|
||||
position: relative;
|
||||
right: 142px;
|
||||
height: 80px;
|
||||
width: 142px;
|
||||
background: linear-gradient(90deg, rgba(249, 250, 251, 0) 0%, #F9FAFB 100%);
|
||||
display: none;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
div {
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
background-color: #F9FAFB;
|
||||
|
||||
.on-hover {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.rectangle {
|
||||
background-color: $grey-4 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,9 @@
|
||||
@import "red-mixins";
|
||||
|
||||
button {
|
||||
font-family: Inconsolata, monospace !important;
|
||||
font-weight: 700 !important;
|
||||
font-family: Inter, sans-serif !important;
|
||||
font-weight: 400 !important;
|
||||
border-radius: 17px !important;
|
||||
}
|
||||
|
||||
a {
|
||||
@ -16,23 +17,34 @@ a {
|
||||
}
|
||||
|
||||
.heading-xl {
|
||||
color: $grey-1;
|
||||
font-family: Inter, sans-serf;
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0;
|
||||
line-height: 39px;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
line-height: 29px;
|
||||
}
|
||||
|
||||
.heading-l {
|
||||
color: #283241;
|
||||
font-family: Inter, sans-serf;
|
||||
font-family: Inter, sans-serif;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.subheading {
|
||||
text-transform: uppercase;
|
||||
opacity: 0.7;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
opacity: 0.7;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.clamp-1 {
|
||||
@include line-clamp(1);
|
||||
|
||||
@ -7,4 +7,6 @@
|
||||
@import "red-dialog";
|
||||
@import "red-input";
|
||||
@import "red-media-queries";
|
||||
@import "red-tables";
|
||||
@import "red-components";
|
||||
@import "red-controls";
|
||||
|
||||
@ -9,9 +9,9 @@ $dark: #000;
|
||||
$grey-1: #283241;
|
||||
$grey-2: #ECECEE;
|
||||
$grey-3: #aaacb3;
|
||||
$grey-4: #E2E4E9;
|
||||
|
||||
$blue-1: #4875F7;
|
||||
$red-1: #F65757;
|
||||
$yellow-1: #FFB83B;
|
||||
$green-1: #46CE7D;
|
||||
|
||||
|
||||
22
yarn.lock
22
yarn.lock
@ -2694,7 +2694,7 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
base64-js@1.3.1, base64-js@^1.0.2:
|
||||
base64-js@^1.0.2:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
|
||||
integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
|
||||
@ -6782,11 +6782,6 @@ jest@26.2.2:
|
||||
import-local "^3.0.2"
|
||||
jest-cli "^26.2.2"
|
||||
|
||||
js-sha256@0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966"
|
||||
integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==
|
||||
|
||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
@ -6949,21 +6944,6 @@ karma-source-map-support@1.4.0:
|
||||
dependencies:
|
||||
source-map-support "^0.5.5"
|
||||
|
||||
keycloak-angular@^8.0.1:
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/keycloak-angular/-/keycloak-angular-8.0.1.tgz#29851e7aded21925faa051c69dfa5872bda6661f"
|
||||
integrity sha512-q68vcaFiSYNjbzPM1v+6LohMpWUyus9hcQBi2rNz06xOtWuRU4U6t5vQgoim6bDhtkhWpR5+a3SYl0lzUJKyrw==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
keycloak-js@10.0.2:
|
||||
version "10.0.2"
|
||||
resolved "https://registry.yarnpkg.com/keycloak-js/-/keycloak-js-10.0.2.tgz#f0cf5b942627c5221f1466552c40e4624503b77b"
|
||||
integrity sha512-7nkg4Ob1khHGcNbuK36AMndKUEuIQFpNlWU9ygWs7nSBPCI9VZ8dJjjXfKJHm0ewgcqLFGPIJ6bxxRlfcQ6sLg==
|
||||
dependencies:
|
||||
base64-js "1.3.1"
|
||||
js-sha256 "0.9.0"
|
||||
|
||||
killable@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user