From e61072c505526508003ac9820a4b968dc7bfcec7 Mon Sep 17 00:00:00 2001 From: rkuffer Date: Tue, 20 Jun 2023 15:13:30 +0200 Subject: [PATCH] refacto intents view --- .../web/src/app/intents/intents.component.css | 120 ----- .../src/app/intents/intents.component.html | 410 +++++++----------- .../src/app/intents/intents.component.scss | 64 +++ .../web/src/app/intents/intents.component.ts | 84 ++-- 4 files changed, 252 insertions(+), 426 deletions(-) delete mode 100644 nlp/admin/web/src/app/intents/intents.component.css create mode 100644 nlp/admin/web/src/app/intents/intents.component.scss diff --git a/nlp/admin/web/src/app/intents/intents.component.css b/nlp/admin/web/src/app/intents/intents.component.css deleted file mode 100644 index 371d9a32f6..0000000000 --- a/nlp/admin/web/src/app/intents/intents.component.css +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2017/2021 e-voyageurs technologies - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -.default_category { - font-style: italic; -} - -.category { - font-size: x-large; -} - -.tree { - margin-top: 20px; -} - -.tree-open { - display: block; -} - -.entity_icon { - position: relative; - top: 7px; -} - -.intent_name { - /* Fixes #733 Responsiveness issues. */ - display: inline-block; - max-width: 200px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.intent_id { - text-align: center; - /* Fixes #733 Responsiveness issues. */ - display: inline-block; - max-width: 200px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.intent_description { - white-space: pre-wrap; -} - -.shared_application_label { - font-size: smaller; -} - -.shared { - vertical-align: top; - text-align: center; -} - -.shared_list { - padding-top: 10px; -} - -.states { - vertical-align: top; - text-align: center; -} - -.actions { - text-align: center; -} -.action { - margin-right: 2px; -} - -.entity { - white-space: nowrap; -} - -.status { - border-radius: 25px; - padding: 8px; -} - -.removeEntity { - transform: translateX(-8px); - padding-left: 5px !important; -} - -.intents { - margin-top: 20px; -} - -button:focus { - outline: 1px dotted; - outline: 0px auto transparent; -} - -.entities { - width: 25%; - text-align: center; -} - -.description { - text-align: center; -} - -.intent { - width: 200px -} diff --git a/nlp/admin/web/src/app/intents/intents.component.html b/nlp/admin/web/src/app/intents/intents.component.html index 167c2e4c6d..b306adcdf3 100644 --- a/nlp/admin/web/src/app/intents/intents.component.html +++ b/nlp/admin/web/src/app/intents/intents.component.html @@ -14,291 +14,189 @@ ~ limitations under the License. --> - - - The default intent category is expanded by default. - - -
-

No Intent found

-

To create Intents, start from New Sentence or New Story in Tock Studio, or the API.

-
- - - + + + + {{ category.category }} + - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+
Intent
+
Entities
+
Shared Intents
+
Mandatory States
+
Actions
+
+
- {{ intentColumn }} -
- - {{ row.data.category }} - {{ state.isOtherNamespaceIntent(row.data) ? row.data.qualifiedName() : row.data.intentLabel() }} -
- Multi-application intent - share -
-
- {{ descriptionColumn }} - - {{ row.data.description }} - - {{ entitiesColumn }} - - - - extension +
+
+ + {{ state.isOtherNamespaceIntent(intent) ? intent.qualifiedName() : intent.intentLabel() }} + {{ e.qualifiedName(state.user) }} + + +
+ {{ intent.description }} +
+ +
+ +
+ {{ e.qualifiedName(state.user) }} +
-   - -
- {{ sharedIntentsColumn }} - -
+
+ +
+ + +
+ {{ state.findIntentById(intentId)?.name }} +
+ +
+
+ -
- + +
+ + - - {{ state.findIntentById(intentId)?.name }} - - - - +
-
-
- {{ mandatoryStatesColumn }} - -
+ + + + + +
+ +
- -
- - {{ s }} - -
- + + +
-
- {{ actionsColumn }} - -
- - - -
-
-
-
+ + + + + diff --git a/nlp/admin/web/src/app/intents/intents.component.scss b/nlp/admin/web/src/app/intents/intents.component.scss new file mode 100644 index 0000000000..81c9910c10 --- /dev/null +++ b/nlp/admin/web/src/app/intents/intents.component.scss @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2017/2021 e-voyageurs technologies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.no-shadow { + box-shadow: none; +} + +.compensate-accordion-item-padding { + margin-top: -1.5rem; + margin-bottom: -1rem; +} + +.table-list { + display: grid; + grid-template-columns: 2fr 1fr 1fr 1fr 8rem; + column-gap: 0.5rem; + min-width: 50rem; + + &.table-list-header { + font-size: smaller; + font-weight: bold; + opacity: 0.6; + } + &:not(:last-child) { + .table-list-entry { + border-bottom: 1px solid var(--border-basic-color-3); + } + } + + .table-list-entry { + min-width: 8rem; + padding: 1rem 0; + &.bordered { + border-right: 1px solid var(--border-basic-color-3); + } + } +} + +.tag { + display: inline-flex; + width: fit-content; + max-width: 8rem; + padding: 0rem 0.3rem 0rem 0.9rem; + margin-right: 2px; + margin-bottom: 2px; + border-radius: 10rem; + background-color: var(--border-basic-color-3); + font-size: 0.7rem; + line-height: 1.25rem; + white-space: nowrap; +} diff --git a/nlp/admin/web/src/app/intents/intents.component.ts b/nlp/admin/web/src/app/intents/intents.component.ts index a2e859ef17..57b41cd7c6 100644 --- a/nlp/admin/web/src/app/intents/intents.component.ts +++ b/nlp/admin/web/src/app/intents/intents.component.ts @@ -15,7 +15,7 @@ */ import { saveAs } from 'file-saver-es'; -import { Component, ElementRef, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { StateService } from '../core-nlp/state.service'; import { EntityDefinition, Intent, IntentsCategory } from '../model/nlp'; import { ConfirmDialogComponent } from '../shared-nlp/confirm-dialog/confirm-dialog.component'; @@ -24,42 +24,19 @@ import { ApplicationService } from '../core-nlp/applications.service'; import { AddStateDialogComponent } from './add-state/add-state-dialog.component'; import { UserRole } from '../model/auth'; import { IntentDialogComponent } from '../sentence-analysis/intent-dialog/intent-dialog.component'; -import { BehaviorSubject } from 'rxjs'; import { DialogService } from '../core-nlp/dialog.service'; import { AddSharedIntentDialogComponent } from './add-shared-intent/add-shared-intent-dialog.component'; -interface TreeNode { - data: T; - children?: TreeNode[]; - expanded?: boolean; -} - @Component({ selector: 'tock-intents', templateUrl: './intents.component.html', - styleUrls: ['./intents.component.css'] + styleUrls: ['./intents.component.scss'] }) export class IntentsComponent implements OnInit { UserRole = UserRole; - intentsCategories: BehaviorSubject = new BehaviorSubject([]); - expandedCategories: Set = new Set(['default']); selectedIntent: Intent; - intentColumn = 'Intent'; - descriptionColumn = 'Description'; - entitiesColumn = 'Entities'; - sharedIntentsColumn = 'Shared Intents'; - mandatoryStatesColumn = 'Mandatory States'; - actionsColumn = 'Actions'; - allColumns = [ - this.intentColumn, - this.descriptionColumn, - this.entitiesColumn, - this.sharedIntentsColumn, - this.mandatoryStatesColumn, - this.actionsColumn - ]; - nodes: TreeNode[]; + intentsCategories: IntentsCategory[]; constructor( public state: StateService, @@ -70,25 +47,11 @@ export class IntentsComponent implements OnInit { ngOnInit() { this.state.currentNamespaceIntentsCategories.subscribe((it) => { - this.nodes = Array.from(it, (element) => { - return { - expanded: element.category === 'default', - data: { - category: element.category, - expandable: true - }, - children: element.intents.map((s) => { - return { - data: s - }; - }) - }; - }); - this.intentsCategories.next(it); + this.intentsCategories = it; }); } - updateIntent(intent: Intent) { + updateIntent(intent: Intent): void { const dialogRef = this.dialog.openDialog(IntentDialogComponent, { context: { name: intent.name, @@ -122,7 +85,7 @@ export class IntentsComponent implements OnInit { }); } - deleteIntent(intent: Intent) { + deleteIntent(intent: Intent): void { const dialogRef = this.dialog.openDialog(ConfirmDialogComponent, { context: { title: `Remove the Intent ${intent.name}`, @@ -143,7 +106,7 @@ export class IntentsComponent implements OnInit { }); } - removeState(intent: Intent, state: string) { + removeState(intent: Intent, state: string): void { this.nlp.removeState(this.state.currentApplication, intent, state).subscribe( (_) => { intent.mandatoryStates.splice(intent.mandatoryStates.indexOf(state), 1); @@ -155,7 +118,7 @@ export class IntentsComponent implements OnInit { ); } - addState(intent: Intent) { + addState(intent: Intent): void { const dialogRef = this.dialog.openDialog(AddStateDialogComponent, { context: { title: `Add a state for intent \"${intent.name}\"` @@ -177,7 +140,7 @@ export class IntentsComponent implements OnInit { }); } - removeEntity(intent: Intent, entity: EntityDefinition) { + removeEntity(intent: Intent, entity: EntityDefinition): void { const entityName = entity.qualifiedName(this.state.user); const dialogRef = this.dialog.openDialog(ConfirmDialogComponent, { context: { @@ -199,7 +162,7 @@ export class IntentsComponent implements OnInit { }); } - removeSharedIntent(intent: Intent, intentId: string) { + removeSharedIntent(intent: Intent, intentId: string): void { this.selectedIntent = null; this.nlp.removeSharedIntent(this.state.currentApplication, intent, intentId).subscribe( (_) => { @@ -212,7 +175,7 @@ export class IntentsComponent implements OnInit { ); } - displayAddSharedIntentDialog(intent: Intent) { + displayAddSharedIntentDialog(intent: Intent): void { this.selectedIntent = intent; const dialogRef = this.dialog.openDialog(AddSharedIntentDialogComponent, { context: { @@ -229,7 +192,7 @@ export class IntentsComponent implements OnInit { }); } - addSharedIntent(intent: Intent, intentId: string) { + addSharedIntent(intent: Intent, intentId: string): void { if (intent.sharedIntents.indexOf(intentId) === -1) { this.selectedIntent = null; intent.sharedIntents.push(intentId); @@ -245,7 +208,7 @@ export class IntentsComponent implements OnInit { } } - downloadSentencesDump(intent: Intent) { + downloadSentencesDump(intent: Intent): void { this.applicationService .getSentencesDumpForIntent( this.state.currentApplication, @@ -258,4 +221,25 @@ export class IntentsComponent implements OnInit { this.dialog.notify(`Dump provided`, 'Dump'); }); } + + expandedCategory: string = 'default'; + + isCategoryExpanded(category: IntentsCategory): boolean { + return category.category.toLowerCase() === this.expandedCategory.toLowerCase(); + } + + collapsedChange(category: IntentsCategory): void { + this.expandedCategory = category.category; + } + + // To share with Scenario's version after merge + getContrastYIQ(hexcolor: string): '' | 'black' | 'white' { + if (!hexcolor) return ''; + hexcolor = hexcolor.replace('#', ''); + let r = parseInt(hexcolor.substring(0, 2), 16); + let g = parseInt(hexcolor.substring(2, 4), 16); + let b = parseInt(hexcolor.substring(4, 6), 16); + let yiq = (r * 299 + g * 587 + b * 114) / 1000; + return yiq >= 128 ? 'black' : 'white'; + } }