diff --git a/libs/story-angular/i18n/zhHans.ts b/libs/story-angular/i18n/zhHans.ts index 7f09672f8..0f7e677e0 100644 --- a/libs/story-angular/i18n/zhHans.ts +++ b/libs/story-angular/i18n/zhHans.ts @@ -683,6 +683,9 @@ export const ZhHans = { Tags: '标签', PreviewExceedsMaximum: '文件大小超过限制', }, + Explorer: { + AddDimensions: '添加维度', + }, STYLING: { CSS: { BACKGROUND: { diff --git a/libs/story-angular/src/lib/explorer/explorer.component.html b/libs/story-angular/src/lib/explorer/explorer.component.html index 907908460..b1f12dcb6 100644 --- a/libs/story-angular/src/lib/explorer/explorer.component.html +++ b/libs/story-angular/src/lib/explorer/explorer.component.html @@ -1,173 +1,272 @@ -
+
- +
- Measures + {{ 'PAC.KEY_WORDS.Measures' | translate: {Default: 'Measures'} }}
- - + + {{item.caption}}
-
-
-
+
+
- - {{item.caption}} - +
+ + {{item.caption}} + +
+
+
+
+ +
+
+ + + + + +
+
+
Show Dimensions
+
Bring in more dimensions from your dataset and start exploring.
-
-
-
- +
+
-
-
-
+
+
+ +
+
{{ 'PAC.KEY_WORDS.Dimensions' | translate: {Default: 'Dimensions'} }}
+
-
{{ 'PAC.KEY_WORDS.Dimensions' | translate: {Default: 'Dimensions'} }}
-
- - -
+ [cdkDropListEnterPredicate]="dropRowPredicate"> + + +
-
-
-
- {{'FORMLY.CHART.' + group.label | translate: {Default: group.label} }} -
-
- -
-
+
{{ 'PAC.KEY_WORDS.Measures' | translate: {Default: 'Measures'} }}
+
+ + +
+
-
-
- - - - +
+
+
+ {{'FORMLY.CHART.' + group.label | translate: {Default: group.label} }}
- -
- + +
+
+
+
+
+
+ + - - Table - Chart - + +
+ +
+ + Visual + Options + -
- -
-
+ + Table + Chart + + +
+
+
+
+ + + +
+
+

+ {{ 'Story.Explorer.AddDimensions' | translate: { Default: 'Add dimensions' } }} +

+
+ +
+ + + {{property.caption}} + + +
-
\ No newline at end of file + +
+ + + +
+
+
+ diff --git a/libs/story-angular/src/lib/explorer/explorer.component.scss b/libs/story-angular/src/lib/explorer/explorer.component.scss index e5a58fcf8..8b39d2842 100644 --- a/libs/story-angular/src/lib/explorer/explorer.component.scss +++ b/libs/story-angular/src/lib/explorer/explorer.component.scss @@ -7,4 +7,8 @@ } .ngm-story-explorer__chart.selected { @apply ring-violet-500; -} \ No newline at end of file +} + +.cdk-drag-placeholder { + opacity: 0; +} diff --git a/libs/story-angular/src/lib/explorer/explorer.component.ts b/libs/story-angular/src/lib/explorer/explorer.component.ts index 055f7017e..bae93769c 100644 --- a/libs/story-angular/src/lib/explorer/explorer.component.ts +++ b/libs/story-angular/src/lib/explorer/explorer.component.ts @@ -1,6 +1,6 @@ -import { CdkDrag, CdkDragDrop, DragDropModule } from '@angular/cdk/drag-drop' +import { CdkDrag, CdkDragDrop, DragDropModule, moveItemInArray } from '@angular/cdk/drag-drop' import { CommonModule } from '@angular/common' -import { Component, EventEmitter, Input, Output, computed, effect, inject, signal } from '@angular/core' +import { Component, ElementRef, EventEmitter, Input, Output, TemplateRef, ViewChild, computed, effect, inject, signal } from '@angular/core' import { toObservable, toSignal } from '@angular/core/rxjs-interop' import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { MatButtonModule } from '@angular/material/button' @@ -25,9 +25,11 @@ import { DataSettings, Dimension, DisplayBehaviour, + FilterSelectionType, ISlicer, assignDeepOmitBlank, cloneDeep, + compact, getEntityDimensions, getEntityMeasures, nonNullable, @@ -37,6 +39,9 @@ import { WidgetComponentType } from '@metad/story/core' import { TranslateModule } from '@ngx-translate/core' import { filter, map, switchMap } from 'rxjs/operators' import { CHARTS, getChartType } from './types' +import { MatIconModule } from '@angular/material/icon' +import { ResizerModule } from '@metad/ocap-angular/common' +import { MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dialog' @Component({ standalone: true, @@ -51,6 +56,8 @@ import { CHARTS, getChartType } from './types' MatButtonToggleModule, MatDividerModule, MatTooltipModule, + MatIconModule, + MatDialogModule, DragDropModule, NxTableModule, NgmPrismHighlightComponent, @@ -59,7 +66,8 @@ import { CHARTS, getChartType } from './types' NgmMemberTreeComponent, AnalyticalCardModule, AnalyticalGridModule, - PropertyModule + PropertyModule, + ResizerModule ], selector: 'ngm-story-explorer', templateUrl: 'explorer.component.html', @@ -70,8 +78,10 @@ export class StoryExplorerComponent { DisplayDensity = DisplayDensity PropertyCapacity = PropertyCapacity ComponentType = WidgetComponentType + FilterSelectionType = FilterSelectionType private readonly dsCoreService = inject(NgmDSCoreService) + private readonly _dialog = inject(MatDialog) @Input() get data() { @@ -89,6 +99,7 @@ export class StoryExplorerComponent { }) this.rows.set(chartAnnotation.dimensions) this.columns.set(chartAnnotation.measures) + this._dimensions.set(chartAnnotation.dimensions?.map((d) => d.dimension) ?? []) } } @@ -97,6 +108,12 @@ export class StoryExplorerComponent { @Output() closed = new EventEmitter() + @ViewChild('addDimensionsTempl') addDimensionsTempl: TemplateRef + + private dialogRef: MatDialogRef, any> + + readonly _dimensionsCache = signal([]) + private _dimensions = signal([]) dimensions = signal<{ dimension: Dimension; caption: string; hierarchies: Dimension[] }[]>([]) readonly entityType = toSignal( @@ -109,9 +126,15 @@ export class StoryExplorerComponent { ) ) ) - + readonly dimensionList = computed(() => { + return getEntityDimensions(this.entityType()) + }) readonly measureList = computed(() => { - return getEntityMeasures(this.entityType()) + return getEntityMeasures(this.entityType()).map((property) => ({ + dimension: C_MEASURES, + measure: property.name, + caption: property.caption + })) }) readonly dataSettings = computed(() => { return pick(this.data?.dataSettings, 'dataSource', 'entitySet') as DataSettings @@ -147,7 +170,6 @@ export class StoryExplorerComponent { chartAnnotation.dimensions = chartAnnotation.dimensions.filter((d) => d.dimension) chartAnnotation.measures = chartAnnotation.measures.filter((d) => d.dimension) - console.log('chartAnnotation:', chartAnnotation) return { ...(this.data?.dataSettings ?? {}), chartAnnotation @@ -162,10 +184,16 @@ export class StoryExplorerComponent { const analytics = { ...(this.data?.analytics ?? {}), rows: this.rows(), - columns: this.measures().map((measure) => ({ - dimension: C_MEASURES, - measure - })) + columns: [ + ...this.columns(), + ...this.measures().map((measure) => ({ + dimension: C_MEASURES, + measure, + formatting: { + shortNumber: true + } + })) + ] } console.log('analytics:', analytics) return { @@ -206,7 +234,7 @@ export class StoryExplorerComponent { () => { if (this.entityType()) { this.dimensions.set( - getEntityDimensions(this.entityType()).map(({ name, caption, hierarchies }) => ({ + getEntityDimensions(this.entityType()).filter(({name}) => this._dimensions().includes(name)) .map(({ name, caption, hierarchies }) => ({ dimension: { dimension: name, displayBehaviour: DisplayBehaviour.descriptionOnly @@ -252,21 +280,53 @@ export class StoryExplorerComponent { } dropRowPredicate(item: CdkDrag) { - return true + return item.dropContainer.id === 'ngm-story-explorer__drop-list-dimensions-container' } dropRow(event: CdkDragDrop) { - this.rows.set([...this.rows(), { ...event.item.data }]) + const items = [...this.rows()] + if (event.previousContainer === event.container) { + moveItemInArray(items, event.previousIndex, event.currentIndex) + } else { + items.splice(event.currentIndex, 0, { ...event.item.data.dimension }) + } + this.rows.set(items) + } + + removeRow(i: number) { + const items = [...this.rows()] + items.splice(i, 1) + this.rows.set(items) + } + + dropColumnPredicate(item: CdkDrag) { + return item.dropContainer.id === 'ngm-story-explorer__drop-list-measures' } dropColumn(event: CdkDragDrop) { - this.columns.set([...this.columns(), { ...event.item.data }]) + const items = [...this.columns()] + if (event.previousContainer === event.container) { + moveItemInArray(items, event.previousIndex, event.currentIndex) + } else { + items.splice(event.currentIndex, 0, { ...event.item.data }) + } + this.columns.set(items) + } + + removeColumn(i: number) { + const items = [...this.columns()] + items.splice(i, 1) + this.columns.set(items) } onRowChange(row: Dimension, i: number) { this.rows.set([...this.rows().slice(0, i), row, ...this.rows().slice(i + 1)]) } + onColumnChange(row: Dimension, i: number) { + this.columns.set([...this.columns().slice(0, i), row, ...this.columns().slice(i + 1)]) + } + onMeasuresChange(measures: string[]) { this.measures.set(measures) } @@ -282,4 +342,26 @@ export class StoryExplorerComponent { console.log(widget) this.component.set(widget) } + + addDimensionToCache(event) { + this._dimensionsCache.set([...event]) + } + + openDimensions() { + this._dimensionsCache.set([...this._dimensions()]) + this.dialogRef = this._dialog.open(this.addDimensionsTempl) + } + + addDimensions() { + this._dimensions.set([...this._dimensionsCache()]) + this.dialogRef.close() + } + + moveDimension(event: CdkDragDrop) { + const items = [...this.dimensions()] + if (event.previousContainer === event.container) { + moveItemInArray(items, event.previousIndex, event.currentIndex) + this.dimensions.set(items) + } + } } diff --git a/packages/angular/controls/member-tree/member-tree.component.ts b/packages/angular/controls/member-tree/member-tree.component.ts index dea1c26c7..ab514c035 100644 --- a/packages/angular/controls/member-tree/member-tree.component.ts +++ b/packages/angular/controls/member-tree/member-tree.component.ts @@ -1,9 +1,9 @@ import { SelectionModel } from '@angular/cdk/collections' import { FlatTreeControl } from '@angular/cdk/tree' -import { ChangeDetectionStrategy, Component, EventEmitter, forwardRef, HostBinding, inject, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core' +import { ChangeDetectionStrategy, Component, EventEmitter, forwardRef, HostBinding, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core' import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms' import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree' -import { DisplayDensity, NgmAppearance, NgmDSCoreService, OcapCoreModule } from '@metad/ocap-angular/core' +import { DisplayDensity, NgmAppearance, OcapCoreModule } from '@metad/ocap-angular/core' import { DataSettings, Dimension, @@ -72,7 +72,7 @@ export class NgmMemberTreeComponent