diff --git a/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.html b/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.html index cbdec3485..8fea6ffe6 100644 --- a/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.html +++ b/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.html @@ -3,17 +3,23 @@ [disabled]="!enabledFeature(feature)"> - {{ feature.name }} + {{ 'PAC.Feature.Features.' + feature.code + '.Name' | translate: {Default: feature.name } }} - {{ feature.description }} + {{ 'PAC.Feature.Features.' + feature.code + '.Description' | translate: {Default: feature.description } }} - + + - {{ child?.name }} + +
+ {{ 'PAC.Feature.Features.' + child.code + '.Name' | translate: {Default: child.name } }} + {{ 'PAC.Feature.Features.' + child.code + '.Description' | translate: {Default: child.description } }} +
+
diff --git a/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.scss b/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.scss index 38f3ef31e..bdb16be2a 100644 --- a/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.scss +++ b/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.scss @@ -1,3 +1,7 @@ :host { @apply w-full; +} + +.mat-mdc-slide-toggle { + @apply inline-flex; } \ No newline at end of file diff --git a/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.ts b/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.ts index e415705e6..9e49618d7 100644 --- a/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.ts +++ b/apps/cloud/src/app/@shared/feature-toggle/feature-toggle.component.ts @@ -1,31 +1,30 @@ -import { Component, OnChanges, OnInit, SimpleChanges } from '@angular/core' +import { Component, OnInit, inject } from '@angular/core' +import { takeUntilDestroyed } from '@angular/core/rxjs-interop' import { MatDialog } from '@angular/material/dialog' import { ActivatedRoute } from '@angular/router' +import { CountdownConfirmationComponent } from '@metad/components/confirm' import { IFeature, IFeatureOrganization, IFeatureToggle } from '@metad/contracts' import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy' -import { TranslateService } from '@ngx-translate/core' -import { CountdownConfirmationComponent } from '@metad/components/confirm' import { combineLatest, firstValueFrom, of } from 'rxjs' -import { - distinctUntilChanged, - map, - shareReplay, - startWith, - switchMap, - tap, - withLatestFrom -} from 'rxjs/operators' +import { distinctUntilChanged, map, shareReplay, startWith, switchMap, tap, withLatestFrom } from 'rxjs/operators' import { environment } from '../../../environments/environment' import { FeatureService, FeatureStoreService, Store } from '../../@core/services' import { TranslationBaseComponent } from '../language/translation-base.component' + @UntilDestroy({ checkProperties: true }) @Component({ selector: 'pac-feature-toggle', templateUrl: './feature-toggle.component.html', styleUrls: ['./feature-toggle.component.scss'] }) -export class FeatureToggleComponent extends TranslationBaseComponent implements OnInit, OnChanges { +export class FeatureToggleComponent extends TranslationBaseComponent implements OnInit { + private readonly _activatedRoute = inject(ActivatedRoute) + private readonly _featureService = inject(FeatureService) + private readonly _featureStoreService = inject(FeatureStoreService) + private readonly _storeService = inject(Store) + private readonly _matDialog = inject(MatDialog) + loading = false featureToggles = [] featureTogglesDefinitions: IFeatureToggle[] = [] @@ -34,7 +33,7 @@ export class FeatureToggleComponent extends TranslationBaseComponent implements startWith(this._activatedRoute.snapshot.data), map((data) => data?.isOrganization), distinctUntilChanged(), - untilDestroyed(this), + takeUntilDestroyed(), shareReplay(1) ) public readonly organization$ = this._storeService.selectedOrganization$ @@ -52,21 +51,10 @@ export class FeatureToggleComponent extends TranslationBaseComponent implements } return this._featureStoreService.loadFeatureOrganizations(['feature'], request).pipe(map(({ items }) => items)) }), - untilDestroyed(this), + takeUntilDestroyed(), shareReplay(1) ) - constructor( - private readonly _activatedRoute: ActivatedRoute, - private readonly _featureService: FeatureService, - private readonly _featureStoreService: FeatureStoreService, - private readonly _storeService: Store, - public readonly translationService: TranslateService, - private readonly _matDialog: MatDialog - ) { - super() - } - ngOnInit(): void { combineLatest([this.featureTenant$, this.featureOrganizations$]) .pipe(withLatestFrom(combineLatest([this.isOrganization$, this.organization$])), untilDestroyed(this)) @@ -99,26 +87,24 @@ export class FeatureToggleComponent extends TranslationBaseComponent implements .subscribe() } - ngOnChanges(change: SimpleChanges): void {} - getFeatures() { this._featureStoreService.loadFeatures(['children']).pipe(untilDestroyed(this)).subscribe() } - async featureChanged(event: boolean, feature: IFeature) { + async featureChanged(isEnabled: boolean, feature: IFeature) { const result = await firstValueFrom( this._matDialog .open(CountdownConfirmationComponent, { - // context: { - // recordType: feature.description, - // isEnabled: isEnabled - // }, + data: { + recordType: feature.description, + isEnabled: isEnabled + }, }) .afterClosed() ) if (result) { - await this.emitFeatureToggle({ feature, isEnabled: !!event }) + await this.emitFeatureToggle({ feature, isEnabled: !!isEnabled }) } else { if (!environment.IS_ELECTRON) { window.location.reload() @@ -126,18 +112,18 @@ export class FeatureToggleComponent extends TranslationBaseComponent implements } } - async emitFeatureToggle({feature, isEnabled}: { feature: IFeature; isEnabled: boolean }) { + async emitFeatureToggle({ feature, isEnabled }: { feature: IFeature; isEnabled: boolean }) { const isOrganization = await firstValueFrom(this.isOrganization$) const organization = await firstValueFrom(this.organization$) const { id: featureId } = feature - const request = { - featureId, - isEnabled - } - if (organization && isOrganization) { - const { id: organizationId } = organization - request['organizationId'] = organizationId - } + const request = { + featureId, + isEnabled + } + if (organization && isOrganization) { + const { id: organizationId } = organization + request['organizationId'] = organizationId + } await firstValueFrom(this._featureStoreService.changedFeature(request)) if (!environment.IS_ELECTRON) { window.location.reload() diff --git a/apps/cloud/src/app/@theme/header/organization-selector/organization-selector.component.ts b/apps/cloud/src/app/@theme/header/organization-selector/organization-selector.component.ts index 5b24dafab..698e96333 100644 --- a/apps/cloud/src/app/@theme/header/organization-selector/organization-selector.component.ts +++ b/apps/cloud/src/app/@theme/header/organization-selector/organization-selector.component.ts @@ -1,10 +1,10 @@ import { CommonModule } from '@angular/common' -import { Component, OnInit, inject } from '@angular/core' +import { Component, DestroyRef, OnInit, inject } from '@angular/core' +import { takeUntilDestroyed } from '@angular/core/rxjs-interop' import { MatIconModule } from '@angular/material/icon' import { MatMenuModule } from '@angular/material/menu' import { MatTooltipModule } from '@angular/material/tooltip' import { Ability } from '@casl/ability' -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy' import { nonNullable } from '@metad/core' import { uniqBy } from 'lodash-es' import { filter, map, shareReplay, switchMap, tap } from 'rxjs' @@ -12,7 +12,7 @@ import { AbilityActions, IOrganization, Store, UsersOrganizationsService } from import { OrgAvatarComponent } from '../../../@shared' import { TranslationBaseComponent } from '../../../@shared/language/translation-base.component' -@UntilDestroy() + @Component({ standalone: true, selector: 'pac-organization-selector', @@ -23,6 +23,7 @@ export class OrganizationSelectorComponent extends TranslationBaseComponent impl private readonly store = inject(Store) private readonly userOrganizationService = inject(UsersOrganizationsService) private readonly ability = inject(Ability) + private readonly destroyRef = inject(DestroyRef) selectedOrganization: IOrganization @@ -76,7 +77,7 @@ export class OrganizationSelectorComponent extends TranslationBaseComponent impl ] : organizations ), - untilDestroyed(this), + takeUntilDestroyed(), shareReplay(1) ) @@ -94,7 +95,7 @@ export class OrganizationSelectorComponent extends TranslationBaseComponent impl this.selectedOrganization = organization this.store.featureOrganizations = organization.featureOrganizations ?? [] }), - untilDestroyed(this) + takeUntilDestroyed(this.destroyRef) ) .subscribe() } @@ -108,7 +109,10 @@ export class OrganizationSelectorComponent extends TranslationBaseComponent impl this.store.selectedOrganization = null this.store.organizationId = null this.store.selectedEmployee = null - this.selectedOrganization = { name: 'All Org', id: null } as IOrganization + this.selectedOrganization = { + name: this.getTranslation('PAC.Header.Organization.AllOrg', { Default: 'All Org' }), + id: null + } as IOrganization } } } diff --git a/apps/cloud/src/app/app.component.ts b/apps/cloud/src/app/app.component.ts index e6afe46bb..5c1922f14 100644 --- a/apps/cloud/src/app/app.component.ts +++ b/apps/cloud/src/app/app.component.ts @@ -67,7 +67,7 @@ export class AppComponent implements OnInit { ngOnInit() { combineLatest([this.appService.isMobile$, this.store.preferredTheme$]) .subscribe(([isMobile, preferredTheme]) => { - const [primaryTheme, primaryColor] = preferredTheme.split('-') + const [primaryTheme, primaryColor] = (preferredTheme ?? '').split('-') preferredTheme = preferredTheme ?? ThemesEnum.default const theme = `ngm-theme-${preferredTheme} ${primaryTheme} ${preferredTheme}` // for body diff --git a/apps/cloud/src/app/features/features.module.ts b/apps/cloud/src/app/features/features.module.ts index df8496f7a..2bc2ab352 100644 --- a/apps/cloud/src/app/features/features.module.ts +++ b/apps/cloud/src/app/features/features.module.ts @@ -12,6 +12,7 @@ import { DataSource, Type } from '@metad/ocap-core' import { LetDirective } from '@ngrx/component' import { PacAuthModule } from '@metad/cloud/auth' import { NxTableModule } from '@metad/components/table' +import { NgmFormlyModule } from '@metad/formly' import { NgmCopilotService } from '@metad/core' import { PACMaterialThemeModule } from '@metad/material-theme' import { NX_STORY_FEED, NX_STORY_MODEL, NX_STORY_STORE } from '@metad/story/core' @@ -50,7 +51,10 @@ import { FeaturesComponent } from './features.component' CopilotChatComponent, NxTableModule.forRoot(), DensityDirective, - CopilotGlobalComponent + CopilotGlobalComponent, + + // Formly + NgmFormlyModule.forRoot({}), ], providers: [ DirtyCheckGuard, diff --git a/apps/cloud/src/app/features/home/_home-theme.scss b/apps/cloud/src/app/features/home/_home-theme.scss index 7f7f32e62..448cae153 100644 --- a/apps/cloud/src/app/features/home/_home-theme.scss +++ b/apps/cloud/src/app/features/home/_home-theme.scss @@ -1,21 +1,17 @@ @use 'sass:map'; @use 'sass:color'; @use '@angular/material' as mat; -@use './insight/insight-theme' as insight; @use './dashboard/dashboard-theme' as dashboard; @mixin color($theme) { - @include insight.color($theme); @include dashboard.color($theme); } @mixin typography($theme) { - @include insight.typography($theme); @include dashboard.typography($theme); } @mixin density($theme) { - @include insight.density($theme); @include dashboard.density($theme); } diff --git a/apps/cloud/src/app/features/home/_home.scss b/apps/cloud/src/app/features/home/_home.scss index 2a65f5447..bddfc43a2 100644 --- a/apps/cloud/src/app/features/home/_home.scss +++ b/apps/cloud/src/app/features/home/_home.scss @@ -1,3 +1,5 @@ +@import './insight/_insight.component'; + .pac-home__content { .pac-home__gridster-item { background: transparent; diff --git a/apps/cloud/src/app/features/home/home.component.ts b/apps/cloud/src/app/features/home/home.component.ts index 1e43e3b73..c077d577f 100644 --- a/apps/cloud/src/app/features/home/home.component.ts +++ b/apps/cloud/src/app/features/home/home.component.ts @@ -1,6 +1,7 @@ import { DragDropModule } from '@angular/cdk/drag-drop' import { CommonModule } from '@angular/common' import { ChangeDetectionStrategy, Component, inject } from '@angular/core' +import { toSignal } from '@angular/core/rxjs-interop' import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { MatButtonModule } from '@angular/material/button' import { MatDialogModule } from '@angular/material/dialog' @@ -14,12 +15,11 @@ import { MatTabsModule } from '@angular/material/tabs' import { RouterModule } from '@angular/router' import { NgmCommonModule } from '@metad/ocap-angular/common' import { AppearanceDirective, ButtonGroupDirective, DensityDirective } from '@metad/ocap-angular/core' -import { UntilDestroy } from '@ngneat/until-destroy' import { TranslateModule } from '@ngx-translate/core' +import { AnalyticsFeatures, FeatureEnum, Store, routeAnimations } from '../../@core' import { AppService } from '../../app.service' -import { routeAnimations } from '../../@core' -@UntilDestroy({ checkProperties: true }) + @Component({ standalone: true, imports: [ @@ -47,51 +47,66 @@ import { routeAnimations } from '../../@core' ], selector: 'pac-home', template: ` - - - - + + + + `, styles: [ ` @@ -109,6 +124,13 @@ import { routeAnimations } from '../../@core' }) export class HomeComponent { private readonly appService = inject(AppService) + private readonly store = inject(Store) + public readonly copilotEnabled = toSignal(this.appService.copilotEnabled$) + + FeatureEnum = FeatureEnum + AnalyticsFeatures = AnalyticsFeatures - public readonly copilotEnabled$ = this.appService.copilotEnabled$ + hasFeatureEnabled(featureKey: FeatureEnum | AnalyticsFeatures) { + return this.store.hasFeatureEnabled(featureKey) + } } diff --git a/apps/cloud/src/app/features/home/insight/_insight-theme.scss b/apps/cloud/src/app/features/home/insight/_insight-theme.scss deleted file mode 100644 index 448ba88ee..000000000 --- a/apps/cloud/src/app/features/home/insight/_insight-theme.scss +++ /dev/null @@ -1,42 +0,0 @@ -@use 'sass:map'; -@use 'sass:color'; -@use '@angular/material' as mat; - -@mixin color($theme) { - $config: mat.get-color-config($theme); - - $primary: map.get($config, 'primary'); - $accent: map.get($config, accent); - $background: map.get($config, background); - $foreground: map.get($config, foreground); - - .mat-autocomplete-panel.pac-insight__autocomplete { - @apply mb-4; - } - - .pac-indight__answer-panel .mat-expansion-panel-body { - padding: 0; - } -} - -@mixin typography($theme) { -} - -@mixin density($theme) { -} - -@mixin theme($theme) { - $color: mat.get-color-config($theme); - $density: mat.get-density-config($theme); - $typography: mat.get-typography-config($theme); - - @if $color != null { - @include color($color); - } - @if $density != null { - @include density($density); - } - @if $typography != null { - @include typography($typography); - } -} diff --git a/apps/cloud/src/app/features/home/insight/_insight.component.scss b/apps/cloud/src/app/features/home/insight/_insight.component.scss new file mode 100644 index 000000000..4fa22d755 --- /dev/null +++ b/apps/cloud/src/app/features/home/insight/_insight.component.scss @@ -0,0 +1,7 @@ +.mat-autocomplete-panel.pac-insight__autocomplete { + @apply mb-4; +} + +.pac-indight__answer-panel .mat-expansion-panel-body { + padding: 0; +} \ No newline at end of file diff --git a/apps/cloud/src/app/features/home/insight/insight.component.html b/apps/cloud/src/app/features/home/insight/insight.component.html index 0851e4857..65346af5f 100644 --- a/apps/cloud/src/app/features/home/insight/insight.component.html +++ b/apps/cloud/src/app/features/home/insight/insight.component.html @@ -1,6 +1,6 @@
- @@ -14,6 +14,12 @@ (click)="$event.stopPropagation();$event.preventDefault();setPrompt(answer.title)"> edit + + question_answer @@ -42,9 +48,8 @@
- + {{ 'PAC.MENU.CALCULATED_MEMBERS' | translate: {Default: "Calculated Members"} }} diff --git a/apps/cloud/src/app/features/semantic-model/model/entity/cube-structure/cube-structure.component.scss b/apps/cloud/src/app/features/semantic-model/model/entity/cube-structure/cube-structure.component.scss index ae406193d..5518a0d59 100644 --- a/apps/cloud/src/app/features/semantic-model/model/entity/cube-structure/cube-structure.component.scss +++ b/apps/cloud/src/app/features/semantic-model/model/entity/cube-structure/cube-structure.component.scss @@ -1,3 +1,7 @@ +:host { + @apply bg-white rounded-lg overflow-hidden shadow-lg border border-solid border-slate-200 m-1; +} + .pac-cdk-drop__placeholder { @apply bg-gray-200 border-dashed border-2 border-gray-400 min-h-[60px] transition-transform; } \ No newline at end of file diff --git a/apps/cloud/src/app/features/semantic-model/model/entity/entity.component.html b/apps/cloud/src/app/features/semantic-model/model/entity/entity.component.html index 6ef7ac5af..db7a6ea73 100644 --- a/apps/cloud/src/app/features/semantic-model/model/entity/entity.component.html +++ b/apps/cloud/src/app/features/semantic-model/model/entity/entity.component.html @@ -1,4 +1,4 @@ - +
@@ -42,7 +42,7 @@ {{ 'PAC.MENU.Attributes' | translate: {Default: "Attributes"} }}
-
+ - diff --git a/apps/cloud/src/app/features/semantic-model/model/entity/entity.component.scss b/apps/cloud/src/app/features/semantic-model/model/entity/entity.component.scss index 8a346d3c7..ea6e3a5b3 100644 --- a/apps/cloud/src/app/features/semantic-model/model/entity/entity.component.scss +++ b/apps/cloud/src/app/features/semantic-model/model/entity/entity.component.scss @@ -1,9 +1,7 @@ :host { - flex: 1; - height: 100%; - display: flex; - flex-direction: column; - position: relative; + @apply relative h-full flex-1 flex flex-col bg-white; + + --mat-sidenav-content-background-color: theme(colors.white); &.pac-fullscreen { position: fixed; @@ -14,13 +12,11 @@ } .pac-model-entity__workspace { - display: flex; - flex-direction: column; + @apply flex flex-col; } + .pac-model-entity__workspace-router { - display: flex; - flex-direction: column; - overflow: hidden; + @apply flex flex-col bg-white rounded-lg overflow-hidden shadow-lg border border-solid border-slate-200 m-1; } .ngm-property-modeling { @@ -33,6 +29,10 @@ margin: 5px 0; } -// .pac-model__settings-container { -// width: 300px; -// } \ No newline at end of file +.mat-drawer.mat-drawer-side { + @apply border-0; +} + +.pac-model__settings-container { + @apply bg-white rounded-lg overflow-hidden shadow-lg border border-solid border-slate-200 m-1; +} \ No newline at end of file diff --git a/apps/cloud/src/app/features/semantic-model/model/entity/structure/structure.component.html b/apps/cloud/src/app/features/semantic-model/model/entity/structure/structure.component.html index 49ea79b1c..8de561f43 100644 --- a/apps/cloud/src/app/features/semantic-model/model/entity/structure/structure.component.html +++ b/apps/cloud/src/app/features/semantic-model/model/entity/structure/structure.component.html @@ -1,8 +1,8 @@ -
+
@@ -111,7 +111,7 @@ -
item.visible) || this.measures.find((item) => item.visible)) && this.allVisible + return ( + !!(this.dimensions.find((item) => item.visible) || this.measures.find((item) => item.visible)) && this.allVisible + ) } get visibleEmpty() { return !(this.dimensions.find((item) => item.visible) || this.measures.find((item) => item.visible)) @@ -68,12 +78,13 @@ export class ModelEntityStructureComponent extends TranslationBaseComponent impl shareReplay(1) ) public readonly fectTableFieldOptions$ = this.fectTableFields$.pipe( - map((properties) => properties.map((property) => ({ - key: property.name, - value: property, - caption: property.caption, - - }))) + map((properties) => + properties.map((property) => ({ + key: property.name, + value: property, + caption: property.caption + })) + ) ) options$ = combineLatest([this.modelService.wordWrap$, this.coreService.onThemeChange()]).pipe( @@ -84,7 +95,7 @@ export class ModelEntityStructureComponent extends TranslationBaseComponent impl tap((options) => console.debug(`[pac-model-structure] editor options`, options)) ) - public readonly expression$ = this.entityService.cube$.pipe(map((cube) => cube?.expression)) + public readonly expression = toSignal(this.entityService.cube$.pipe(map((cube) => cube?.expression))) private _tableJoins = {} private _tableTypes = {} @@ -119,7 +130,7 @@ export class ModelEntityStructureComponent extends TranslationBaseComponent impl this.entityService.select((state) => state.measures) ), filter(([properties, dimensions, measures]) => isEmpty(this.dimensions) && isEmpty(this.measures)), - untilDestroyed(this) + takeUntilDestroyed(this._destroyRef) ) .subscribe(([properties, dimensions, measures]) => { this.dimensions = @@ -129,7 +140,9 @@ export class ModelEntityStructureComponent extends TranslationBaseComponent impl ) this.measures = measures ?? - properties.filter((item) => item.role === AggregationRole.measure || item.dataType?.toLowerCase() === 'numeric') + properties.filter( + (item) => item.role === AggregationRole.measure || item.dataType?.toLowerCase() === 'numeric' + ) this._cdr.detectChanges() }) } @@ -158,19 +171,24 @@ export class ModelEntityStructureComponent extends TranslationBaseComponent impl } async confirmOverwriteCube() { - if (!this.dimensions.filter((item) => item.visible).length && !this.measures.filter((item) => item.visible).length) { - this._toastrService.warning('PAC.MODEL.ENTITY.PleaseSelectFields', {Default: 'Please select fields!'}) + if ( + !this.dimensions.filter((item) => item.visible).length && + !this.measures.filter((item) => item.visible).length + ) { + this._toastrService.warning('PAC.MODEL.ENTITY.PleaseSelectFields', { Default: 'Please select fields!' }) return false } const cube = await firstValueFrom(this.entityService.cube$) if (cube.dimensions?.length || cube.measures?.length) { - return await firstValueFrom(this._toastrService.confirm({ - code: 'PAC.MODEL.ENTITY.ConfirmOverwriteCube', - params: { - Default: 'The cube configured. Confirm overwrite?' - } - })) + return await firstValueFrom( + this._toastrService.confirm({ + code: 'PAC.MODEL.ENTITY.ConfirmOverwriteCube', + params: { + Default: 'The cube configured. Confirm overwrite?' + } + }) + ) } return true @@ -189,7 +207,11 @@ export class ModelEntityStructureComponent extends TranslationBaseComponent impl const dimensions = this.dimensions .filter((item) => item.visible) // Xmla 数据源的直接同步,sql 数据源的 1 生成 olap 维度 2 生成 sql 维度 - .map((item) => modelType === MODEL_TYPE.XMLA ? {...item, __id__: uuid(),} : newDimensionFromColumn(item, modelType === MODEL_TYPE.OLAP)) + .map((item) => + modelType === MODEL_TYPE.XMLA + ? { ...item, __id__: uuid() } + : newDimensionFromColumn(item, modelType === MODEL_TYPE.OLAP) + ) const measures = this.measures .filter((item) => item.visible) @@ -219,8 +241,7 @@ export class ModelEntityStructureComponent extends TranslationBaseComponent impl } async createDimension() { - const levels = this.dimensions - .filter((item) => item.visible) + const levels = this.dimensions.filter((item) => item.visible) this.entityService.addDimension({ __id__: uuid(), name: '', @@ -233,7 +254,7 @@ export class ModelEntityStructureComponent extends TranslationBaseComponent impl __id__: uuid(), name: property.name, caption: property.caption, - column: property.name, + column: property.name })) } ] @@ -302,7 +323,7 @@ export class ModelEntityStructureComponent extends TranslationBaseComponent impl if (!this._tableJoins[table.__id__]) { this._tableJoins[table.__id__] = this.tables$.pipe( map((tables) => tables.find(({ __id__ }) => __id__ === table.__id__)?.join), - untilDestroyed(this), + takeUntilDestroyed(this._destroyRef), shareReplay(1) ) } @@ -312,24 +333,20 @@ export class ModelEntityStructureComponent extends TranslationBaseComponent impl selectTableType(table: Table) { if (!this._tableTypes[table?.name]) { this._tableTypes[table?.name] = this.modelService.selectOriginalEntityType(table?.name).pipe( - map((entityType) => values(entityType?.properties).map((property) => ({ - value: property, - key: property.name, - caption: property.caption - }))), - untilDestroyed(this), + map((entityType) => + values(entityType?.properties).map((property) => ({ + value: property, + key: property.name, + caption: property.caption + })) + ), + takeUntilDestroyed(this._destroyRef), shareReplay(1) ) } return this._tableTypes[table?.name] } - setModel(event) { - // 不再从编辑器修改模型 - // this.entityService.setCube(event.cube) - // this.entityService.setEntityType(event.entityType) - } - changeExpression(value) { this.entityService.setExpression(value) } diff --git a/apps/cloud/src/app/features/semantic-model/model/preferences/preferences.component.html b/apps/cloud/src/app/features/semantic-model/model/preferences/preferences.component.html index 44c3699cb..e4351a5a2 100644 --- a/apps/cloud/src/app/features/semantic-model/model/preferences/preferences.component.html +++ b/apps/cloud/src/app/features/semantic-model/model/preferences/preferences.component.html @@ -9,7 +9,7 @@

(modelChange)="onFormChange(model)"> -
+ diff --git a/apps/cloud/src/app/features/semantic-model/model/preferences/preferences.component.ts b/apps/cloud/src/app/features/semantic-model/model/preferences/preferences.component.ts index 57c80511f..9250c5384 100644 --- a/apps/cloud/src/app/features/semantic-model/model/preferences/preferences.component.ts +++ b/apps/cloud/src/app/features/semantic-model/model/preferences/preferences.component.ts @@ -7,7 +7,7 @@ import { FORMLY_ROW, FORMLY_W_1_2 } from '@metad/story/designer' import { cloneDeep, merge } from 'lodash-es' import { firstValueFrom, map } from 'rxjs' import { LANGUAGES, Visibility } from '../../../../@core/types' -import { TranslationBaseComponent } from 'apps/cloud/src/app/@shared/language/translation-base.component' +import { TranslationBaseComponent } from '../../../../@shared' @Component({ selector: 'pac-model-preferences', @@ -152,7 +152,8 @@ export class ModelPreferencesComponent extends TranslationBaseComponent implemen key: 'exposeXmla', type: 'toggle', props: { - label: TRANSLATE?.EnableExposeXMLA ?? 'Expose XMLA Service' + label: TRANSLATE?.EnableExposeXMLA ?? 'Expose XMLA Service', + placeholder: TRANSLATE?.EnableExposeXMLA ?? 'Expose XMLA Service', } } ] diff --git a/apps/cloud/src/app/features/setting/account/account.component.html b/apps/cloud/src/app/features/setting/account/account.component.html index 9b6839d93..7e913d9fe 100644 --- a/apps/cloud/src/app/features/setting/account/account.component.html +++ b/apps/cloud/src/app/features/setting/account/account.component.html @@ -8,7 +8,8 @@
{{user()?.email}}
-

-
+
+ + + -
@@ -104,10 +109,13 @@ - + + +
+
- +
diff --git a/libs/component-angular/property/property-select/property-select.component.scss b/libs/component-angular/property/property-select/property-select.component.scss index 12c62a9e6..f8680d249 100644 --- a/libs/component-angular/property/property-select/property-select.component.scss +++ b/libs/component-angular/property/property-select/property-select.component.scss @@ -1,6 +1,5 @@ :host { - display: flex; - flex: 1; + @apply flex-1 flex flex-col; } .ngm-property-select__create-calculation { diff --git a/libs/component-angular/property/property-select/property-select.component.ts b/libs/component-angular/property/property-select/property-select.component.ts index e465ffdd9..6964f123f 100644 --- a/libs/component-angular/property/property-select/property-select.component.ts +++ b/libs/component-angular/property/property-select/property-select.component.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, ChangeDetectionStrategy, Component, computed, EventEmitter, forwardRef, HostBinding, inject, Input, OnInit, Output, ViewChild, ViewContainerRef } from '@angular/core' +import { AfterViewInit, ChangeDetectionStrategy, Component, computed, EventEmitter, forwardRef, HostBinding, inject, Input, OnInit, Output, signal, ViewChild, ViewContainerRef } from '@angular/core' import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms' import { MatDialog } from '@angular/material/dialog' import { @@ -9,7 +9,6 @@ import { DataSettings, Dimension, DisplayBehaviour, - EntitySet, EntityType, FilterSelectionType, getEntityProperty, @@ -233,7 +232,7 @@ export class PropertySelectComponent implements ControlValueAccessor, OnInit, Af zeroSuppression: new FormControl(true), formatting: new FormControl(), parameter: new FormControl(), - order: new FormControl(null) + order: new FormControl(null), }) // 初始值 private readonly _formValue = this.formGroup.value @@ -406,7 +405,7 @@ export class PropertySelectComponent implements ControlValueAccessor, OnInit, Af }) ) - public readonly selectTrigger$ = combineLatest([ + private readonly selectTrigger$ = combineLatest([ this.property$.pipe(startWith(null)), this.hierarchy$.pipe(startWith(null)), this.level$.pipe(startWith(null)), @@ -440,6 +439,8 @@ export class PropertySelectComponent implements ControlValueAccessor, OnInit, Af }) ) + public readonly selectTrigger = toSignal(this.selectTrigger$) + get caption() { return this.formGroup.get('caption').value } @@ -582,6 +583,8 @@ export class PropertySelectComponent implements ControlValueAccessor, OnInit, Af return this.capacities?.includes(PropertyCapacity.Order) } + showMore = signal(false) + private onChange: any private onTouched: any @@ -639,8 +642,12 @@ export class PropertySelectComponent implements ControlValueAccessor, OnInit, Af }) }) - // 订阅 formGroup 发回给双向绑定 - this.formGroup.valueChanges.pipe(untilDestroyed(this)).subscribe((value) => { + // subscribe formGroup to export value + this.formGroup.valueChanges.pipe( + // Update value when property is initialized + filter(() => !!this.property$.value), + untilDestroyed(this) + ).subscribe((value) => { if (this.property$.value?.role === AggregationRole.measure) { value = { ...value, diff --git a/libs/component-angular/selection/base-slicers.ts b/libs/component-angular/selection/base-slicers.ts index 4d7cd942a..ed10a7384 100644 --- a/libs/component-angular/selection/base-slicers.ts +++ b/libs/component-angular/selection/base-slicers.ts @@ -206,7 +206,7 @@ export class BaseSlicersComponent { const dialogRef = this._dialog.open(NgmValueHelpComponent, { viewContainerRef: this.viewContainerRef, data: { - dimension: pick(slicer, 'dimension', 'hierarchy'), + dimension: pick(slicer?.dimension, 'dimension', 'hierarchy', 'displayBehaviour'), slicer: slicer, dataSettings: this.dataSettings, options: { diff --git a/libs/core-angular/src/lib/smart-chart/types.ts b/libs/core-angular/src/lib/smart-chart/types.ts index fc6537d49..aad1d1f77 100644 --- a/libs/core-angular/src/lib/smart-chart/types.ts +++ b/libs/core-angular/src/lib/smart-chart/types.ts @@ -67,6 +67,7 @@ export enum NxChartType { ColumnStacked100 = 'ColumnStacked100', ColumnStackedDual100 = 'ColumnStackedDual100', ColumnGrouped = 'ColumnGrouped', + ColumnPolar = 'ColumnPolar', Bar = 'Bar', BarStacked = 'BarStacked', BarDual = 'BarDual', diff --git a/libs/formly/.eslintrc.json b/libs/formly/.eslintrc.json index 5d6bb91a6..98edd07f0 100644 --- a/libs/formly/.eslintrc.json +++ b/libs/formly/.eslintrc.json @@ -17,7 +17,7 @@ "error", { "type": "element", - "prefix": "pac-formly", + "prefix": "pac-formly|ngm-formly", "style": "kebab-case" } ] diff --git a/libs/formly/_formly-theme.scss b/libs/formly/_formly-theme.scss index ccc6c3414..7e7aca22d 100644 --- a/libs/formly/_formly-theme.scss +++ b/libs/formly/_formly-theme.scss @@ -125,7 +125,7 @@ } .ngm-formly__row { - @apply grid grid-cols-12 gap-4; + @apply grid grid-cols-12 gap-x-4; } .ngm-formly__col-12 { @apply col-span-12 max-w-full; diff --git a/libs/formly/_formly.scss b/libs/formly/_formly.scss new file mode 100644 index 000000000..9d60e1711 --- /dev/null +++ b/libs/formly/_formly.scss @@ -0,0 +1,6 @@ +.ngm-formly__gap-2 { + @apply gap-2; +} +.ngm-formly__my-2 { + @apply my-2; +} \ No newline at end of file diff --git a/libs/formly/accordion/accordion-wrapper.component.html b/libs/formly/accordion/accordion-wrapper.component.html new file mode 100644 index 000000000..6933e220c --- /dev/null +++ b/libs/formly/accordion/accordion-wrapper.component.html @@ -0,0 +1,25 @@ + + + + + {{item.props.label}} + + + + + + + + + + + + diff --git a/libs/formly/accordion/accordion-wrapper.component.scss b/libs/formly/accordion/accordion-wrapper.component.scss new file mode 100644 index 000000000..d6dc7fb47 --- /dev/null +++ b/libs/formly/accordion/accordion-wrapper.component.scss @@ -0,0 +1,14 @@ +.mat-expansion-panel-header-description { + justify-content: flex-end; + flex: 0; +} + +:host::ng-deep { + & + > .mat-accordion + > .mat-expansion-panel + > .mat-expansion-panel-header + > .mat-content { + overflow: visible; + } +} diff --git a/libs/formly/accordion/accordion-wrapper.component.stories.ts b/libs/formly/accordion/accordion-wrapper.component.stories.ts new file mode 100644 index 000000000..478394e5c --- /dev/null +++ b/libs/formly/accordion/accordion-wrapper.component.stories.ts @@ -0,0 +1,346 @@ +import { FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { FormlyModule } from '@ngx-formly/core'; +import { FormlyMaterialModule } from '@ngx-formly/material'; +import { Meta, moduleMetadata, Story } from '@storybook/angular'; +import { MetadFormlyEmptyModule } from '../empty'; +import { MetadFormlyPanelModule } from '../panel'; +import { MetadFormlyAccordionComponent } from './accordion-wrapper.component'; +import { MetadFormlyAccordionModule } from './accordion-wrapper.module'; + +export default { + title: 'Material/Accordion', + component: MetadFormlyAccordionComponent, + decorators: [ + moduleMetadata({ + imports: [ + BrowserAnimationsModule, + ReactiveFormsModule, + MatButtonModule, + FormlyModule.forRoot(), + FormlyMaterialModule, + MetadFormlyAccordionModule, + MetadFormlyPanelModule, + MetadFormlyEmptyModule, + ], + }), + ], +} as Meta; + +const Template: Story = (args: MetadFormlyAccordionComponent) => ({ + props: args, + template: ` + +
Result:
+
{{form.value | json}}
`, +}); + +function fieldGroup() { + return [ + { + className: 'metad-formly__col col-6', + key: 'show', + type: 'checkbox', + templateOptions: { + label: 'Is Show', + }, + }, + { + className: 'metad-formly__col col-6', + key: 'type', + type: 'select', + templateOptions: { + label: 'Type', + options: [ + { value: 'value', label: 'Value' }, + { value: 'category', label: 'Category' }, + ], + }, + }, + ]; +} + +const AccordionFieldGroup = [ + { + key: 'value', + hideExpression: `!field.parent.model.showValue`, + templateOptions: { + label: 'Expansion Value', + keyShow: 'showValue', + toggleable: true, + }, + fieldGroup: fieldGroup(), + }, + { + key: 'value2', + hideExpression: `!field.parent.model.showValue2`, + templateOptions: { + label: 'Expansion Value2', + keyShow: 'showValue2', + toggleable: true, + }, + fieldGroup: fieldGroup(), + }, + { + key: 'value3', + hideExpression: `!field.parent.model.showValue3`, + templateOptions: { + label: 'Expansion Value3', + keyShow: 'showValue3', + toggleable: true, + disabled: true, + }, + fieldGroup: fieldGroup(), + }, + { + key: 'value4', + hideExpression: `!field.parent.model.showValue4`, + fieldGroup: fieldGroup(), + }, + { + key: 'value5', + fieldGroup: fieldGroup(), + }, +]; + +const ShowValues = [ + { + key: 'showValue', + type: 'empty', + }, + { + key: 'showValue2', + type: 'empty', + }, + { + key: 'showValue3', + type: 'empty', + }, +]; + +const ShowValueTrues = [ + { + key: 'showValue', + type: 'empty', + defaultValue: true, + }, + { + key: 'showValue2', + type: 'empty', + defaultValue: true, + }, + { + key: 'showValue3', + type: 'empty', + defaultValue: true, + }, +]; + +export const Primary = Template.bind({}); +Primary.args = { + form: new FormGroup({}), + model: {}, + schema: [ + ...ShowValues, + { + wrappers: ['accordion'], + templateOptions: { + label: 'Expansion Type', + }, + fieldGroup: AccordionFieldGroup, + }, + ], +}; + +export const DisplayMode = Template.bind({}); +DisplayMode.args = { + form: new FormGroup({}), + model: {}, + schema: [ + ...ShowValues, + { + wrappers: ['accordion'], + templateOptions: { + displayMode: 'default', + }, + fieldGroup: AccordionFieldGroup, + }, + ], +}; + +export const HideToggle = Template.bind({}); +HideToggle.args = { + form: new FormGroup({}), + model: {}, + schema: [ + ...ShowValues, + { + wrappers: ['accordion'], + templateOptions: { + hideToggle: true, + }, + fieldGroup: AccordionFieldGroup, + }, + ], +}; + +export const ExpandedMulti = Template.bind({}); +ExpandedMulti.args = { + form: new FormGroup({}), + model: {}, + schema: [ + ...ShowValueTrues, + { + wrappers: ['accordion'], + templateOptions: { + expandedMulti: true, + }, + fieldGroup: AccordionFieldGroup, + }, + ], +}; + +export const TogglePosition = Template.bind({}); +TogglePosition.args = { + form: new FormGroup({}), + model: {}, + schema: [ + ...ShowValueTrues, + { + wrappers: ['accordion'], + templateOptions: { + togglePosition: 'after', + }, + fieldGroup: AccordionFieldGroup, + }, + ], +}; + +export const ElevationZ = Template.bind({}); +ElevationZ.args = { + form: new FormGroup({}), + model: {}, + schema: [ + ...ShowValues, + { + wrappers: ['accordion'], + templateOptions: { + elevationZ: true, + }, + fieldGroup: AccordionFieldGroup, + }, + ], +}; + +export const SubAccordion = Template.bind({}); +SubAccordion.args = { + form: new FormGroup({}), + model: {}, + schema: [ + { + key: 'showValue', + type: 'empty', + }, + { + wrappers: ['accordion'], + fieldGroup: [ + { + key: 'value', + templateOptions: { + label: 'Sub Accordion Value', + }, + fieldGroup: [ + ...ShowValues, + { + wrappers: ['accordion'], + templateOptions: { + elevationZ: true, + }, + fieldGroup: AccordionFieldGroup, + }, + ], + }, + ], + }, + ], +}; + +export const SubAccordionWithHide = Template.bind({}); +SubAccordionWithHide.args = { + form: new FormGroup({}), + model: {}, + schema: [ + { + key: 'showValue', + type: 'empty', + }, + { + wrappers: ['accordion'], + fieldGroup: [ + { + key: 'value', + hideExpression: `!field.parent.model.showValue`, + templateOptions: { + label: 'Sub Accordion Value', + keyShow: 'showValue', + }, + fieldGroup: [ + ...ShowValues, + { + wrappers: ['accordion'], + templateOptions: { + elevationZ: true, + }, + fieldGroup: AccordionFieldGroup, + }, + ], + }, + ], + }, + ], +}; + + +export const SubAccordionWithFlatFields = Template.bind({}); +SubAccordionWithFlatFields.args = { + form: new FormGroup({}), + model: {}, + schema: [ + { + key: 'showValue', + type: 'empty', + defaultValue: true + }, + { + wrappers: ['accordion'], + fieldGroup: [ + { + key: 'value', + hideExpression: `!field.parent.model.showValue`, + templateOptions: { + label: 'Sub Accordion Value', + keyShow: 'showValue', + }, + fieldGroup: [ + { + key: 'flatField', + type: 'input', + templateOptions: { + label: 'Flat Field' + } + }, + ...ShowValues, + { + wrappers: ['accordion'], + templateOptions: { + elevationZ: true, + }, + fieldGroup: AccordionFieldGroup, + }, + ], + }, + ], + }, + ], +}; diff --git a/libs/formly/accordion/accordion-wrapper.component.ts b/libs/formly/accordion/accordion-wrapper.component.ts new file mode 100644 index 000000000..9ee1309e8 --- /dev/null +++ b/libs/formly/accordion/accordion-wrapper.component.ts @@ -0,0 +1,32 @@ +import { Component } from '@angular/core'; +import { MatExpansionPanel } from '@angular/material/expansion'; +import { MatSlideToggleChange } from '@angular/material/slide-toggle'; +import { FieldWrapper, FormlyFieldConfig } from '@ngx-formly/core'; + +@Component({ + selector: 'ngm-formly-accordion', + templateUrl: './accordion-wrapper.component.html', + styleUrls: ['./accordion-wrapper.component.scss'], + host: { + class: 'ngm-formly-accordion', + }, +}) +export class NgmFormlyAccordionComponent< + F extends FormlyFieldConfig = FormlyFieldConfig +> extends FieldWrapper { + onToggle( + event: MatSlideToggleChange, + field: FormlyFieldConfig, + expansionPanel: MatExpansionPanel + ) { + this.formControl.patchValue({ + [field.props.keyShow]: event.checked, + }); + + if (this.formControl.value[field.props.keyShow]) { + expansionPanel?.open(); + } else { + expansionPanel?.close(); + } + } +} diff --git a/libs/formly/accordion/accordion-wrapper.module.ts b/libs/formly/accordion/accordion-wrapper.module.ts new file mode 100644 index 000000000..dd1560ad2 --- /dev/null +++ b/libs/formly/accordion/accordion-wrapper.module.ts @@ -0,0 +1,40 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatExpansionModule } from '@angular/material/expansion'; +import { MatIconModule } from '@angular/material/icon'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { FormlyModule } from '@ngx-formly/core'; +import { NgmFormlyAccordionComponent } from './accordion-wrapper.component'; + +@NgModule({ + declarations: [NgmFormlyAccordionComponent], + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + MatIconModule, + MatButtonModule, + MatDividerModule, + MatSlideToggleModule, + MatExpansionModule, + FormlyModule.forChild({ + types: [ + { + name: 'accordion', + component: NgmFormlyAccordionComponent, + }, + ], + wrappers: [ + { + name: 'accordion', + component: NgmFormlyAccordionComponent, + }, + ], + }), + ], + exports: [NgmFormlyAccordionComponent], +}) +export class NgmFormlyAccordionModule {} diff --git a/libs/formly/tab-group/index.ts b/libs/formly/accordion/index.ts similarity index 100% rename from libs/formly/tab-group/index.ts rename to libs/formly/accordion/index.ts diff --git a/libs/formly/tab-group/ng-package.json b/libs/formly/accordion/ng-package.json similarity index 53% rename from libs/formly/tab-group/ng-package.json rename to libs/formly/accordion/ng-package.json index 4141100c0..3b2206adc 100644 --- a/libs/formly/tab-group/ng-package.json +++ b/libs/formly/accordion/ng-package.json @@ -1,7 +1,7 @@ { "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", - "dest": "../../../dist/libs/formly/tab-group", + "dest": "../../../dist/libs/material/accordion", "lib": { - "entryFile": "./index.ts" + "entryFile": "index.ts" } } diff --git a/libs/formly/accordion/public-api.ts b/libs/formly/accordion/public-api.ts new file mode 100644 index 000000000..82ea72621 --- /dev/null +++ b/libs/formly/accordion/public-api.ts @@ -0,0 +1,2 @@ +export * from './accordion-wrapper.component'; +export * from './accordion-wrapper.module'; diff --git a/libs/formly/array/array.module.ts b/libs/formly/array/array.module.ts index 549a6d1f0..bea4bcc94 100644 --- a/libs/formly/array/array.module.ts +++ b/libs/formly/array/array.module.ts @@ -4,13 +4,13 @@ import { NgModule } from '@angular/core' import { ReactiveFormsModule } from '@angular/forms' import { MatButtonModule } from '@angular/material/button' import { MatIconModule } from '@angular/material/icon' -import { AppearanceDirective } from '@metad/ocap-angular/core' +import { AppearanceDirective, DensityDirective } from '@metad/ocap-angular/core' import { FormlyModule } from '@ngx-formly/core' import { TranslateModule } from '@ngx-translate/core' -import { NxFormlyArrayComponent } from './array.type' +import { NgmFormlyArrayComponent } from './array.type' @NgModule({ - declarations: [NxFormlyArrayComponent], + declarations: [NgmFormlyArrayComponent], imports: [ CommonModule, ReactiveFormsModule, @@ -19,16 +19,17 @@ import { NxFormlyArrayComponent } from './array.type' MatButtonModule, TranslateModule, AppearanceDirective, + DensityDirective, FormlyModule.forChild({ types: [ { name: 'array', - component: NxFormlyArrayComponent, + component: NgmFormlyArrayComponent, }, ], }), ], - exports: [NxFormlyArrayComponent], + exports: [NgmFormlyArrayComponent], }) -export class PACFormlyArrayModule {} +export class NgmFormlyArrayModule {} diff --git a/libs/formly/array/array.type.scss b/libs/formly/array/array.type.scss new file mode 100644 index 000000000..792e7dc68 --- /dev/null +++ b/libs/formly/array/array.type.scss @@ -0,0 +1,14 @@ +:host { + flex: 1; +} +.ngm-formly-cdk__drag-placeholder { + min-height: 60px; +} + +.ngm-formly__array-row { + @apply pb-2 border-b border-solid border-slate-200; +} + +.ngm-formly-cdk__drag-list { + @apply mb-2; +} \ No newline at end of file diff --git a/libs/formly/array/array.type.ts b/libs/formly/array/array.type.ts index d76d27390..db20e9514 100644 --- a/libs/formly/array/array.type.ts +++ b/libs/formly/array/array.type.ts @@ -4,10 +4,11 @@ import { FormArray } from '@angular/forms'; import { FieldArrayType } from '@ngx-formly/core' @Component({ - selector: 'pac-formly-array', + selector: 'ngm-formly-array', template: ` -
{{ to.label }}
-
{{ to.label }}
+
@@ -20,17 +21,21 @@ import { FieldArrayType } from '@ngx-formly/core'
+
+
{{model[i]?.[props.labelField]}}
+ +
- - -
- `, host: { - class: 'pac-formly-array' + class: 'ngm-formly-array' }, - styles: [ -` -:host { - flex: 1; -} -.ngm-formly-cdk__drag-placeholder { - min-height: 60px; -} -`, - ] + styleUrls: ['array.type.scss'], }) -export class NxFormlyArrayComponent extends FieldArrayType { +export class NgmFormlyArrayComponent extends FieldArrayType { drop(event: CdkDragDrop) { if (!Array.isArray(this.field.fieldGroup) || !Array.isArray(this.field.model)) { diff --git a/libs/formly/chart-type/chart-type.component.html b/libs/formly/chart-type/chart-type.component.html index d919f63ea..7103d5698 100644 --- a/libs/formly/chart-type/chart-type.component.html +++ b/libs/formly/chart-type/chart-type.component.html @@ -1,206 +1,176 @@ -
-
- -
- - - - -
- {{ 'FORMLY.CHART.' + typeLabel | translate: {Default: typeLabel} }} - :{{name.value}} -
- - - - - - - - - - - - -
- - -- {{'FORMLY.CHART.None' | translate: {Default: 'None'} }} -- - - - - {{ 'FORMLY.CHART.' + chart.label | translate: {Default: chart.label} }} - - -
- -
+
+
+
+ +
+ + + + +
+ {{ 'FORMLY.CHART.' + typeLabel | translate: {Default: typeLabel} }} + :{{name.value}} +
+ + + + - - - - - - - - - - - +
+
- -
-

- {{ 'FORMLY.CHART.Map' | translate: {Default: 'Map'} }} -

-
+
+
+ edit_attributes + {{ 'FORMLY.CHART.ChartType' | translate: {Default: 'Chart Type'} }} +
- + + +
+ + + + {{'FORMLY.CHART.'+orient.label | translate: {Default: orient.label} }} + + +
-
- - {{ 'FORMLY.CHART.MapName' | translate: {Default: 'Map Name'} }} - - +
+ + + + {{ 'FORMLY.CHART.'+option.label | translate: {Default: option.label} }} + + +
+
- - {{ 'FORMLY.CHART.MapUrl' | translate: {Default: 'Map Url'} }} - - + +
+ map + {{ 'FORMLY.CHART.GeoMapConfig' | translate: {Default: 'GeoMap Config'} }} +
+ + + + {{ 'FORMLY.CHART.IsTopoJSON' | translate: {Default: 'Is TopoJSON'} }} - - - {{ 'FORMLY.CHART.FeatureObjectNames' | translate: {Default: 'Feature Object Names'} }} - - - - - {{ 'FORMLY.CHART.MapProjection' | translate: {Default: 'Map Projection'} }} - - {{ 'FORMLY.CHART.None' | translate: {Default: 'None'} }} - {{ proj }} - - - - - - -
- - -
-
+
+ - +
+
+ analytics + {{ 'FORMLY.CHART.ChartOptions' | translate: {Default: 'Chart Options'} }} +
-
-
- - -
- - +
-
- - -
+ +
+ +
+
+ + +
+ + +
+
+ + +
+
+
+ -
+
-
+
🤖
-
- - -
- -
-
diff --git a/libs/formly/chart-type/chart-type.component.scss b/libs/formly/chart-type/chart-type.component.scss index 895988e9a..a24dc474a 100644 --- a/libs/formly/chart-type/chart-type.component.scss +++ b/libs/formly/chart-type/chart-type.component.scss @@ -1,11 +1,4 @@ :host { + --mat-expansion-header-text-size: 12px; @apply flex-1 flex flex-col border border-transparent; - - &.pac-formly-chart-type__custom-code { - @apply border-dashed border-slate-300 rounded-sm; - } -} - -.mat-mdc-input-element { - @apply text-slate-900 bg-gray-50 p-1 outline-none text-sm; } diff --git a/libs/formly/chart-type/chart-type.component.ts b/libs/formly/chart-type/chart-type.component.ts index 9c1a6c3a7..695dac43c 100644 --- a/libs/formly/chart-type/chart-type.component.ts +++ b/libs/formly/chart-type/chart-type.component.ts @@ -1,36 +1,53 @@ -import { ChangeDetectionStrategy, Component, HostBinding, inject, OnInit, TemplateRef, ViewChild } from '@angular/core' +import { ChangeDetectionStrategy, Component, effect, HostBinding, inject, OnInit, signal, TemplateRef, ViewChild } from '@angular/core' import { FormArray, FormControl, FormGroup } from '@angular/forms' import { MatDialog } from '@angular/material/dialog' import { CopilotChatMessageRoleEnum } from '@metad/copilot' import { MetadFormlyArrayComponent } from '@metad/formly-mat/array' -import { cloneDeep, isNil, isString } from '@metad/ocap-core' -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy' +import { isEqual, isNil, isString, omit } from '@metad/ocap-core' import { FieldType } from '@ngx-formly/core' import { NgmCopilotService, NxChartType } from '@metad/core' import { NgxPopperjsPlacements, NgxPopperjsTriggers } from 'ngx-popperjs' -import { BehaviorSubject, firstValueFrom } from 'rxjs' -import { CHART_TYPES, GeoProjections } from './types' +import { BehaviorSubject, distinctUntilChanged, map } from 'rxjs' import { TranslateService } from '@ngx-translate/core' -import { NxSettingsPanelService } from '@metad/story/designer' +import { STORY_DESIGNER_SCHEMA } from '@metad/story/designer' +import { ChartOptionsSchemaService } from '@metad/story/widgets/analytical-card' +import { toSignal } from '@angular/core/rxjs-interop' +import { CHART_TYPES, GeoProjections } from './types' + -@UntilDestroy({ checkProperties: true }) @Component({ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'pac-formly-chart-type', templateUrl: './chart-type.component.html', - styleUrls: ['chart-type.component.scss'] + styleUrls: ['chart-type.component.scss'], + providers: [ + { + provide: STORY_DESIGNER_SCHEMA, + useClass: ChartOptionsSchemaService + }, + ] }) export class PACFormlyChartTypeComponent extends FieldType implements OnInit { @HostBinding('class.pac-formly-chart-type') readonly _hostClass = true NgxPopperjsTriggers = NgxPopperjsTriggers NgxPopperjsPlacements = NgxPopperjsPlacements NxChartType = NxChartType - GeoProjections = GeoProjections + GeoProjections = [ + { + key: null, + caption: '--' + }, + ...GeoProjections.map((geoProjection) => ({ + key: geoProjection, + caption: geoProjection + })) + ] - private readonly _dialog = inject(MatDialog) private readonly formlyArray? = inject(MetadFormlyArrayComponent,{ optional: true }) - private readonly translateService = inject(TranslateService) - private readonly settingsService = inject(NxSettingsPanelService) + private readonly schema = inject(STORY_DESIGNER_SCHEMA) + private copilotService = inject(NgmCopilotService) + + @ViewChild('mapTemp') mapTemplate: TemplateRef ORIENTS = [ { value: 'horizontal', label: 'Horizontal', icon: 'align_horizontal_left' }, @@ -48,7 +65,8 @@ export class PACFormlyChartTypeComponent extends FieldType implements OnInit { VARIANTS = { Bar: [ { value: null, label: 'None' }, - { value: 'polar', label: 'Polar' } + { value: 'polar', label: 'Polar' }, + { value: 'stacked', label: 'Stacked' }, ], Waterfall: [ { @@ -78,14 +96,6 @@ export class PACFormlyChartTypeComponent extends FieldType implements OnInit { ] } - private copilotService = inject(NgmCopilotService) - - @ViewChild('mapTemp') mapTemplate: TemplateRef - - get chartType() { - return this.chartTypeForm.value - } - chartTypeForm = new FormGroup({ name: new FormControl(null), type: new FormControl(null), @@ -101,10 +111,10 @@ export class PACFormlyChartTypeComponent extends FieldType implements OnInit { return this.chartTypeForm.get('type') as FormControl } get type() { - return this.chartType?.type + return this.chartType()?.type } get typeLabel() { - return this.getChartType(this.chartType?.type)?.label + return this.getChartType(this.chartType()?.type)?.label } chartTypeGroups = CHART_TYPES @@ -128,6 +138,15 @@ export class PACFormlyChartTypeComponent extends FieldType implements OnInit { this.chartTypeForm.patchValue({ scripts: value }) } + get chartOptions() { + return this.chartTypeForm.value?.chartOptions + } + set chartOptions(value) { + this.chartTypeForm.patchValue({ + chartOptions: value + }) + } + // Form for geomap type mapFormGroup = new FormGroup({ map: new FormControl(null), @@ -141,8 +160,10 @@ export class PACFormlyChartTypeComponent extends FieldType implements OnInit { return this.field.props?.['removable'] } - @HostBinding('class.pac-formly-chart-type__custom-code') - showCustomCode = false + showMore = signal(false) + showCustomCode = signal(false) + + chartType = toSignal(this.chartTypeForm.valueChanges.pipe(map((value) => omit(value, 'chartOptions')), distinctUntilChanged(isEqual))) prompt = '' answering = false @@ -155,6 +176,13 @@ data 数据类型为 {data: <实际数据对象(包含measure对应的属性 automaticLayout: true } + constructor() { + super() + effect(() => { + this.schema.chartType = this.chartType() + }, {allowSignalWrites: true}) + } + ngOnInit(): void { if (isNil(this.field.formControl.value) || isString(this.field.formControl.value)) { this.chartTypeForm.patchValue({ type: this.field.formControl.value }) @@ -167,13 +195,8 @@ data 数据类型为 {data: <实际数据对象(包含measure对应的属性 }) } - async openMap() { - this.mapFormGroup.patchValue({ - ...this.field.formControl.value, - }) - - const result = await firstValueFrom(this._dialog.open(this.mapTemplate, { panelClass: 'ngm-dialog-container' }).afterClosed()) - if (result) { + confirmMap(ok?: boolean) { + if (ok) { this.field.formControl.setValue({ ...this.mapFormGroup.value, ...this.chartTypeForm.value @@ -181,6 +204,7 @@ data 数据类型为 {data: <实际数据对象(包含measure对应的属性 } else { this.mapFormGroup.reset() } + this.mapFormGroup.markAsPristine() } getChartType(type: string) { @@ -197,27 +221,6 @@ data 数据类型为 {data: <实际数据对象(包含measure对应的属性 return chart } - async openChartOptions() { - const title = await firstValueFrom( - this.translateService.get('FORMLY.PROPERTY_SELECT.ChartOptions', { Default: 'Chart Options' }) - ) - - const result = this.settingsService.openSecondDesigner( - 'ChartOptions', - cloneDeep(this.field.formControl.value), - title, - true - ) - .pipe(untilDestroyed(this)) - .subscribe((result) => { - if (result) { - this.chartTypeForm.patchValue({ - chartOptions: cloneDeep(result.chartOptions) - }) - } - }) - } - killMyself() { if (this.field.form instanceof FormArray) { const index = this.field.parent.fieldGroup.indexOf(this.field) diff --git a/libs/formly/chart-type/chart-type.module.ts b/libs/formly/chart-type/chart-type.module.ts index 7dbeb6841..094192768 100644 --- a/libs/formly/chart-type/chart-type.module.ts +++ b/libs/formly/chart-type/chart-type.module.ts @@ -4,7 +4,6 @@ import { NgModule } from '@angular/core' import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { MatButtonModule } from '@angular/material/button' import { MatDialogModule } from '@angular/material/dialog' -import { MatFormFieldModule } from '@angular/material/form-field' import { MatIconModule } from '@angular/material/icon' import { MatInputModule } from '@angular/material/input' import { MatMenuModule } from '@angular/material/menu' @@ -19,6 +18,7 @@ import { NgxPopperjsModule } from 'ngx-popperjs' import { MonacoEditorModule } from 'ngx-monaco-editor' import { NgmCommonModule, ResizerModule } from '@metad/ocap-angular/common' import { MatTooltipModule } from '@angular/material/tooltip' +import { NgmDesignerFormComponent } from '@metad/story/designer' @NgModule({ declarations: [PACFormlyChartTypeComponent], @@ -43,6 +43,7 @@ import { MatTooltipModule } from '@angular/material/tooltip' NgmCommonModule, ResizerModule, NgxPopperjsModule, + NgmDesignerFormComponent, FormlyModule.forChild({ types: [ { diff --git a/libs/formly/checkbox/checkbox.module.ts b/libs/formly/checkbox/checkbox.module.ts index 55e9eecdc..d65d0f092 100644 --- a/libs/formly/checkbox/checkbox.module.ts +++ b/libs/formly/checkbox/checkbox.module.ts @@ -6,10 +6,10 @@ import { ReactiveFormsModule } from '@angular/forms'; import { FormlyMatFormFieldModule } from '@ngx-formly/material/form-field'; import { MatCheckboxModule } from '@angular/material/checkbox'; -import { FormlyFieldCheckboxComponent } from './checkbox.type'; +import { NgmFormlyCheckboxComponent } from './checkbox.type'; @NgModule({ - declarations: [FormlyFieldCheckboxComponent], + declarations: [NgmFormlyCheckboxComponent], imports: [ CommonModule, ReactiveFormsModule, @@ -21,7 +21,7 @@ import { FormlyFieldCheckboxComponent } from './checkbox.type'; types: [ { name: 'checkbox', - component: FormlyFieldCheckboxComponent, + component: NgmFormlyCheckboxComponent, // wrappers: ['form-field'], }, { @@ -32,4 +32,4 @@ import { FormlyFieldCheckboxComponent } from './checkbox.type'; }), ], }) -export class FormlyMatCheckboxModule {} +export class NgmFormlyMatCheckboxModule {} diff --git a/libs/formly/checkbox/checkbox.type.ts b/libs/formly/checkbox/checkbox.type.ts index 5bcf64c91..1329f84ca 100644 --- a/libs/formly/checkbox/checkbox.type.ts +++ b/libs/formly/checkbox/checkbox.type.ts @@ -12,7 +12,6 @@ import { FieldTypeConfig, FormlyFieldConfig } from '@ngx-formly/core'; import { FieldType, FormlyFieldProps } from '@ngx-formly/material/form-field'; import { MatCheckbox } from '@angular/material/checkbox'; import { FocusMonitor } from '@angular/cdk/a11y'; -import { FormlyFieldCheckbox } from '@ngx-formly/material/checkbox'; interface CheckboxProps extends FormlyFieldProps { indeterminate?: boolean; @@ -20,11 +19,11 @@ interface CheckboxProps extends FormlyFieldProps { } export interface FormlyCheckboxFieldConfig extends FormlyFieldConfig { - type: 'checkbox' | Type; + type: 'checkbox' | Type; } @Component({ - selector: 'pac-formly-field-mat-checkbox', + selector: 'ngm-formly-mat-checkbox', template: ` > implements AfterViewInit, AfterViewChecked, OnDestroy { diff --git a/libs/formly/mat-toggle/toggle.module.ts b/libs/formly/mat-toggle/toggle.module.ts index 55f11c9a4..1ada078ab 100644 --- a/libs/formly/mat-toggle/toggle.module.ts +++ b/libs/formly/mat-toggle/toggle.module.ts @@ -3,26 +3,23 @@ import { CommonModule } from '@angular/common'; import { FormlyModule } from '@ngx-formly/core'; import { ReactiveFormsModule } from '@angular/forms'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; -import { FormlyMatFormFieldModule } from '@ngx-formly/material/form-field'; - -import { FormlyFieldToggle } from './toggle.type'; +import { NgmFormlyToggleComponent } from './toggle.type'; @NgModule({ - declarations: [FormlyFieldToggle], + declarations: [NgmFormlyToggleComponent], imports: [ CommonModule, ReactiveFormsModule, MatSlideToggleModule, - FormlyMatFormFieldModule, FormlyModule.forChild({ types: [ { name: 'toggle', - component: FormlyFieldToggle, + component: NgmFormlyToggleComponent, // wrappers: ['form-field'], }, ], }), ], }) -export class FormlyMatToggleModule {} +export class NgmFormlyMatToggleModule {} diff --git a/libs/formly/mat-toggle/toggle.type.scss b/libs/formly/mat-toggle/toggle.type.scss index b95fb3294..02034f3e7 100644 --- a/libs/formly/mat-toggle/toggle.type.scss +++ b/libs/formly/mat-toggle/toggle.type.scss @@ -1,3 +1,3 @@ :host { - @apply flex items-center w-full min-h-[42px]; + @apply h-full flex items-center w-full min-h-[42px]; } \ No newline at end of file diff --git a/libs/formly/mat-toggle/toggle.type.ts b/libs/formly/mat-toggle/toggle.type.ts index 0347ba032..449f45c39 100644 --- a/libs/formly/mat-toggle/toggle.type.ts +++ b/libs/formly/mat-toggle/toggle.type.ts @@ -8,11 +8,11 @@ interface ToggleProps extends FormlyFieldProps { } export interface FormlyToggleFieldConfig extends FormlyFieldConfig { - type: 'toggle' | Type; + type: 'toggle' | Type; } @Component({ - selector: 'formly-field-mat-toggle', + selector: 'ngm-formly-mat-toggle', template: ` changeDetection: ChangeDetectionStrategy.OnPush, styleUrls: ['toggle.type.scss'] }) -export class FormlyFieldToggle extends FieldType> { +export class NgmFormlyToggleComponent extends FieldType> { @ViewChild(MatSlideToggle, { static: true }) slideToggle!: MatSlideToggle; override defaultOptions = { props: { diff --git a/libs/formly/panel/index.ts b/libs/formly/panel/index.ts new file mode 100644 index 000000000..3d5a01709 --- /dev/null +++ b/libs/formly/panel/index.ts @@ -0,0 +1 @@ +export * from './public-api' diff --git a/libs/formly/panel/ng-package.json b/libs/formly/panel/ng-package.json new file mode 100644 index 000000000..5382b27b5 --- /dev/null +++ b/libs/formly/panel/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../../dist/libs/material/panel", + "lib": { + "entryFile": "index.ts" + } +} diff --git a/libs/formly/panel/panel.module.ts b/libs/formly/panel/panel.module.ts new file mode 100644 index 000000000..31811df1d --- /dev/null +++ b/libs/formly/panel/panel.module.ts @@ -0,0 +1,22 @@ +import { CommonModule } from '@angular/common' +import { NgModule } from '@angular/core' +import { ReactiveFormsModule } from '@angular/forms' +import { MatButtonModule } from '@angular/material/button' +import { MatIconModule } from '@angular/material/icon' +import { FormlyModule } from '@ngx-formly/core' +import { MetadFormlyPanelComponent } from './panel.type' + +@NgModule({ + declarations: [MetadFormlyPanelComponent], + imports: [ + CommonModule, + ReactiveFormsModule, + MatIconModule, + MatButtonModule, + FormlyModule.forChild({ + wrappers: [{ name: 'panel', component: MetadFormlyPanelComponent }] + }) + ], + exports: [MetadFormlyPanelComponent] +}) +export class MetadFormlyPanelModule {} diff --git a/libs/formly/panel/panel.type.stories.ts b/libs/formly/panel/panel.type.stories.ts new file mode 100644 index 000000000..5d76b5383 --- /dev/null +++ b/libs/formly/panel/panel.type.stories.ts @@ -0,0 +1,74 @@ +import { FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { FormlyModule } from '@ngx-formly/core'; +import { FormlyMaterialModule } from '@ngx-formly/material'; +import { Meta, moduleMetadata, Story } from '@storybook/angular'; +import { MetadFormlyPanelModule } from './panel.module'; +import { MetadFormlyPanelComponent } from './panel.type'; + + +export default { + title: 'Material/Panel', + component: MetadFormlyPanelComponent, + decorators: [ + moduleMetadata({ + imports: [ + BrowserAnimationsModule, + ReactiveFormsModule, + MatButtonModule, + FormlyModule.forRoot(), + FormlyMaterialModule, + MetadFormlyPanelModule, + ], + }), + ], +} as Meta; + +const Template: Story = (args: MetadFormlyPanelComponent) => ({ + props: args, + template: ` + +
Result:
+
{{form.value | json}}
`, +}); + +function fieldGroup() { + return [ + { + key: 'show', + type: 'checkbox', + templateOptions: { + label: 'Is Show', + }, + }, + { + key: 'type', + type: 'select', + templateOptions: { + label: 'Type', + options: [ + { value: 'value', label: 'Value' }, + { value: 'category', label: 'Category' }, + ], + }, + }, + ] +} + +export const Primary = Template.bind({}); +Primary.args = { + form: new FormGroup({}), + model: {}, + schema: [ + { + key: 'value', + wrappers: ['panel'], + templateOptions: { + label: 'Panel Type', + padding: true + }, + fieldGroup: fieldGroup(), + }, + ], +}; diff --git a/libs/formly/panel/panel.type.ts b/libs/formly/panel/panel.type.ts new file mode 100644 index 000000000..2b38d6ab6 --- /dev/null +++ b/libs/formly/panel/panel.type.ts @@ -0,0 +1,34 @@ +import { Component, HostBinding } from '@angular/core'; +import { FieldWrapper } from '@ngx-formly/core'; + +@Component({ + selector: 'metad-formly-panel-wrapper', + template: ` +
{{ to?.label }}
+
+ +
+`, + styles: [ + `:host { +display: flex; +flex-direction: column; +flex: 1; +max-width: 100%; +margin-top: 1rem; +} +:host.metad-formly__panel-padding { + padding: 0 1.5rem; +}` + ], + host: { + class: 'metad-formly__panel-wrapper' + } +}) +export class MetadFormlyPanelComponent extends FieldWrapper { + @HostBinding('class.metad-formly__nested-area') nestedArea = true + @HostBinding('class.metad-formly__panel-padding') + get isPadding() { + return this.to?.padding + } +} diff --git a/libs/formly/panel/public-api.ts b/libs/formly/panel/public-api.ts new file mode 100644 index 000000000..3edefab80 --- /dev/null +++ b/libs/formly/panel/public-api.ts @@ -0,0 +1,2 @@ +export * from './panel.module' +export * from './panel.type' diff --git a/libs/formly/property-select/property-select.component.html b/libs/formly/property-select/property-select.component.html index 4c59e7688..2ce57ae74 100644 --- a/libs/formly/property-select/property-select.component.html +++ b/libs/formly/property-select/property-select.component.html @@ -32,7 +32,7 @@ adjust - +
- {{ 'PAC.KEY_WORDS.Measures' | translate: {Default: 'Measures'} }} + {{ 'Story.Common.Measures' | translate: {Default: 'Measures'} }}
- + - - {{item.caption}} - - + [cdkDragData]="item"> + + +
-
-
-
-
- - {{item.caption}} - -
+
+
+ {{item.caption}} +
@@ -74,8 +66,8 @@
-
Show Dimensions
-
Bring in more dimensions from your dataset and start exploring.
+
{{'Story.Explorer.ShowDimensions' | translate: {Default: 'Show Dimensions'} }}
+
{{'Story.Explorer.BringMoreDimensions' | translate: {Default: 'Bring in more dimensions from your dataset and start exploring'} }}.
@@ -86,76 +78,95 @@ >
-
-
-
+
+
-
{{ 'PAC.KEY_WORDS.Dimensions' | translate: {Default: 'Dimensions'} }}
-
- - - -
+ + +
{{ 'Story.Explorer.Dimensions' | translate: {Default: 'Dimensions'} }}
+
-
{{ 'PAC.KEY_WORDS.Measures' | translate: {Default: 'Measures'} }}
-
- - - -
+ + + +
+ +
{{ 'Story.Explorer.Measures' | translate: {Default: 'Measures'} }}
+
+ + + + +
+ + +
{{ 'Story.Explorer.ChartOptions' | translate: {Default: 'Chart Options'} }}
+ +
+
+ + + + +
- {{'FORMLY.CHART.' + group.label | translate: {Default: group.label} }} + {{'Story.Chart.' + group.label | translate: {Default: group.label} }}
-
+
@@ -181,57 +192,61 @@
- - Visual - Options + + {{ 'Story.Explorer.Visual' | translate: {Default: 'Visual'} }} + + + settings + - - Table - Chart + + {{ 'Story.Explorer.Table' | translate: {Default: 'Table'} }} + + + {{ 'Story.Explorer.Chart' | translate: {Default: 'Chart'} }} + -
- +
+ +
- -
diff --git a/libs/story-angular/src/lib/explorer/explorer.component.scss b/libs/story-angular/src/lib/explorer/explorer.component.scss index 8b39d2842..9cb395d66 100644 --- a/libs/story-angular/src/lib/explorer/explorer.component.scss +++ b/libs/story-angular/src/lib/explorer/explorer.component.scss @@ -2,9 +2,16 @@ @apply flex flex-col justify-start items-stretch bg-slate-100; } +.tag:not(.selected) { + @apply bg-slate-50; +} .tag.selected { + @apply bg-slate-200; +} +.tag.selected.slicered { @apply text-amber-500 bg-amber-100; } + .ngm-story-explorer__chart.selected { @apply ring-violet-500; } diff --git a/libs/story-angular/src/lib/explorer/explorer.component.ts b/libs/story-angular/src/lib/explorer/explorer.component.ts index bae93769c..c6ce0b040 100644 --- a/libs/story-angular/src/lib/explorer/explorer.component.ts +++ b/libs/story-angular/src/lib/explorer/explorer.component.ts @@ -1,23 +1,41 @@ import { CdkDrag, CdkDragDrop, DragDropModule, moveItemInArray } from '@angular/cdk/drag-drop' import { CommonModule } from '@angular/common' -import { Component, ElementRef, EventEmitter, Input, Output, TemplateRef, ViewChild, computed, effect, inject, signal } from '@angular/core' +import { + Component, + ElementRef, + EventEmitter, + HostBinding, + 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 { FormControl, 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 { MatTabsModule } from '@angular/material/tabs' +import { MatRadioModule } from '@angular/material/radio' +import { MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dialog' 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 { NxChartType, nonBlank } 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 { EntityCapacity, NgmEntityPropertyComponent, NgmEntitySchemaComponent } from '@metad/ocap-angular/entity' +import { NgmChartPropertyComponent, NgmChartSettingsComponent, NgmFormlyChartTypeComponent } from '@metad/story/widgets/analytical-card' +import { NgmGridSettingsComponent } from '@metad/story/widgets/analytical-grid' import { C_MEASURES, ChartAnnotation, @@ -27,21 +45,28 @@ import { DisplayBehaviour, FilterSelectionType, ISlicer, + Measure, assignDeepOmitBlank, cloneDeep, - compact, getEntityDimensions, + getEntityLevel, getEntityMeasures, + getEntityProperty, + isString, nonNullable, - pick + omit, + pick, + uniqBy } 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' +import { TranslateModule, TranslateService } from '@ngx-translate/core' +import { combineLatestWith, filter, map, startWith, switchMap } from 'rxjs/operators' import { MatIconModule } from '@angular/material/icon' -import { ResizerModule } from '@metad/ocap-angular/common' -import { MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dialog' +import { NgmSearchComponent, ResizerModule } from '@metad/ocap-angular/common' +import { CHARTS, getChartType } from './types' +import { firstValueFrom } from 'rxjs' +import { ExplainComponent } from '@metad/story/story' + @Component({ standalone: true, @@ -58,6 +83,8 @@ import { MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dial MatTooltipModule, MatIconModule, MatDialogModule, + MatTabsModule, + MatRadioModule, DragDropModule, NxTableModule, NgmPrismHighlightComponent, @@ -67,11 +94,17 @@ import { MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dial AnalyticalCardModule, AnalyticalGridModule, PropertyModule, - ResizerModule + ResizerModule, + NgmEntityPropertyComponent, + NgmSearchComponent, + NgmChartSettingsComponent, + NgmChartPropertyComponent, + NgmFormlyChartTypeComponent, + NgmGridSettingsComponent ], selector: 'ngm-story-explorer', templateUrl: 'explorer.component.html', - styleUrls: ['explorer.component.scss'] + styleUrls: ['explorer.component.scss'], }) export class StoryExplorerComponent { EntityCapacity = EntityCapacity @@ -80,8 +113,11 @@ export class StoryExplorerComponent { ComponentType = WidgetComponentType FilterSelectionType = FilterSelectionType + @HostBinding('class.ngm-story-explorer') isStoryExplorerComponent = true + private readonly dsCoreService = inject(NgmDSCoreService) private readonly _dialog = inject(MatDialog) + private readonly translateService = inject(TranslateService) @Input() get data() { @@ -91,6 +127,7 @@ export class StoryExplorerComponent { this._data.set(value) if (value) { const chartAnnotation = value?.dataSettings?.chartAnnotation + const analytics = value?.dataSettings?.analytics if (chartAnnotation) { this.component.set({ component: WidgetComponentType.AnalyticalCard, @@ -99,27 +136,74 @@ export class StoryExplorerComponent { }) this.rows.set(chartAnnotation.dimensions) this.columns.set(chartAnnotation.measures) - this._dimensions.set(chartAnnotation.dimensions?.map((d) => d.dimension) ?? []) + this._dimensions.set(chartAnnotation.dimensions?.map((d) => pick(d, 'dimension', 'hierarchy')) ?? []) + this._chartSettings.set({ + chartOptions: value.chartOptions, + chartSettings: value.chartSettings + }) + this.visualPanel = 'visual' + this.view = 'chart' + } else if (analytics) { + this.component.set({ + label: null, + component: WidgetComponentType.AnalyticalGrid, + dataSettings: value.dataSettings + }) + + this.rows.set(analytics.rows) + this.columns.set(analytics.columns) + this._dimensions.set( + [...analytics.rows, ...analytics.columns].filter((d) => d.dimension !== C_MEASURES).map((d) => pick(d, 'dimension', 'hierarchy')) + ) + this.gridSettings = { + options: value.options + } + this.visualPanel = 'options' + this.view = 'table' } - } + const dimensions = [...this._dimensions()] + if (value?.dataSettings?.selectionVariant?.selectOptions?.length) { + // Set slicers from selectionVariant + this.slicers.set( + (value.dataSettings.selectionVariant.selectOptions).reduce((acc, curr) => { + if (!curr.dimension) { + return acc + } + acc[curr.dimension.dimension] = curr + return acc + }, {}) + ) + // Udpate dimensions + dimensions.push(...value.dataSettings.selectionVariant.selectOptions + .filter((slicer) => !!slicer.dimension) + .map((slicer) => pick(slicer.dimension, 'dimension', 'hierarchy')) + .filter((d) => d.dimension)) + } + this._dimensions.set(uniqBy(dimensions, 'dimension')) + } } private readonly _data = signal<{ dataSettings: DataSettings; chartAnnotation: ChartAnnotation }>(null) - @Output() closed = new EventEmitter() + @Output() closed = new EventEmitter() @ViewChild('addDimensionsTempl') addDimensionsTempl: TemplateRef private dialogRef: MatDialogRef, any> - + + measureSearch = new FormControl('') + + readonly i18n = toSignal(this.translateService.stream('Story.Explorer')) readonly _dimensionsCache = signal([]) - private _dimensions = signal([]) + private _dimensions = signal([]) dimensions = signal<{ dimension: Dimension; caption: string; hierarchies: Dimension[] }[]>([]) readonly entityType = toSignal( toObservable(this._data).pipe( filter(nonNullable), - switchMap(({ dataSettings }) => + map(({ dataSettings }) => dataSettings), + filter((dataSettings) => !!(dataSettings?.dataSource && dataSettings?.entitySet)), + switchMap((dataSettings) => this.dsCoreService .selectEntitySet(dataSettings.dataSource, dataSettings.entitySet) .pipe(map(({ entityType }) => entityType)) @@ -129,40 +213,41 @@ export class StoryExplorerComponent { readonly dimensionList = computed(() => { return getEntityDimensions(this.entityType()) }) - readonly measureList = computed(() => { - return getEntityMeasures(this.entityType()).map((property) => ({ - dimension: C_MEASURES, - measure: property.name, - caption: property.caption - })) - }) + readonly measureList = toSignal( + toObservable(this.entityType).pipe( + map(getEntityMeasures), + combineLatestWith(this.measureSearch.valueChanges.pipe(startWith(''))), + map(([measures, search]) => { + return search + ? measures.filter( + (measure) => + measure.name.toLowerCase().includes(search.toLowerCase()) || + measure.caption.toLowerCase().includes(search.toLowerCase()) + ) + : measures + }) + ) + ) + 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 ?? {}) + ...cloneDeep( + omit( + this.component()?.dataSettings?.chartAnnotation ?? this.data?.chartAnnotation ?? {}, + 'dimensions', + 'measures' + ) + ) }, { dimensions: this.rows().map((row) => ({ - ...row, - chartOptions: { - dataZoom: { - type: 'inside' - } - } + ...row })), - measures: [ - ...this.columns(), - ...this.measures().map((measure) => ({ - dimension: C_MEASURES, - measure, - formatting: { - shortNumber: true - } - })) - ] + measures: [...this.columns()] }, 5 ) @@ -172,7 +257,12 @@ export class StoryExplorerComponent { return { ...(this.data?.dataSettings ?? {}), - chartAnnotation + chartAnnotation, + selectionVariant: { + selectOptions: Object.values(this.slicers()) + .map((slicer) => slicer) + .filter((slicer) => slicer?.members?.length) + } } }) readonly chartOptions = signal({ @@ -180,35 +270,47 @@ export class StoryExplorerComponent { show: true } }) + readonly chartTitle = computed(() => { + let title = '' + title += this.columns().map((column) => { + const property = getEntityProperty(this.entityType(), column) + return property?.caption + }).filter(nonBlank).join(` ${this.i18n()?.And ?? 'and'} `) + + const by = this.rows().map((row) => { + const property = getEntityLevel(this.entityType(), row) + return property?.caption + }).filter(nonBlank).join(` ${this.i18n()?.And ?? 'and'} `) + + if (by) { + title += ` ${this.i18n()?.By ?? 'by'} (${by})` + } + return title + }) + readonly dataSettingsGrid = computed(() => { const analytics = { ...(this.data?.analytics ?? {}), rows: this.rows(), - columns: [ - ...this.columns(), - ...this.measures().map((measure) => ({ - dimension: C_MEASURES, - measure, - formatting: { - shortNumber: true - } - })) - ] + columns: [...this.columns()] } - console.log('analytics:', analytics) + + console.log(`Explorer analytics:`, analytics) + return { ...(this.data?.dataSettings ?? {}), - analytics - } - }) - - readonly _slicers = computed(() => { - return Object.values(this.slicers()).map((slicer) => slicer) + analytics, + selectionVariant: { + selectOptions: Object.values(this.slicers()) + .map((slicer) => slicer) + .filter(nonNullable) + .filter((slicer) => slicer?.members?.length) + } + } as DataSettings }) readonly rows = signal([]) - readonly columns = signal([]) - readonly measures = signal([]) + readonly columns = signal<(Dimension | Measure)[]>([]) readonly slicers = signal<{ [name: string]: ISlicer }>({}) readonly component = signal({ label: NxChartType.Bar, @@ -222,31 +324,118 @@ export class StoryExplorerComponent { dimensions: [{}], measures: [{}] } - } + } as DataSettings + }) + readonly chartType = computed(() => { + return this.component()?.dataSettings?.chartAnnotation?.chartType }) + get chartTypeChartOptions() { + return this.component()?.dataSettings?.chartAnnotation?.chartType?.chartOptions + } + set chartTypeChartOptions(value) { + this.component.set({ + ...this.component(), + dataSettings: { + ...this.component().dataSettings, + chartAnnotation: { + ...this.component().dataSettings.chartAnnotation, + chartType: { + ...this.component().dataSettings.chartAnnotation.chartType, + chartOptions: value + } + } + } + }) + } + view: 'table' | 'chart' = 'table' visualPanel: 'visual' | 'options' = 'visual' charts = CHARTS.map((item) => cloneDeep(item) as any) + get chartSettings() { + return this._chartSettings() + } + set chartSettings(value) { + this._chartSettings.set(value) + } + private _chartSettings = signal<{ chartSettings?: any; chartOptions?: any }>({}) + + get gridSettings() { + return this._gridSettings() + } + set gridSettings(value) { + this._gridSettings.set(value) + } + private _gridSettings = signal<{ options?: any }>({options: { + showToolbar: true, + paging: true, + pageSize: 20, + sticky: true, + sortable: true + }}) + + readonly dimensionCapacities = computed(() => { + if (this.component().component === WidgetComponentType.AnalyticalCard) { + return [ + PropertyCapacity.Dimension, + PropertyCapacity.Order, + PropertyCapacity.DimensionChart + ] + } else { + return [ + PropertyCapacity.Dimension, + PropertyCapacity.Order, + ] + } + }) + readonly measureCapacities = computed(() => { + if (this.component().component === WidgetComponentType.AnalyticalCard) { + return [ + PropertyCapacity.Measure, + PropertyCapacity.Order, + PropertyCapacity.MeasureAttributes, + PropertyCapacity.MeasureStyle, + PropertyCapacity.MeasureStyleRole, + PropertyCapacity.MeasureStyleShape, + PropertyCapacity.MeasureStylePalette, + PropertyCapacity.MeasureStylePalettePattern, + PropertyCapacity.MeasureStyleReferenceLine, + PropertyCapacity.MeasureStyleChartOptions + ] + } else { + return [ + PropertyCapacity.Measure, + PropertyCapacity.Order, + PropertyCapacity.MeasureAttributes, + PropertyCapacity.MeasureStylePalette, + PropertyCapacity.MeasureStyleGridBar + ] + } + }) + + explains = signal([]) + constructor() { effect( () => { if (this.entityType()) { - this.dimensions.set( - getEntityDimensions(this.entityType()).filter(({name}) => this._dimensions().includes(name)) .map(({ name, caption, hierarchies }) => ({ + this.dimensions.set(this._dimensions().map((d) => { + const property = getEntityProperty(this.entityType(), d) + return { dimension: { - dimension: name, + dimension: d.dimension, + hierarchy: d.hierarchy, displayBehaviour: DisplayBehaviour.descriptionOnly }, - caption, - hierarchies: hierarchies.map((hierarchy) => ({ - dimension: name, + caption: property.caption, + hierarchies: property.hierarchies.map((hierarchy) => ({ + dimension: d.dimension, hierarchy: hierarchy.name, caption: hierarchy.caption })) - })) - ) + } + })) } }, { allowSignalWrites: true } @@ -260,27 +449,37 @@ export class StoryExplorerComponent { 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) - ]) + setHierarchy(dimension: string, hierarchy: string | null) { + const dimensions = [...this.dimensions()] + const index = dimensions.findIndex((d) => d.dimension.dimension === dimension) + dimensions[index] = { + ...dimensions[index], + dimension: { + ...dimensions[index].dimension, + hierarchy + } + } + // Update dimensions + this.dimensions.set(dimensions) + } + + toggleHierarchy(dimension: string, hierarchy: string | null) { + // Clear slicers for the dimension + this.slicers.set({ + ...this.slicers(), + [dimension]: {} + }) + + this.setHierarchy(dimension, hierarchy) } dropRowPredicate(item: CdkDrag) { - return item.dropContainer.id === 'ngm-story-explorer__drop-list-dimensions-container' + return item.dropContainer.id === 'ngm-story-explorer__drop-list-dimensions' } dropRow(event: CdkDragDrop) { @@ -288,7 +487,11 @@ export class StoryExplorerComponent { if (event.previousContainer === event.container) { moveItemInArray(items, event.previousIndex, event.currentIndex) } else { - items.splice(event.currentIndex, 0, { ...event.item.data.dimension }) + items.splice( + event.currentIndex, + 0, + isString(event.item.data.dimension) ? { ...event.item.data } : { ...event.item.data.dimension } + ) } this.rows.set(items) } @@ -303,12 +506,16 @@ export class StoryExplorerComponent { return item.dropContainer.id === 'ngm-story-explorer__drop-list-measures' } - dropColumn(event: CdkDragDrop) { + dropColumn(event: CdkDragDrop<(Dimension | Measure)[]>) { const items = [...this.columns()] if (event.previousContainer === event.container) { moveItemInArray(items, event.previousIndex, event.currentIndex) } else { - items.splice(event.currentIndex, 0, { ...event.item.data }) + items.splice(event.currentIndex, 0, { + dimension: C_MEASURES, + measure: event.item.data.name, + caption: event.item.data.caption + }) } this.columns.set(items) } @@ -327,11 +534,8 @@ export class StoryExplorerComponent { this.columns.set([...this.columns().slice(0, i), row, ...this.columns().slice(i + 1)]) } - onMeasuresChange(measures: string[]) { - this.measures.set(measures) - } - onSlicersChange(slicer: ISlicer, dimension: string) { + // Set slicer for the dimension this.slicers.set({ ...this.slicers(), [dimension]: slicer @@ -339,8 +543,10 @@ export class StoryExplorerComponent { } createWidget(widget: any) { - console.log(widget) this.component.set(widget) + if (this.component().component === WidgetComponentType.AnalyticalCard) { + this.view = 'chart' + } } addDimensionToCache(event) { @@ -348,12 +554,32 @@ export class StoryExplorerComponent { } openDimensions() { - this._dimensionsCache.set([...this._dimensions()]) + this._dimensionsCache.set(this._dimensions().map((d) => d.dimension)) this.dialogRef = this._dialog.open(this.addDimensionsTempl) } addDimensions() { - this._dimensions.set([...this._dimensionsCache()]) + // Add new dimensions + this._dimensionsCache().forEach((dimension) => { + const index = this._dimensions().findIndex((d) => d.dimension === dimension) + if (index === -1) { + this._dimensions.set([ + ...this._dimensions(), + { + dimension, + hierarchy: null + } + ]) + } + }) + // Remove dimensions + this._dimensions().forEach((dimension) => { + const index = this._dimensionsCache().findIndex((d) => d === dimension.dimension) + if (index === -1) { + this._dimensions.set(this._dimensions().filter((d) => d.dimension !== dimension.dimension)) + this.slicers.set(omit(this.slicers(), dimension.dimension)) + } + }) this.dialogRef.close() } @@ -362,6 +588,31 @@ export class StoryExplorerComponent { if (event.previousContainer === event.container) { moveItemInArray(items, event.previousIndex, event.currentIndex) this.dimensions.set(items) - } + } + } + + setExplains(explains) { + this.explains.set(explains) + } + + async openExplain() { + await firstValueFrom(this._dialog.open(ExplainComponent, { + data: [...(this.explains() ?? []), {slicers: this.slicers()}]} + ).afterClosed()) + } + + close() { + if (this.component().component === WidgetComponentType.AnalyticalCard) { + this.closed.emit({ + dataSettings: this.dataSettingsChart(), + chartSettings: this.chartSettings?.chartSettings, + chartOptions: this.chartSettings?.chartOptions, + }) + } else { + this.closed.emit({ + dataSettings:this.dataSettingsGrid(), + options: this.gridSettings?.options, + }) + } } } diff --git a/libs/story-angular/src/lib/explorer/types.ts b/libs/story-angular/src/lib/explorer/types.ts index f2ffedc2d..123870192 100644 --- a/libs/story-angular/src/lib/explorer/types.ts +++ b/libs/story-angular/src/lib/explorer/types.ts @@ -39,7 +39,8 @@ export const CHARTS: ChartGroup[] = [ value: { chartType: { type: NxChartType.Bar, - orient: ChartOrient.vertical + orient: ChartOrient.vertical, + variant: 'stacked' }, dimensions: [ {}, @@ -56,7 +57,8 @@ export const CHARTS: ChartGroup[] = [ value: { chartType: { type: NxChartType.Bar, - orient: ChartOrient.horizontal + orient: ChartOrient.horizontal, + variant: 'stacked' }, dimensions: [ {}, @@ -109,6 +111,25 @@ export const CHARTS: ChartGroup[] = [ }, icon: 'bar-polar-bg.svg' }, + { + label: NxChartType.ColumnPolar, + value: { + chartType: { + type: NxChartType.Bar, + orient: ChartOrient.vertical, + variant: 'polar', + chartOptions: { + seriesStyle: { + colorBy: 'data', + roundCap: true + } + } + }, + dimensions: [{}], + measures: [{}] + }, + icon: 'column-polar-stacked.jpg' + }, { label: NxChartType.Histogram, value: { @@ -511,6 +532,20 @@ export const CHARTS: ChartGroup[] = [ dimensions: [], measures: [{}, {}, {}] } + }, + { + label: NxChartType.Radar, + icon: 'radar.jpg', + value: { + chartType: { + type: NxChartType.Radar, + chartOptions: { + seriesStyle: {} + } + }, + dimensions: [{}], + measures: [{}] + } } ] }, @@ -606,12 +641,22 @@ export const CHARTS: ChartGroup[] = [ } ] +/** + * Find Chart Type by type/variant/orient + * @param chartType + * @returns + */ export function getChartType(chartType: ChartType) { for(const group of CHARTS) { for(const chart of group.charts) { - if(chart.value.chartType.type === chartType?.type) { + if(chart.value.chartType.type === chartType?.type && + (chartType?.variant ? chart.value.chartType.variant === chartType?.variant : true) && + (chartType?.orient ? chart.value.chartType.orient === chartType?.orient : true) + ) { return chart } } } -} \ No newline at end of file + + throw new Error(`Chart Type ${chartType?.type}/${chartType?.orient}/${chartType?.variant} not found`) +} diff --git a/libs/story-angular/src/lib/settings/preferences/schema.ts b/libs/story-angular/src/lib/settings/preferences/schema.ts index be731cff1..34a63ccbd 100644 --- a/libs/story-angular/src/lib/settings/preferences/schema.ts +++ b/libs/story-angular/src/lib/settings/preferences/schema.ts @@ -19,30 +19,26 @@ export function PreferencesSchema(Story: any) { return [ { - wrappers: ['expansion'], + wrappers: ['accordion'], props: { - label: Story?.Widgets?.Common?.StoryStyling ?? 'Story Styling', - expanded: false + elevationZ: true }, fieldGroup: [ { key: 'storyStyling', type: 'styling', - props: {} - } - ] - }, - { - wrappers: ['expansion'], - props: { - label: Story?.Preferences?.PageStyles ?? 'Page Styles', - expanded: false - }, - fieldGroup: [ + props: { + label: Story?.Widgets?.Common?.StoryStyling ?? 'Story Styling', + expanded: false + } + }, { key: 'pageStyling', type: 'styling', - props: {} + props: { + label: Story?.Preferences?.PageStyles ?? 'Page Styles', + expanded: false + } } ] }, diff --git a/libs/story-angular/src/lib/settings/schemas/flex-layout.schema.ts b/libs/story-angular/src/lib/settings/schemas/flex-layout.schema.ts index 2fe4530e1..bb375f41b 100644 --- a/libs/story-angular/src/lib/settings/schemas/flex-layout.schema.ts +++ b/libs/story-angular/src/lib/settings/schemas/flex-layout.schema.ts @@ -8,7 +8,7 @@ export class FlexLayoutSchemaService extends BaseDesignerSchemaService { return [ { - wrappers: ['expansion'], + wrappers: ['accordion'], props: { - label: DESIGNER?.Widgets?.Common?.ComponentStyling ?? 'Component Styling', - expanded: true + expandedMulti: true, + elevationZ: true, }, fieldGroup: [ { key: 'component', type: 'styling', props: { + label: DESIGNER?.Widgets?.Common?.ComponentStyling ?? 'Component Styling', + expanded: true, } + }, + + { + key: 'appearance', + props: { + label: DESIGNER?.Widgets?.Common?.Appearance ?? 'Appearance', + expanded: true, + }, + fieldGroupClassName: FORMLY_ROW, + fieldGroup: Appearances(FORMLY_W_1_2, DESIGNER?.Widgets?.Common) } ] - }, - Appearance(FORMLY_W_FULL, DESIGNER?.Widgets?.Common) - // StylingWidgetSchema(FORMLY_W_1_2, DESIGNER) + } ] }) ) diff --git a/libs/story-angular/story/public-api.ts b/libs/story-angular/story/public-api.ts index 541a7d917..4a8f35d0b 100644 --- a/libs/story-angular/story/public-api.ts +++ b/libs/story-angular/story/public-api.ts @@ -6,4 +6,5 @@ export * from './story/story.component' export * from './shares/shares.component' export * from './placeholder/add/add.component' export * from './story-point/story-point.component' -export * from './story-widget/story-widget.component' \ No newline at end of file +export * from './story-widget/story-widget.component' +export * from './explain/explain.component' \ 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 ad4eeebc3..3be360610 100644 --- a/libs/story-angular/story/story-widget/story-widget.component.html +++ b/libs/story-angular/story/story-widget/story-widget.component.html @@ -102,7 +102,7 @@ {{ 'Story.Widget.Refresh' | translate: {Default: "Refresh"} }} diff --git a/libs/story-angular/story/story-widget/story-widget.component.ts b/libs/story-angular/story/story-widget/story-widget.component.ts index eff3ad1d7..d819b5459 100644 --- a/libs/story-angular/story/story-widget/story-widget.component.ts +++ b/libs/story-angular/story/story-widget/story-widget.component.ts @@ -205,6 +205,10 @@ export class NxStoryWidgetComponent extends ComponentStore imp filter(Boolean), map((type) => this._widgetComponents.find((component) => component.type === type)) ) + readonly componentProvider = toSignal(this.component$.pipe( + filter(Boolean), + map((type) => this._widgetComponents.find((component) => component.type === type)) + )) readonly componentCategory$ = this.componentProvider$.pipe(map((componentProvider) => componentProvider?.category)) readonly componentClasses$ = this.componentCategory$.pipe( map((category) => ({ @@ -809,12 +813,15 @@ export class NxStoryWidgetComponent extends ComponentStore imp } async explore() { - const dataSettings = await firstValueFrom(this.dataSettings$) - const queryParams: Params = { explore: btoa(JSON.stringify({ - dataSettings: dataSettings, - chartAnnotation: dataSettings.chartAnnotation, - analytics: dataSettings.analytics, - })) } + // const dataSettings = await firstValueFrom(this.dataSettings$) + const fields = this.componentProvider().mapping.filter((field) => field !== 'styling') + + const queryParams: Params = { + widgetKey: this.key, + explore: btoa(unescape(encodeURIComponent(JSON.stringify({ + ...pick(this.widget(), ...fields) + })))) + } this.router.navigate([], { relativeTo: this.route, queryParams: queryParams, diff --git a/libs/story-angular/widgets/analytical-card/analytical-card.schema.ts b/libs/story-angular/widgets/analytical-card/analytical-card.schema.ts index 9a8a18d22..f89f67b72 100644 --- a/libs/story-angular/widgets/analytical-card/analytical-card.schema.ts +++ b/libs/story-angular/widgets/analytical-card/analytical-card.schema.ts @@ -1,29 +1,32 @@ -import { Injectable } from '@angular/core' +import { inject, Injectable } from '@angular/core' +import { PropertyCapacity as FormlyPropertyCapacity, PropertyCapacity } from '@metad/components/property' +import { ColorPalettes } from '@metad/core' import { ChartAnnotation, - ChartDimensionRoleType, ChartOptions, ChartSettings, ChartType, getEntityProperty, isIndicatorMeasureProperty, isMeasure, + omit, SelectionPresentationVariant } from '@metad/ocap-core' -import { PropertyCapacity } from '@metad/components/property' -import { PropertyCapacity as FormlyPropertyCapacity } from '@metad/components/property' import { AccordionWrappers, - BaseDesignerSchemaService, - BaseSchemaState, DataSettingsSchemaService, + DesignerSchema, + FORMLY_GAP_2, + FORMLY_MY_2, FORMLY_ROW, FORMLY_W_1_2, PresentationVariantExpansion, SchemaState, SelectionVariantExpansion } from '@metad/story/designer' +import { TranslateService } from '@ngx-translate/core' import { isEmpty, isEqual } from 'lodash-es' +import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs' import { distinctUntilChanged, map, withLatestFrom } from 'rxjs/operators' import { AllCapacity, @@ -37,8 +40,6 @@ import { TooltipCapacity, VisualMapCapacity } from './schemas' -import { ColorPalettes } from '@metad/core' - export interface AnalyticalCardSchemaState extends SchemaState { model: { @@ -89,34 +90,29 @@ export class AnalyticalCardSchemaService extends DataSettingsSchemaService { - this.STORY_DESIGNER = STORY_DESIGNER + withLatestFrom(this.translate.stream('Story')), + map(([type, i18nStory]) => { + this.STORY_DESIGNER = i18nStory const chartType = this.get((state) => state.model?.dataSettings?.chartAnnotation?.chartType) - return this.getBuilderSchema(chartType, STORY_DESIGNER) + return this.getBuilderSchema(chartType, i18nStory) }) ) } - getBuilderSchema(chartType: ChartType, STORY_DESIGNER?) { - - const BUILDER = STORY_DESIGNER?.BUILDER + getBuilderSchema(chartType: ChartType, i18nStory?) { + const BUILDER = i18nStory?.Widgets?.Common - const dataSettings = this.generateDataSettingsSchema(BUILDER) - dataSettings.wrappers = ['expansion'] - - dataSettings.fieldGroup.splice( - 2, - 0, + const dataSettings = this.generateDataSettingsSchema( + BUILDER, { key: 'chartAnnotation', props: { label: 'Chart Annotation', required: true, - type: 'expansion', icon: 'analytics' }, - fieldGroup: this.getChartAnnotationFieldGroup(chartType, BUILDER?.CHART) + fieldGroupClassName: FORMLY_GAP_2 + ' ' + FORMLY_MY_2, + fieldGroup: this.getChartAnnotationFieldGroup(i18nStory?.Widgets?.CHART) } as unknown, ...SelectionVariantExpansion(BUILDER, this.dataSettings$), ...PresentationVariantExpansion(BUILDER, this.dataSettings$, this.entityType$, this.properties$) @@ -133,72 +129,23 @@ export class AnalyticalCardSchemaService extends DataSettingsSchemaService { - // return ( - // field.parent.parent.model?.dataSettings?.chartAnnotation?.chartType?.type !== NxChartType.Custom - // ) - // } - // } - // } + } ] + }, + { + key: 'chartSettings', + label: i18nStory?.Widgets?.CHART?.ChartSettings ?? 'Chart Settings', + toggleable: false, + fieldGroup: chartSettingsFieldGroup(i18nStory?.Widgets) } ]), - getChartOptionsSchema(chartType, STORY_DESIGNER?.STYLING?.ECHARTS) + getChartOptionsSchema(chartType, i18nStory?.STYLING?.ECHARTS) ] } - getChartAnnotationFieldGroup(chartType, CHART?) { - const results = [ + getChartAnnotationFieldGroup(CHART?) { + return [ { key: 'chartType', type: 'chart-type' - } - ] as any - - results.push( + }, { key: 'measures', type: 'array', @@ -301,7 +222,7 @@ export class AnalyticalCardSchemaService extends DataSettingsSchemaService { - public readonly storyDesigner$ = this.translate.stream('STORY_DESIGNER') +export class MeasureChartOptionsSchemaService implements DesignerSchema { + protected translate = inject(TranslateService) + get model() { + return this.model$.value + } + set model(value) { + this.model$.next(value) + } + private readonly model$ = new BehaviorSubject(null) + + get chartType() { + return this.chartType$.value + } + set chartType(value) { + this.chartType$.next(value) + } + private readonly chartType$ = new BehaviorSubject(null) - public readonly chartType$ = this.model$.pipe(map((model) => model.chartType)) + public readonly storyDesigner$ = this.translate.stream('Story') + + getTitle(): Observable { + return of(`Chart measure options`) + } getSchema() { - return this.storyDesigner$.pipe( - map((STORY_DESIGNER) => STORY_DESIGNER?.STYLING?.ECHARTS), - map((ECHARTS) => { - const chartType = this.get((state) => state.model.chartType) - return [{ key: 'chartType', type: 'empty' }, this.getChartOptions(chartType, ECHARTS)] - }) + return combineLatest([this.storyDesigner$.pipe(map((i18n) => i18n?.STYLING?.ECHARTS)), this.chartType$]).pipe( + map(([ECHARTS, chartType]) => this.getChartOptions(chartType, ECHARTS).fieldGroup) ) } @@ -414,107 +341,203 @@ export class MeasureChartOptionsSchemaService extends BaseDesignerSchemaService< } @Injectable() -export class DimensionChartOptionsSchemaService extends BaseDesignerSchemaService { - public readonly storyDesigner$ = this.translate.stream('STORY_DESIGNER') +export class DimensionChartOptionsSchemaService implements DesignerSchema { + protected translate = inject(TranslateService) + get model() { + return this.model$.value + } + set model(value) { + this.model$.next(value) + } + private readonly model$ = new BehaviorSubject(null) + + getTitle(): Observable { + return of(`Chart dimension options`) + } public readonly role$ = this.model$.pipe(map((model) => model.role)) + public readonly storyDesigner$ = this.translate.stream('Story') getSchema() { return this.storyDesigner$.pipe( map((STORY_DESIGNER) => STORY_DESIGNER?.STYLING?.ECHARTS), - map((ECHARTS) => { - const role = this.get((state) => state.model.role) - return [{ key: 'role', type: 'empty' }, this.getChartOptions(role, ECHARTS)] + map((I18N) => { + const className = FORMLY_W_1_2 + const role = this.model?.role + return [ + ...AccordionWrappers([ + { + key: 'axis', + label: I18N?.CATEGORY_AXIS?.TITLE ?? 'Axis', + fieldGroup: CategoryAxis(className, I18N) + }, + { + key: 'dataZoom', + label: I18N?.DATAZOOM_STYLE?.DATAZOOM ?? 'Data Zoom', + fieldGroup: [ + { + fieldGroupClassName: FORMLY_ROW, + fieldGroup: DataZoomAttributes(className, I18N) + } + ] + } + ]) + ] }) ) } +} - getChartOptions(role: ChartDimensionRoleType, I18N) { - const className = FORMLY_W_1_2 - const chartOptions: any = { - key: 'chartOptions', - props: {}, - fieldGroup: [] - } - chartOptions.fieldGroup = [ - ...AccordionWrappers([ - { - key: 'axis', - label: I18N?.CATEGORY_AXIS?.TITLE ?? 'Axis', - fieldGroup: CategoryAxis(className, I18N) - }, - { - key: 'dataZoom', - label: I18N?.DATAZOOM_STYLE?.DATAZOOM ?? 'Data Zoom', - fieldGroup: [ - { - fieldGroupClassName: FORMLY_ROW, - fieldGroup: DataZoomAttributes(className, I18N) - } - ] - } - ]), - ] +@Injectable() +export class ChartOptionsSchemaService implements DesignerSchema { + protected translate = inject(TranslateService) - return chartOptions + get model() { + return this.model$.value } -} + set model(value) { + this.model$.next(value) + } + private readonly model$ = new BehaviorSubject(null) -@Injectable() -export class ChartOptionsSchemaService extends BaseDesignerSchemaService { + get chartType() { + return this.chartType$.value + } + set chartType(value) { + this.chartType$.next(value) + } + private readonly chartType$ = new BehaviorSubject(null) - public readonly storyDesigner$ = this.translate.stream('STORY_DESIGNER') + public readonly storyDesigner$ = this.translate.stream('Story') - getSchema() { - return this.storyDesigner$.pipe( - map((STORY_DESIGNER) => STORY_DESIGNER?.STYLING?.ECHARTS), - map((ECHARTS) => { - const chartType = this.get((state) => state.model) + getTitle(): Observable { + return of(`Chart options`) + } - return [ - getChartOptionsSchema(chartType, ECHARTS) - ] as any - }) + getSchema() { + return combineLatest([this.storyDesigner$.pipe(map((i18n) => i18n?.STYLING?.ECHARTS)), + this.chartType$.pipe(map((chartType) => omit(chartType, 'chartOptions')), distinctUntilChanged(isEqual)) + ]).pipe( + map(([ECHARTS, chartType]) => getChartOptionsSchema(chartType, ECHARTS).fieldGroup) ) } } export function getChartOptionsSchema(chartType: ChartType, I18N) { - const className = FORMLY_W_1_2 - const chartOptions: any = { - key: 'chartOptions', - fieldGroup: [...GlobalCapacity(className, I18N)] - } + const className = FORMLY_W_1_2 + const chartOptions: any = { + key: 'chartOptions', + fieldGroup: [...GlobalCapacity(className, I18N)] + } - if (!chartType) { - return chartOptions - } + if (!chartType) { + return chartOptions + } - let capacityMatrix - const capacityName = chartType.type + (chartType.variant ?? '') - if (CapacityMatrix[capacityName]) { - capacityMatrix = CapacityMatrix[capacityName] - } else if (CapacityMatrix[chartType.type]) { - capacityMatrix = CapacityMatrix[chartType.type] + let capacityMatrix + const capacityName = chartType.type + (chartType.variant ?? '') + if (CapacityMatrix[capacityName]) { + capacityMatrix = CapacityMatrix[capacityName] + } else if (CapacityMatrix[chartType.type]) { + capacityMatrix = CapacityMatrix[chartType.type] + } + + capacityMatrix?.forEach((capacity) => { + const fieldGroup = capacity(FORMLY_W_1_2, I18N) + if (Array.isArray(fieldGroup)) { + chartOptions.fieldGroup.push(...fieldGroup) + } else { + chartOptions.fieldGroup.push(fieldGroup) } + }) + + AllCapacity.forEach((capacity) => { + const fieldGroup = capacity(FORMLY_W_1_2, I18N) + if (Array.isArray(fieldGroup)) { + chartOptions.fieldGroup.push(...fieldGroup) + } else { + chartOptions.fieldGroup.push(fieldGroup) + } + }) - capacityMatrix?.forEach((capacity) => { - const fieldGroup = capacity(FORMLY_W_1_2, I18N) - if (Array.isArray(fieldGroup)) { - chartOptions.fieldGroup.push(...fieldGroup) - } else { - chartOptions.fieldGroup.push(fieldGroup) - } - }) + return chartOptions +} - AllCapacity.forEach((capacity) => { - const fieldGroup = capacity(FORMLY_W_1_2, I18N) - if (Array.isArray(fieldGroup)) { - chartOptions.fieldGroup.push(...fieldGroup) - } else { - chartOptions.fieldGroup.push(fieldGroup) +export function chartSettingsFieldGroup(i18n) { + return [ + { + fieldGroupClassName: FORMLY_ROW, + fieldGroup: [ + { + className: FORMLY_W_1_2, + key: 'maximumLimit', + type: 'input', + props: { + label: i18n?.CHART?.MaximumLimit ?? 'Maximum Limit', + type: 'number' + } + }, + { + className: FORMLY_W_1_2, + key: 'digitInfo', + type: 'input', + props: { + label: i18n?.CHART?.DigitInfo ?? 'Digit Info' + } + }, + { + className: FORMLY_W_1_2, + key: 'trellisHorizontal', + type: 'slider', + props: { + label: i18n?.CHART?.TrellisHorizontal ?? 'Trellis Horizontal', + type: 'number', + thumbLabel: true, + autoScale: true, + min: 1, + max: 10 + } + }, + { + className: FORMLY_W_1_2, + key: 'universalTransition', + type: 'checkbox', + props: { + label: i18n?.CHART?.UniversalTransition ?? 'Universal Transition' + } + } + ] + }, + { + key: 'chartTypes', + type: 'array', + props: { + label: i18n?.CHART?.ChartVariants ?? 'Chart Variants', + hideDelete: true, + sortable: true + }, + fieldArray: { + type: 'chart-type', + props: { + removable: true + } } - }) + } - return chartOptions -} \ No newline at end of file + // { + // key: 'customLogic', + // type: 'code-editor', + // props: { + // label: i18nStory?.Widgets?.CHART?.CustomLogic ?? 'Custom Logic', + // language: 'javascript' + // }, + // expressions: { + // hide: (field: FormlyFieldConfig) => { + // return ( + // field.parent.parent.model?.dataSettings?.chartAnnotation?.chartType?.type !== NxChartType.Custom + // ) + // } + // } + // } + ] +} diff --git a/libs/story-angular/widgets/analytical-card/chart-property/_chart-property.component.scss b/libs/story-angular/widgets/analytical-card/chart-property/_chart-property.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/libs/story-angular/widgets/analytical-card/chart-property/chart-measure.component.ts b/libs/story-angular/widgets/analytical-card/chart-property/chart-measure.component.ts new file mode 100644 index 000000000..2db9e6d01 --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/chart-property/chart-measure.component.ts @@ -0,0 +1,79 @@ +import { CommonModule } from '@angular/common' +import { Component, Input, forwardRef, inject } from '@angular/core' +import { takeUntilDestroyed } from '@angular/core/rxjs-interop' +import { ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms' +import { MatButtonModule } from '@angular/material/button' +import { MatIconModule } from '@angular/material/icon' +import { ChartType } from '@metad/ocap-core' +import { NgmDesignerFormComponent, NxDesignerModule, STORY_DESIGNER_SCHEMA } from '@metad/story/designer' +import { TranslateModule } from '@ngx-translate/core' +import { MeasureChartOptionsSchemaService } from '../analytical-card.schema' + +@Component({ + standalone: true, + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + MatButtonModule, + MatIconModule, + TranslateModule, + + NxDesignerModule, + NgmDesignerFormComponent + ], + selector: 'ngm-chart-measure-form', + template: ``, + styles: [ + ` + :host { + padding: 0; + } + ` + ], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: forwardRef(() => NgmChartMeasureComponent) + }, + { + provide: STORY_DESIGNER_SCHEMA, + useClass: MeasureChartOptionsSchemaService + } + ] +}) +export class NgmChartMeasureComponent implements ControlValueAccessor { + private readonly schema = inject(STORY_DESIGNER_SCHEMA) + + @Input() get chartType(): ChartType { + return this.schema.chartType + } + set chartType(value: ChartType) { + this.schema.chartType = value + } + + formControl = new FormControl({}) + + private valueSub = this.formControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => { + this.onChange?.(value) + }) + + onChange: (input: any) => void + onTouched: () => void + + writeValue(obj: any): void { + if (obj) { + this.formControl.patchValue(obj) + } + } + registerOnChange(fn: any): void { + this.onChange = fn + } + registerOnTouched(fn: any): void { + this.onTouched = fn + } + setDisabledState?(isDisabled: boolean): void { + isDisabled ? this.formControl.disable() : this.formControl.enable() + } +} diff --git a/libs/story-angular/widgets/analytical-card/chart-property/chart-property.component.html b/libs/story-angular/widgets/analytical-card/chart-property/chart-property.component.html new file mode 100644 index 000000000..46a4a55c9 --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/chart-property/chart-property.component.html @@ -0,0 +1,168 @@ + +
+ +
+ +
+ +
+ + + + {{ 'FORMLY.PROPERTY_SELECT.' + role.label | translate: {Default: role.label} }} + + +
+ +
+ + +
+
+ +
+ + + + {{ 'FORMLY.PROPERTY_SELECT.' + role.label | translate: {Default: role.label} }} + + +
+ +
+ + + + {{ 'FORMLY.PROPERTY_SELECT.None' | translate: {Default: 'None'} }} + + + {{ 'FORMLY.PROPERTY_SELECT.' + shape.label | translate: {Default: shape.label} }} + + +
+ +
+ + + + {{ 'FORMLY.PROPERTY_SELECT.None' | translate: {Default: 'None'} }} + + + {{item.label}} + + +
+ +
+ + + + +
+ + +
+
+ + +
+ +
+ sort + {{ 'FORMLY.PROPERTY_SELECT.BarChart' | translate: {Default: 'Bar Chart'} }} +
+
+
+ + +
+ + + +
+ +
+ + + +
+
+
+ + + + + + + + + + + + + + + + diff --git a/libs/story-angular/widgets/analytical-card/chart-property/chart-property.component.scss b/libs/story-angular/widgets/analytical-card/chart-property/chart-property.component.scss new file mode 100644 index 000000000..641100cae --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/chart-property/chart-property.component.scss @@ -0,0 +1,34 @@ +:host { + --mat-expansion-header-text-size: 12px; + @apply flex-1 flex; + + .ngm-property-select { + flex: 1; + } +} + +.ngm-formly__remove { + visibility: hidden; +} + +.ngm-property-select:hover { + .ngm-formly__remove { + visibility: visible; + } +} + +.ngm-chart-property__card { + @apply p-2 flex flex-col bg-white rounded-lg; +} +.ngm-chart-property__card-title { + @apply text-sm font-semibold; +} + +::ng-deep { + .ngm-chart-property__palette-trigger.mat-mdc-menu-trigger { + @apply my-2; + .mdc-button__label { + @apply w-full; + } + } +} \ No newline at end of file diff --git a/libs/story-angular/widgets/analytical-card/chart-property/chart-property.component.ts b/libs/story-angular/widgets/analytical-card/chart-property/chart-property.component.ts new file mode 100644 index 000000000..dbd8dce7e --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/chart-property/chart-property.component.ts @@ -0,0 +1,364 @@ +import { coerceBooleanProperty } from '@angular/cdk/coercion' +import { CommonModule } from '@angular/common' +import { Component, Input, computed, forwardRef, inject, signal } from '@angular/core' +import { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop' +import { ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms' +import { MatButtonModule } from '@angular/material/button' +import { MatCheckboxModule } from '@angular/material/checkbox' +import { MatIconModule } from '@angular/material/icon' +import { MatMenuModule } from '@angular/material/menu' +import { MatRadioModule } from '@angular/material/radio' +import { NgmColorsComponent } from '@metad/components/form-field' +import { + NgmChromaticInterpolateGroup, + NxChromaticPreviewComponent, + getScaleChromaticInterpolates +} from '@metad/components/palette' +import { PropertyCapacity, PropertyModule } from '@metad/components/property' +import { ColorPalettes, NxCoreService } from '@metad/core' +import { DensityDirective, NgmDSCoreService } from '@metad/ocap-angular/core' +import { + AggregationRole, + CalculationProperty, + ChartDimensionRoleType, + ChartMeasureRoleType, + ChartPattern, + ChartType, + DataSettings, + EntityType, + getEntityProperty, + isEqual, + pick +} from '@metad/ocap-core' +import { NgmDesignerFormComponent, NxDesignerModule, NxSettingsPanelService, STORY_DESIGNER_SCHEMA } from '@metad/story/designer' +import { TranslateModule, TranslateService } from '@ngx-translate/core' +import { BehaviorSubject, distinctUntilChanged, from, map } from 'rxjs' +import { DimensionChartOptionsSchemaService } from '../analytical-card.schema' +import { NgmReferenceLineComponent } from './reference-line.component' +import { NgmChartMeasureComponent } from './chart-measure.component' + +@Component({ + standalone: true, + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + MatButtonModule, + MatIconModule, + MatMenuModule, + MatRadioModule, + MatCheckboxModule, + TranslateModule, + + PropertyModule, + NxDesignerModule, + NxChromaticPreviewComponent, + DensityDirective, + NgmColorsComponent, + NgmDesignerFormComponent, + NgmReferenceLineComponent, + NgmChartMeasureComponent + ], + selector: 'ngm-chart-property', + templateUrl: 'chart-property.component.html', + styleUrls: ['chart-property.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: forwardRef(() => NgmChartPropertyComponent) + }, + { + provide: STORY_DESIGNER_SCHEMA, + useClass: DimensionChartOptionsSchemaService + }, + ] +}) +export class NgmChartPropertyComponent implements ControlValueAccessor { + public coreService = inject(NxCoreService) + public dsCoreService = inject(NgmDSCoreService) + public settingsService? = inject(NxSettingsPanelService, { optional: true }) + public translateService = inject(TranslateService) + + @Input() capacities: PropertyCapacity[] + @Input() get removable() { + return this._removable() + } + set removable(value: string | boolean) { + this._removable.set(coerceBooleanProperty(value)) + } + private readonly _removable = signal(false) + + @Input() get dataSettings(): DataSettings { + return this._dataSettings() + } + set dataSettings(value) { + this._dataSettings.set(value) + } + private readonly _dataSettings = signal(null) + + @Input() get entityType(): EntityType { + return this._entityType() + } + set entityType(value) { + this._entityType.set(value) + } + private readonly _entityType = signal(null) + + @Input() chartType: ChartType + + + public interpolateGroups: NgmChromaticInterpolateGroup[] + public colorPalettes = ColorPalettes + + DIMENSION_ROLES = [ + { label: 'None', value: null }, + { label: 'Category', value: ChartDimensionRoleType.Category }, + { label: 'Category2', value: ChartDimensionRoleType.Category2 }, + { label: 'Group', value: ChartDimensionRoleType.Group }, + { label: 'Stacked', value: ChartDimensionRoleType.Stacked }, + // { label: 'Color', value: ChartDimensionRoleType.Color }, 应该是还未支持 + { label: 'Trellis', value: ChartDimensionRoleType.Trellis } + ] + + MEASURE_ROLES = [ + { label: 'None', value: null }, + { label: 'Axis1', value: ChartMeasureRoleType.Axis1 }, + { label: 'Axis2', value: ChartMeasureRoleType.Axis2 }, + { label: 'Axis3', value: ChartMeasureRoleType.Axis3 }, + { label: 'Size', value: ChartMeasureRoleType.Size }, + { label: 'Lightness', value: ChartMeasureRoleType.Lightness }, + { label: 'SizeLightness', value: ChartMeasureRoleType.SizeLightness }, + { label: 'Tooltip', value: ChartMeasureRoleType.Tooltip } + ] + + PATTERNS = [ + { label: 'A', value: ChartPattern.a }, + { label: 'B', value: ChartPattern.b }, + { label: 'C', value: ChartPattern.c }, + { label: 'D', value: ChartPattern.d }, + { label: 'E', value: ChartPattern.e }, + { label: 'F', value: ChartPattern.f }, + { label: 'G', value: ChartPattern.g }, + { label: 'H', value: ChartPattern.h } + ] + + SHAPE_TYPES = [ + { label: 'Bar', value: 'bar', icon: 'stacked_bar_chart' }, + { label: 'Line', value: 'line', icon: 'show_chart' }, + { label: 'Scatter', value: 'scatter', icon: 'scatter_plot' } + ] + + private readonly model = signal(null) + + /** + * 对接 ngm-property-select 的 FormControl, 与当前组件的 formControl 连接 + */ + formControl = new FormControl() + + get showMeasureStyle() { + return this.capacities?.includes(PropertyCapacity.MeasureStyle) + } + get showColorPalette() { + return this.capacities?.includes(PropertyCapacity.MeasureStylePalette) + } + get showMeasurePalettePattern() { + return this.capacities?.includes(PropertyCapacity.MeasureStylePalettePattern) + } + get showChartAttributes() { + return this.capacities?.includes(PropertyCapacity.DimensionChart) + } + get showMeasureRole() { + return this.capacities?.includes(PropertyCapacity.MeasureStyleRole) + } + get showMeasureShape() { + return this.capacities?.includes(PropertyCapacity.MeasureStyleShape) + } + get showMeasureGridBar() { + return this.capacities?.includes(PropertyCapacity.MeasureStyleGridBar) + } + get showMeasureReferenceLine() { + return this.capacities?.includes(PropertyCapacity.MeasureStyleReferenceLine) + } + get showMeasureChartOptions() { + return this.capacities?.includes(PropertyCapacity.MeasureStyleChartOptions) + } + + public readonly syntax = computed(() => this.entityType?.syntax) + public readonly restrictedDimensions$ = new BehaviorSubject(null) + + get role() { + return this.model()?.role + } + set role(value) { + this.patchValue({ role: value }) + } + + get palette() { + return this.model()?.palette?.name + } + set palette(value) { + let interpolate = null + this.interpolateGroups.find((group) => + group.values.find((item) => { + if (item.name === value) { + interpolate = item + } + return item.name === value + }) + ) + + this.patchValue({ + palette: { + ...(this.model()?.palette || {}), + name: value, + colors: interpolate?.colors?.map(({ fill }) => fill) + } + }) + } + + get colors() { + return this.model()?.palette?.colors + } + set colors(value) { + this.patchValue({ + palette: { + ...(this.model()?.palette || {}), + colors: value + } + }) + } + + get reverse() { + return this.model()?.palette?.reverse + } + set reverse(value) { + this.patchValue({ + palette: { + ...(this.model()?.palette || {}), + reverse: value + } + }) + } + + get pattern() { + return this.model()?.palette?.pattern + } + set pattern(value) { + this.patchValue({ + palette: { + ...(this.model()?.palette || {}), + pattern: value + } + }) + } + + get shapeType() { + return this.model()?.shapeType + } + set shapeType(value) { + this.patchValue({ shapeType: value }) + } + get bar() { + return this.model()?.bar + } + set bar(value) { + this.patchValue({ bar: value }) + } + + get referenceLines() { + return this.model()?.referenceLines + } + set referenceLines(value) { + this.patchValue({ referenceLines: value }) + } + + get chartOptions() { + return this.model()?.chartOptions + } + set chartOptions(value) { + this.patchValue({ chartOptions: value }) + } + + public readonly dimension = toSignal( + this.formControl.valueChanges.pipe( + map((value) => pick(value, 'dimension', 'hierarchy', 'level', 'measure')), + distinctUntilChanged(isEqual) + ) + ) + + public readonly property = computed(() => getEntityProperty(this.entityType, this.dimension())) + + public readonly isDimension = computed(() => { + return this.property()?.role === AggregationRole.dimension + }) + public readonly isMeasure = computed(() => { + return this.property()?.role === AggregationRole.measure + }) + + /** + |-------------------------------------------------------------------------- + | Subscriptions (effect) + |-------------------------------------------------------------------------- + */ + private colorsSub = from(getScaleChromaticInterpolates()) + .pipe(takeUntilDestroyed()) + .subscribe((interpolateGroups) => { + this.interpolateGroups = interpolateGroups + }) + + private valueSub = toObservable(this.model) + .pipe(takeUntilDestroyed()) + .subscribe((value) => { + this.onChange?.(value) + }) + private formControSub = this.formControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => { + this.model.set({ + ...this.model(), + ...(value ?? {}) + }) + }) + onChange: (input: any) => void + onTouched: () => void + + writeValue(obj: any): void { + if (obj) { + this.formControl.patchValue(obj) + this.model.set(obj) + } + } + registerOnChange(fn: any): void { + this.onChange = fn + } + registerOnTouched(fn: any): void { + this.onTouched = fn + } + setDisabledState?(isDisabled: boolean): void { + isDisabled ? this.formControl.disable() : this.formControl.enable() + } + + patchValue(value) { + this.model.set({ + ...this.model(), + ...(this.formControl.value ?? {}), + ...value + }) + } + + onCalculationChange(property: CalculationProperty) { + this.coreService.storyUpdateEvent$.next({ + type: 'Calculation', + dataSettings: this.dataSettings, + property + }) + } + + onColorsChange(colors: string[]) { + this.patchValue({ + palette: { + ...(this.model()?.palette ?? {}), + name: null + } + }) + } +} diff --git a/libs/story-angular/widgets/analytical-card/chart-property/reference-line.component.ts b/libs/story-angular/widgets/analytical-card/chart-property/reference-line.component.ts new file mode 100644 index 000000000..63b01567c --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/chart-property/reference-line.component.ts @@ -0,0 +1,64 @@ +import { CommonModule } from "@angular/common"; +import { Component, forwardRef } from "@angular/core"; +import { ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from "@angular/forms"; +import { MatButtonModule } from "@angular/material/button"; +import { MatIconModule } from "@angular/material/icon"; +import { NgmDesignerFormComponent, NxDesignerModule, STORY_DESIGNER_SCHEMA } from "@metad/story/designer"; +import { TranslateModule } from "@ngx-translate/core"; +import { ReferenceLineSchemaService } from "../schemas"; +import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; + + +@Component({ + standalone: true, + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + MatButtonModule, + MatIconModule, + TranslateModule, + + NxDesignerModule, + NgmDesignerFormComponent + ], + selector: 'ngm-reference-line', + template: ``, + styles: [`:host {padding: 0;}`], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: forwardRef(() => NgmReferenceLineComponent) + }, + { + provide: STORY_DESIGNER_SCHEMA, + useClass: ReferenceLineSchemaService + }, + ] + }) + export class NgmReferenceLineComponent implements ControlValueAccessor { + formControl = new FormControl({referenceLines: []}) + + private valueSub = this.formControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => { + this.onChange?.(value.referenceLines) + }) + + onChange: (input: any) => void + onTouched: () => void + + writeValue(obj: any): void { + if (obj) { + this.formControl.patchValue({referenceLines: obj}) + } + } + registerOnChange(fn: any): void { + this.onChange = fn + } + registerOnTouched(fn: any): void { + this.onTouched = fn + } + setDisabledState?(isDisabled: boolean): void { + isDisabled ? this.formControl.disable() : this.formControl.enable() + } + } \ No newline at end of file diff --git a/libs/story-angular/widgets/analytical-card/chart-settings/chart-settings.component.html b/libs/story-angular/widgets/analytical-card/chart-settings/chart-settings.component.html new file mode 100644 index 000000000..5626c0807 --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/chart-settings/chart-settings.component.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/libs/story-angular/widgets/analytical-card/chart-settings/chart-settings.component.scss b/libs/story-angular/widgets/analytical-card/chart-settings/chart-settings.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/libs/story-angular/widgets/analytical-card/chart-settings/chart-settings.component.ts b/libs/story-angular/widgets/analytical-card/chart-settings/chart-settings.component.ts new file mode 100644 index 000000000..b77e75850 --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/chart-settings/chart-settings.component.ts @@ -0,0 +1,88 @@ +import { CommonModule } from '@angular/common' +import { Component, Input, forwardRef, inject } from '@angular/core' +import { ControlValueAccessor, FormGroup, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms' +import { FormlyModule } from '@ngx-formly/core' +import { TranslateModule, TranslateService } from '@ngx-translate/core' +import { chartSettingsFieldGroup, getChartOptionsSchema } from '../analytical-card.schema' +import { ChartType, cloneDeep, isEqual } from '@metad/ocap-core' +import { AccordionWrappers } from '@metad/story/designer' +import { toSignal } from '@angular/core/rxjs-interop' +import { distinctUntilChanged, map } from 'rxjs/operators' +import { BehaviorSubject, combineLatest } from 'rxjs' + +@Component({ + standalone: true, + imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, FormlyModule], + selector: 'ngm-chart-settings', + templateUrl: 'chart-settings.component.html', + styleUrls: ['chart-settings.component.scss'], + host: { + class: 'ngm-chart-settings' + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: forwardRef(() => NgmChartSettingsComponent) + } + ] +}) +export class NgmChartSettingsComponent implements ControlValueAccessor { + private readonly translateService = inject(TranslateService) + + @Input() + get chartType() { + return this.chartType$.value + } + set chartType(value) { + this.chartType$.next(value) + } + private chartType$ = new BehaviorSubject(null) + + formGroup = new FormGroup({}) + + fields = toSignal(combineLatest([ + this.chartType$.pipe(distinctUntilChanged(isEqual)), + this.translateService.stream('Story') + ]).pipe( + map(([chartType, i18nStory]) => { + return [ + ...AccordionWrappers([ + { + key: 'chartSettings', + label: i18nStory?.Widgets?.CHART?.ChartSettings ?? 'Chart Settings', + toggleable: false, + fieldGroup: chartSettingsFieldGroup(i18nStory?.Widgets) + } + ]), + + getChartOptionsSchema(chartType, i18nStory?.STYLING?.ECHARTS) + ] + })) + ) + + model = {} + options = {} + + onChange: (input: any) => void + onTouched: () => void + + writeValue(obj: any): void { + if (obj) { + this.formGroup.patchValue(obj) + this.model = cloneDeep(obj) + } + } + registerOnChange(fn: any): void { + this.onChange = fn + } + registerOnTouched(fn: any): void { + this.onTouched = fn + } + setDisabledState?(isDisabled: boolean): void { + isDisabled ? this.formGroup.disable() : this.formGroup.enable() + } + onModelChange(event) { + this.onChange(event) + } +} diff --git a/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.component.html b/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.component.html new file mode 100644 index 000000000..8de542b0a --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.component.html @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.component.scss b/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.component.scss new file mode 100644 index 000000000..2d0267188 --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.component.scss @@ -0,0 +1,18 @@ +:host { + display: flex; + flex: 1; + + .ngm-property-select { + flex: 1; + } +} + +.ngm-formly__remove { + visibility: hidden; +} + +.ngm-property-select:hover { + .ngm-formly__remove { + visibility: visible; + } +} diff --git a/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.component.ts b/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.component.ts new file mode 100644 index 000000000..057b3466a --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.component.ts @@ -0,0 +1,86 @@ +import { Component, DestroyRef, OnInit, Optional, inject } from '@angular/core' +import { takeUntilDestroyed } from '@angular/core/rxjs-interop' +import { FormControl, FormArray } from '@angular/forms' +import { PropertyCapacity } from '@metad/components/property' +import { MetadFormlyArrayComponent } from '@metad/formly-mat/array' +import { ChartType, DataSettings, EntitySet, EntityType } from '@metad/ocap-core' +import { FieldType, FormlyFieldConfig, FormlyFieldProps } from '@ngx-formly/core' +import { BehaviorSubject, Observable, map } from 'rxjs' + + +@Component({ + selector: 'ngm-formly-chart-property', + templateUrl: './chart-property.component.html', + styleUrls: ['./chart-property.component.scss'] +}) +export class NgmFormlyChartPropertyComponent extends FieldType<{ + capacities: PropertyCapacity[]; + chartType$: Observable; +} & FormlyFieldConfig> implements OnInit { + private readonly destroyRef = inject(DestroyRef) + + get formControl() { + return super.formControl as FormControl + } + get capacities() { + return this.props.capacities + } + get chartType$() { + return this.props.chartType$ + } + public readonly dataSettings$ = new BehaviorSubject(null) + public readonly entitySet$ = new BehaviorSubject(null) + public readonly entityType$ = new BehaviorSubject(null) + public readonly syntax$ = this.entityType$.pipe(map((entityType) => entityType?.syntax)) + public readonly restrictedDimensions$ = new BehaviorSubject(null) + + constructor( + @Optional() + private formlyArray?: MetadFormlyArrayComponent + ) { + super() + } + + ngOnInit(): void { + // 初始化完成后再发送数据 + if (this.field?.props?.entityType instanceof Observable) { + this.field.props.entityType + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((event) => this.entityType$.next(event)) + } else if (this.field.props.entityType) { + this.entityType$.next(this.field.props.entityType) + // 注意: 这样的 of(event) 异步事件会紧跟着一个 complete 事件导致 this.entityType$ 被 Complete + // of(this.field.props.entityType).subscribe(this.entityType$) + } + + if (this.field?.props?.dataSettings instanceof Observable) { + this.field.props.dataSettings + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((event) => this.dataSettings$.next(event)) + } else if (this.field?.props?.dataSettings) { + this.dataSettings$.next(this.field.props.dataSettings) + } + + if (this.field?.props?.restrictedDimensions instanceof Observable) { + this.field.props.restrictedDimensions + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((event) => this.restrictedDimensions$.next(event)) + } else if (this.field?.props?.restrictedDimensions) { + this.restrictedDimensions$.next(this.field.props.restrictedDimensions) + } + } + + killMyself() { + if (this.field.form instanceof FormArray) { + const index = this.field.parent.fieldGroup.indexOf(this.field) + this.formlyArray?.remove(index) + } else { + const index = this.field.parent.fieldGroup.findIndex((field) => field.key === this.field.key) + if (index > -1) { + this.field.parent.fieldGroup.splice(index, 1) + this.field.parent.model[this.field.key as string] = null + } + this.field.parent.formControl.setValue(this.field.parent.model) + } + } +} diff --git a/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.module.ts b/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.module.ts new file mode 100644 index 000000000..d24056ef7 --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/formly/chart-property/chart-property.module.ts @@ -0,0 +1,44 @@ +import { CommonModule } from '@angular/common' +import { NgModule } from '@angular/core' +import { FormsModule, ReactiveFormsModule } from '@angular/forms' +import { MatButtonModule } from '@angular/material/button' +import { MatCheckboxModule } from '@angular/material/checkbox' +import { MatIconModule } from '@angular/material/icon' +import { MatMenuModule } from '@angular/material/menu' +import { MatRadioModule } from '@angular/material/radio' +import { NgmColorsComponent } from '@metad/components/form-field' +import { DensityDirective } from '@metad/ocap-angular/core' +import { FormlyModule } from '@ngx-formly/core' +import { TranslateModule } from '@ngx-translate/core' +import { NgmFormlyChartPropertyComponent } from './chart-property.component' +import { NgmChartPropertyComponent } from '../../chart-property/chart-property.component' + +@NgModule({ + declarations: [NgmFormlyChartPropertyComponent], + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + MatButtonModule, + MatIconModule, + MatMenuModule, + MatRadioModule, + MatCheckboxModule, + TranslateModule, + + DensityDirective, + NgmColorsComponent, + NgmChartPropertyComponent, + + FormlyModule.forChild({ + types: [ + { + name: 'chart-property', + component: NgmFormlyChartPropertyComponent + } + ] + }) + ], + exports: [NgmFormlyChartPropertyComponent] +}) +export class NgmFormlyChartPropertModule {} diff --git a/libs/story-angular/widgets/analytical-card/formly/chart-type/chart-type.component.ts b/libs/story-angular/widgets/analytical-card/formly/chart-type/chart-type.component.ts new file mode 100644 index 000000000..472f8b512 --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/formly/chart-type/chart-type.component.ts @@ -0,0 +1,85 @@ +import { CommonModule } from '@angular/common' +import { Component, Input, forwardRef, inject } from '@angular/core' +import { takeUntilDestroyed } from '@angular/core/rxjs-interop' +import { ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms' +import { MatButtonModule } from '@angular/material/button' +import { MatIconModule } from '@angular/material/icon' +import { ChartType, isEqual } from '@metad/ocap-core' +import { NgmDesignerFormComponent, NxDesignerModule, STORY_DESIGNER_SCHEMA } from '@metad/story/designer' +import { TranslateModule } from '@ngx-translate/core' +import { ChartOptionsSchemaService } from '../../analytical-card.schema' +import { debounceTime, distinctUntilChanged } from 'rxjs/operators' + + +@Component({ + standalone: true, + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + MatButtonModule, + MatIconModule, + TranslateModule, + + NxDesignerModule, + NgmDesignerFormComponent + ], + selector: 'ngm-chart-type-form', + template: ``, + styles: [ + ` + :host { + padding: 0; + } + ` + ], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: forwardRef(() => NgmFormlyChartTypeComponent) + }, + { + provide: STORY_DESIGNER_SCHEMA, + useClass: ChartOptionsSchemaService + } + ] +}) +export class NgmFormlyChartTypeComponent implements ControlValueAccessor { + private readonly schema = inject(STORY_DESIGNER_SCHEMA) + + @Input() get chartType(): ChartType { + return this.schema.chartType + } + set chartType(value: ChartType) { + this.schema.chartType = value + } + + formControl = new FormControl({}) + + private valueSub = this.formControl.valueChanges.pipe( + debounceTime(100), + distinctUntilChanged(isEqual), + takeUntilDestroyed() + ).subscribe((value) => { + this.onChange?.(value) + }) + + onChange: (input: any) => void + onTouched: () => void + + writeValue(obj: any): void { + if (obj) { + this.formControl.setValue(obj) + } + } + registerOnChange(fn: any): void { + this.onChange = fn + } + registerOnTouched(fn: any): void { + this.onTouched = fn + } + setDisabledState?(isDisabled: boolean): void { + isDisabled ? this.formControl.disable() : this.formControl.enable() + } +} diff --git a/libs/story-angular/widgets/analytical-card/formly/index.ts b/libs/story-angular/widgets/analytical-card/formly/index.ts new file mode 100644 index 000000000..c67fbe0de --- /dev/null +++ b/libs/story-angular/widgets/analytical-card/formly/index.ts @@ -0,0 +1,3 @@ +export * from './chart-property/chart-property.component' +export * from './chart-property/chart-property.module' +export * from './chart-type/chart-type.component' \ No newline at end of file diff --git a/libs/story-angular/widgets/analytical-card/index.ts b/libs/story-angular/widgets/analytical-card/index.ts index d76a0fb57..fddffd7f1 100644 --- a/libs/story-angular/widgets/analytical-card/index.ts +++ b/libs/story-angular/widgets/analytical-card/index.ts @@ -1,4 +1,7 @@ export * from './analytical-card.component' export * from './analytical-card.module' export * from './analytical-card.schema' -export * from './schemas/reference-line.schema' \ No newline at end of file +export * from './schemas/reference-line.schema' +export * from './chart-settings/chart-settings.component' +export * from './chart-property/chart-property.component' +export * from './formly/index' \ No newline at end of file diff --git a/libs/story-angular/widgets/analytical-card/schemas/aria.ts b/libs/story-angular/widgets/analytical-card/schemas/aria.ts index 56ba27bd1..4df757550 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/aria.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/aria.ts @@ -1,13 +1,13 @@ -import { AccordionWrappers, FORMLY_W_FULL } from "@metad/story/designer" +import { AccordionWrappers, FORMLY_ROW, FORMLY_W_FULL } from "@metad/story/designer" export function AriaCapacity(className: string, I18N?) { return AccordionWrappers([{ key: 'aria', - label: I18N.ARIA?.TITLE ?? 'Aria', + label: I18N?.ARIA?.TITLE ?? 'Aria', fieldGroup: [ { key: 'decal', - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { className, diff --git a/libs/story-angular/widgets/analytical-card/schemas/axis.ts b/libs/story-angular/widgets/analytical-card/schemas/axis.ts index 300228b80..e94dad5c4 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/axis.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/axis.ts @@ -98,7 +98,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'position', type: 'select', props: { - label: I18N.CATEGORY_AXIS?.Position ?? 'Position', + label: I18N?.CATEGORY_AXIS?.Position ?? 'Position', options: [ { value: null, label: 'None' }, { value: 'top', label: 'Top' }, @@ -111,7 +111,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'offset', type: 'input', props: { - label: I18N.CATEGORY_AXIS?.Offset ?? 'Offset', + label: I18N?.CATEGORY_AXIS?.Offset ?? 'Offset', type: 'number' } }, @@ -121,7 +121,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'showName', type: 'toggle', props: { - label: I18N.CATEGORY_AXIS?.ShowName ?? 'Show Name' + label: I18N?.CATEGORY_AXIS?.ShowName ?? 'Show Name' } }, @@ -131,7 +131,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'name', type: 'input', props: { - label: I18N.CATEGORY_AXIS?.Name ?? 'Name' + label: I18N?.CATEGORY_AXIS?.Name ?? 'Name' } }, { @@ -140,7 +140,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'nameLocation', type: 'select', props: { - label: I18N.CATEGORY_AXIS?.NameLocation ?? 'Name Location', + label: I18N?.CATEGORY_AXIS?.NameLocation ?? 'Name Location', options: [ { value: null, label: 'None' }, { value: 'start', label: 'Start' }, @@ -155,7 +155,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'nameGap', type: 'input', props: { - label: I18N.CATEGORY_AXIS?.NameGap ?? 'Name Gap', + label: I18N?.CATEGORY_AXIS?.NameGap ?? 'Name Gap', type: 'number' } }, @@ -165,7 +165,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'nameRotate', type: 'input', props: { - label: I18N.CATEGORY_AXIS?.NameRotate ?? 'Name Rotate', + label: I18N?.CATEGORY_AXIS?.NameRotate ?? 'Name Rotate', type: 'number' } }, @@ -174,7 +174,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'inverse', type: 'checkbox', props: { - label: I18N.CATEGORY_AXIS?.Inverse ?? 'Inverse' + label: I18N?.CATEGORY_AXIS?.Inverse ?? 'Inverse' } }, { @@ -182,7 +182,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'boundaryGap', type: 'checkbox', props: { - label: I18N.CATEGORY_AXIS?.BoundaryGap ?? 'Boundary Gap' + label: I18N?.CATEGORY_AXIS?.BoundaryGap ?? 'Boundary Gap' } }, { @@ -190,7 +190,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'min', type: 'input', props: { - label: I18N.CATEGORY_AXIS?.Min ?? 'Min' + label: I18N?.CATEGORY_AXIS?.Min ?? 'Min' } }, { @@ -198,7 +198,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'max', type: 'input', props: { - label: I18N.CATEGORY_AXIS?.Max ?? 'Max' + label: I18N?.CATEGORY_AXIS?.Max ?? 'Max' } }, { @@ -206,7 +206,7 @@ export function CategoryAxis(className: string, I18N?) { key: 'silent', type: 'checkbox', props: { - label: I18N.CATEGORY_AXIS?.Silent ?? 'Silent' + label: I18N?.CATEGORY_AXIS?.Silent ?? 'Silent' } } ] @@ -310,7 +310,7 @@ export function ValueAxis(className: string, I18N?) { key: 'show', type: 'checkbox', props: { - label: I18N.VALUE_AXIS?.SHOW ?? 'Show' + label: I18N?.VALUE_AXIS?.SHOW ?? 'Show' } }, { @@ -318,7 +318,7 @@ export function ValueAxis(className: string, I18N?) { key: 'showName', type: 'toggle', props: { - label: I18N.CATEGORY_AXIS?.ShowName ?? 'Show Name' + label: I18N?.CATEGORY_AXIS?.ShowName ?? 'Show Name' } }, @@ -328,7 +328,7 @@ export function ValueAxis(className: string, I18N?) { key: 'name', type: 'input', props: { - label: I18N.CATEGORY_AXIS?.Name ?? 'Name' + label: I18N?.CATEGORY_AXIS?.Name ?? 'Name' } }, { @@ -337,7 +337,7 @@ export function ValueAxis(className: string, I18N?) { key: 'nameLocation', type: 'select', props: { - label: I18N.CATEGORY_AXIS?.NameLocation ?? 'Name Location', + label: I18N?.CATEGORY_AXIS?.NameLocation ?? 'Name Location', options: [ { value: null, label: 'None' }, { value: 'start', label: 'Start' }, @@ -352,7 +352,7 @@ export function ValueAxis(className: string, I18N?) { key: 'nameGap', type: 'input', props: { - label: I18N.CATEGORY_AXIS?.NameGap ?? 'Name Gap', + label: I18N?.CATEGORY_AXIS?.NameGap ?? 'Name Gap', type: 'number' } }, @@ -362,7 +362,7 @@ export function ValueAxis(className: string, I18N?) { key: 'nameRotate', type: 'input', props: { - label: I18N.CATEGORY_AXIS?.NameRotate ?? 'Name Rotate', + label: I18N?.CATEGORY_AXIS?.NameRotate ?? 'Name Rotate', type: 'number' } }, @@ -371,7 +371,7 @@ export function ValueAxis(className: string, I18N?) { key: 'splitNumber', type: 'slider', props: { - label: I18N.VALUE_AXIS?.SplitNumber ?? 'Split Number', + label: I18N?.VALUE_AXIS?.SplitNumber ?? 'Split Number', type: 'number', placeholder: 'splitNumber', thumbLabel: true, @@ -385,17 +385,17 @@ export function ValueAxis(className: string, I18N?) { key: 'scale', type: 'checkbox', props: { - label: I18N.VALUE_AXIS?.ValueScale ?? 'Value Scale', + label: I18N?.VALUE_AXIS?.ValueScale ?? 'Value Scale', placeholder: 'scale' } }, { - hideExpression: `!model || model.scale`, + hideExpression: `!!model && model.scale`, className, key: 'min', type: 'slider', props: { - label: I18N.VALUE_AXIS?.Min ?? 'Min', + label: I18N?.VALUE_AXIS?.Min ?? 'Min', type: 'number', placeholder: 'min', thumbLabel: true, @@ -403,12 +403,12 @@ export function ValueAxis(className: string, I18N?) { } }, { - hideExpression: `!model || model.scale`, + hideExpression: `!!model && model.scale`, className, key: 'max', type: 'slider', props: { - label: I18N.VALUE_AXIS?.Max ?? 'Max', + label: I18N?.VALUE_AXIS?.Max ?? 'Max', type: 'number', placeholder: 'max', thumbLabel: true, @@ -420,7 +420,7 @@ export function ValueAxis(className: string, I18N?) { key: 'position', type: 'select', props: { - label: I18N.CATEGORY_AXIS?.Position ?? 'Position', + label: I18N?.CATEGORY_AXIS?.Position ?? 'Position', options: [ { value: null, label: I18N?.Common?.None ?? 'None' }, { value: 'left', label: I18N?.Common?.Left ?? 'Left' }, diff --git a/libs/story-angular/widgets/analytical-card/schemas/common.ts b/libs/story-angular/widgets/analytical-card/schemas/common.ts index debb5fd24..d81019dbb 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/common.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/common.ts @@ -1,4 +1,3 @@ -import { C_FORMLY_INITIAL_VALUE } from '@metad/formly-mat/expansion' import { AccordionWrappers, FORMLY_ROW, FORMLY_W_FULL } from '@metad/story/designer' import { LineStyle } from './axis' @@ -11,7 +10,7 @@ export function ItemStyle(className: string, I18N) { }, fieldGroup: [ { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ SingleColor(className, I18N), ...Borders(className, I18N), @@ -66,77 +65,6 @@ export function ItemStyle(className: string, I18N) { } } -// /** -// * @deprecated use ItemStyleAccordionWrappers -// */ -// export function ItemStyleExpansion(className: string, I18N, keyShow: string, extensions?) { -// return { -// key: 'itemStyle', -// hideExpression: `!field.form.value.` + keyShow, -// props: { -// label: I18N?.ItemStyle?.Title ?? 'Item Style', -// toggleable: true, -// keyShow: keyShow -// }, -// fieldGroup: [ -// { -// fieldGroupClassName: 'ngm-formly__row', -// fieldGroup: [ -// SingleColor(className, I18N), -// ...Borders(className, I18N), - -// // for CanvasRenderingContext2D -// { -// className, -// key: 'borderCap', -// type: 'select', -// props: { -// label: I18N?.Common?.BorderCap ?? 'Border Cap', -// placeholder: 'lineCap', -// options: [ -// { value: null, label: 'None' }, -// { value: 'butt', label: 'butt' }, -// { value: 'round', label: 'round' }, -// { value: 'square', label: 'square' } -// ] -// } -// }, -// { -// className, -// key: 'borderJoin', -// type: 'select', -// props: { -// label: I18N?.Common?.BorderJoin ?? 'Border Join', -// placeholder: 'lineJoin', -// options: [ -// { value: null, label: 'None' }, -// { value: 'bevel', label: 'bevel' }, -// { value: 'round', label: 'round' }, -// { value: 'miter', label: 'miter' } -// ] -// } -// }, -// { -// className, -// key: 'borderMiterLimit', -// type: 'input', -// props: { -// label: I18N?.Common?.BorderMiterLimit ?? 'Border Miter Limit', -// placeholder: 'Default is 10.0', -// type: 'number' -// } -// }, - -// ...Shadows(className, I18N), -// Opacity(className, I18N), - -// ...(extensions ?? []) -// ] -// } -// ] -// } -// } - export function ItemStyleAccordionWrappers(className: string, I18N, extensions?) { return AccordionWrappers([ { @@ -144,7 +72,7 @@ export function ItemStyleAccordionWrappers(className: string, I18N, extensions?) label: I18N?.ItemStyle?.Title ?? 'Item Style', fieldGroup: [ { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { className, @@ -304,75 +232,56 @@ export function SelectedMode(className: string, I18N) { } } -export function SelectExpansion(className: string, I18N, keyShow: string) { - return { - key: 'select', - hideExpression: `!field.parent && !field.parent.model.` + keyShow, - props: { +export function SelectAccordionWrappers(className: string, I18N) { + return AccordionWrappers([ + { + key: 'select', label: I18N?.Select?.Title ?? 'Select', - toggleable: true, - keyShow: keyShow - }, - fieldGroup: [ - { - key: 'disabled', - type: 'toggle', - props: { - label: I18N?.Common?.Disabled ?? 'Disabled' - } - }, - ItemStyle(className, I18N) - ] - } -} - -export function MarkLineExpansion(className: string, I18N, keyShow: string) { - return { - key: 'markLine', - hideExpression: `!field.parent && !field.parent.model.` + keyShow, - props: { - label: I18N?.MarkLine?.Title ?? 'Mark Line', - toggleable: true, - keyShow: keyShow - }, - fieldGroup: MarkLine(className, I18N).fieldGroup - } + fieldGroup: [ + { + key: 'disabled', + type: 'toggle', + props: { + label: I18N?.Common?.Disabled ?? 'Disabled' + } + }, + ItemStyle(className, I18N) + ] + } + ]) } -export function MarkLine(className, I18N) { - return { - key: 'markLine', - defaultValue: C_FORMLY_INITIAL_VALUE, - wrappers: ['expansion'], - props: { +export function MarkLineAccordionWrappers(className: string, I18N) { + return AccordionWrappers([ + { + key: 'markLine', label: I18N?.MarkLine?.Title ?? 'Mark Line', - toggleable: true - }, - fieldGroup: [ - { - fieldGroupClassName: 'ngm-formly__row', - fieldGroup: [ - { - className, - key: 'silent', - type: 'checkbox', - props: { - label: I18N?.Common?.Silent ?? 'Silent' + fieldGroup: [ + { + fieldGroupClassName: FORMLY_ROW, + fieldGroup: [ + { + className, + key: 'silent', + type: 'checkbox', + props: { + label: I18N?.Common?.Silent ?? 'Silent' + } } - } - ] - }, - { - key: 'lineStyle', - wrappers: ['panel'], - fieldGroupClassName: 'ngm-formly__row', - props: { - label: I18N?.MarkLine?.LineStyle ?? 'Line Style' + ] }, - fieldGroup: LineStyle(className, I18N) - } - ] - } + { + key: 'lineStyle', + wrappers: ['panel'], + fieldGroupClassName: FORMLY_ROW, + props: { + label: I18N?.MarkLine?.LineStyle ?? 'Line Style' + }, + fieldGroup: LineStyle(className, I18N) + } + ] + } + ]) } export function Shadows(className: string, I18N?) { @@ -382,7 +291,7 @@ export function Shadows(className: string, I18N?) { key: 'shadowColor', type: 'color', props: { - label: I18N.SHADOW?.SHADOW_COLOR ?? 'Shadow Color', + label: I18N?.SHADOW?.SHADOW_COLOR ?? 'Shadow Color', placeholder: 'shadowColor' } }, @@ -391,7 +300,7 @@ export function Shadows(className: string, I18N?) { key: 'shadowBlur', type: 'input', props: { - label: I18N.SHADOW?.SHADOW_BLUR ?? 'Shadow Blur', + label: I18N?.SHADOW?.SHADOW_BLUR ?? 'Shadow Blur', placeholder: 'shadowBlur' } }, @@ -400,7 +309,7 @@ export function Shadows(className: string, I18N?) { key: 'shadowOffsetX', type: 'input', props: { - label: I18N.SHADOW?.SHADOW_OFFSETX ?? 'Shadow OffsetX', + label: I18N?.SHADOW?.SHADOW_OFFSETX ?? 'Shadow OffsetX', type: 'number', placeholder: 'shadowOffsetX' } @@ -410,7 +319,7 @@ export function Shadows(className: string, I18N?) { key: 'shadowOffsetY', type: 'input', props: { - label: I18N.SHADOW?.SHADOW_OFFSETY ?? 'Shadow OffsetY', + label: I18N?.SHADOW?.SHADOW_OFFSETY ?? 'Shadow OffsetY', type: 'number', placeholder: 'shadowOffsetY' } @@ -431,30 +340,9 @@ export function EmphasisAccordionWrappers(className: string, I18N, extensions?: ]) } -// /** -// * -// * @deprecated use EmphasisAccordionWrappers -// */ -// export function EmphasisExpansion(className: string, I18N, keyShow: string) { -// return { -// key: 'emphasis', -// hideExpression: `!field.parent && !field.parent.model.` + keyShow, -// props: { -// label: I18N?.EMPHASIS?.TITLE ?? 'Emphasis', -// toggleable: true, -// keyShow: keyShow -// }, -// fieldGroupClassName: 'ngm-formly__row', -// fieldGroup: Emphasis(className, I18N).fieldGroup -// } -// } - export function Emphasis(className: string, I18N) { return { key: 'emphasis', - // wrappers: ['expansion'], - // defaultValue: C_FORMLY_INITIAL_VALUE, - // fieldGroupClassName: 'ngm-formly__row', props: { label: I18N?.EMPHASIS?.TITLE ?? 'Emphasis', icon: 'announcement', @@ -507,7 +395,7 @@ export function Positions(className: string, I18N) { key: 'top', type: 'input-inline', props: { - label: I18N.Common?.TOP ?? 'Top', + label: I18N?.Common?.TOP ?? 'Top', placeholder: 'top', options: [ { @@ -558,7 +446,7 @@ export function Positions(className: string, I18N) { key: 'right', type: 'input-inline', props: { - label: I18N.Common?.RIGHT ?? 'Right', + label: I18N?.Common?.RIGHT ?? 'Right', placeholder: 'right', options: [ { @@ -609,7 +497,7 @@ export function Positions(className: string, I18N) { key: 'bottom', type: 'input-inline', props: { - label: I18N.Common?.BOTTOM ?? 'Bottom', + label: I18N?.Common?.BOTTOM ?? 'Bottom', placeholder: 'bottom', options: [ { @@ -660,7 +548,7 @@ export function Positions(className: string, I18N) { key: 'left', type: 'input-inline', props: { - label: I18N.Common?.LEFT ?? 'Left', + label: I18N?.Common?.LEFT ?? 'Left', placeholder: 'left', options: [ { @@ -1008,7 +896,7 @@ export function Symbols(className: string, I18N) { key: 'symbol', type: 'select', props: { - label: I18N.Common?.Symbol ?? 'Symbol', + label: I18N?.Common?.Symbol ?? 'Symbol', options: SymbolOptions(I18N) } }, @@ -1018,7 +906,7 @@ export function Symbols(className: string, I18N) { key: 'symbolSize', type: 'input', props: { - label: I18N.Common?.SymbolSize ?? 'Symbol Size', + label: I18N?.Common?.SymbolSize ?? 'Symbol Size', type: 'number' } }, @@ -1028,7 +916,7 @@ export function Symbols(className: string, I18N) { key: 'symbolRotate', type: 'input', props: { - label: I18N.Common?.SymbolRotate ?? 'Symbol Rotate', + label: I18N?.Common?.SymbolRotate ?? 'Symbol Rotate', type: 'number' } }, @@ -1038,7 +926,7 @@ export function Symbols(className: string, I18N) { key: 'symbolOffset', type: 'input', props: { - label: I18N.Common?.SymbolOffset ?? 'Symbol Offset', + label: I18N?.Common?.SymbolOffset ?? 'Symbol Offset', type: 'number' } }, @@ -1059,7 +947,7 @@ export function Stacks(className: string, I18N) { key: 'stack', type: 'input', props: { - label: I18N.Common?.Stack ?? 'Stack' + label: I18N?.Common?.Stack ?? 'Stack' } }, ] @@ -1330,3 +1218,19 @@ export function AreaStyles(className: string, I18N) { ...Shadows(className, I18N) ] } + +export function BackgroundStyleAccordionWrappers(className: string, I18N, extensions?: any[]) { + return AccordionWrappers([ + { + key: 'backgroundStyle', + label: I18N?.Bar?.Background ?? 'Background', + fieldGroup: [ + SingleColor(className, I18N), + ...Borders(className, I18N), + ...Shadows(className, I18N), + Opacity(className, I18N), + ...(extensions ?? []) + ] + } + ]) +} diff --git a/libs/story-angular/widgets/analytical-card/schemas/data-zoom.ts b/libs/story-angular/widgets/analytical-card/schemas/data-zoom.ts index 7e0fda21a..5e8b89c3f 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/data-zoom.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/data-zoom.ts @@ -56,7 +56,7 @@ export function DataZoomAttributes(className: string, I18N) { key: 'filterMode', type: 'select-inline', props: { - label: dataZoomI18n?.FILTER_MODE, + label: dataZoomI18n?.FILTER_MODE ?? 'Filter Mode', options: [ { value: null, label: I18N?.Common?.None ?? 'Default' }, { value: 'filter', label: 'Filter' }, @@ -119,7 +119,7 @@ export function DataZoomAttributes(className: string, I18N) { key: 'startValue', type: 'input-inline', props: { - label: dataZoomI18n?.START_VALUE + label: dataZoomI18n?.START_VALUE ?? 'Start Value' }, expressions: { hide: `!model || model.start !== null && model.start !== undefined` @@ -130,7 +130,7 @@ export function DataZoomAttributes(className: string, I18N) { key: 'endValue', type: 'input-inline', props: { - label: dataZoomI18n?.END_VALUE + label: dataZoomI18n?.END_VALUE ?? 'End Value' }, expressions: { hide: `!model || model.end !== null && model.end !== undefined` @@ -141,7 +141,7 @@ export function DataZoomAttributes(className: string, I18N) { key: 'minSpan', type: 'slider', props: { - label: dataZoomI18n?.MIN_SPAN, + label: dataZoomI18n?.MIN_SPAN ?? 'Min Span', type: 'number', placeholder: '0 ~ 100', thumbLabel: true, @@ -152,7 +152,7 @@ export function DataZoomAttributes(className: string, I18N) { key: 'maxSpan', type: 'slider', props: { - label: dataZoomI18n?.MAX_SPAN, + label: dataZoomI18n?.MAX_SPAN ?? 'Max Span', type: 'number', placeholder: '0 ~ 100', thumbLabel: true, @@ -200,9 +200,9 @@ export function DataZoomAttributes(className: string, I18N) { label: dataZoomI18n?.PreventDefaultMouseMove ?? 'Prevent Default Mouse Move' } }, - MouseMode('zoomOnMouseWheel', dataZoomI18n?.zoomOnMouseWheel ?? 'zoomOnMouseWheel', className, dataZoomI18n), - MouseMode('moveOnMouseMove', dataZoomI18n?.moveOnMouseMove ?? 'moveOnMouseMove', className, dataZoomI18n), - MouseMode('moveOnMouseWheel ', dataZoomI18n?.moveOnMouseWheel ?? 'moveOnMouseWheel ', className, dataZoomI18n) + MouseMode('zoomOnMouseWheel', dataZoomI18n?.zoomOnMouseWheel ?? 'Zoom On Mouse Wheel', className, dataZoomI18n), + MouseMode('moveOnMouseMove', dataZoomI18n?.moveOnMouseMove ?? 'Move on Mouse Move', className, dataZoomI18n), + MouseMode('moveOnMouseWheel ', dataZoomI18n?.moveOnMouseWheel ?? 'Move on Mouse Wheel ', className, dataZoomI18n) ] } diff --git a/libs/story-angular/widgets/analytical-card/schemas/geo.ts b/libs/story-angular/widgets/analytical-card/schemas/geo.ts index a482fcd56..939e8dc25 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/geo.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/geo.ts @@ -1,3 +1,4 @@ +import { FORMLY_ROW } from '@metad/story/designer' import { ItemStyle } from './common' export function GeoCapacity(className: string, I18N) { @@ -17,10 +18,10 @@ export function GeoCapacity(className: string, I18N) { key: 'geo', hideExpression: `!field.parent.model || !field.parent.model.` + showKey, templateOptions: { - label: I18N.Geo?.Title ?? 'Geo', + label: I18N?.Geo?.Title ?? 'Geo', keyShow: showKey }, - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ItemStyle(className, I18N)] } ] diff --git a/libs/story-angular/widgets/analytical-card/schemas/global.ts b/libs/story-angular/widgets/analytical-card/schemas/global.ts index 00dd9f608..7fe0bbc20 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/global.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/global.ts @@ -1,3 +1,5 @@ +import { FORMLY_ROW } from "@metad/story/designer" + export function GlobalCapacity(className: string, I18N?) { return [ { @@ -10,7 +12,7 @@ export function GlobalCapacity(className: string, I18N?) { props: { label: I18N?.Global?.Title ?? 'Global' }, - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { className, diff --git a/libs/story-angular/widgets/analytical-card/schemas/grid.ts b/libs/story-angular/widgets/analytical-card/schemas/grid.ts index 2831c6c97..684864ae3 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/grid.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/grid.ts @@ -1,14 +1,14 @@ -import { AccordionWrappers } from '@metad/story/designer' +import { AccordionWrappers, FORMLY_ROW } from '@metad/story/designer' import { Positions, Shadows } from './common' export function GridCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'grid', - label: I18N.GRID?.GRID ?? 'Grid', + label: I18N?.GRID?.GRID ?? 'Grid', fieldGroup: [ { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: Grid(className, I18N) } ] @@ -23,7 +23,7 @@ export function Grid(className?, I18N?) { key: 'show', type: 'checkbox', templateOptions: { - label: I18N.GRID?.SHOW ?? 'Show' + label: I18N?.GRID?.SHOW ?? 'Show' } }, { @@ -31,7 +31,7 @@ export function Grid(className?, I18N?) { key: 'containLabel', type: 'checkbox', templateOptions: { - label: I18N.GRID?.CONTAIN_LABEL ?? 'Contain Axis Label' + label: I18N?.GRID?.CONTAIN_LABEL ?? 'Contain Axis Label' } }, ...Positions(className, I18N), @@ -40,7 +40,7 @@ export function Grid(className?, I18N?) { key: 'backgroundColor', type: 'color', templateOptions: { - label: I18N.GRID?.BACKGROUND_COLOR ?? 'Background Color' + label: I18N?.GRID?.BACKGROUND_COLOR ?? 'Background Color' } }, { @@ -48,7 +48,7 @@ export function Grid(className?, I18N?) { key: 'borderColor', type: 'color', templateOptions: { - label: I18N.GRID?.BORDER_COLOR ?? 'Border Color' + label: I18N?.GRID?.BORDER_COLOR ?? 'Border Color' } }, { @@ -56,7 +56,7 @@ export function Grid(className?, I18N?) { key: 'borderWidth', type: 'input', templateOptions: { - label: I18N.GRID?.BORDER_WIDTH ?? 'Background Width', + label: I18N?.GRID?.BORDER_WIDTH ?? 'Background Width', type: 'number' } }, diff --git a/libs/story-angular/widgets/analytical-card/schemas/grid3D.ts b/libs/story-angular/widgets/analytical-card/schemas/grid3D.ts index 56ac9ebb6..c73134088 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/grid3D.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/grid3D.ts @@ -1,15 +1,21 @@ -import { AccordionWrappers } from "@metad/story/designer"; -import { AxisLabelAccordionWrappers, AxisLineAccordionWrappers, AxisPointerAccordionWrappers, AxisTickAccordionWrappers, SplitLineAccordionWrappers } from "./axis"; -import { Positions, WidthHeight } from "./common"; +import { AccordionWrappers, FORMLY_ROW } from '@metad/story/designer' +import { + AxisLabelAccordionWrappers, + AxisLineAccordionWrappers, + AxisPointerAccordionWrappers, + AxisTickAccordionWrappers, + SplitLineAccordionWrappers +} from './axis' +import { Positions, WidthHeight } from './common' export function Grid3DCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'grid3D', - label: I18N.DDD?.GridTitle ?? 'Grid 3D', + label: I18N?.DDD?.GridTitle ?? 'Grid 3D', fieldGroup: [ { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ ...Positions(className, I18N), ...WidthHeight(className, I18N), @@ -18,7 +24,7 @@ export function Grid3DCapacity(className: string, I18N) { key: 'boxWidth', type: 'input', props: { - label: I18N.DDD?.BoxWidth ?? 'Box Width', + label: I18N?.DDD?.BoxWidth ?? 'Box Width', type: 'number' } }, @@ -27,7 +33,7 @@ export function Grid3DCapacity(className: string, I18N) { key: 'boxHeight', type: 'input', props: { - label: I18N.DDD?.BoxHeight ?? 'Box Height', + label: I18N?.DDD?.BoxHeight ?? 'Box Height', type: 'number' } }, @@ -36,7 +42,7 @@ export function Grid3DCapacity(className: string, I18N) { key: 'boxDepth', type: 'input', props: { - label: I18N.DDD?.BoxDepth ?? 'Box Depth', + label: I18N?.DDD?.BoxDepth ?? 'Box Depth', type: 'number' } }, @@ -45,9 +51,9 @@ export function Grid3DCapacity(className: string, I18N) { key: 'environment', type: 'json', props: { - label: I18N.DDD?.Environment ?? 'Environment', + label: I18N?.DDD?.Environment ?? 'Environment', placeholder: 'json', - autosize: true, + autosize: true } }, { @@ -55,7 +61,7 @@ export function Grid3DCapacity(className: string, I18N) { key: 'light', type: 'json', props: { - label: I18N.DDD?.Light ?? 'Light', + label: I18N?.DDD?.Light ?? 'Light', placeholder: 'json', autosize: true, autosizeMinRows: 2 @@ -66,7 +72,7 @@ export function Grid3DCapacity(className: string, I18N) { key: 'postEffect', type: 'json', props: { - label: I18N.DDD?.PostEffect ?? 'Post Effect', + label: I18N?.DDD?.PostEffect ?? 'Post Effect', placeholder: 'json', autosize: true, autosizeMinRows: 2 @@ -77,19 +83,19 @@ export function Grid3DCapacity(className: string, I18N) { key: 'viewControl', type: 'json', props: { - label: I18N.DDD?.ViewControl ?? 'View Control', + label: I18N?.DDD?.ViewControl ?? 'View Control', placeholder: 'json', autosize: true, autosizeMinRows: 2 } - }, + } ] }, { key: 'temporalSuperSampling', wrappers: ['panel'], props: { - label: I18N.DDD?.TemporalSuperSampling ?? 'Temporal Super Sampling', + label: I18N?.DDD?.TemporalSuperSampling ?? 'Temporal Super Sampling' }, fieldGroup: [ { @@ -97,7 +103,7 @@ export function Grid3DCapacity(className: string, I18N) { key: 'enable', type: 'toggle', props: { - label: I18N.DDD?.Enable ?? 'Enable', + label: I18N?.DDD?.Enable ?? 'Enable', type: 'number' } } diff --git a/libs/story-angular/widgets/analytical-card/schemas/legend.ts b/libs/story-angular/widgets/analytical-card/schemas/legend.ts index d9e41b616..2dbea8703 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/legend.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/legend.ts @@ -1,4 +1,4 @@ -import { AccordionWrappers } from '@metad/story/designer' +import { AccordionWrappers, FORMLY_ROW } from '@metad/story/designer' import { LineStyle } from './axis' import { ItemStyleAccordionWrappers, Orient, PaddingJSON, SymbolOptions, TextStyles, WidthHeight } from './common' @@ -6,7 +6,7 @@ export function LegendCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'legend', - label: I18N.LEGEND?.TITLE ?? 'Legend', + label: I18N?.LEGEND?.TITLE ?? 'Legend', fieldGroup: [ ...Legend(className, I18N), ...ItemStyleAccordionWrappers(className, I18N), @@ -21,7 +21,7 @@ export function LegendCapacity(className: string, I18N) { label: I18N?.LEGEND?.TextStyle ?? 'Text Style', fieldGroup: [ { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: TextStyles(className, I18N) } ] @@ -35,7 +35,7 @@ export function LegendCapacity(className: string, I18N) { export function Legend(className: string, I18N) { return [ { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { className, diff --git a/libs/story-angular/widgets/analytical-card/schemas/polar.ts b/libs/story-angular/widgets/analytical-card/schemas/polar.ts index 62a6f6fc0..7aac158e6 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/polar.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/polar.ts @@ -1,13 +1,13 @@ -import { AccordionWrappers } from "@metad/story/designer" +import { AccordionWrappers, FORMLY_ROW } from "@metad/story/designer" export function PolarCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'polar', - label: I18N.Polar?.Title ?? 'Polar', + label: I18N?.Polar?.Title ?? 'Polar', fieldGroup: [ { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { key: 'radius', diff --git a/libs/story-angular/widgets/analytical-card/schemas/reference-line.schema.ts b/libs/story-angular/widgets/analytical-card/schemas/reference-line.schema.ts index 673e01001..f63a58a09 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/reference-line.schema.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/reference-line.schema.ts @@ -1,40 +1,44 @@ -import { Injectable, Injector } from '@angular/core' +import { Injectable, inject } from '@angular/core' import { ReferenceLineAggregation, ReferenceLineType, ReferenceLineValueType } from '@metad/ocap-core' -import { BaseDesignerSchemaService, BaseSchemaState } from '@metad/story/designer' -import { map, Observable } from 'rxjs' +import { DesignerSchema, FORMLY_ROW, FORMLY_W_1_2 } from '@metad/story/designer' +import { TranslateService } from '@ngx-translate/core' +import { BehaviorSubject, Observable, map } from 'rxjs' @Injectable() -export class ReferenceLineSchemaService extends BaseDesignerSchemaService { - public readonly storyDesigner$ = this.translate.stream('STORY_DESIGNER') - - constructor(public injector: Injector) { - super(injector) +export class ReferenceLineSchemaService implements DesignerSchema { + protected translate = inject(TranslateService) + get model() { + return this.model$.value + } + set model(value) { + this.model$.next(value) } + private readonly model$ = new BehaviorSubject(null) + + public readonly storyDesigner$ = this.translate.stream('Story.Widgets') getTitle(): Observable { return this.storyDesigner$.pipe( - map((STORY_DESIGNER) => STORY_DESIGNER?.BUILDER?.CHART?.ReferenceLine?.Title ?? 'Create Reference Lines') + map((i18n) => i18n?.CHART?.ReferenceLine?.Title ?? 'Create Reference Lines') ) } getSchema() { return this.storyDesigner$.pipe( - map((STORY_DESIGNER) => STORY_DESIGNER?.BUILDER?.CHART?.ReferenceLine), + map((i18n) => i18n?.CHART?.ReferenceLine), map((ReferenceLine) => { - const className = 'ngm-formly__col ngm-formly__col-6' + const className = FORMLY_W_1_2 return [ { key: 'referenceLines', - wrappers: ['panel'], - type: 'array-tabs', - templateOptions: { - label: ReferenceLine?.ReferenceLine ?? 'Reference Line', + type: 'array', + props: { padding: true, labelField: 'label', removeLabel: ReferenceLine?.removeLabel ?? 'Remove' }, fieldArray: { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { className, diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/bar.ts b/libs/story-angular/widgets/analytical-card/schemas/series/bar.ts index 0ab7e0dd8..e96735822 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/bar.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/bar.ts @@ -1,168 +1,128 @@ import { AccordionWrappers, FORMLY_ROW } from '@metad/story/designer' import { - Borders, + BackgroundStyleAccordionWrappers, EmphasisAccordionWrappers, ItemStyleAccordionWrappers, - MarkLineExpansion, - Opacity, - SelectExpansion, + MarkLineAccordionWrappers, + SelectAccordionWrappers, SeriesCommon, - Shadows, - SingleColor, Stacks } from '../common' import { LabelAccordionWrappers, LabelLineAccordionWrappers } from './label' export function BarCapacity(className: string, I18N) { - return AccordionWrappers([{ - key: 'seriesStyle', - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', - fieldGroup: [ - { - fieldGroupClassName: FORMLY_ROW, - fieldGroup: [ - { - className, - key: 'barWidth', - type: 'slider', - props: { - label: I18N?.Bar?.BarWidth ?? 'Bar Width', - type: 'number', - placeholder: 'barWidth', - thumbLabel: true, - autoScale: true + return AccordionWrappers([ + { + key: 'seriesStyle', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', + fieldGroup: [ + { + fieldGroupClassName: FORMLY_ROW, + fieldGroup: [ + { + className, + key: 'barWidth', + type: 'slider', + props: { + label: I18N?.Bar?.BarWidth ?? 'Bar Width', + type: 'number', + placeholder: 'barWidth', + thumbLabel: true, + autoScale: true + } + }, + { + className, + key: 'barMaxWidth', + type: 'slider', + props: { + label: I18N?.Bar?.BarMaxWidth ?? 'Bar Max Width', + type: 'number', + placeholder: 'barMaxWidth', + thumbLabel: true, + autoScale: true + } + }, + { + className, + key: 'barMinWidth', + type: 'slider', + props: { + label: I18N?.Bar?.BarMinWidth ?? 'Bar Min Width', + type: 'number', + placeholder: 'barMinWidth', + thumbLabel: true, + autoScale: true + } + }, + { + className, + key: 'barMinHeight', + type: 'slider', + props: { + label: I18N?.Bar?.BarMinHeight ?? 'Bar Min Height', + type: 'number', + placeholder: 'barMinHeight', + thumbLabel: true, + autoScale: true + } + }, + { + className, + key: 'barMinAngle', + type: 'slider', + props: { + label: I18N?.Bar?.BarMinAngle ?? 'Bar Min Angle', + type: 'number', + placeholder: 'barMinAngle', + thumbLabel: true, + min: 0, + max: 90 + } + }, + { + className, + key: 'barGap', + type: 'input', + props: { + label: I18N?.Bar?.BarGap ?? 'Bar Gap', + placeholder: 'barGap', + thumbLabel: true, + autoScale: true + } + }, + { + className, + key: 'barCategoryGap', + type: 'input', + props: { + label: I18N?.Bar?.BarCategoryGap ?? 'Bar Category Gap', + placeholder: 'barCategoryGap', + thumbLabel: true, + autoScale: true + } + }, + ...Stacks(className, I18N), + ...SeriesCommon(className, I18N).fieldGroup, + { + className, + key: 'roundCap', + type: 'checkbox', + props: { + label: I18N?.Bar?.RoundCap ?? 'Round Cap' + } } - }, - { - className, - key: 'barMaxWidth', - type: 'slider', - props: { - label: I18N?.Bar?.BarMaxWidth ?? 'Bar Max Width', - type: 'number', - placeholder: 'barMaxWidth', - thumbLabel: true, - autoScale: true - } - }, - { - className, - key: 'barMinWidth', - type: 'slider', - props: { - label: I18N?.Bar?.BarMinWidth ?? 'Bar Min Width', - type: 'number', - placeholder: 'barMinWidth', - thumbLabel: true, - autoScale: true - } - }, - { - className, - key: 'barMinHeight', - type: 'slider', - props: { - label: I18N?.Bar?.BarMinHeight ?? 'Bar Min Height', - type: 'number', - placeholder: 'barMinHeight', - thumbLabel: true, - autoScale: true - } - }, - { - className, - key: 'barMinAngle', - type: 'slider', - props: { - label: I18N?.Bar?.BarMinAngle ?? 'Bar Min Angle', - type: 'number', - placeholder: 'barMinAngle', - thumbLabel: true, - min: 0, - max: 90, - } - }, - { - className, - key: 'barGap', - type: 'input', - props: { - label: I18N?.Bar?.BarGap ?? 'Bar Gap', - placeholder: 'barGap', - thumbLabel: true, - autoScale: true - } - }, - { - className, - key: 'barCategoryGap', - type: 'input', - props: { - label: I18N?.Bar?.BarCategoryGap ?? 'Bar Category Gap', - placeholder: 'barCategoryGap', - thumbLabel: true, - autoScale: true - } - }, - ...Stacks(className, I18N), - ...(SeriesCommon(className, I18N).fieldGroup), - { - className, - key: 'roundCap', - type: 'checkbox', - props: { - label: I18N?.Bar?.RoundCap ?? 'Round Cap', - } - }, - ] - }, - - ...ItemStyleAccordionWrappers(className, I18N), - ...LabelAccordionWrappers(className, I18N), - ...LabelLineAccordionWrappers(className, I18N), - ...EmphasisAccordionWrappers(className, I18N), - { - key: '__showSelect__', - type: 'empty' - }, - { - key: '__showMarkLine__', - type: 'empty' - }, - { - key: 'showBackground', - type: 'empty' - }, - { - wrappers: ['accordion'], - props: { - elevationZ: true + ] }, - fieldGroup: [ - SelectExpansion(className, I18N, '__showSelect__'), - MarkLineExpansion(className, I18N, '__showMarkLine__'), - BackgroundStyleExpansion(className, I18N, 'showBackground') - ] - } - ] - }]) -} -function BackgroundStyleExpansion(className: string, I18N, keyShow: string) { - return { - key: 'backgroundStyle', - hideExpression: `!field.parent && !field.parent.model.` + keyShow, - props: { - label: I18N?.Bar?.Background ?? 'Background', - toggleable: true, - keyShow: keyShow - }, - fieldGroupClassName: FORMLY_ROW, - fieldGroup: [ - SingleColor(className, I18N), - ...Borders(className, I18N), - ...Shadows(className, I18N), - Opacity(className, I18N) - ] - } + ...ItemStyleAccordionWrappers(className, I18N), + ...LabelAccordionWrappers(className, I18N), + ...LabelLineAccordionWrappers(className, I18N), + ...EmphasisAccordionWrappers(className, I18N), + ...BackgroundStyleAccordionWrappers(className, I18N), + ...SelectAccordionWrappers(className, I18N), + ...MarkLineAccordionWrappers(className, I18N) + ] + } + ]) } diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/bar3D.ts b/libs/story-angular/widgets/analytical-card/schemas/series/bar3D.ts index 3da1b0a4c..817f766fa 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/bar3D.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/bar3D.ts @@ -5,7 +5,7 @@ export function Bar3DCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'seriesStyle', - label: I18N.DDD?.BarSeriesTitle ?? 'Series Attributes', + label: I18N?.DDD?.BarSeriesTitle ?? 'Series Attributes', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, @@ -15,7 +15,7 @@ export function Bar3DCapacity(className: string, I18N) { key: 'bevelSize', type: 'number', props: { - label: I18N.DDD?.BevelSize ?? 'Bevel Size', + label: I18N?.DDD?.BevelSize ?? 'Bevel Size', placeholder: '0 ~ 1' } }, @@ -24,7 +24,7 @@ export function Bar3DCapacity(className: string, I18N) { key: 'bevelSmoothness', type: 'number', props: { - label: I18N.DDD?.BevelSmoothness ?? 'Bevel Smoothness', + label: I18N?.DDD?.BevelSmoothness ?? 'Bevel Smoothness', placeholder: '0 ~ 1' } }, @@ -33,7 +33,7 @@ export function Bar3DCapacity(className: string, I18N) { key: 'stack', type: 'input', props: { - label: I18N.DDD?.Stack ?? 'Stack' + label: I18N?.DDD?.Stack ?? 'Stack' } }, // { @@ -41,7 +41,7 @@ export function Bar3DCapacity(className: string, I18N) { // key: 'stackStrategy', // type: 'select', // props: { - // label: I18N.DDD?.StackStrategy ?? 'Stack Strategy', + // label: I18N?.DDD?.StackStrategy ?? 'Stack Strategy', // options: [ // { value: null, label: 'None' }, // { value: 'color', label: 'color' }, @@ -55,7 +55,7 @@ export function Bar3DCapacity(className: string, I18N) { key: 'minHeight', type: 'number', props: { - label: I18N.DDD?.MinHeight ?? 'MinHeight' + label: I18N?.DDD?.MinHeight ?? 'MinHeight' } }, { @@ -63,7 +63,7 @@ export function Bar3DCapacity(className: string, I18N) { key: 'silent', type: 'checkbox', props: { - label: I18N.DDD?.Silent ?? 'Silent' + label: I18N?.DDD?.Silent ?? 'Silent' } }, { @@ -71,7 +71,7 @@ export function Bar3DCapacity(className: string, I18N) { key: 'shading', type: 'select', props: { - label: I18N.DDD?.Shading ?? 'Shading', + label: I18N?.DDD?.Shading ?? 'Shading', options: [ { value: null, label: 'None' }, { value: 'color', label: 'color' }, @@ -85,7 +85,7 @@ export function Bar3DCapacity(className: string, I18N) { ...AccordionWrappers([ { key: 'itemStyle', - label: I18N.DDD?.ItemStyle ?? 'Item Style', + label: I18N?.DDD?.ItemStyle ?? 'Item Style', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, @@ -110,7 +110,7 @@ function Label(className: string, I18N) { key: 'show', type: 'toggle', props: { - label: I18N.DDD?.Show ?? 'Show' + label: I18N?.DDD?.Show ?? 'Show' } }, { @@ -118,7 +118,7 @@ function Label(className: string, I18N) { key: 'distance', type: 'number', props: { - label: I18N.DDD?.Distance ?? 'Distance' + label: I18N?.DDD?.Distance ?? 'Distance' } }, { @@ -126,7 +126,7 @@ function Label(className: string, I18N) { key: 'formatter', type: 'input', props: { - label: I18N.DDD?.Formatter ?? 'Formatter' + label: I18N?.DDD?.Formatter ?? 'Formatter' } } ] @@ -135,7 +135,7 @@ function Label(className: string, I18N) { key: 'textStyle', wrappers: ['panel'], props: { - label: I18N.DDD?.TextStyle ?? 'Text Style' + label: I18N?.DDD?.TextStyle ?? 'Text Style' }, fieldGroup: [ { @@ -151,18 +151,18 @@ export function Common3D(className: string, I18N) { return AccordionWrappers([ { key: 'label', - label: I18N.DDD?.Label ?? 'Label', + label: I18N?.DDD?.Label ?? 'Label', fieldGroup: Label(className, I18N) }, { key: 'emphasis', - label: I18N.DDD?.Emphasis ?? 'Emphasis', + label: I18N?.DDD?.Emphasis ?? 'Emphasis', fieldGroup: [ { key: 'itemStyle', wrappers: ['panel'], props: { - label: I18N.DDD?.ItemStyle ?? 'Item Style' + label: I18N?.DDD?.ItemStyle ?? 'Item Style' }, fieldGroup: [ { @@ -176,7 +176,7 @@ export function Common3D(className: string, I18N) { key: 'label', wrappers: ['panel'], props: { - label: I18N.DDD?.Label ?? 'Label' + label: I18N?.DDD?.Label ?? 'Label' }, fieldGroup: Label(className, I18N) } diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/boxplot.ts b/libs/story-angular/widgets/analytical-card/schemas/series/boxplot.ts index 03d7706b4..956fd1b05 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/boxplot.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/boxplot.ts @@ -5,7 +5,7 @@ export function BoxplotCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'seriesStyle', - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/funnel.ts b/libs/story-angular/widgets/analytical-card/schemas/series/funnel.ts index 5393d1eac..573ec526a 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/funnel.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/funnel.ts @@ -18,7 +18,7 @@ export function FunnelCapacity(className: string, I18N) { key: 'seriesStyle', hideExpression: `!field.parent.model.__showSeriesAttributes__`, templateOptions: { - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', keyShow: '__showSeriesAttributes__' }, fieldGroup: [ @@ -30,7 +30,7 @@ export function FunnelCapacity(className: string, I18N) { key: 'funnelAlign', type: 'select', templateOptions: { - label: I18N.SeriesStyle?.FunnelAlign ?? 'Funnel Align', + label: I18N?.SeriesStyle?.FunnelAlign ?? 'Funnel Align', options: [ { value: null, label: 'None' }, { value: 'left', label: 'Left' }, diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/line.ts b/libs/story-angular/widgets/analytical-card/schemas/series/line.ts index 98f7a77a4..76eaf6296 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/line.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/line.ts @@ -7,7 +7,7 @@ export function LineCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'seriesStyle', - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', fieldGroup: [ SeriesCommon(className, I18N), { @@ -18,7 +18,7 @@ export function LineCapacity(className: string, I18N) { key: 'showSymbol', type: 'checkbox', props: { - label: I18N.Line?.ShowSymbol ?? 'Show Symbol' + label: I18N?.Line?.ShowSymbol ?? 'Show Symbol' } }, { @@ -26,7 +26,7 @@ export function LineCapacity(className: string, I18N) { key: 'showAllSymbol', type: 'checkbox', props: { - label: I18N.Line?.ShowAllSymbol ?? 'Show All Symbol' + label: I18N?.Line?.ShowAllSymbol ?? 'Show All Symbol' } }, @@ -37,7 +37,7 @@ export function LineCapacity(className: string, I18N) { key: 'smooth', type: 'checkbox', props: { - label: I18N.Line?.Smooth ?? 'Smooth' + label: I18N?.Line?.Smooth ?? 'Smooth' } }, @@ -46,7 +46,7 @@ export function LineCapacity(className: string, I18N) { key: 'stack', type: 'input', props: { - label: I18N.Line?.Stack ?? 'Stack' + label: I18N?.Line?.Stack ?? 'Stack' } }, { @@ -54,7 +54,7 @@ export function LineCapacity(className: string, I18N) { key: 'step', type: 'select', props: { - label: I18N.Line?.Step ?? 'Step', + label: I18N?.Line?.Step ?? 'Step', options: [ { value: true, label: 'True' }, { value: false, label: 'False' }, diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/map.ts b/libs/story-angular/widgets/analytical-card/schemas/series/map.ts index 6134b9047..08a8dffe1 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/map.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/map.ts @@ -5,7 +5,7 @@ export function MapCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'seriesStyle', - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', fieldGroup: [ SeriesCommon(className, I18N), { diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/pie.ts b/libs/story-angular/widgets/analytical-card/schemas/series/pie.ts index 1a78fd265..d77cb847b 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/pie.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/pie.ts @@ -14,7 +14,7 @@ export function PieCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'seriesStyle', - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/sankey.ts b/libs/story-angular/widgets/analytical-card/schemas/series/sankey.ts index 3544ea2e1..beb74cc21 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/sankey.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/sankey.ts @@ -16,7 +16,7 @@ export function SankeyCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'seriesStyle', - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/scatter.ts b/libs/story-angular/widgets/analytical-card/schemas/series/scatter.ts index c334237ec..4386175db 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/scatter.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/scatter.ts @@ -1,14 +1,11 @@ import { AccordionWrappers, FORMLY_ROW } from '@metad/story/designer' import { - Borders, + BackgroundStyleAccordionWrappers, EmphasisAccordionWrappers, ItemStyleAccordionWrappers, - MarkLineExpansion, - Opacity, - SelectExpansion, + MarkLineAccordionWrappers, + SelectAccordionWrappers, SeriesCommon, - Shadows, - SingleColor, Symbols } from '../common' import { LabelAccordionWrappers, LabelLayoutAccordionWrappers, LabelLineAccordionWrappers } from './label' @@ -17,7 +14,7 @@ export function ScatterCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'seriesStyle', - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, @@ -40,49 +37,10 @@ export function ScatterCapacity(className: string, I18N) { ...LabelLineAccordionWrappers(className, I18N), ...LabelLayoutAccordionWrappers(className, I18N), ...EmphasisAccordionWrappers(className, I18N), - { - key: '__showSelect__', - type: 'empty' - }, - { - key: '__showMarkLine__', - type: 'empty' - }, - { - key: 'showBackground', - type: 'empty' - }, - { - wrappers: ['accordion'], - props: { - elevationZ: true - }, - fieldGroup: [ - SelectExpansion(className, I18N, '__showSelect__'), - MarkLineExpansion(className, I18N, '__showMarkLine__'), - BackgroundStyleExpansion(className, I18N, 'showBackground') - ] - } + ...SelectAccordionWrappers(className, I18N), + ...MarkLineAccordionWrappers(className, I18N), + ...BackgroundStyleAccordionWrappers(className, I18N) ] } ]) } - -function BackgroundStyleExpansion(className: string, I18N, keyShow: string) { - return { - key: 'backgroundStyle', - hideExpression: `!field.parent && !field.parent.model.` + keyShow, - props: { - label: I18N?.Bar?.Background ?? 'Background', - toggleable: true, - keyShow: keyShow - }, - fieldGroupClassName: FORMLY_ROW, - fieldGroup: [ - SingleColor(className, I18N), - ...Borders(className, I18N), - ...Shadows(className, I18N), - Opacity(className, I18N) - ] - } -} diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/scatter3D.ts b/libs/story-angular/widgets/analytical-card/schemas/series/scatter3D.ts index a9e760c18..fd8d8393f 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/scatter3D.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/scatter3D.ts @@ -6,7 +6,7 @@ export function Scatter3DCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'seriesStyle', - label: I18N.DDD?.BarSeriesTitle ?? 'Series Attributes', + label: I18N?.DDD?.BarSeriesTitle ?? 'Series Attributes', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, @@ -17,7 +17,7 @@ export function Scatter3DCapacity(className: string, I18N) { key: 'blendMode', type: 'select', templateOptions: { - label: I18N.DDD?.BlendMode ?? 'Blend Mode', + label: I18N?.DDD?.BlendMode ?? 'Blend Mode', options: [ { value: null, label: 'None' }, { value: 'source-over', label: 'alpha 混合' }, @@ -30,7 +30,7 @@ export function Scatter3DCapacity(className: string, I18N) { key: 'silent', type: 'checkbox', props: { - label: I18N.DDD?.Silent ?? 'Silent' + label: I18N?.DDD?.Silent ?? 'Silent' } }, ] @@ -38,7 +38,7 @@ export function Scatter3DCapacity(className: string, I18N) { ...AccordionWrappers([ { key: 'itemStyle', - label: I18N.DDD?.ItemStyle ?? 'Item Style', + label: I18N?.DDD?.ItemStyle ?? 'Item Style', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/sunburst.ts b/libs/story-angular/widgets/analytical-card/schemas/series/sunburst.ts index 36b4df327..0e35ea008 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/sunburst.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/sunburst.ts @@ -20,7 +20,7 @@ export function SunburstCapacity(className: string, I18N) { key: 'seriesStyle', hideExpression: `!field.parent.model || !field.parent.model.${keyShow}`, props: { - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', keyShow }, fieldGroup: [ diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/themeRiver.ts b/libs/story-angular/widgets/analytical-card/schemas/series/themeRiver.ts index 2653e46d2..a76182379 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/themeRiver.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/themeRiver.ts @@ -16,7 +16,7 @@ export function ThemeRiverCapacity(className: string, I18N) { key: 'boundaryGap', type: 'json', props: { - label: I18N.SeriesStyle?.BoundaryGap ?? 'Boundary Gap', + label: I18N?.SeriesStyle?.BoundaryGap ?? 'Boundary Gap', placeholder: '["10%", "10%"]', autosize: true } diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/tree.ts b/libs/story-angular/widgets/analytical-card/schemas/series/tree.ts index 60f5f1320..f6b707af0 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/tree.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/tree.ts @@ -1,4 +1,3 @@ -import { C_FORMLY_INITIAL_VALUE } from '@metad/formly-mat/expansion' import { Positions, UniversalTransition } from '../common' import { FORMLY_ROW } from '@metad/story/designer' @@ -11,14 +10,14 @@ export function TreeCapacity(className, I18N?) { }, { wrappers: ['accordion'], - templateOptions: { + props: { elevationZ: true }, fieldGroup: [ { key: 'seriesStyle', hideExpression: `!field.parent.model || !field.parent.model.${keyShow}`, - templateOptions: { + props: { label: I18N?.Tree?.SeriesStyle?.Title ?? 'Series Style', keyShow }, @@ -33,7 +32,7 @@ export function TreeCapacity(className, I18N?) { // className, // key: 'layout', // type: 'select', - // templateOptions: { + // props: { // label: I18N?.Tree?.SeriesStyle?.Layout ?? 'Layout', // options: [ // { value: 'orthogonal', label: I18N?.Tree?.SeriesStyle?.Orthogonal ?? 'Orthogonal' }, @@ -46,7 +45,7 @@ export function TreeCapacity(className, I18N?) { className, key: 'orient', type: 'select', - templateOptions: { + props: { label: I18N?.Tree?.SeriesStyle?.Orient ?? 'Orient', options: [ { value: 'LR', label: 'LR' }, @@ -61,7 +60,7 @@ export function TreeCapacity(className, I18N?) { className, key: 'edgeShape', type: 'select', - templateOptions: { + props: { label: I18N?.Tree?.SeriesStyle?.EdgeShape ?? 'Edge Shape', options: [ { value: 'curve', label: 'Curve' }, @@ -73,7 +72,7 @@ export function TreeCapacity(className, I18N?) { className, key: 'edgeForkPosition', type: 'input', - templateOptions: { + props: { label: I18N?.Tree?.SeriesStyle?.EdgeForkPosition ?? 'Edge Fork Position' } }, @@ -82,7 +81,7 @@ export function TreeCapacity(className, I18N?) { className, key: 'symbolSize', type: 'input', - templateOptions: { + props: { label: I18N?.Common?.SymbolSize ?? 'Symbol Size', type: 'number' } @@ -92,7 +91,7 @@ export function TreeCapacity(className, I18N?) { key: 'initialTreeDepth', type: 'input', defaultValue: 2, - templateOptions: { + props: { label: I18N?.Tree?.SeriesStyle?.InitialTreeDepth ?? 'Initial Tree Depth', type: 'number' } @@ -108,7 +107,7 @@ export function TreeCapacity(className, I18N?) { }, { wrappers: ['accordion'], - templateOptions: { + props: { elevationZ: true }, fieldGroup: [LeavesExpansion(className, I18N, '__showLeaves__')] @@ -137,7 +136,7 @@ export function TreeLabel(className, I18N?) { return { key: 'label', wrappers: ['panel'], - templateOptions: { + props: { label: I18N?.Common?.Label ?? 'Label' }, fieldGroupClassName: FORMLY_ROW, @@ -146,7 +145,7 @@ export function TreeLabel(className, I18N?) { className, key: 'position', type: 'select', - templateOptions: { + props: { label: I18N?.Common?.Position ?? 'Position', options: [ { @@ -167,9 +166,8 @@ export function TreeLabel(className, I18N?) { export function Emphasis(className: string, I18N) { return { key: 'emphasis', - wrappers: ['expansion'], - defaultValue: C_FORMLY_INITIAL_VALUE, - templateOptions: { + wrappers: ['accordion'], + props: { label: I18N?.EMPHASIS?.TITLE ?? 'Emphasis', toggleable: true }, @@ -179,7 +177,7 @@ export function Emphasis(className: string, I18N) { className, key: 'focus', type: 'select', - templateOptions: { + props: { label: I18N?.EMPHASIS?.FOCUS ?? 'Focus', options: [ { value: null, label: 'None' }, @@ -195,7 +193,7 @@ export function Emphasis(className: string, I18N) { className, key: 'blurScope', type: 'select', - templateOptions: { + props: { label: I18N?.EMPHASIS?.BlurScope ?? 'Blur Scope', options: [ { value: null, label: 'None' }, diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/treemap.ts b/libs/story-angular/widgets/analytical-card/schemas/series/treemap.ts index 318008fa7..dd00fe298 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/treemap.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/treemap.ts @@ -6,7 +6,7 @@ export function TreemapCapacity(className: string, I18N?) { return AccordionWrappers([ { key: 'seriesStyle', - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, diff --git a/libs/story-angular/widgets/analytical-card/schemas/series/waterfall.ts b/libs/story-angular/widgets/analytical-card/schemas/series/waterfall.ts index 52c157f75..bd8456bb9 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/series/waterfall.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/series/waterfall.ts @@ -1,14 +1,11 @@ import { AccordionWrappers, FORMLY_ROW } from '@metad/story/designer' import { - Borders, + BackgroundStyleAccordionWrappers, EmphasisAccordionWrappers, ItemStyleAccordionWrappers, - MarkLineExpansion, - Opacity, - SelectExpansion, + MarkLineAccordionWrappers, + SelectAccordionWrappers, SeriesCommon, - Shadows, - SingleColor, Stacks } from '../common' import { LabelAccordionWrappers, LabelLineAccordionWrappers } from './label' @@ -17,7 +14,7 @@ export function WaterfallCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'seriesStyle', - label: I18N.SeriesStyle?.Title ?? 'Series Attributes', + label: I18N?.SeriesStyle?.Title ?? 'Series Attributes', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, @@ -115,49 +112,10 @@ export function WaterfallCapacity(className: string, I18N) { ...LabelAccordionWrappers(className, I18N), ...LabelLineAccordionWrappers(className, I18N), ...EmphasisAccordionWrappers(className, I18N), - { - key: '__showSelect__', - type: 'empty' - }, - { - key: '__showMarkLine__', - type: 'empty' - }, - { - key: 'showBackground', - type: 'empty' - }, - { - wrappers: ['accordion'], - props: { - elevationZ: true - }, - fieldGroup: [ - SelectExpansion(className, I18N, '__showSelect__'), - MarkLineExpansion(className, I18N, '__showMarkLine__'), - BackgroundStyleExpansion(className, I18N, 'showBackground') - ] - } + ...BackgroundStyleAccordionWrappers(className, I18N), + ...SelectAccordionWrappers(className, I18N), + ...MarkLineAccordionWrappers(className, I18N) ] } ]) } - -function BackgroundStyleExpansion(className: string, I18N, keyShow: string) { - return { - key: 'backgroundStyle', - hideExpression: `!field.parent && !field.parent.model.` + keyShow, - props: { - label: I18N?.Bar?.Background ?? 'Background', - toggleable: true, - keyShow: keyShow - }, - fieldGroupClassName: FORMLY_ROW, - fieldGroup: [ - SingleColor(className, I18N), - ...Borders(className, I18N), - ...Shadows(className, I18N), - Opacity(className, I18N) - ] - } -} diff --git a/libs/story-angular/widgets/analytical-card/schemas/title.ts b/libs/story-angular/widgets/analytical-card/schemas/title.ts index 5606f2496..07adeec42 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/title.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/title.ts @@ -1,3 +1,5 @@ +import { FORMLY_ROW } from "@metad/story/designer" + export function TitleCapacity(className: string, I18N) { const showKey = '__showTitle__' return [ @@ -15,17 +17,17 @@ export function TitleCapacity(className: string, I18N) { key: 'title', hideExpression: `!field.parent.model || !field.parent.model.` + showKey, props: { - label: I18N.Title?.Title ?? 'Title', + label: I18N?.Title?.Title ?? 'Title', keyShow: showKey }, - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { className, key: 'text', type: 'input', props: { - label: I18N.Title?.Text ?? 'Text', + label: I18N?.Title?.Text ?? 'Text', } }, { @@ -33,7 +35,7 @@ export function TitleCapacity(className: string, I18N) { key: 'link', type: 'input', props: { - label: I18N.Title?.Link ?? 'Link', + label: I18N?.Title?.Link ?? 'Link', } }, { @@ -41,7 +43,7 @@ export function TitleCapacity(className: string, I18N) { key: 'subtext', type: 'input', props: { - label: I18N.Title?.SubText ?? 'SubText', + label: I18N?.Title?.SubText ?? 'SubText', } }, { @@ -49,7 +51,7 @@ export function TitleCapacity(className: string, I18N) { key: 'sublink', type: 'input', props: { - label: I18N.Title?.SubLink ?? 'SubLink', + label: I18N?.Title?.SubLink ?? 'SubLink', } }, @@ -58,7 +60,7 @@ export function TitleCapacity(className: string, I18N) { key: 'left', type: 'input', props: { - label: I18N.Title?.Left ?? 'Left', + label: I18N?.Title?.Left ?? 'Left', } }, { @@ -66,7 +68,7 @@ export function TitleCapacity(className: string, I18N) { key: 'top', type: 'input', props: { - label: I18N.Title?.Top ?? 'Top', + label: I18N?.Title?.Top ?? 'Top', } }, { @@ -74,7 +76,7 @@ export function TitleCapacity(className: string, I18N) { key: 'right', type: 'input', props: { - label: I18N.Title?.Right ?? 'Right', + label: I18N?.Title?.Right ?? 'Right', } }, { @@ -82,7 +84,7 @@ export function TitleCapacity(className: string, I18N) { key: 'bottom', type: 'input', props: { - label: I18N.Title?.Bottom ?? 'Bottom', + label: I18N?.Title?.Bottom ?? 'Bottom', } }, { @@ -90,12 +92,12 @@ export function TitleCapacity(className: string, I18N) { key: 'textAlign', type: 'select', props: { - label: I18N.Common?.TextAlign?.Title ?? 'Title', + label: I18N?.Common?.TextAlign?.Title ?? 'Title', options: [ - { value: 'auto', label: I18N.Common?.TextAlign?.Auto ?? 'Auto' }, - { value: 'left', label: I18N.Common?.TextAlign?.Left ?? 'Left' }, - { value: 'right', label: I18N.Common?.TextAlign?.Right ?? 'Right' }, - { value: 'center', label: I18N.Common?.TextAlign?.Center ?? 'Center' } + { value: 'auto', label: I18N?.Common?.TextAlign?.Auto ?? 'Auto' }, + { value: 'left', label: I18N?.Common?.TextAlign?.Left ?? 'Left' }, + { value: 'right', label: I18N?.Common?.TextAlign?.Right ?? 'Right' }, + { value: 'center', label: I18N?.Common?.TextAlign?.Center ?? 'Center' } ] } } diff --git a/libs/story-angular/widgets/analytical-card/schemas/tooltip.ts b/libs/story-angular/widgets/analytical-card/schemas/tooltip.ts index 2207dfe4f..9ff518a77 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/tooltip.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/tooltip.ts @@ -5,7 +5,7 @@ export function TooltipCapacity(className: string, I18N) { return AccordionWrappers([ { key: 'tooltip', - label: I18N.TOOLTIP?.TITLE ?? 'Tooltip', + label: I18N?.TOOLTIP?.TITLE ?? 'Tooltip', fieldGroup: [ { fieldGroupClassName: FORMLY_ROW, diff --git a/libs/story-angular/widgets/analytical-card/schemas/visualMap.ts b/libs/story-angular/widgets/analytical-card/schemas/visualMap.ts index 22f3e5b1d..5a114c351 100644 --- a/libs/story-angular/widgets/analytical-card/schemas/visualMap.ts +++ b/libs/story-angular/widgets/analytical-card/schemas/visualMap.ts @@ -9,38 +9,6 @@ export function VisualMapCapacity(className: string, I18N?) { }]) } -// export function VisualMapsCapacity(className: string, I18N?) { -// const keyShow = '__showVisualMaps__' -// return [ -// { -// key: keyShow, -// type: 'empty' -// }, -// { -// wrappers: ['accordion'], -// props: { -// elevationZ: true -// }, -// fieldGroup: [ -// { -// key: 'visualMaps', -// type: 'array-tabs', -// hideExpression: `!field.parent.model || !field.parent.model.` + keyShow, -// props: { -// label: I18N?.VisualMap?.Title ?? 'VisualMaps', -// labelField: 'type', -// removeLabel: I18N?.VisualMap?.RemoveLabel ?? 'Remove', -// keyShow -// }, -// fieldArray: { -// fieldGroup: VisualMap(className, I18N) -// } -// } -// ] -// } -// ] -// } - export function VisualMap(className: string, I18N?) { const isNotPiecewise = `!model || model.type !== 'piecewise'` return [ @@ -72,7 +40,7 @@ export function VisualMap(className: string, I18N?) { key: 'show', type: 'toggle', props: { - label: I18N.VisualMap?.Show ?? 'Show' + label: I18N?.VisualMap?.Show ?? 'Show' } }, @@ -83,7 +51,7 @@ export function VisualMap(className: string, I18N?) { key: 'inverse', type: 'checkbox', props: { - label: I18N.VisualMap?.Inverse ?? 'Inverse' + label: I18N?.VisualMap?.Inverse ?? 'Inverse' } }, @@ -92,7 +60,7 @@ export function VisualMap(className: string, I18N?) { key: 'realtime', type: 'checkbox', props: { - label: I18N.VisualMap?.Realtime ?? 'Realtime' + label: I18N?.VisualMap?.Realtime ?? 'Realtime' } }, { @@ -100,7 +68,7 @@ export function VisualMap(className: string, I18N?) { key: 'calculable', type: 'checkbox', props: { - label: I18N.VisualMap?.Calculable ?? 'Calculable' + label: I18N?.VisualMap?.Calculable ?? 'Calculable' } }, { @@ -108,7 +76,7 @@ export function VisualMap(className: string, I18N?) { key: 'min', type: 'input', props: { - label: I18N.VisualMap?.Min ?? 'Min', + label: I18N?.VisualMap?.Min ?? 'Min', type: 'number' } }, @@ -117,7 +85,7 @@ export function VisualMap(className: string, I18N?) { key: 'max', type: 'input', props: { - label: I18N.VisualMap?.Max ?? 'Max', + label: I18N?.VisualMap?.Max ?? 'Max', type: 'number' } }, @@ -126,7 +94,7 @@ export function VisualMap(className: string, I18N?) { key: 'range', type: 'json', props: { - label: I18N.VisualMap?.Range ?? 'Range', + label: I18N?.VisualMap?.Range ?? 'Range', placeholder: `[number, number]`, autosize: true } @@ -136,7 +104,7 @@ export function VisualMap(className: string, I18N?) { key: 'showLabel', type: 'checkbox', props: { - label: I18N.VisualMap?.ShowLabel ?? 'Show Label' + label: I18N?.VisualMap?.ShowLabel ?? 'Show Label' } }, { @@ -144,7 +112,7 @@ export function VisualMap(className: string, I18N?) { key: 'text', type: 'json', props: { - label: I18N.VisualMap?.Text ?? 'Text', + label: I18N?.VisualMap?.Text ?? 'Text', placeholder: `["High", "Low"]`, autosize: true } @@ -154,7 +122,7 @@ export function VisualMap(className: string, I18N?) { key: 'precision', type: 'input', props: { - label: I18N.VisualMap?.Precision ?? 'Precision', + label: I18N?.VisualMap?.Precision ?? 'Precision', type: 'number' } }, @@ -163,7 +131,7 @@ export function VisualMap(className: string, I18N?) { key: 'splitNumber', type: 'input', props: { - label: I18N.VisualMap?.SplitNumber ?? 'Split Number', + label: I18N?.VisualMap?.SplitNumber ?? 'Split Number', type: 'number' }, expressions: { @@ -175,7 +143,7 @@ export function VisualMap(className: string, I18N?) { key: 'pieces', type: 'json', props: { - label: I18N.VisualMap?.Pieces ?? 'Pieces', + label: I18N?.VisualMap?.Pieces ?? 'Pieces', autosize: true }, expressions: { @@ -187,7 +155,7 @@ export function VisualMap(className: string, I18N?) { key: 'itemGap', type: 'input', props: { - label: I18N.VisualMap?.ItemGap ?? 'Item Gap', + label: I18N?.VisualMap?.ItemGap ?? 'Item Gap', type: 'number' }, expressions: { @@ -212,14 +180,14 @@ export function VisualMap(className: string, I18N?) { ...AccordionWrappers([ { key: 'inRange', - label: I18N.VisualMap?.InRange ?? 'In Range', + label: I18N?.VisualMap?.InRange ?? 'In Range', fieldGroup: [ { key: 'color', type: 'json', props: { - label: I18N.Common?.Color ?? 'Color', - placeholder: I18N.Common?.ColorJSONPlaceholder ?? 'Color by JSON format', + label: I18N?.Common?.Color ?? 'Color', + placeholder: I18N?.Common?.ColorJSONPlaceholder ?? 'Color by JSON format', autosize: true } }, @@ -227,7 +195,7 @@ export function VisualMap(className: string, I18N?) { key: 'symbolSize', type: 'json', props: { - label: I18N.VisualMap?.SymbolSize ?? 'SymbolSize', + label: I18N?.VisualMap?.SymbolSize ?? 'SymbolSize', placeholder: `[number, number]`, autosize: true } @@ -236,7 +204,7 @@ export function VisualMap(className: string, I18N?) { key: 'colorLightness', type: 'json', props: { - label: I18N.VisualMap?.ColorLightness ?? 'Color Lightness', + label: I18N?.VisualMap?.ColorLightness ?? 'Color Lightness', placeholder: `[number, number]`, autosize: true } @@ -245,14 +213,14 @@ export function VisualMap(className: string, I18N?) { }, { key: 'outOfRange', - label: I18N.VisualMap?.OutofRange ?? 'Out of Range', + label: I18N?.VisualMap?.OutofRange ?? 'Out of Range', fieldGroup: [ { key: 'color', type: 'json', props: { - label: I18N.Common?.Color ?? 'Color', - placeholder: I18N.Common?.ColorJSONPlaceholder ?? 'Color by JSON format', + label: I18N?.Common?.Color ?? 'Color', + placeholder: I18N?.Common?.ColorJSONPlaceholder ?? 'Color by JSON format', autosize: true } }, @@ -260,7 +228,7 @@ export function VisualMap(className: string, I18N?) { key: 'symbolSize', type: 'json', props: { - label: I18N.VisualMap?.SymbolSize ?? 'SymbolSize', + label: I18N?.VisualMap?.SymbolSize ?? 'SymbolSize', placeholder: `[number, number]`, autosize: true } @@ -269,7 +237,7 @@ export function VisualMap(className: string, I18N?) { key: 'colorLightness', type: 'json', props: { - label: I18N.VisualMap?.ColorLightness ?? 'Color Lightness', + label: I18N?.VisualMap?.ColorLightness ?? 'Color Lightness', placeholder: `[number]`, autosize: true } @@ -278,21 +246,21 @@ export function VisualMap(className: string, I18N?) { }, { key: 'controller', - label: I18N.VisualMap?.Controller ?? 'Controller', + label: I18N?.VisualMap?.Controller ?? 'Controller', fieldGroup: [ { key: 'inRange', wrappers: ['panel'], props: { - label: I18N.VisualMap?.InRange ?? 'In Range' + label: I18N?.VisualMap?.InRange ?? 'In Range' }, fieldGroup: [ { key: 'color', type: 'json', props: { - label: I18N.Common?.Color ?? 'Color', - placeholder: I18N.Common?.ColorJSONPlaceholder ?? 'Color by JSON format', + label: I18N?.Common?.Color ?? 'Color', + placeholder: I18N?.Common?.ColorJSONPlaceholder ?? 'Color by JSON format', autosize: true } } @@ -302,15 +270,15 @@ export function VisualMap(className: string, I18N?) { key: 'outOfRange', wrappers: ['panel'], props: { - label: I18N.VisualMap?.OutofRange ?? 'Out of Range' + label: I18N?.VisualMap?.OutofRange ?? 'Out of Range' }, fieldGroup: [ { key: 'color', type: 'json', props: { - label: I18N.Common?.Color ?? 'Color', - placeholder: I18N.Common?.ColorJSONPlaceholder ?? 'Color by JSON format', + label: I18N?.Common?.Color ?? 'Color', + placeholder: I18N?.Common?.ColorJSONPlaceholder ?? 'Color by JSON format', autosize: true } } diff --git a/libs/story-angular/widgets/analytical-grid/analytical-grid-styling.schema.ts b/libs/story-angular/widgets/analytical-grid/analytical-grid-styling.schema.ts index 4e4fd056f..56e61ab9b 100644 --- a/libs/story-angular/widgets/analytical-grid/analytical-grid-styling.schema.ts +++ b/libs/story-angular/widgets/analytical-grid/analytical-grid-styling.schema.ts @@ -2,12 +2,11 @@ import { Injectable } from '@angular/core' import { StoryWidget } from '@metad/story/core' import { AccordionWrappers, - Appearance, + Appearances, BaseDesignerSchemaService, BaseSchemaState, FORMLY_ROW, FORMLY_W_1_2, - FORMLY_W_FULL } from '@metad/story/designer' import { map } from 'rxjs/operators' @@ -18,20 +17,33 @@ export class AnalyticalGridStylingSchema extends BaseDesignerSchemaService { return [ { - wrappers: ['expansion'], + wrappers: ['accordion'], props: { - label: i18n?.Common?.ComponentStyling ?? 'Component Styling', - expanded: true + expandedMulti: true, + elevationZ: true, }, fieldGroup: [ { key: 'component', type: 'styling', - props: {} + props: { + label: i18n?.Common?.ComponentStyling ?? 'Component Styling', + expanded: true + } + }, + + { + key: 'appearance', + props: { + label: i18n?.Common?.Appearance ?? 'Appearance', + expanded: true, + }, + fieldGroupClassName: FORMLY_ROW, + fieldGroup: Appearances(FORMLY_W_1_2, i18n?.Common) } ] }, - Appearance(FORMLY_W_FULL, i18n?.Common), + ...AccordionWrappers([ { key: 'bar', diff --git a/libs/story-angular/widgets/analytical-grid/analytical-grid.schema.ts b/libs/story-angular/widgets/analytical-grid/analytical-grid.schema.ts index ab10cc8ee..4b7adf311 100644 --- a/libs/story-angular/widgets/analytical-grid/analytical-grid.schema.ts +++ b/libs/story-angular/widgets/analytical-grid/analytical-grid.schema.ts @@ -4,7 +4,10 @@ import { PropertyCapacity } from '@metad/components/property' import { ColorPalettes } from '@metad/core' import { PropertyCapacity as FormlyPropertyCapacity } from '@metad/components/property' import { + AccordionWrappers, DataSettingsSchemaService, + FORMLY_GAP_2, + FORMLY_MY_2, FORMLY_ROW, FORMLY_W_1_2, PresentationVariantExpansion, @@ -36,270 +39,280 @@ export class AnalyticalGridSchemaService extends DataSettingsSchemaService { ...PresentationVariantExpansion(Widgets?.Common, this.dataSettings$, this.entityType$, this.properties$), ) - dataSettings.wrappers = ['expansion'] - - const className = FORMLY_W_1_2 + return [ { wrappers: ['panel'], - templateOptions: { + props: { padding: true }, fieldGroup: [ { key: 'title', type: 'input', - templateOptions: { + props: { label: Widgets?.Common?.Title ?? 'Title', required: true } } ] }, - dataSettings, - - { - key: 'options', - wrappers: ['expansion'], - templateOptions: { - label: Widgets?.AnalyticalGrid?.GridOptions ?? 'Grid Options', - expanded: true + ...AccordionWrappers([ + { + key: 'dataSettings', + label: Widgets?.Common?.DATA_SETTINGS ?? 'Data Settings', + toggleable: false, + expanded: true, + fieldGroup: dataSettings.fieldGroup[0].fieldGroup }, - fieldGroup: [ - { - fieldGroupClassName: FORMLY_ROW, - fieldGroup: [ - { - className, - key: 'showToolbar', - type: 'checkbox', - templateOptions: { - label: Widgets?.AnalyticalGrid?.showToolbar ?? 'Show Toolbar' - } - }, - { - - className, - key: 'hideDataDownload', - type: 'checkbox', - templateOptions: { - label: Widgets?.AnalyticalGrid?.HideDataDownload ?? 'Hide Data Download' - } - }, - { - className, - key: 'strip', - type: 'checkbox', - templateOptions: { - label: Widgets?.AnalyticalGrid?.Strip ?? 'Strip' - } - }, - { - className, - key: 'grid', - type: 'checkbox', - templateOptions: { - label: Widgets?.AnalyticalGrid?.Grid ?? 'Grid' - } - }, - { - className, - key: 'sticky', - type: 'checkbox', - templateOptions: { - label: Widgets?.AnalyticalGrid?.TableHeaderSticky ?? 'Table Header Sticky' - } - }, - { - className, - key: 'sortable', - type: 'checkbox', - templateOptions: { - label: Widgets?.AnalyticalGrid?.Sortable ?? 'Sortable' - } - }, - { - className, - key: 'selectable', - type: 'checkbox', - templateOptions: { - label: Widgets?.AnalyticalGrid?.ColumnSelectable ?? 'Column Selectable' - } - }, - ] - }, - - { - fieldGroupClassName: FORMLY_ROW, - fieldGroup: [ - { - className, - key: 'paging', - type: 'checkbox', - templateOptions: { - label: Widgets?.AnalyticalGrid?.Paging ?? 'Paging' - } - }, - { - className, - key: 'pageSize', - type: 'input', - templateOptions: { - type: 'number', - label: Widgets?.AnalyticalGrid?.PageSize ?? 'Page Size' - } - }, - - { - className, - key: 'initialRowLevel', - type: 'input', - templateOptions: { - label: Widgets?.AnalyticalGrid?.InitialRowLevel ?? 'Initial Row Level', - type: 'number' - } - }, - { - className, - key: 'initialColumnLevel', - type: 'input', - templateOptions: { - label: Widgets?.AnalyticalGrid?.InitialColumnLevel ?? 'Initial Column Level', - type: 'number' - } - }, - - { - className, - key: 'digitsInfo', - type: 'input', - props: { - label: Widgets?.AnalyticalGrid?.DigitsInfo ?? 'Digits Info', - } - }, - { - className, - key: 'unit', - type: 'input', - props: { - label: Widgets?.AnalyticalGrid?.Unit ?? 'Unit', - } - }, - { - className, - key: 'currencyCode', - type: 'input', - props: { - label: Widgets?.AnalyticalGrid?.CurrencyCode ?? 'Currency Code', - } - } - ] - } - ] - } + ], {expandedMulti: true}), + ...getGridOptionsSchema(Widgets) ] as any } } - -export function GridOptionsSchema(className: string, Widgets) { - - return [ +export function getGridOptionsSchema(Widgets) { + const className = FORMLY_W_1_2 + return AccordionWrappers([ { - fieldGroupClassName: FORMLY_ROW, + key: 'options', + label: Widgets?.AnalyticalGrid?.GridOptions ?? 'Grid Options', + toggleable: false, + expanded: true, fieldGroup: [ { - className, - key: 'showToolbar', - type: 'toggle', - templateOptions: { - label: Widgets?.AnalyticalGrid?.showToolbar ?? 'Show Toolbar' - } - } - ] - }, - - { - fieldGroupClassName: FORMLY_ROW, - fieldGroup: [ - { - className, - key: 'exportExcel', - type: 'toggle', - templateOptions: { - label: Widgets?.AnalyticalGrid?.exportExcel ?? 'Export Excel' - } + fieldGroupClassName: FORMLY_ROW, + fieldGroup: [ + { + className, + key: 'showToolbar', + type: 'checkbox', + props: { + label: Widgets?.AnalyticalGrid?.showToolbar ?? 'Show Toolbar' + } + }, + { + + className, + key: 'hideDataDownload', + type: 'checkbox', + props: { + label: Widgets?.AnalyticalGrid?.HideDataDownload ?? 'Hide Data Download' + } + }, + { + className, + key: 'strip', + type: 'checkbox', + props: { + label: Widgets?.AnalyticalGrid?.Strip ?? 'Strip' + } + }, + { + className, + key: 'grid', + type: 'checkbox', + props: { + label: Widgets?.AnalyticalGrid?.Grid ?? 'Grid' + } + }, + { + className, + key: 'sticky', + type: 'checkbox', + props: { + label: Widgets?.AnalyticalGrid?.TableHeaderSticky ?? 'Table Header Sticky' + } + }, + { + className, + key: 'sortable', + type: 'checkbox', + props: { + label: Widgets?.AnalyticalGrid?.Sortable ?? 'Sortable' + } + }, + { + className, + key: 'selectable', + type: 'checkbox', + props: { + label: Widgets?.AnalyticalGrid?.ColumnSelectable ?? 'Column Selectable' + } + }, + ] }, - { - className, - key: 'columnPinning', - type: 'toggle', - templateOptions: { - label: Widgets?.AnalyticalGrid?.columnPinning ?? 'Column Pinning' - } - } - ] - }, - { - fieldGroupClassName: FORMLY_ROW, - fieldGroup: [ - { - className, - key: 'allowFiltering', - type: 'toggle', - templateOptions: { label: 'Allow Filtering' } - }, { - className, - key: 'filterMode', - type: 'select', - templateOptions: { - label: 'Allow Filtering', - options: [ - { value: 'quickFilter', label: 'Quick Filter' }, - { value: 'excelStyleFilter', label: 'Excel Style Filter' } - ] - } + fieldGroupClassName: FORMLY_ROW, + fieldGroup: [ + { + className, + key: 'paging', + type: 'checkbox', + props: { + label: Widgets?.AnalyticalGrid?.Paging ?? 'Paging' + } + }, + { + className, + key: 'pageSize', + type: 'input', + props: { + type: 'number', + label: Widgets?.AnalyticalGrid?.PageSize ?? 'Page Size' + } + }, + + { + className, + key: 'initialRowLevel', + type: 'input', + props: { + label: Widgets?.AnalyticalGrid?.InitialRowLevel ?? 'Initial Row Level', + type: 'number' + } + }, + { + className, + key: 'initialColumnLevel', + type: 'input', + props: { + label: Widgets?.AnalyticalGrid?.InitialColumnLevel ?? 'Initial Column Level', + type: 'number' + } + }, + + { + className, + key: 'digitsInfo', + type: 'input', + props: { + label: Widgets?.AnalyticalGrid?.DigitsInfo ?? 'Digits Info', + } + }, + { + className, + key: 'unit', + type: 'input', + props: { + label: Widgets?.AnalyticalGrid?.Unit ?? 'Unit', + } + }, + { + className, + key: 'currencyCode', + type: 'input', + props: { + label: Widgets?.AnalyticalGrid?.CurrencyCode ?? 'Currency Code', + } + } + ] } ] }, - { - fieldGroupClassName: FORMLY_ROW, - key: 'column', - wrappers: ['panel'], - fieldGroup: [ - { - className, - key: 'resizable', - type: 'checkbox', - templateOptions: { - label: 'Resizable' - } - }, - { - className, - key: 'width', - type: 'input', - templateOptions: { - type: 'number', - label: 'Width' - } - } - ] - } - ] + ]) } +// export function GridOptionsSchema(className: string, Widgets) { + +// return [ +// { +// fieldGroupClassName: FORMLY_ROW, +// fieldGroup: [ +// { +// className, +// key: 'showToolbar', +// type: 'toggle', +// props: { +// label: Widgets?.AnalyticalGrid?.showToolbar ?? 'Show Toolbar' +// } +// } +// ] +// }, + +// { +// fieldGroupClassName: FORMLY_ROW, +// fieldGroup: [ +// { +// className, +// key: 'exportExcel', +// type: 'toggle', +// props: { +// label: Widgets?.AnalyticalGrid?.exportExcel ?? 'Export Excel' +// } +// }, +// { +// className, +// key: 'columnPinning', +// type: 'toggle', +// props: { +// label: Widgets?.AnalyticalGrid?.columnPinning ?? 'Column Pinning' +// } +// } +// ] +// }, + +// { +// fieldGroupClassName: FORMLY_ROW, +// fieldGroup: [ +// { +// className, +// key: 'allowFiltering', +// type: 'toggle', +// props: { label: 'Allow Filtering' } +// }, +// { +// className, +// key: 'filterMode', +// type: 'select', +// props: { +// label: 'Allow Filtering', +// options: [ +// { value: 'quickFilter', label: 'Quick Filter' }, +// { value: 'excelStyleFilter', label: 'Excel Style Filter' } +// ] +// } +// } +// ] +// }, +// { +// fieldGroupClassName: FORMLY_ROW, +// key: 'column', +// wrappers: ['panel'], +// fieldGroup: [ +// { +// className, +// key: 'resizable', +// type: 'checkbox', +// props: { +// label: 'Resizable' +// } +// }, +// { +// className, +// key: 'width', +// type: 'input', +// props: { +// type: 'number', +// label: 'Width' +// } +// } +// ] +// } +// ] +// } + export function AnalyticsAnnotationSchema(Widgets, dataSettings$: Observable, entityType$: Observable) { return { key: 'analytics', + fieldGroupClassName: FORMLY_GAP_2 + ' ' + FORMLY_MY_2, fieldGroup: [ { key: 'rows', type: 'array', - templateOptions: { + props: { label: Widgets?.AnalyticalGrid?.Rows ?? 'Rows', hideDelete: true }, @@ -327,13 +340,13 @@ export function AnalyticsAnnotationSchema(Widgets, dataSettings$: Observable \ No newline at end of file diff --git a/libs/story-angular/widgets/analytical-grid/options/grid-settings.component.ts b/libs/story-angular/widgets/analytical-grid/options/grid-settings.component.ts new file mode 100644 index 000000000..72a44d8c2 --- /dev/null +++ b/libs/story-angular/widgets/analytical-grid/options/grid-settings.component.ts @@ -0,0 +1,65 @@ +import { CommonModule } from '@angular/common' +import { Component, forwardRef, inject } from '@angular/core' +import { toSignal } from '@angular/core/rxjs-interop' +import { ControlValueAccessor, FormGroup, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms' +import { cloneDeep } from '@metad/ocap-core' +import { FormlyModule } from '@ngx-formly/core' +import { TranslateModule, TranslateService } from '@ngx-translate/core' +import { map } from 'rxjs/operators' +import { getGridOptionsSchema } from '../analytical-grid.schema' + +@Component({ + standalone: true, + imports: [CommonModule, FormsModule, ReactiveFormsModule, TranslateModule, FormlyModule], + selector: 'ngm-grid-settings', + templateUrl: 'grid-settings.component.html', + styles: [], + host: { + class: 'ngm-grid-settings' + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: forwardRef(() => NgmGridSettingsComponent) + } + ] +}) +export class NgmGridSettingsComponent implements ControlValueAccessor { + private readonly translateService = inject(TranslateService) + + formGroup = new FormGroup({}) + + fields = toSignal( + this.translateService.stream('Story.Widgets').pipe( + map((i18n) => { + return getGridOptionsSchema(i18n) + }) + ) + ) + + model = {} + options = {} + + onChange: (input: any) => void + onTouched: () => void + + writeValue(obj: any): void { + if (obj) { + this.formGroup.patchValue(obj) + this.model = cloneDeep(obj) + } + } + registerOnChange(fn: any): void { + this.onChange = fn + } + registerOnTouched(fn: any): void { + this.onTouched = fn + } + setDisabledState?(isDisabled: boolean): void { + isDisabled ? this.formGroup.disable() : this.formGroup.enable() + } + onModelChange(event) { + this.onChange(event) + } +} diff --git a/libs/story-angular/widgets/filter-bar/filter-bar.schema.ts b/libs/story-angular/widgets/filter-bar/filter-bar.schema.ts index a040d0c45..d94e6b3b7 100644 --- a/libs/story-angular/widgets/filter-bar/filter-bar.schema.ts +++ b/libs/story-angular/widgets/filter-bar/filter-bar.schema.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core' import { Dimension, nonNullable } from '@metad/ocap-core' import { PropertyCapacity } from '@metad/components/property' import { + AccordionWrappers, DataSettingsSchemaService, FORMLY_ROW, FORMLY_W_1_2, @@ -31,7 +32,23 @@ export class StoryFilterBarSchemaService ex return combineLatest([this.translate.stream('Story'), this.translate.stream('DateVariable')]).pipe( map(([STORY_DESIGNER, DateVariable]) => { this.STORY_DESIGNER = STORY_DESIGNER - return [this.filterBarDataSettings, this.getOptions(DateVariable)] + const i18nStoryWidgets = STORY_DESIGNER?.Widgets + return AccordionWrappers([ + { + key: 'dataSettings', + label: i18nStoryWidgets?.Common?.DATA_SETTINGS ?? 'Data Settings', + toggleable: false, + expanded: true, + fieldGroup: this.filterBarDataSettings.fieldGroup[0].fieldGroup + }, + { + key: 'options', + label: i18nStoryWidgets?.FilterBar?.OPTIONS ?? 'Options', + toggleable: false, + expanded: true, + fieldGroup: this.getOptions(DateVariable).fieldGroup + } + ], {expandedMulti: true}) }) ) } @@ -76,7 +93,7 @@ export class StoryFilterBarSchemaService ex const FILTER_BAR = this.STORY_DESIGNER.Widgets?.FilterBar return { key: 'options', - wrappers: ['expansion'], + wrappers: ['accordion'], templateOptions: { label: FILTER_BAR?.OPTIONS ?? 'Options', expanded: true diff --git a/libs/story-angular/widgets/input-control/input-control.schema.ts b/libs/story-angular/widgets/input-control/input-control.schema.ts index 5914cb609..965110a25 100644 --- a/libs/story-angular/widgets/input-control/input-control.schema.ts +++ b/libs/story-angular/widgets/input-control/input-control.schema.ts @@ -1,4 +1,6 @@ import { Injectable } from '@angular/core' +import { PropertyCapacity } from '@metad/components/property' +import { ControlType, NxCoreService } from '@metad/core' import { FilterSelectionType, getEntityProperty, @@ -8,11 +10,9 @@ import { ParameterProperty, Property } from '@metad/ocap-core' -import { FormlyFieldConfig } from '@ngx-formly/core' -import { PropertyCapacity } from '@metad/components/property' -import { ControlType, NxCoreService } from '@metad/core' import { FilterControlType } from '@metad/story/core' import { + AccordionWrappers, ColorOptions, DataSettingsSchemaService, DataTable, @@ -23,6 +23,7 @@ import { hierarchyAttributes, SelectionType } from '@metad/story/designer' +import { FormlyFieldConfig } from '@ngx-formly/core' import { combineLatest, distinctUntilChanged, map, startWith, withLatestFrom } from 'rxjs' import { determineControlType } from './types' @@ -79,7 +80,7 @@ export class InputControlSchemaService extends DataSettingsSchemaService { { key: 'defaultMembers', type: 'empty', - className: FORMLY_W_FULL, + className: FORMLY_W_FULL } ] @@ -192,65 +193,29 @@ export class InputControlSchemaService extends DataSettingsSchemaService { } ] }, - dataSettings, - { - key: 'options', - wrappers: ['expansion'], - props: { - label: i18nStoryWidgets?.InputControl?.Options ?? 'Options', - expanded: true + ...AccordionWrappers([ + { + key: 'dataSettings', + label: i18nStoryWidgets?.Common?.DATA_SETTINGS ?? 'Data Settings', + toggleable: false, + expanded: true, + fieldGroup: dataSettings.fieldGroup[0].fieldGroup }, - fieldGroup: [ - { - fieldGroupClassName: FORMLY_ROW, - fieldGroup: [ - // { - // className: 'ngm-formly__col ngm-formly__col-12', - // key: 'dimension', - // type: 'input-control', - // props: { - // dataSettings: this.dataSettings$, - // entityType: this.entityType$, - // capacities: [PropertyCapacity.Dimension, PropertyCapacity.Parameter, PropertyCapacity.MeasureControl] - // } - // }, - ...optionsFieldGroup - ] - } - ] - } + { + key: 'options', + label: i18nStoryWidgets?.InputControl?.Options ?? 'Options', + toggleable: false, + expanded: true, + fieldGroup: [ + { + fieldGroupClassName: FORMLY_ROW, + fieldGroup: [...optionsFieldGroup] + } + ] + } + ], {expandedMulti: true}) ] } - - // get timeFilters() { - // return [ - // { - // key: 'Full Period', - // type: 'select', - // props: { - // label: 'Full Period', - // placeholder: 'Select Full Period', - // options: [ - // { label: 'Year', value: 'Year' }, - // { label: 'Month', value: 'Month' } - // ] - // } - // }, - // { - // key: 'To Date', - // type: 'select', - // props: { - // label: 'To Date', - // placeholder: 'Select To Date', - // options: [ - // { label: 'Year', value: 'Year' }, - // { label: 'Quarter', value: 'Quarter' }, - // { label: 'Month', value: 'Month' } - // ] - // } - // } - // ] - // } } function ParameterSchema(property: ParameterProperty, className: string, I18N) { @@ -404,7 +369,7 @@ function InputControlControlType(className: string, InputControl) { } } -function MeasureControlFieldGroup(className: string, I18N,) { +function MeasureControlFieldGroup(className: string, I18N) { return [ { className, @@ -434,7 +399,7 @@ function MeasureControlFieldGroup(className: string, I18N,) { key: 'hideSingleSelectionIndicator', type: 'checkbox', props: { - label: I18N?.InputControl?.HideSelectionIndicator ?? 'Hide Selection Indicator', + label: I18N?.InputControl?.HideSelectionIndicator ?? 'Hide Selection Indicator' } }, @@ -443,8 +408,8 @@ function MeasureControlFieldGroup(className: string, I18N,) { key: 'highlighted', type: 'checkbox', props: { - label: I18N?.InputControl?.HighlightedOptions ?? 'Highlighted Options', + label: I18N?.InputControl?.HighlightedOptions ?? 'Highlighted Options' } - }, + } ] -} \ No newline at end of file +} diff --git a/libs/story-angular/widgets/kpi/kpi.schema.ts b/libs/story-angular/widgets/kpi/kpi.schema.ts index ff28d6656..7fd048fa3 100644 --- a/libs/story-angular/widgets/kpi/kpi.schema.ts +++ b/libs/story-angular/widgets/kpi/kpi.schema.ts @@ -1,24 +1,13 @@ import { Injectable, inject } from '@angular/core' import { PropertyCapacity } from '@metad/components/property' -import { WidgetStylingSchema } from '@metad/story' import { NxStoryService } from '@metad/story/core' -import { - Appearance, - IntentNavigation, - DataSettingsSchemaService, - FORMLY_W_1_2, - FORMLY_W_1_3, - FORMLY_W_FULL, - FontCss, - StylingWidgetSchema -} from '@metad/story/designer' +import { AccordionWrappers, DataSettingsSchemaService, FORMLY_W_1_2, IntentNavigation } from '@metad/story/designer' import { map } from 'rxjs/operators' @Injectable() export class KpiSchemaService extends DataSettingsSchemaService { - protected readonly storyService = inject(NxStoryService) - + getSchema() { return this.translate.stream('Story.Widgets').pipe( map((STORY_DESIGNER) => { @@ -28,12 +17,27 @@ export class KpiSchemaService extends DataSettingsSchemaService { ) } - getBuilderSchema(STORY_DESIGNER?: any) { - const dataSettings = this.generateDataSettingsSchema(STORY_DESIGNER?.Common, this.getKPIAnnotation(STORY_DESIGNER)) - - dataSettings.wrappers = ['expansion'] + getBuilderSchema(i18nStoryWidgets?: any) { + const dataSettings = this.generateDataSettingsSchema( + i18nStoryWidgets?.Common, + this.getKPIAnnotation(i18nStoryWidgets) + ) - return [dataSettings, this.kpiOptions] + return AccordionWrappers([ + { + key: 'dataSettings', + label: i18nStoryWidgets?.Common?.DATA_SETTINGS ?? 'Data Settings', + toggleable: false, + expanded: true, + fieldGroup: dataSettings.fieldGroup[0].fieldGroup + }, + { + key: 'options', + label: i18nStoryWidgets?.KPI?.Options ?? 'Options', + expanded: true, + fieldGroup: this.kpiOptions + } + ], {expandedMulti: true}) } getKPIAnnotation(BUILDER) { @@ -63,10 +67,7 @@ export class KpiSchemaService extends DataSettingsSchemaService { required: true, dataSettings: this.dataSettings$, entityType: this.entityType$, - capacities: [ - PropertyCapacity.Measure, - PropertyCapacity.MeasureAttributes - ] + capacities: [PropertyCapacity.Measure, PropertyCapacity.MeasureAttributes] } }, { @@ -77,10 +78,7 @@ export class KpiSchemaService extends DataSettingsSchemaService { required: true, dataSettings: this.dataSettings$, entityType: this.entityType$, - capacities: [ - PropertyCapacity.Measure, - PropertyCapacity.MeasureAttributes - ] + capacities: [PropertyCapacity.Measure, PropertyCapacity.MeasureAttributes] } } ] @@ -109,10 +107,7 @@ export class KpiSchemaService extends DataSettingsSchemaService { required: true, dataSettings: this.dataSettings$, entityType: this.entityType$, - capacities: [ - PropertyCapacity.Measure, - PropertyCapacity.MeasureAttributes - ] + capacities: [PropertyCapacity.Measure, PropertyCapacity.MeasureAttributes] } }, { @@ -123,10 +118,7 @@ export class KpiSchemaService extends DataSettingsSchemaService { required: true, dataSettings: this.dataSettings$, entityType: this.entityType$, - capacities: [ - PropertyCapacity.Measure, - PropertyCapacity.MeasureAttributes - ] + capacities: [PropertyCapacity.Measure, PropertyCapacity.MeasureAttributes] } } ] @@ -139,111 +131,73 @@ export class KpiSchemaService extends DataSettingsSchemaService { get kpiOptions() { const BUILDER = this.STORY_DESIGNER const className = FORMLY_W_1_2 - return { - key: 'options', - wrappers: ['expansion'], - props: { - label: BUILDER?.KPI?.Options ?? 'Options', - expanded: true - }, - fieldGroup: [ - { - fieldGroupClassName: 'ngm-formly__row', - fieldGroup: [ - { - className, - key: 'shortNumber', - type: 'checkbox', - props: { - label: BUILDER?.KPI?.ShortNumber ?? 'Short Number' - } - }, - { - className, - key: 'digitsInfo', - type: 'input', - props: { - label: BUILDER?.KPI?.DigitsInfo ?? 'Digits Info', - placeholder: `Eg. 0.0-2` - } - }, - { - className, - key: 'unit', - type: 'input', - props: { - label: BUILDER?.KPI?.Unit ?? 'Unit' - } - }, - { - className, - key: 'unitSemantics', - type: 'select', - props: { - label: BUILDER?.KPI?.UnitSemantics ?? 'Unit Semantics', - options: [ - { - value: 'currency-code', - label: BUILDER?.KPI?.CurrencyCode ?? 'Currency Code' - }, - { - value: 'unit-of-measure', - label: BUILDER?.KPI?.UnitOfMeasure ?? 'Unit of Measure' - } - ] - } - }, - { - className, - key: 'showDeviation', - type: 'checkbox', - props: { - label: BUILDER?.KPI?.ShowDeviation ?? 'Show Deviation' - } - }, - { - className, - key: 'deviationText', - type: 'input', - props: { - label: BUILDER?.KPI?.DeviationText ?? 'Deviation Text' - } - }, - - ] - }, - IntentNavigation(className, BUILDER, this.storyService) - ] - } - } -} - -/** - * 组件样式属性, 包括组件内部样式 - */ -@Injectable() -export class KpiStylingSchemaService extends WidgetStylingSchema { - getSchema() { - return this.translate.stream('STORY_DESIGNER').pipe( - map((DESIGNER) => { - return [ - Appearance(FORMLY_W_FULL, DESIGNER?.COMMON), - StylingWidgetSchema(FORMLY_W_1_2, DESIGNER), + return [ + { + fieldGroupClassName: 'ngm-formly__row', + fieldGroup: [ { - wrappers: ['expansion'], + className, + key: 'shortNumber', + type: 'checkbox', props: { - label: DESIGNER?.BUILDER?.KPI?.TitleStyle ?? 'Title Style' - }, - fieldGroup: [ - { - fieldGroupClassName: 'ngm-formly__row', - key: 'title', - fieldGroup: FontCss(FORMLY_W_1_3, DESIGNER?.STYLING?.CSS?.FONT) - } - ] + label: BUILDER?.KPI?.ShortNumber ?? 'Short Number' + } + }, + { + className, + key: 'digitsInfo', + type: 'input', + props: { + label: BUILDER?.KPI?.DigitsInfo ?? 'Digits Info', + placeholder: `Eg. 0.0-2` + } + }, + { + className, + key: 'unit', + type: 'input', + props: { + label: BUILDER?.KPI?.Unit ?? 'Unit' + } + }, + { + className, + key: 'unitSemantics', + type: 'select', + props: { + label: BUILDER?.KPI?.UnitSemantics ?? 'Unit Semantics', + options: [ + { + value: 'currency-code', + label: BUILDER?.KPI?.CurrencyCode ?? 'Currency Code' + }, + { + value: 'unit-of-measure', + label: BUILDER?.KPI?.UnitOfMeasure ?? 'Unit of Measure' + } + ] + } + }, + { + className, + key: 'showDeviation', + type: 'checkbox', + props: { + label: BUILDER?.KPI?.ShowDeviation ?? 'Show Deviation' + } + }, + { + className, + key: 'deviationText', + type: 'input', + props: { + label: BUILDER?.KPI?.DeviationText ?? 'Deviation Text' + } } - ] as any[] - }) - ) + ] + }, + IntentNavigation(className, BUILDER, this.storyService) + ] } } + diff --git a/libs/story-angular/widgets/kpi/kpi.styling.schema.ts b/libs/story-angular/widgets/kpi/kpi.styling.schema.ts index 2c120a07f..c3b226789 100644 --- a/libs/story-angular/widgets/kpi/kpi.styling.schema.ts +++ b/libs/story-angular/widgets/kpi/kpi.styling.schema.ts @@ -7,55 +7,41 @@ import { map } from 'rxjs/operators' export class KpiStylingSchema extends BaseDesignerSchemaService> { getSchema() { return this.translate.stream('Story').pipe( - map((STORY) => { - return [ - { - wrappers: ['expansion'], - props: { - label: STORY?.Widgets?.Common?.ComponentStyling ?? 'Component Styling', - expanded: false - }, - fieldGroup: [ - { - key: 'component', - type: 'styling', - props: { - } - } - ] + map((STORY) => [ + { + wrappers: ['accordion'], + props: { + expandedMulti: true, + elevationZ: true }, - { - wrappers: ['expansion'], - props: { - label: STORY?.Widgets?.Common?.TitleStyling ?? 'Title Styling', - expanded: false + fieldGroup: [ + { + key: 'component', + type: 'styling', + props: { + label: STORY?.Widgets?.Common?.ComponentStyling ?? 'Component Styling', + expanded: false + } }, - fieldGroup: [ - { - key: 'title', - type: 'styling', - props: { - } + { + key: 'title', + type: 'styling', + props: { + label: STORY?.Widgets?.Common?.TitleStyling ?? 'Title Styling', + expanded: false } - ] - }, - { - wrappers: ['expansion'], - props: { - label: STORY?.Widgets?.Common?.ValueStyling ?? 'Value Styling', - expanded: false }, - fieldGroup: [ - { - key: 'value', - type: 'styling', - props: { - } + { + key: 'value', + type: 'styling', + props: { + label: STORY?.Widgets?.Common?.ValueStyling ?? 'Value Styling', + expanded: false } - ] - }, - ] - }) + } + ] + } + ]) ) } } diff --git a/libs/story-angular/widgets/pivot-grid/pivot-grid.schema.ts b/libs/story-angular/widgets/pivot-grid/pivot-grid.schema.ts index e1a8989b0..e82cc2d85 100644 --- a/libs/story-angular/widgets/pivot-grid/pivot-grid.schema.ts +++ b/libs/story-angular/widgets/pivot-grid/pivot-grid.schema.ts @@ -1,8 +1,7 @@ import { Injectable, Injector } from '@angular/core' import { FormlyFieldConfig } from '@ngx-formly/core' import { getEntityProperty } from '@metad/ocap-core' -import { DataSettingsSchemaService, SelectionVariant } from '@metad/story/designer' -import { GridSelectionMode } from 'igniteui-angular' +import { DataSettingsSchemaService } from '@metad/story/designer' import { isNil, negate } from 'lodash-es' import { combineLatest } from 'rxjs' import { map, startWith } from 'rxjs/operators' @@ -30,10 +29,8 @@ export class PivotGridSchemaService extends DataSettingsSchemaService { const dataSettings = this.generateDataSettingsSchema( BUILDER, this.analytics, - SelectionVariant(BUILDER, this.dataSettings$) + // SelectionVariant(BUILDER, this.dataSettings$) ) - // dataSettings.wrappers = ['expansion'] - // dataSettings.templateOptions.enableSelectFields = true const schema = [ { @@ -54,7 +51,6 @@ export class PivotGridSchemaService extends DataSettingsSchemaService { }, dataSettings, // { - // wrappers: ['expansion'], // templateOptions: { // label: '数据配置', // enableSelectFields: true, @@ -66,7 +62,6 @@ export class PivotGridSchemaService extends DataSettingsSchemaService { // }, { key: 'options', - wrappers: ['expansion'], templateOptions: { label: BUILDER.PIVOT_GRID?.OPTIONS ?? 'Grid Options', expanded: true @@ -157,7 +152,7 @@ export class PivotGridSchemaService extends DataSettingsSchemaService { .map((propertyPath) => getEntityProperty(entityType, propertyPath)) .filter(negate(isNil)) .map((property) => { - return { value: property.name, label: property.label || property.name } + return { value: property.name, label: property.caption || property.name } }) }) ) @@ -290,9 +285,9 @@ export function GridOptionsSchema(BUILDER) { templateOptions: { label: BUILDER?.PIVOT_GRID?.ColumnSelection ?? 'Column Selection', options: [ - { value: GridSelectionMode.none, label: 'None' }, - { value: GridSelectionMode.single, label: 'Single' }, - { value: GridSelectionMode.multiple, label: 'Multiple' } + // { value: GridSelectionMode.none, label: 'None' }, + // { value: GridSelectionMode.single, label: 'Single' }, + // { value: GridSelectionMode.multiple, label: 'Multiple' } ] } }, diff --git a/libs/story-angular/widgets/swiper/styling.schema.ts b/libs/story-angular/widgets/swiper/styling.schema.ts index 25164b1b3..0fb0003dd 100644 --- a/libs/story-angular/widgets/swiper/styling.schema.ts +++ b/libs/story-angular/widgets/swiper/styling.schema.ts @@ -1,6 +1,12 @@ import { Injectable } from '@angular/core' import { StoryWidget } from '@metad/story/core' -import { Appearance, BaseDesignerSchemaService, BaseSchemaState, FORMLY_W_FULL } from '@metad/story/designer' +import { + Appearances, + BaseDesignerSchemaService, + BaseSchemaState, + FORMLY_ROW, + FORMLY_W_1_2 +} from '@metad/story/designer' import { map } from 'rxjs/operators' @Injectable() @@ -10,34 +16,39 @@ export class SlideStylingSchema extends BaseDesignerSchemaService { return [ { - wrappers: ['expansion'], + wrappers: ['accordion'], props: { - label: STORY?.Widgets?.Common?.ComponentStyling ?? 'Component Styling', - expanded: true + expandedMulti: true, + elevationZ: true }, fieldGroup: [ { key: 'component', type: 'styling', - props: {} - } - ] - }, - { - wrappers: ['expansion'], - props: { - label: STORY?.Widgets?.Common?.SlideStyling ?? 'Slide Styling', - expanded: false - }, - fieldGroup: [ + props: { + label: STORY?.Widgets?.Common?.ComponentStyling ?? 'Component Styling', + expanded: true + } + }, { key: 'slide', type: 'styling', - props: {} + props: { + label: STORY?.Widgets?.Common?.SlideStyling ?? 'Slide Styling', + expanded: false + } + }, + { + key: 'appearance', + props: { + label: STORY?.Widgets?.Common?.Appearance ?? 'Appearance', + expanded: true + }, + fieldGroupClassName: FORMLY_ROW, + fieldGroup: Appearances(FORMLY_W_1_2, STORY?.Widgets?.Common) } ] - }, - Appearance(FORMLY_W_FULL, STORY?.Widgets?.Common) + } ] }) ) diff --git a/libs/story-angular/widgets/swiper/swiper.schema.ts b/libs/story-angular/widgets/swiper/swiper.schema.ts index d328886f1..64456365f 100644 --- a/libs/story-angular/widgets/swiper/swiper.schema.ts +++ b/libs/story-angular/widgets/swiper/swiper.schema.ts @@ -20,12 +20,11 @@ export class SwiperSchemaService extends DataSettingsSchemaService { key: 'options', fieldGroup: [ { - fieldGroupClassName: FORMLY_ROW, - wrappers: ['expansion'], + wrappers: ['panel'], props: { - label: BUILDER?.Swiper?.Options ?? 'Options', - expanded: true + padding: true }, + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { className, @@ -241,13 +240,13 @@ export class SwiperSchemaService extends DataSettingsSchemaService { { key: 'slides', type: 'table-inline', - wrappers: ['expansion'], + wrappers: ['panel'], props: { label: BUILDER?.Swiper?.Slides ?? 'Slides', - expanded: true + padding: true }, fieldArray: { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { key: 'type', @@ -299,7 +298,7 @@ export class SwiperSchemaService extends DataSettingsSchemaService { label: BUILDER?.Swiper?.Autoplay ?? 'Autoplay', fieldGroup: [ { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { className, @@ -365,7 +364,7 @@ export class SwiperSchemaService extends DataSettingsSchemaService { label: BUILDER?.Swiper?.Pagination ?? 'Pagination', fieldGroup: [ { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { className, @@ -422,7 +421,7 @@ export class SwiperSchemaService extends DataSettingsSchemaService { label: BUILDER?.Swiper?.KeyboardControl ?? 'Keyboard Control', fieldGroup: [ { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, fieldGroup: [ { className, @@ -455,10 +454,10 @@ export class SwiperSchemaService extends DataSettingsSchemaService { ]), { - fieldGroupClassName: 'ngm-formly__row', + fieldGroupClassName: FORMLY_ROW, key: 'breakpoints', type: 'table-inline', - wrappers: ['expansion'], + wrappers: ['accordion'], props: { label: BUILDER?.Swiper?.Breakpoints ?? 'Breakpoints', expanded: true diff --git a/libs/story-angular/widgets/table/igx-grid/smart-grid.schema.ts b/libs/story-angular/widgets/table/igx-grid/smart-grid.schema.ts index e10d681a0..c28077315 100644 --- a/libs/story-angular/widgets/table/igx-grid/smart-grid.schema.ts +++ b/libs/story-angular/widgets/table/igx-grid/smart-grid.schema.ts @@ -47,9 +47,6 @@ export class SmartGridSettingsSchemaService extends PivotGridSchemaService { this.selectionVariant as any ) - dataSettings.wrappers = ['expansion'] - dataSettings.templateOptions.enableSelectFields = true - return [ { wrappers: ['panel'], @@ -71,7 +68,6 @@ export class SmartGridSettingsSchemaService extends PivotGridSchemaService { { key: 'options', - wrappers: ['expansion'], templateOptions: { label: 'Grid Options', }, diff --git a/packages/analytics/src/core/features.ts b/packages/analytics/src/core/features.ts index 857f5aab0..615aaf5b7 100644 --- a/packages/analytics/src/core/features.ts +++ b/packages/analytics/src/core/features.ts @@ -1,6 +1,38 @@ -import { AnalyticsFeatures, IFeatureCreateInput } from '@metad/contracts' +import { AnalyticsFeatures, FeatureEnum, IFeatureCreateInput } from '@metad/contracts' -export const DEFAULT_FEATURES: IFeatureCreateInput[] = [ +export const DEFAULT_FEATURES: Partial[] = [ + { + code: FeatureEnum.FEATURE_HOME, + children: [ + { + name: 'Catalog', + code: AnalyticsFeatures.FEATURE_HOME_CATALOG, + description: 'Catalog of Story, Indicator and Models', + link: 'catalog', + isEnabled: true, + icon: 'catalog-outline', + status: 'primary' + }, + { + name: 'Trend', + code: AnalyticsFeatures.FEATURE_HOME_TREND, + description: 'Trend of Public Story Dashboards', + link: 'trend', + isEnabled: true, + icon: 'trend-outline', + status: 'primary' + }, + { + name: 'Insight', + code: AnalyticsFeatures.FEATURE_HOME_INSIGHT, + description: 'Insight', + link: 'insight', + isEnabled: true, + icon: 'insight-outline', + status: 'primary' + }, + ] + }, { name: 'Business Area', code: AnalyticsFeatures.FEATURE_BUSINESS_AREA, @@ -43,50 +75,50 @@ export const DEFAULT_FEATURES: IFeatureCreateInput[] = [ status: 'warning' }, { - name: 'My Indicator', - code: AnalyticsFeatures.FEATURE_INDICATOR_MY, - description: 'My Indicator', - image: 'estimate-received.png', - link: 'indicator/my', - isEnabled: true, - icon: 'file-text-outline', - status: 'warning' - } - ] - }, - { - name: 'Insight', - code: AnalyticsFeatures.FEATURE_INSIGHT, - description: 'Manage and View Insight Model', - image: 'estimate.png', - link: 'insight', - isEnabled: true, - icon: 'file-text-outline', - status: 'success', - children: [ - { - name: 'Insight Admin', - code: AnalyticsFeatures.FEATURE_INSIGHT_ADMIN, - description: - 'Manage Insight', - image: 'estimate-received.png', - link: 'insight/admin', - isEnabled: true, - icon: 'file-text-outline', - status: 'warning' - }, - { - name: 'Insight Model Viewer', - code: AnalyticsFeatures.FEATURE_INSIGHT_VIEWER, - description: 'View Insight Model', - image: 'estimate-received.png', - link: 'insight', + name: 'Indicator Application', + code: AnalyticsFeatures.FEATURE_INDICATOR_APP, + description: 'View Indicators in Application', + image: 'indicator.png', + link: 'indicator-app', isEnabled: true, icon: 'file-text-outline', status: 'warning' } ] }, + // { + // name: 'Insight', + // code: AnalyticsFeatures.FEATURE_INSIGHT, + // description: 'Manage and View Insight Model', + // image: 'estimate.png', + // link: 'insight', + // isEnabled: true, + // icon: 'file-text-outline', + // status: 'success', + // children: [ + // { + // name: 'Insight Admin', + // code: AnalyticsFeatures.FEATURE_INSIGHT_ADMIN, + // description: + // 'Manage Insight', + // image: 'estimate-received.png', + // link: 'insight/admin', + // isEnabled: true, + // icon: 'file-text-outline', + // status: 'warning' + // }, + // { + // name: 'Insight Model Viewer', + // code: AnalyticsFeatures.FEATURE_INSIGHT_VIEWER, + // description: 'View Insight Model', + // image: 'estimate-received.png', + // link: 'insight', + // isEnabled: true, + // icon: 'file-text-outline', + // status: 'warning' + // } + // ] + // }, { name: 'Story Model', code: AnalyticsFeatures.FEATURE_MODEL, @@ -106,5 +138,15 @@ export const DEFAULT_FEATURES: IFeatureCreateInput[] = [ isEnabled: true, icon: 'file-text-outline', status: 'success', + }, + { + name: 'Project', + code: AnalyticsFeatures.FEATURE_PROJECT, + description: 'Go to Project, Manage Story and Indicator', + image: 'project.png', + link: 'project', + isEnabled: true, + icon: 'project-outline', + status: 'success', } ] \ No newline at end of file diff --git a/packages/analytics/src/core/prepare.ts b/packages/analytics/src/core/prepare.ts index 9a02e5a1e..354e826d5 100644 --- a/packages/analytics/src/core/prepare.ts +++ b/packages/analytics/src/core/prepare.ts @@ -1,16 +1,17 @@ -import { Type } from '@nestjs/common' +import { IFeatureCreateInput } from '@metad/contracts' +import { setConfig } from '@metad/server-config' import { coreEntities, coreSubscribers, DEFAULT_FEATURES as SERVER_DEFAULT_FEATURES, setDefaultFeatures, - setDefaultRolePermissions, + setDefaultRolePermissions } from '@metad/server-core' -import { setConfig } from '@metad/server-config' +import { Type } from '@nestjs/common' import { ALL_ENTITIES } from './entities/index' +import { coreSubscribers as analyticsSubscribers } from './entities/subscribers' import { DEFAULT_FEATURES } from './features' import { ANALYTICS_ROLE_PERMISSIONS } from './role-permissions' -import { coreSubscribers as analyticsSubscribers } from './entities/subscribers' export function prepare() { const allEntities = coreEntities as Array> @@ -19,13 +20,22 @@ export function prepare() { dbConnectionOptions: { entities: allEntities, subscribers: [...coreSubscribers, ...analyticsSubscribers] - }, + } }) + // Append Features of analytics project into System default features const features = [...SERVER_DEFAULT_FEATURES] - features.push(...DEFAULT_FEATURES) + DEFAULT_FEATURES.forEach((feature) => { + const index = features.findIndex((item) => item.code === feature.code) + if (index > -1) { + features[index].children.push(...feature.children) + } else { + features.push(feature as IFeatureCreateInput) + } + }) setDefaultFeatures(features) + // Append role permissions of analytics project into System default role permissions ANALYTICS_ROLE_PERMISSIONS.forEach(({ role, defaultEnabledPermissions }) => { setDefaultRolePermissions(role, defaultEnabledPermissions) }) diff --git a/packages/angular/_index.scss b/packages/angular/_index.scss index ba15a44b5..d8417a160 100644 --- a/packages/angular/_index.scss +++ b/packages/angular/_index.scss @@ -10,4 +10,5 @@ @import './controls/smart-filter/_smart-filter.component'; @import './analytical-grid/_analytical-grid.component'; @import './core/style/accordion-theme'; -@import './core/style/mat-autocomplete-theme'; \ No newline at end of file +@import './core/style/mat-autocomplete-theme'; +@import './core/directives/_appearance'; \ No newline at end of file diff --git a/packages/angular/common/select/select/select.component.html b/packages/angular/common/select/select/select.component.html index f36f4088a..56be7c96a 100644 --- a/packages/angular/common/select/select/select.component.html +++ b/packages/angular/common/select/select/select.component.html @@ -1,4 +1,4 @@ -