Pull request #60: Rules editor
Merge in RED/ui from rules to master * commit 'f1cd540de3e4698a80c612b050b8340892b2c0e3': Editor theme Rules editor
This commit is contained in:
commit
7bcb8c04e5
12
angular.json
12
angular.json
@ -33,10 +33,20 @@
|
||||
"input": "apps/red-ui/src/assets/",
|
||||
"output": "/assets/"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "node_modules/ace-builds/src-min/",
|
||||
"output": "/assets/ace-builds"
|
||||
},
|
||||
"apps/red-ui/src/manifest.webmanifest"
|
||||
],
|
||||
"styles": ["apps/red-ui/src/styles.scss"],
|
||||
"scripts": ["node_modules/@pdftron/webviewer/webviewer.min.js", "node_modules/ace-builds/src-min/ace.js"]
|
||||
"scripts": [
|
||||
"node_modules/@pdftron/webviewer/webviewer.min.js",
|
||||
"node_modules/ace-builds/src-min/ace.js",
|
||||
"node_modules/ace-builds/src-min/mode-java.js",
|
||||
"node_modules/ace-builds/src-min/theme-eclipse.js"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { AppLoadStateService } from './utils/app-load-state.service';
|
||||
|
||||
declare var ace;
|
||||
|
||||
ace.config.set('basePath', '/assets/ace-builds/');
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-root',
|
||||
templateUrl: './app.component.html',
|
||||
|
||||
@ -92,6 +92,7 @@ import { TeamMembersComponent } from './components/team-members/team-members.com
|
||||
import { AdminBreadcrumbsComponent } from './components/admin-page-header/admin-breadcrumbs.component';
|
||||
import { UserListingScreenComponent } from './screens/admin/users/user-listing-screen.component';
|
||||
import { NotificationsComponent } from './components/notifications/notifications.component';
|
||||
import { RulesScreenComponent } from './screens/admin/rules-screen/rules-screen.component';
|
||||
|
||||
export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
|
||||
@ -167,6 +168,14 @@ const routes = [
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'rules',
|
||||
component: RulesScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -248,7 +257,8 @@ const matImports = [
|
||||
TeamMembersComponent,
|
||||
AdminBreadcrumbsComponent,
|
||||
UserListingScreenComponent,
|
||||
NotificationsComponent
|
||||
NotificationsComponent,
|
||||
RulesScreenComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@ -8,6 +8,15 @@
|
||||
*ngIf="screen === 'dictionaries' || root"
|
||||
></a>
|
||||
|
||||
<a
|
||||
class="ml-32 breadcrumb"
|
||||
[routerLink]="'/ui/admin/rules'"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
routerLinkActive="active"
|
||||
translate="rule-editor"
|
||||
*ngIf="screen === 'rules' || root"
|
||||
></a>
|
||||
|
||||
<a
|
||||
class="ml-32 breadcrumb"
|
||||
[routerLink]="'/ui/admin/users'"
|
||||
|
||||
@ -61,12 +61,13 @@
|
||||
<ace-editor
|
||||
#editorComponent
|
||||
[mode]="'text'"
|
||||
[theme]="'redaction'"
|
||||
[theme]="'eclipse'"
|
||||
[options]="aceOptions"
|
||||
[readOnly]="!permissionsService.isAdmin()"
|
||||
(textChanged)="textChanged($event)"
|
||||
[autoUpdateContent]="true"
|
||||
[text]="dictionaryEntriesAsText"
|
||||
class="ace-redaction"
|
||||
>
|
||||
</ace-editor>
|
||||
</div>
|
||||
|
||||
@ -3,19 +3,16 @@
|
||||
|
||||
.editor-container {
|
||||
height: calc(100% - 50px);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
ace-editor {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.changes-box {
|
||||
right: 403px;
|
||||
}
|
||||
|
||||
.left-container {
|
||||
width: calc(100vw - 383px);
|
||||
height: calc(100vh - 141px);
|
||||
width: calc(100vw - 353px);
|
||||
padding: 15px;
|
||||
box-shadow: inset 0 4px 3px -2px #e2e4e9;
|
||||
@include inset-shadow;
|
||||
}
|
||||
|
||||
.right-container {
|
||||
@ -24,28 +21,6 @@
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.changes-box {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
bottom: 40px;
|
||||
right: 403px;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background-color: $white;
|
||||
box-shadow: 0 2px 6px 0 rgba(40, 50, 65, 0.3);
|
||||
z-index: 5000;
|
||||
}
|
||||
|
||||
ace-editor {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid $grey-5;
|
||||
border-radius: 8px;
|
||||
background-color: $white;
|
||||
}
|
||||
|
||||
.dictionary-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@ -51,7 +51,6 @@ export class DictionaryOverviewScreenComponent {
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
private readonly _appStateService: AppStateService
|
||||
) {
|
||||
ace.config.set('basePath', '/assets/ace-editor/');
|
||||
this._activatedRoute.params.subscribe((params) => {
|
||||
this.dictionary = this._appStateService.dictionaryData[params.type];
|
||||
if (!this.dictionary) {
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs></redaction-admin-breadcrumbs>
|
||||
<div class="actions">
|
||||
<redaction-circle-button
|
||||
class="ml-6"
|
||||
*ngIf="permissionsService.isUser()"
|
||||
[routerLink]="['/ui/projects/']"
|
||||
tooltip="common.close"
|
||||
tooltipPosition="before"
|
||||
icon="red:close"
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="red-content-inner">
|
||||
<div class="editor-container">
|
||||
<ace-editor
|
||||
#editorComponent
|
||||
[mode]="'java'"
|
||||
[theme]="'eclipse'"
|
||||
[options]="aceOptions"
|
||||
[readOnly]="!permissionsService.isAdmin()"
|
||||
(textChanged)="textChanged($event)"
|
||||
[autoUpdateContent]="true"
|
||||
[text]="rules"
|
||||
class="ace-redaction"
|
||||
>
|
||||
</ace-editor>
|
||||
</div>
|
||||
<div class="changes-box" *ngIf="hasChanges">
|
||||
<redaction-icon-button
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
icon="red:check"
|
||||
(action)="save()"
|
||||
text="dictionary-overview.save-changes"
|
||||
[primary]="true"
|
||||
></redaction-icon-button>
|
||||
<redaction-icon-button
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
(action)="revert()"
|
||||
text="dictionary-overview.revert-changes"
|
||||
[linkButton]="true"
|
||||
></redaction-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<redaction-full-page-loading-indicator [displayed]="processing"></redaction-full-page-loading-indicator>
|
||||
@ -0,0 +1,11 @@
|
||||
@import '../../../../assets/styles/red-mixins';
|
||||
|
||||
.editor-container {
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
@include inset-shadow;
|
||||
}
|
||||
|
||||
.changes-box {
|
||||
right: 40px;
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { PermissionsService } from '../../../common/service/permissions.service';
|
||||
import { AceEditorComponent } from 'ng2-ace-editor';
|
||||
import { RulesControllerService } from '@redaction/red-ui-http';
|
||||
import { NotificationService, NotificationType } from '../../../notification/notification.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
declare var ace;
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-rules-screen',
|
||||
templateUrl: './rules-screen.component.html',
|
||||
styleUrls: ['./rules-screen.component.scss']
|
||||
})
|
||||
export class RulesScreenComponent {
|
||||
public aceOptions = { showPrintMargin: false };
|
||||
public rules: string;
|
||||
public processing = true;
|
||||
|
||||
public initialLines: string[] = [];
|
||||
public currentLines: string[] = [];
|
||||
public changedLines: number[] = [];
|
||||
public activeEditMarkers: any[] = [];
|
||||
|
||||
@ViewChild('editorComponent', { static: true })
|
||||
editorComponent: AceEditorComponent;
|
||||
|
||||
constructor(
|
||||
public readonly permissionsService: PermissionsService,
|
||||
private readonly _rulesControllerService: RulesControllerService,
|
||||
private readonly _notificationService: NotificationService,
|
||||
private readonly _translateService: TranslateService
|
||||
) {
|
||||
this._initialize();
|
||||
}
|
||||
|
||||
private _initialize() {
|
||||
this._rulesControllerService.downloadRules().subscribe(
|
||||
(rules) => {
|
||||
this.rules = rules.rules;
|
||||
this.revert();
|
||||
},
|
||||
() => {
|
||||
this.processing = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public textChanged($event: any) {
|
||||
this.currentLines = $event.split('\n');
|
||||
this.changedLines = [];
|
||||
this.activeEditMarkers.forEach((am) => {
|
||||
this.editorComponent.getEditor().getSession().removeMarker(am);
|
||||
});
|
||||
this.activeEditMarkers = [];
|
||||
|
||||
for (let i = 0; i < this.currentLines.length; i++) {
|
||||
const currentEntry = this.currentLines[i];
|
||||
if (this.initialLines.indexOf(currentEntry) < 0) {
|
||||
this.changedLines.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
const Range = ace.require('ace/range').Range;
|
||||
for (const i of this.changedLines) {
|
||||
const entry = this.currentLines[i];
|
||||
if (entry?.trim().length > 0) {
|
||||
// only mark non-empty lines
|
||||
this.activeEditMarkers.push(this.editorComponent.getEditor().getSession().addMarker(new Range(i, 0, i, 1), 'changed-row-marker', 'fullLine'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get hasChanges(): boolean {
|
||||
return this.activeEditMarkers.length > 0;
|
||||
}
|
||||
|
||||
public async save(): Promise<void> {
|
||||
this.processing = true;
|
||||
this._rulesControllerService.uploadRules({ rules: this.editorComponent.getEditor().getValue() }).subscribe(
|
||||
() => {
|
||||
this._initialize();
|
||||
this._notificationService.showToastNotification(this._translateService.instant('rules-screen.success.generic'), null, NotificationType.SUCCESS);
|
||||
},
|
||||
() => {
|
||||
this.processing = false;
|
||||
this._notificationService.showToastNotification(this._translateService.instant('rules-screen.error.generic'), null, NotificationType.ERROR);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public revert(): void {
|
||||
this.initialLines = this.rules.split('\n');
|
||||
this.editorComponent.getEditor().setValue(this.rules);
|
||||
this.editorComponent.getEditor().clearSelection();
|
||||
this.processing = false;
|
||||
}
|
||||
}
|
||||
@ -546,6 +546,14 @@
|
||||
},
|
||||
"search": "Search..."
|
||||
},
|
||||
"rules-screen": {
|
||||
"error": {
|
||||
"generic": "Something went wrong... Rules update failed!"
|
||||
},
|
||||
"success": {
|
||||
"generic": "Rules updated!"
|
||||
}
|
||||
},
|
||||
"dictionaries": "Dictionaries",
|
||||
"user-management": "User Management",
|
||||
"notifications": {
|
||||
@ -554,5 +562,6 @@
|
||||
"tomorrow": "Tomorrow",
|
||||
"mark-read": "Mark as read",
|
||||
"mark-unread": "Mark as unread"
|
||||
}
|
||||
},
|
||||
"rule-editor": "Rule Editor"
|
||||
}
|
||||
|
||||
@ -20,12 +20,16 @@
|
||||
}
|
||||
|
||||
.ace-redaction {
|
||||
background-color: $white;
|
||||
color: $accent;
|
||||
|
||||
.ace_gutter {
|
||||
background: $grey-2;
|
||||
color: $grey-7;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.ace_active-line {
|
||||
background: $grey-6;
|
||||
}
|
||||
|
||||
.ace_print-margin {
|
||||
@ -57,3 +61,30 @@
|
||||
color: $grey-4;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-container {
|
||||
width: 100%;
|
||||
|
||||
ace-editor {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid $grey-5;
|
||||
border-radius: 8px;
|
||||
background-color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
.changes-box {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
bottom: 40px;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background-color: $white;
|
||||
box-shadow: 0 2px 6px 0 rgba(40, 50, 65, 0.3);
|
||||
z-index: 5000;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user