diff --git a/.deploy/webapp/package.json b/.deploy/webapp/package.json
index d9085058e..74982c92c 100644
--- a/.deploy/webapp/package.json
+++ b/.deploy/webapp/package.json
@@ -67,6 +67,7 @@
"immer": "^10.0.1",
"js-yaml": "^4.1.0",
"json5": "^2.2.3",
+ "langchain": "^0.0.152",
"lato-font": "^3.0.0",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
@@ -94,6 +95,8 @@
"tslib": "^2.3.0",
"typeorm": "^0.2.37",
"xlsx": "^0.18.5",
+ "zod": "^3.22.2",
+ "zod-to-json-schema": "^3.21.4",
"zone.js": "0.13.1"
},
"devDependencies": {
diff --git a/apps/cloud/src/app/features/story/story/story.component.html b/apps/cloud/src/app/features/story/story/story.component.html
index 1850b4714..797a7d102 100644
--- a/apps/cloud/src/app/features/story/story/story.component.html
+++ b/apps/cloud/src/app/features/story/story/story.component.html
@@ -139,3 +139,9 @@
{{error}}
+
+
\ No newline at end of file
diff --git a/apps/cloud/src/app/features/story/story/story.component.ts b/apps/cloud/src/app/features/story/story/story.component.ts
index fecbdf6f3..95ea874e4 100644
--- a/apps/cloud/src/app/features/story/story/story.component.ts
+++ b/apps/cloud/src/app/features/story/story/story.component.ts
@@ -14,9 +14,10 @@ import {
ViewChild
} from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
+import { CdkDragEnd } from '@angular/cdk/drag-drop'
import { ResizerModule } from '@metad/ocap-angular/common'
import { NgmDSCoreService, OcapCoreModule } from '@metad/ocap-angular/core'
-import { AgentType, isEqual } from '@metad/ocap-core'
+import { AgentType, C_MEASURES, isEqual } from '@metad/ocap-core'
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'
import { TranslateModule } from '@ngx-translate/core'
import { NgMapPipeModule, NxCoreService, ReversePipe } from '@metad/core'
@@ -29,8 +30,10 @@ import {
StoryPointType,
WidgetComponentType
} from '@metad/story/core'
+import { WasmAgentService } from '@metad/ocap-angular/wasm-agent'
import { NxDesignerModule, NxSettingsPanelService } from '@metad/story/designer'
import { NxStoryComponent, NxStoryModule } from '@metad/story/story'
+import { StoryExplorerModule } from '@metad/story'
import { registerTheme } from 'echarts/core'
import { NGXLogger } from 'ngx-logger'
import { firstValueFrom } from 'rxjs'
@@ -39,9 +42,8 @@ import { MenuCatalog, registerWasmAgentModel, Store } from '../../../@core'
import { MaterialModule } from '../../../@shared'
import { AppService } from '../../../app.service'
import { StoryToolbarComponent } from '../toolbar/toolbar.component'
-import { CdkDragEnd } from '@angular/cdk/drag-drop'
import { StoryToolbarService } from '../toolbar/toolbar.service'
-import { WasmAgentService } from '@metad/ocap-angular/wasm-agent'
+
type ResponsiveBreakpointType = {
name: string;
@@ -65,6 +67,7 @@ type ResponsiveBreakpointType = {
NxStoryModule,
NxDesignerModule,
StoryToolbarComponent,
+ StoryExplorerModule
],
selector: 'pac-story',
templateUrl: './story.component.html',
@@ -156,6 +159,10 @@ export class StoryComponent implements OnInit {
readonly pageKey$ = this.route.queryParams.pipe(map((queryParams) => queryParams['pageKey']))
readonly widgetKey$ = this.route.queryParams.pipe(map((queryParams) => queryParams['widgetKey']))
+ // Story explorer
+ showExplorer = signal(false)
+ explore = signal(null)
+
/**
|--------------------------------------------------------------------------
| Subscriptions (effect)
@@ -193,6 +200,11 @@ export class StoryComponent implements OnInit {
if (params.$language) {
this.storyOptions.locale = params.$language
}
+
+ if (params.explore) {
+ this.showExplorer.set(true)
+ this.explore.set(JSON.parse(atob(params.explore)))
+ }
})
private themeSub = this.storyService.themeChanging$.pipe(delay(300)).subscribe(async ([prev, current]) => {
@@ -320,4 +332,13 @@ export class StoryComponent implements OnInit {
onToolbarDragEnded(event: CdkDragEnd) {
this.toolbarComponent.calculateRightSide(event)
}
+
+ closeExplorer(event) {
+ this.showExplorer.set(false)
+ this._router.navigate([], {
+ relativeTo: this.route,
+ queryParams: {explore: null},
+ queryParamsHandling: 'merge' // remove to replace all query params by provided
+ })
+ }
}
diff --git a/apps/cloud/src/app/features/story/toolbar/toolbar.component.ts b/apps/cloud/src/app/features/story/toolbar/toolbar.component.ts
index c0efde378..5409b4532 100644
--- a/apps/cloud/src/app/features/story/toolbar/toolbar.component.ts
+++ b/apps/cloud/src/app/features/story/toolbar/toolbar.component.ts
@@ -29,6 +29,7 @@ import { ConfirmUniqueComponent } from '@metad/components/confirm'
import { ConfirmCodeEditorComponent } from '@metad/components/editor'
import { DeepPartial, IsNilPipe } from '@metad/core'
import {
+ CHARTS,
ParametersComponent,
PreferencesComponent,
QuerySettingComponent,
@@ -55,7 +56,7 @@ import { SaveAsTemplateComponent } from '../save-as-template/save-as-template.co
import { StoryDetailsComponent } from '../story-details/story-details.component'
import { DeviceOrientation, DeviceZooms, EmulatedDevices, StoryScales, downloadStory } from '../types'
import { StoryToolbarService } from './toolbar.service'
-import { CHARTS, COMPONENTS, PAGES } from './types'
+import { COMPONENTS, PAGES } from './types'
@Component({
diff --git a/apps/cloud/src/app/features/story/toolbar/types.ts b/apps/cloud/src/app/features/story/toolbar/types.ts
index b313b19e5..7f00b4850 100644
--- a/apps/cloud/src/app/features/story/toolbar/types.ts
+++ b/apps/cloud/src/app/features/story/toolbar/types.ts
@@ -1,613 +1,7 @@
-import { ChartAnnotation, ChartDimensionRoleType, ChartMeasureRoleType, ChartOrient } from '@metad/ocap-core'
-import { DeepPartial, NxChartType } from '@metad/core'
+
import { StoryPoint, StoryPointType, WidgetComponentType } from '@metad/story/core'
import { DisplayGrid } from 'angular-gridster2'
-export interface ChartGroup {
- label: string
- charts: { label: string; icon: string; rotate?: boolean; width?: string; value: DeepPartial }[]
-}
-
-export const CHARTS: ChartGroup[] = [
- {
- label: 'Comparison',
- charts: [
- {
- label: NxChartType.Bar,
- icon: 'bar.svg',
- value: {
- chartType: {
- type: NxChartType.Bar,
- orient: ChartOrient.horizontal
- },
- dimensions: [{}],
- measures: [{}]
- }
- },
- {
- label: NxChartType.Column,
- icon: 'column.svg',
- value: {
- chartType: {
- type: NxChartType.Bar,
- orient: ChartOrient.vertical
- },
- dimensions: [{}],
- measures: [{}]
- }
- },
- {
- label: NxChartType.ColumnStacked,
- value: {
- chartType: {
- type: NxChartType.Bar,
- orient: ChartOrient.vertical
- },
- dimensions: [
- {},
- {
- role: ChartDimensionRoleType.Stacked
- }
- ],
- measures: [{}]
- },
- icon: 'column-stacked.svg'
- },
- {
- label: NxChartType.BarStacked,
- value: {
- chartType: {
- type: NxChartType.Bar,
- orient: ChartOrient.horizontal
- },
- dimensions: [
- {},
- {
- role: ChartDimensionRoleType.Stacked
- }
- ],
- measures: [{}]
- },
- icon: 'column-stacked.svg',
- rotate: true
- },
- {
- label: NxChartType.BarPolar,
- value: {
- chartType: {
- type: NxChartType.Bar,
- orient: ChartOrient.horizontal,
- variant: 'polar',
- chartOptions: {
- seriesStyle: {
- colorBy: 'data',
- roundCap: true
- }
- }
- },
- dimensions: [{}],
- measures: [{}]
- },
- icon: 'bar-polar.svg'
- },
- {
- label: NxChartType.BarPolar + 'Background',
- value: {
- chartType: {
- type: NxChartType.Bar,
- orient: ChartOrient.horizontal,
- variant: 'polar',
- chartOptions: {
- seriesStyle: {
- colorBy: 'data',
- roundCap: true,
- showBackground: true,
- backgroundStyle: {}
- }
- }
- },
- dimensions: [{}],
- measures: [{}]
- },
- icon: 'bar-polar-bg.svg'
- },
- {
- label: NxChartType.Histogram,
- value: {
- chartType: {
- type: NxChartType.Bar,
- orient: ChartOrient.vertical,
- chartOptions: {
- seriesStyle: {
- barWidth: '99.3%'
- }
- }
- },
- dimensions: [{}],
- measures: [{}]
- },
- icon: 'histogram.svg'
- },
- {
- label: NxChartType.Combination,
- value: {
- chartType: {
- type: NxChartType.Bar,
- orient: ChartOrient.vertical,
- chartOptions: {
- seriesStyle: {
- }
- }
- },
- dimensions: [{}],
- measures: [
- {},
- {
- role: ChartMeasureRoleType.Axis2,
- shapeType: 'line'
- }
- ]
- },
- icon: 'combination.svg',
- width: '50px',
- },
- {
- label: NxChartType.Bar + 'Trellis',
- value: {
- chartType: {
- type: NxChartType.Bar,
- orient: ChartOrient.vertical,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [
- {},
- {
- role: ChartDimensionRoleType.Trellis,
- }
- ],
- measures: [{}]
- },
- icon: 'bar-trellis.svg'
- },
- {
- label: NxChartType.Pie,
- value: {
- chartType: {
- type: NxChartType.Pie,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}],
- measures: [{}]
- },
- icon: 'pie.svg'
- },
- {
- label: NxChartType.Doughnut,
- value: {
- chartType: {
- type: NxChartType.Pie,
- variant: 'Doughnut',
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}],
- measures: [{}]
- },
- icon: 'doughnut.svg'
- },
- {
- label: NxChartType.Doughnut + '2',
- value: {
- chartType: {
- type: NxChartType.Pie,
- variant: 'Doughnut',
- chartOptions: {
- seriesStyle: {
- radius: ['80%', '90%']
- }
- }
- },
- dimensions: [{}],
- measures: [{}]
- },
- icon: 'doughnut-2.svg'
- },
- {
- label: NxChartType.Nightingale,
- value: {
- chartType: {
- type: NxChartType.Pie,
- variant: 'Nightingale',
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}],
- measures: [{}]
- },
- icon: 'nightingale.svg'
- },
- {
- label: NxChartType.Nightingale + '2',
- value: {
- chartType: {
- type: NxChartType.Pie,
- variant: 'Nightingale',
- chartOptions: {
- seriesStyle: {
- radius: [0]
- }
- }
- },
- dimensions: [{}],
- measures: [{}]
- },
- icon: 'nightingale-2.svg'
- },
- {
- label: NxChartType.Waterfall,
- value: {
- chartType: {
- type: NxChartType.Waterfall,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}],
- measures: [{}]
- },
- icon: 'waterfall.svg',
- width: '40px'
- }
- ]
- },
- {
- label: 'Trend',
- charts: [
- {
- label: NxChartType.Line,
- icon: 'line.svg',
- width: '50px',
- value: {
- chartType: {
- type: NxChartType.Line,
- orient: ChartOrient.vertical
- },
- dimensions: [{}],
- measures: [{}]
- }
- },
- {
- label: NxChartType.Line + '2',
- icon: 'line.svg',
- width: '50px',
- value: {
- chartType: {
- type: NxChartType.Line,
- orient: ChartOrient.horizontal
- },
- dimensions: [{}],
- measures: [{}]
- },
- rotate: true
- },
- {
- label: NxChartType.Area,
- icon: 'area.svg',
- width: '50px',
- value: {
- chartType: {
- type: NxChartType.Line,
- orient: ChartOrient.vertical,
- chartOptions: {
- seriesStyle: {
- areaStyle: {}
- }
- }
- },
- dimensions: [{}],
- measures: [{}]
- }
- },
- {
- label: NxChartType.AreaStacked,
- icon: 'area-stacked.svg',
- width: '50px',
- value: {
- chartType: {
- type: NxChartType.Line,
- orient: ChartOrient.vertical,
- chartOptions: {
- seriesStyle: {
- areaStyle: {},
- stack: 'normal'
- }
- }
- },
- dimensions: [{}],
- measures: [{}, {}]
- }
- },
- {
- label: NxChartType.ThemeRiver,
- icon: 'theme-river.svg',
- width: '50px',
- value: {
- chartType: {
- type: NxChartType.ThemeRiver,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}],
- measures: [{}]
- }
- }
- ]
- },
- {
- label: 'Correlation',
- charts: [
- {
- label: NxChartType.Scatter,
- icon: 'scatter.svg',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.Scatter,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}],
- measures: [{}, {}]
- }
- },
- {
- label: NxChartType.Bubble,
- icon: 'bubble.svg',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.Scatter,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}],
- measures: [
- {},
- {},
- {
- role: ChartMeasureRoleType.Size
- }
- ]
- }
- },
- {
- label: NxChartType.Heatmap,
- icon: 'heatmap.svg',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.Heatmap,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}, {}],
- measures: [{}]
- }
- }
- ]
- },
- {
- label: 'Distribution',
- charts: [
- {
- label: NxChartType.Boxplot,
- icon: 'boxplot.png',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.Boxplot,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}, {}],
- measures: [{}]
- }
- },
- {
- label: NxChartType.Tree,
- icon: 'tree.svg',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.Tree,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [
- {
- displayHierarchy: true
- }
- ],
- measures: [{}]
- }
- },
- {
- label: NxChartType.Treemap,
- icon: 'tree-map.svg',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.Treemap,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [
- {
- displayHierarchy: true
- }
- ],
- measures: [{}]
- }
- },
- {
- label: NxChartType.Sunburst,
- icon: 'sunburst.svg',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.Sunburst,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [
- {
- displayHierarchy: true
- }
- ],
- measures: [{}]
- }
- },
- {
- label: NxChartType.Sankey,
- icon: 'sankey.svg',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.Sankey,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [
- {
- displayHierarchy: true
- }
- ],
- measures: [{}]
- }
- },
- {
- label: NxChartType.Funnel,
- icon: 'funnel.svg',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.Funnel,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [],
- measures: [{}, {}, {}]
- }
- }
- ]
- },
- {
- label: 'Geo',
- charts: [
- {
- label: NxChartType.GeoMap,
- icon: 'geomap.svg',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.GeoMap,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}],
- measures: [{}]
- }
- }
- ]
- },
- {
- label: '3D',
- charts: [
- {
- label: NxChartType.Bar3D,
- icon: 'gl.svg',
- width: '60px',
- value: {
- chartType: {
- type: NxChartType.Bar3D,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}, {}, {}],
- measures: [{}]
- }
- },
- {
- label: NxChartType.Line3D,
- icon: 'gl.svg',
- width: '60px',
- value: {
- chartType: {
- type: NxChartType.Line3D,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}, {}, {}],
- measures: [{}]
- }
- },
- {
- label: NxChartType.Scatter3D,
- icon: 'gl.svg',
- width: '60px',
- value: {
- chartType: {
- type: NxChartType.Scatter3D,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}, {}, {}],
- measures: [{}]
- }
- }
- ]
- },
- {
- label: 'Custom',
- charts: [
- {
- label: NxChartType.Custom,
- icon: 'custom.svg',
- width: '40px',
- value: {
- chartType: {
- type: NxChartType.Custom,
- chartOptions: {
- seriesStyle: {}
- }
- },
- dimensions: [{}],
- measures: [{}]
- }
- }
- ]
- }
-]
export const COMPONENTS: {
code: string
diff --git a/libs/component-angular/advanced-filter/advanced-filter.component.html b/libs/component-angular/advanced-filter/advanced-filter.component.html
index a6488ae7b..c989bac4d 100644
--- a/libs/component-angular/advanced-filter/advanced-filter.component.html
+++ b/libs/component-angular/advanced-filter/advanced-filter.component.html
@@ -80,7 +80,6 @@
(null)
- @Input() get entitySet() {
- return this.entitySet$.value
- }
- set entitySet(value) {
- this.entitySet$.next(value)
- }
- private readonly entitySet$ = new BehaviorSubject(null)
-
@Input() get entityType() {
return this.entityType$.value
}
@@ -215,7 +206,6 @@ export class PropertySelectComponent implements ControlValueAccessor, OnInit, Af
@Input() coreService: NxCoreService
@Input() dsCoreService: NgmDSCoreService
- // @Input() calculationEditor: Type
@Input() syntax: Syntax
@Input() displayDensity: DisplayDensity | string
@Input() disabled: boolean
@@ -441,7 +431,7 @@ export class PropertySelectComponent implements ControlValueAccessor, OnInit, Af
}
if (members?.length) {
- property.caption = `${property.caption}:${exclude?' - ':''}${isString(members[0]) ? members[0] : members[0].label || members[0].value}`
+ property.caption = `${property.caption}:${exclude?' - ':''}${isString(members[0]) ? members[0] : members[0].caption || members[0].value}`
if (members.length > 1) {
property.caption += `(+${members.length - 1})`
}
diff --git a/libs/formly/property-select/property-select.component.html b/libs/formly/property-select/property-select.component.html
index 3bb31642f..4c59e7688 100644
--- a/libs/formly/property-select/property-select.component.html
+++ b/libs/formly/property-select/property-select.component.html
@@ -4,7 +4,6 @@
[editable]="true"
[showAttributes]="true"
[dataSettings]="dataSettings$ | async"
- [entitySet]="entitySet$ | async"
[entityType]="entityType$ | async"
[restrictedDimensions]="restrictedDimensions$ | async"
[coreService]="coreService"
diff --git a/libs/story-angular/src/lib/explorer/explorer.component.html b/libs/story-angular/src/lib/explorer/explorer.component.html
new file mode 100644
index 000000000..907908460
--- /dev/null
+++ b/libs/story-angular/src/lib/explorer/explorer.component.html
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+
+
+ Measures
+
+
+
+
+
+ {{item.caption}}
+
+
+
+
+
+
+
+
+
+ {{item.caption}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ 'PAC.KEY_WORDS.Dimensions' | translate: {Default: 'Dimensions'} }}
+
+
+
+
+
+
+
+
+
+ {{'FORMLY.CHART.' + group.label | translate: {Default: group.label} }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Visual
+ Options
+
+
+
+ Table
+ Chart
+
+
+
+
+
+
+
+
+
+
+
+
\ 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
new file mode 100644
index 000000000..e5a58fcf8
--- /dev/null
+++ b/libs/story-angular/src/lib/explorer/explorer.component.scss
@@ -0,0 +1,10 @@
+:host {
+ @apply flex flex-col justify-start items-stretch bg-slate-100;
+}
+
+.tag.selected {
+ @apply text-amber-500 bg-amber-100;
+}
+.ngm-story-explorer__chart.selected {
+ @apply ring-violet-500;
+}
\ No newline at end of file
diff --git a/libs/story-angular/src/lib/explorer/explorer.component.ts b/libs/story-angular/src/lib/explorer/explorer.component.ts
new file mode 100644
index 000000000..055f7017e
--- /dev/null
+++ b/libs/story-angular/src/lib/explorer/explorer.component.ts
@@ -0,0 +1,285 @@
+import { CdkDrag, CdkDragDrop, DragDropModule } from '@angular/cdk/drag-drop'
+import { CommonModule } from '@angular/common'
+import { Component, EventEmitter, Input, Output, 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'
+import { MatButtonToggleModule } from '@angular/material/button-toggle'
+import { MatChipsModule } from '@angular/material/chips'
+import { MatDividerModule } from '@angular/material/divider'
+import { MatListModule } from '@angular/material/list'
+import { MatTooltipModule } from '@angular/material/tooltip'
+import { NgmPrismHighlightComponent } from '@metad/components/prism'
+import { PropertyCapacity, PropertyModule } from '@metad/components/property'
+import { NxTableModule } from '@metad/components/table'
+import { NxChartType } from '@metad/core'
+import { AnalyticalCardModule } from '@metad/ocap-angular/analytical-card'
+import { AnalyticalGridModule } from '@metad/ocap-angular/analytical-grid'
+import { NgmMemberTreeComponent } from '@metad/ocap-angular/controls'
+import { DisplayDensity, NgmDSCoreService, OcapCoreModule } from '@metad/ocap-angular/core'
+import { EntityCapacity, NgmEntitySchemaComponent } from '@metad/ocap-angular/entity'
+import {
+ C_MEASURES,
+ ChartAnnotation,
+ ChartOrient,
+ DataSettings,
+ Dimension,
+ DisplayBehaviour,
+ ISlicer,
+ assignDeepOmitBlank,
+ cloneDeep,
+ getEntityDimensions,
+ getEntityMeasures,
+ nonNullable,
+ pick
+} from '@metad/ocap-core'
+import { WidgetComponentType } from '@metad/story/core'
+import { TranslateModule } from '@ngx-translate/core'
+import { filter, map, switchMap } from 'rxjs/operators'
+import { CHARTS, getChartType } from './types'
+
+@Component({
+ standalone: true,
+ imports: [
+ CommonModule,
+ FormsModule,
+ ReactiveFormsModule,
+ TranslateModule,
+ MatChipsModule,
+ MatButtonModule,
+ MatListModule,
+ MatButtonToggleModule,
+ MatDividerModule,
+ MatTooltipModule,
+ DragDropModule,
+ NxTableModule,
+ NgmPrismHighlightComponent,
+ OcapCoreModule,
+ NgmEntitySchemaComponent,
+ NgmMemberTreeComponent,
+ AnalyticalCardModule,
+ AnalyticalGridModule,
+ PropertyModule
+ ],
+ selector: 'ngm-story-explorer',
+ templateUrl: 'explorer.component.html',
+ styleUrls: ['explorer.component.scss']
+})
+export class StoryExplorerComponent {
+ EntityCapacity = EntityCapacity
+ DisplayDensity = DisplayDensity
+ PropertyCapacity = PropertyCapacity
+ ComponentType = WidgetComponentType
+
+ private readonly dsCoreService = inject(NgmDSCoreService)
+
+ @Input()
+ get data() {
+ return this._data()
+ }
+ set data(value: any) {
+ this._data.set(value)
+ if (value) {
+ const chartAnnotation = value?.dataSettings?.chartAnnotation
+ if (chartAnnotation) {
+ this.component.set({
+ component: WidgetComponentType.AnalyticalCard,
+ label: getChartType(chartAnnotation.chartType)?.label as NxChartType,
+ dataSettings: value.dataSettings
+ })
+ this.rows.set(chartAnnotation.dimensions)
+ this.columns.set(chartAnnotation.measures)
+ }
+ }
+
+ }
+ private readonly _data = signal<{ dataSettings: DataSettings; chartAnnotation: ChartAnnotation }>(null)
+
+ @Output() closed = new EventEmitter()
+
+ dimensions = signal<{ dimension: Dimension; caption: string; hierarchies: Dimension[] }[]>([])
+
+ readonly entityType = toSignal(
+ toObservable(this._data).pipe(
+ filter(nonNullable),
+ switchMap(({ dataSettings }) =>
+ this.dsCoreService
+ .selectEntitySet(dataSettings.dataSource, dataSettings.entitySet)
+ .pipe(map(({ entityType }) => entityType))
+ )
+ )
+ )
+
+ readonly measureList = computed(() => {
+ return getEntityMeasures(this.entityType())
+ })
+ readonly dataSettings = computed(() => {
+ return pick(this.data?.dataSettings, 'dataSource', 'entitySet') as DataSettings
+ })
+ readonly dataSettingsChart = computed(() => {
+ const chartAnnotation = assignDeepOmitBlank(
+ {
+ ...cloneDeep(this.component()?.dataSettings?.chartAnnotation ?? this.data?.chartAnnotation ?? {})
+ },
+ {
+ dimensions: this.rows().map((row) => ({
+ ...row,
+ chartOptions: {
+ dataZoom: {
+ type: 'inside'
+ }
+ }
+ })),
+ measures: [
+ ...this.columns(),
+ ...this.measures().map((measure) => ({
+ dimension: C_MEASURES,
+ measure,
+ formatting: {
+ shortNumber: true
+ }
+ }))
+ ]
+ },
+ 5
+ )
+
+ 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
+ }
+ })
+ readonly chartOptions = signal({
+ legend: {
+ show: true
+ }
+ })
+ readonly dataSettingsGrid = computed(() => {
+ const analytics = {
+ ...(this.data?.analytics ?? {}),
+ rows: this.rows(),
+ columns: this.measures().map((measure) => ({
+ dimension: C_MEASURES,
+ measure
+ }))
+ }
+ console.log('analytics:', analytics)
+ return {
+ ...(this.data?.dataSettings ?? {}),
+ analytics
+ }
+ })
+
+ readonly _slicers = computed(() => {
+ return Object.values(this.slicers()).map((slicer) => slicer)
+ })
+
+ readonly rows = signal([])
+ readonly columns = signal([])
+ readonly measures = signal([])
+ readonly slicers = signal<{ [name: string]: ISlicer }>({})
+ readonly component = signal({
+ label: NxChartType.Bar,
+ component: WidgetComponentType.AnalyticalCard,
+ dataSettings: {
+ chartAnnotation: {
+ chartType: {
+ type: NxChartType.Bar,
+ orient: ChartOrient.horizontal
+ },
+ dimensions: [{}],
+ measures: [{}]
+ }
+ }
+ })
+
+ view: 'table' | 'chart' = 'table'
+ visualPanel: 'visual' | 'options' = 'visual'
+ charts = CHARTS.map((item) => cloneDeep(item) as any)
+
+ constructor() {
+ effect(
+ () => {
+ if (this.entityType()) {
+ this.dimensions.set(
+ getEntityDimensions(this.entityType()).map(({ name, caption, hierarchies }) => ({
+ dimension: {
+ dimension: name,
+ displayBehaviour: DisplayBehaviour.descriptionOnly
+ },
+ caption,
+ hierarchies: hierarchies.map((hierarchy) => ({
+ dimension: name,
+ hierarchy: hierarchy.name,
+ caption: hierarchy.caption
+ }))
+ }))
+ )
+ }
+ },
+ { allowSignalWrites: true }
+ )
+ }
+
+ back() {
+ this.closed.emit()
+ }
+
+ trackByDim(index, item) {
+ return item?.dimension?.dimension
+ }
+ trackByIndex(index, item) {
+ return index
+ }
+
+ toggleHierarchy(hierarchy: string, { dimension }) {
+ const index = this.dimensions().findIndex((d) => d.dimension.dimension === dimension.dimension)
+ this.dimensions.set([
+ ...this.dimensions().slice(0, index),
+ {
+ ...this.dimensions()[index],
+ dimension: {
+ ...this.dimensions()[index].dimension,
+ hierarchy: hierarchy
+ }
+ },
+ ...this.dimensions().slice(index + 1)
+ ])
+ }
+
+ dropRowPredicate(item: CdkDrag) {
+ return true
+ }
+
+ dropRow(event: CdkDragDrop) {
+ this.rows.set([...this.rows(), { ...event.item.data }])
+ }
+
+ dropColumn(event: CdkDragDrop) {
+ this.columns.set([...this.columns(), { ...event.item.data }])
+ }
+
+ onRowChange(row: Dimension, i: number) {
+ this.rows.set([...this.rows().slice(0, i), row, ...this.rows().slice(i + 1)])
+ }
+
+ onMeasuresChange(measures: string[]) {
+ this.measures.set(measures)
+ }
+
+ onSlicersChange(slicer: ISlicer, dimension: string) {
+ this.slicers.set({
+ ...this.slicers(),
+ [dimension]: slicer
+ })
+ }
+
+ createWidget(widget: any) {
+ console.log(widget)
+ this.component.set(widget)
+ }
+}
diff --git a/libs/story-angular/src/lib/explorer/explorer.module.ts b/libs/story-angular/src/lib/explorer/explorer.module.ts
new file mode 100644
index 000000000..5a5757d0a
--- /dev/null
+++ b/libs/story-angular/src/lib/explorer/explorer.module.ts
@@ -0,0 +1,13 @@
+import { NgModule } from '@angular/core'
+import { StoryExplorerComponent } from './explorer.component';
+
+@NgModule({
+ declarations: [],
+ imports: [
+ StoryExplorerComponent
+ ],
+ exports: [
+ StoryExplorerComponent
+ ]
+})
+export class StoryExplorerModule {}
diff --git a/libs/story-angular/src/lib/explorer/index.ts b/libs/story-angular/src/lib/explorer/index.ts
new file mode 100644
index 000000000..0f7a52c80
--- /dev/null
+++ b/libs/story-angular/src/lib/explorer/index.ts
@@ -0,0 +1,3 @@
+export * from './types'
+export * from './explorer.module'
+export * from './explorer.component'
\ No newline at end of file
diff --git a/libs/story-angular/src/lib/explorer/types.ts b/libs/story-angular/src/lib/explorer/types.ts
new file mode 100644
index 000000000..f2ffedc2d
--- /dev/null
+++ b/libs/story-angular/src/lib/explorer/types.ts
@@ -0,0 +1,617 @@
+import { ChartAnnotation, ChartDimensionRoleType, ChartMeasureRoleType, ChartOrient, ChartType } from '@metad/ocap-core'
+import { DeepPartial, NxChartType } from '@metad/core'
+
+export interface ChartGroup {
+ label: string
+ charts: { label: string; icon: string; rotate?: boolean; width?: string; value: DeepPartial }[]
+}
+
+export const CHARTS: ChartGroup[] = [
+ {
+ label: 'Comparison',
+ charts: [
+ {
+ label: NxChartType.Bar,
+ icon: 'bar.svg',
+ value: {
+ chartType: {
+ type: NxChartType.Bar,
+ orient: ChartOrient.horizontal
+ },
+ dimensions: [{}],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.Column,
+ icon: 'column.svg',
+ value: {
+ chartType: {
+ type: NxChartType.Bar,
+ orient: ChartOrient.vertical
+ },
+ dimensions: [{}],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.ColumnStacked,
+ value: {
+ chartType: {
+ type: NxChartType.Bar,
+ orient: ChartOrient.vertical
+ },
+ dimensions: [
+ {},
+ {
+ role: ChartDimensionRoleType.Stacked
+ }
+ ],
+ measures: [{}]
+ },
+ icon: 'column-stacked.svg'
+ },
+ {
+ label: NxChartType.BarStacked,
+ value: {
+ chartType: {
+ type: NxChartType.Bar,
+ orient: ChartOrient.horizontal
+ },
+ dimensions: [
+ {},
+ {
+ role: ChartDimensionRoleType.Stacked
+ }
+ ],
+ measures: [{}]
+ },
+ icon: 'column-stacked.svg',
+ rotate: true
+ },
+ {
+ label: NxChartType.BarPolar,
+ value: {
+ chartType: {
+ type: NxChartType.Bar,
+ orient: ChartOrient.horizontal,
+ variant: 'polar',
+ chartOptions: {
+ seriesStyle: {
+ colorBy: 'data',
+ roundCap: true
+ }
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ },
+ icon: 'bar-polar.svg'
+ },
+ {
+ label: NxChartType.BarPolar + 'Background',
+ value: {
+ chartType: {
+ type: NxChartType.Bar,
+ orient: ChartOrient.horizontal,
+ variant: 'polar',
+ chartOptions: {
+ seriesStyle: {
+ colorBy: 'data',
+ roundCap: true,
+ showBackground: true,
+ backgroundStyle: {}
+ }
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ },
+ icon: 'bar-polar-bg.svg'
+ },
+ {
+ label: NxChartType.Histogram,
+ value: {
+ chartType: {
+ type: NxChartType.Bar,
+ orient: ChartOrient.vertical,
+ chartOptions: {
+ seriesStyle: {
+ barWidth: '99.3%'
+ }
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ },
+ icon: 'histogram.svg'
+ },
+ {
+ label: NxChartType.Combination,
+ value: {
+ chartType: {
+ type: NxChartType.Bar,
+ orient: ChartOrient.vertical,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}],
+ measures: [
+ {},
+ {
+ role: ChartMeasureRoleType.Axis2,
+ shapeType: 'line'
+ }
+ ]
+ },
+ icon: 'combination.svg',
+ width: '50px'
+ },
+ {
+ label: NxChartType.Bar + 'Trellis',
+ value: {
+ chartType: {
+ type: NxChartType.Bar,
+ orient: ChartOrient.vertical,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [
+ {},
+ {
+ role: ChartDimensionRoleType.Trellis
+ }
+ ],
+ measures: [{}]
+ },
+ icon: 'bar-trellis.svg'
+ },
+ {
+ label: NxChartType.Pie,
+ value: {
+ chartType: {
+ type: NxChartType.Pie,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ },
+ icon: 'pie.svg'
+ },
+ {
+ label: NxChartType.Doughnut,
+ value: {
+ chartType: {
+ type: NxChartType.Pie,
+ variant: 'Doughnut',
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ },
+ icon: 'doughnut.svg'
+ },
+ {
+ label: NxChartType.Doughnut + '2',
+ value: {
+ chartType: {
+ type: NxChartType.Pie,
+ variant: 'Doughnut',
+ chartOptions: {
+ seriesStyle: {
+ radius: ['80%', '90%']
+ }
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ },
+ icon: 'doughnut-2.svg'
+ },
+ {
+ label: NxChartType.Nightingale,
+ value: {
+ chartType: {
+ type: NxChartType.Pie,
+ variant: 'Nightingale',
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ },
+ icon: 'nightingale.svg'
+ },
+ {
+ label: NxChartType.Nightingale + '2',
+ value: {
+ chartType: {
+ type: NxChartType.Pie,
+ variant: 'Nightingale',
+ chartOptions: {
+ seriesStyle: {
+ radius: [0]
+ }
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ },
+ icon: 'nightingale-2.svg'
+ },
+ {
+ label: NxChartType.Waterfall,
+ value: {
+ chartType: {
+ type: NxChartType.Waterfall,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ },
+ icon: 'waterfall.svg',
+ width: '40px'
+ }
+ ]
+ },
+ {
+ label: 'Trend',
+ charts: [
+ {
+ label: NxChartType.Line,
+ icon: 'line.svg',
+ width: '50px',
+ value: {
+ chartType: {
+ type: NxChartType.Line,
+ orient: ChartOrient.vertical
+ },
+ dimensions: [{}],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.Line + '2',
+ icon: 'line.svg',
+ width: '50px',
+ value: {
+ chartType: {
+ type: NxChartType.Line,
+ orient: ChartOrient.horizontal
+ },
+ dimensions: [{}],
+ measures: [{}]
+ },
+ rotate: true
+ },
+ {
+ label: NxChartType.Area,
+ icon: 'area.svg',
+ width: '50px',
+ value: {
+ chartType: {
+ type: NxChartType.Line,
+ orient: ChartOrient.vertical,
+ chartOptions: {
+ seriesStyle: {
+ areaStyle: {}
+ }
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.AreaStacked,
+ icon: 'area-stacked.svg',
+ width: '50px',
+ value: {
+ chartType: {
+ type: NxChartType.Line,
+ orient: ChartOrient.vertical,
+ chartOptions: {
+ seriesStyle: {
+ areaStyle: {},
+ stack: 'normal'
+ }
+ }
+ },
+ dimensions: [{}],
+ measures: [{}, {}]
+ }
+ },
+ {
+ label: NxChartType.ThemeRiver,
+ icon: 'theme-river.svg',
+ width: '50px',
+ value: {
+ chartType: {
+ type: NxChartType.ThemeRiver,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ }
+ }
+ ]
+ },
+ {
+ label: 'Correlation',
+ charts: [
+ {
+ label: NxChartType.Scatter,
+ icon: 'scatter.svg',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.Scatter,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}],
+ measures: [{}, {}]
+ }
+ },
+ {
+ label: NxChartType.Bubble,
+ icon: 'bubble.svg',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.Scatter,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}],
+ measures: [
+ {},
+ {},
+ {
+ role: ChartMeasureRoleType.Size
+ }
+ ]
+ }
+ },
+ {
+ label: NxChartType.Heatmap,
+ icon: 'heatmap.svg',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.Heatmap,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}, {}],
+ measures: [{}]
+ }
+ }
+ ]
+ },
+ {
+ label: 'Distribution',
+ charts: [
+ {
+ label: NxChartType.Boxplot,
+ icon: 'boxplot.png',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.Boxplot,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}, {}],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.Tree,
+ icon: 'tree.svg',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.Tree,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [
+ {
+ displayHierarchy: true
+ }
+ ],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.Treemap,
+ icon: 'tree-map.svg',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.Treemap,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [
+ {
+ displayHierarchy: true
+ }
+ ],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.Sunburst,
+ icon: 'sunburst.svg',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.Sunburst,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [
+ {
+ displayHierarchy: true
+ }
+ ],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.Sankey,
+ icon: 'sankey.svg',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.Sankey,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [
+ {
+ displayHierarchy: true
+ }
+ ],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.Funnel,
+ icon: 'funnel.svg',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.Funnel,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [],
+ measures: [{}, {}, {}]
+ }
+ }
+ ]
+ },
+ {
+ label: 'Geo',
+ charts: [
+ {
+ label: NxChartType.GeoMap,
+ icon: 'geomap.svg',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.GeoMap,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ }
+ }
+ ]
+ },
+ {
+ label: '3D',
+ charts: [
+ {
+ label: NxChartType.Bar3D,
+ icon: 'gl.svg',
+ width: '60px',
+ value: {
+ chartType: {
+ type: NxChartType.Bar3D,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}, {}, {}],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.Line3D,
+ icon: 'gl.svg',
+ width: '60px',
+ value: {
+ chartType: {
+ type: NxChartType.Line3D,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}, {}, {}],
+ measures: [{}]
+ }
+ },
+ {
+ label: NxChartType.Scatter3D,
+ icon: 'gl.svg',
+ width: '60px',
+ value: {
+ chartType: {
+ type: NxChartType.Scatter3D,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}, {}, {}],
+ measures: [{}]
+ }
+ }
+ ]
+ },
+ {
+ label: 'Custom',
+ charts: [
+ {
+ label: NxChartType.Custom,
+ icon: 'custom.svg',
+ width: '40px',
+ value: {
+ chartType: {
+ type: NxChartType.Custom,
+ chartOptions: {
+ seriesStyle: {}
+ }
+ },
+ dimensions: [{}],
+ measures: [{}]
+ }
+ }
+ ]
+ }
+]
+
+export function getChartType(chartType: ChartType) {
+ for(const group of CHARTS) {
+ for(const chart of group.charts) {
+ if(chart.value.chartType.type === chartType?.type) {
+ return chart
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/libs/story-angular/src/lib/shared.module.ts b/libs/story-angular/src/lib/shared.module.ts
deleted file mode 100644
index d74aca9e4..000000000
--- a/libs/story-angular/src/lib/shared.module.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-// import { DragDropModule } from '@angular/cdk/drag-drop'
-// import { LayoutModule } from '@angular/cdk/layout'
-// import { PortalModule } from '@angular/cdk/portal'
-// import { CommonModule } from '@angular/common'
-// import { NgModule } from '@angular/core'
-// import { FormsModule, ReactiveFormsModule } from '@angular/forms'
-// import { MatBadgeModule } from '@angular/material/badge'
-// import { MatBottomSheetModule } from '@angular/material/bottom-sheet'
-// import { MatButtonModule } from '@angular/material/button'
-// import { MatCardModule } from '@angular/material/card'
-// import { MatCheckboxModule } from '@angular/material/checkbox'
-// import { MatRippleModule } from '@angular/material/core'
-// import { MatDialogModule } from '@angular/material/dialog'
-// import { MatExpansionModule } from '@angular/material/expansion'
-// import { MatFormFieldModule } from '@angular/material/form-field'
-// import { MatIconModule } from '@angular/material/icon'
-// import { MatInputModule } from '@angular/material/input'
-// import { MatListModule } from '@angular/material/list'
-// import { MatMenuModule } from '@angular/material/menu'
-// import { MatProgressBarModule } from '@angular/material/progress-bar'
-// import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'
-// import { MatSelectModule } from '@angular/material/select'
-// import { MatSidenavModule } from '@angular/material/sidenav'
-// import { MatSlideToggleModule } from '@angular/material/slide-toggle'
-// import { MatStepperModule } from '@angular/material/stepper'
-// import { MatTableModule } from '@angular/material/table'
-// import { MatTabsModule } from '@angular/material/tabs'
-// import { MatToolbarModule } from '@angular/material/toolbar'
-// import { MatTooltipModule } from '@angular/material/tooltip'
-// import { MatTreeModule } from '@angular/material/tree'
-
-// const MAT_MODULES = [
-// MatIconModule,
-// MatButtonModule,
-// MatListModule,
-// MatTabsModule,
-// MatFormFieldModule,
-// MatInputModule,
-// MatDialogModule,
-// MatSidenavModule,
-// MatTableModule,
-// MatBottomSheetModule,
-// MatTreeModule,
-// MatExpansionModule,
-// MatStepperModule,
-// MatMenuModule,
-// MatCheckboxModule,
-// MatToolbarModule,
-// MatTooltipModule,
-// MatSelectModule,
-// MatProgressBarModule,
-// DragDropModule,
-// PortalModule,
-// LayoutModule,
-// MatSlideToggleModule,
-// MatProgressSpinnerModule,
-// MatCardModule,
-// MatBadgeModule,
-// MatRippleModule
-// ]
-
-// @NgModule({
-// declarations: [],
-// imports: [CommonModule, FormsModule, ReactiveFormsModule, ...MAT_MODULES],
-// exports: [CommonModule, FormsModule, ReactiveFormsModule, ...MAT_MODULES]
-// })
-// export class NxStorySharedModule {}
diff --git a/libs/story-angular/src/public-api.ts b/libs/story-angular/src/public-api.ts
index 44926d5de..6c68b721d 100644
--- a/libs/story-angular/src/public-api.ts
+++ b/libs/story-angular/src/public-api.ts
@@ -3,3 +3,4 @@
*/
export * from './lib/settings/index'
+export * from './lib/explorer/index'
\ No newline at end of file
diff --git a/libs/story-angular/story/story-widget/story-widget.component.html b/libs/story-angular/story/story-widget/story-widget.component.html
index 4e060473a..ad4eeebc3 100644
--- a/libs/story-angular/story/story-widget/story-widget.component.html
+++ b/libs/story-angular/story/story-widget/story-widget.component.html
@@ -101,6 +101,10 @@
refresh
{{ 'Story.Widget.Refresh' | translate: {Default: "Refresh"} }}
+