diff --git a/.deploy/webapp/package.json b/.deploy/webapp/package.json index 217117f74..d9085058e 100644 --- a/.deploy/webapp/package.json +++ b/.deploy/webapp/package.json @@ -15,6 +15,7 @@ "@angular/elements": "16.1.7", "@angular/forms": "16.1.7", "@angular/material": "16.1.6", + "@angular/material-date-fns-adapter": "^16.1.6", "@angular/platform-browser": "16.1.7", "@angular/platform-browser-dynamic": "16.1.7", "@angular/router": "16.1.7", diff --git a/README.md b/README.md index 97b7ae703..89e8f0c43 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,33 @@ English | [中文](./README_zh.md) -# Metad Analytics Platform - [uri_metad]: https://mtda.cloud/en/ [uri_license]: https://www.gnu.org/licenses/agpl-3.0.html [uri_license_image]: https://img.shields.io/badge/License-AGPL%20v3-blue.svg -![visitors](https://visitor-badge.laobi.icu/badge?page_id=meta-d.ocap) -[![License: AGPL v3][uri_license_image]][uri_license] -[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/meta-d/ocap) +

+ + Metad + +

+

+ Open-Source Analytics Platform for Enterprise Data Analysis, Indicator Management and Reporting +

+

+ + Visitors + + + Release + + + License: AGPL v3 + + + Gitpod Ready-to-Code + +

+ +# Metad Analytics Platform ## 💡 What's New @@ -16,16 +35,16 @@ We released new version which includes [AI Copilot](https://mtda.cloud/en/blog/c ## 🌟 What is it -[Metad Platform][uri_metad] - **Open-Source Analytics Platform** for Enterprise Data Analysis and Reporting. +[Metad Platform][uri_metad] - **Open-Source Analytics Platform** for Enterprise Data Analysis Indicator Management and Reporting. * **Semantic Model**: Perform multi-dimensional data modeling and analysis, allowing users to explore data from various dimensions and hierarchies. * **Story Dashboard**: Create compelling visual narratives with Story Dashboards, combining interactive visualizations, narrative elements, and data-driven storytelling. * **Indicator Management**: Easily define, manage, and monitor key performance indicators (KPIs) to ensure data quality, consistency, and effective performance analysis. * **AI Copilot**: Benefit from AI-driven insights and recommendations to enhance decision-making processes and identify actionable opportunities. -![Story Workspace](https://github.com/meta-d/meta-d/blob/main/img/story-workspace.png) +![Story Workspace](https://github.com/meta-d/meta-d/blob/main/img/en/story-workspace.png) -![Indicator Application](https://github.com/meta-d/meta-d/blob/main/img/indicator-application.png) +![Indicator Application](https://github.com/meta-d/meta-d/blob/main/img/en/indicator-application.png) ## ✨ Features @@ -81,9 +100,8 @@ Basic feartures of the platform: ### Sales overview [open in new tab](https://app.mtda.cloud/public/story/892690e5-66ab-4649-9bf5-c1a9c432c01b) ![Sales overview Screenshot](https://github.com/meta-d/meta-d/blob/main/img/adv-sales-overview.png) - ### Pareto analysis [open in new tab](https://app.mtda.cloud/public/story/892690e5-66ab-4649-9bf5-c1a9c432c01b?pageKey=bsZ0sjxnxI) -![Pareto analysis Screenshot](https://github.com/meta-d/meta-d/blob/main/img/product-pareto-analysis.png) +![Pareto analysis Screenshot](https://github.com/meta-d/meta-d/blob/main/img/en/story-pareto-analysis.png) ### Product profit analysis [open in new tab](https://app.mtda.cloud/public/story/892690e5-66ab-4649-9bf5-c1a9c432c01b?pageKey=6S4oEUnVO3) ![Product profit analysis Screenshot](https://github.com/meta-d/meta-d/blob/main/img/profit-margin-analysis.jpg) @@ -95,7 +113,7 @@ Basic feartures of the platform: ![Bigview dashboard Screenshot](https://github.com/meta-d/meta-d/blob/main/img/bigview-supermart-sales.png) ### Indicator application [open in new tab](https://www.mtda.cloud/en/blog/2023/07/24/sample-adv-7-indicator-app) -![Indicator application Screenshot](https://github.com/meta-d/meta-d/blob/main/img/indicator-application.png) +![Indicator application Screenshot](https://github.com/meta-d/meta-d/blob/main/img/en/indicator-application.png) ### Indicator mobile app [open in new tab](https://www.mtda.cloud/en/blog/2023/07/24/sample-adv-7-indicator-app) ![Indicator mobile app Screenshot](https://github.com/meta-d/meta-d/blob/main/img/indicator-app-mobile.jpg) diff --git a/apps/cloud/src/app/@core/core.module.ts b/apps/cloud/src/app/@core/core.module.ts index 863329cec..16e307bb4 100644 --- a/apps/cloud/src/app/@core/core.module.ts +++ b/apps/cloud/src/app/@core/core.module.ts @@ -9,58 +9,14 @@ import { import { FormsModule } from '@angular/forms' import { MissingTranslationHandler, - MissingTranslationHandlerParams, TranslateLoader, TranslateModule } from '@ngx-translate/core' -import { TranslateHttpLoader } from '@ngx-translate/http-loader' import { PACStateModule } from '@metad/cloud/state' -import { ZhHans } from '@metad/ocap-angular/i18n' -import { zhHans as CoreZhHans } from '@metad/core' -import { ZhHans as StoryZhHans } from '@metad/story/i18n' -import { ZhHans as AuthZhHans } from '@metad/cloud/auth' -import { ZhHans as IAppZhHans } from '@metad/cloud/indicator-market/i18n' -import { map, Observable } from 'rxjs' import { AuthModule } from './auth/auth.module' import { throwIfAlreadyLoaded } from './module-import-guard' +import { HttpLoaderFactory, MyMissingTranslationHandler } from './theme' -class CustomTranslateHttpLoader extends TranslateHttpLoader { - getTranslation(lang: string): Observable { - let ocapTranslates = {} - switch(lang) { - case 'zh-Hans': - case 'zh-CN': - ocapTranslates = { - ...ZhHans, - ...CoreZhHans, - ...StoryZhHans, - ...AuthZhHans, - ...IAppZhHans - } - break - default: - } - return super.getTranslation(lang).pipe( - map((t) => ({ - ...t, - ...ocapTranslates - })) - ) - } -} - -export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { - return new CustomTranslateHttpLoader(http, `./assets/i18n/`, '.json') -} - -export class MyMissingTranslationHandler implements MissingTranslationHandler { - handle(params: MissingTranslationHandlerParams) { - if (params.interpolateParams) { - return params.interpolateParams['Default'] || params.key - } - return params.key - } -} @NgModule({ imports: [ diff --git a/apps/cloud/src/app/@core/guards/invite.guard.ts b/apps/cloud/src/app/@core/guards/invite.guard.ts index 70be7333f..2cfdf7f7a 100644 --- a/apps/cloud/src/app/@core/guards/invite.guard.ts +++ b/apps/cloud/src/app/@core/guards/invite.guard.ts @@ -1,42 +1,25 @@ -import { Store } from './../services/store.service'; -import { Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, Router } from '@angular/router'; -import { first } from 'rxjs/operators'; -import { PermissionsEnum } from '@metad/contracts'; -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { inject } from '@angular/core' +import { ActivatedRouteSnapshot, Router } from '@angular/router' +import { PermissionsEnum } from '@metad/contracts' +import { combineLatest } from 'rxjs' +import { first, map, tap } from 'rxjs/operators' +import { Store } from './../services/store.service' -@UntilDestroy() -@Injectable() -export class InviteGuard { - hasPermission = false; - organizationInvitesAllowed = false; - - constructor( - private readonly router: Router, - private readonly store: Store - ) {} - - async canActivate(route: ActivatedRouteSnapshot) { - const expectedPermissions: PermissionsEnum[] = - route.data.expectedPermissions; - this.store.userRolePermissions$.pipe(first()).subscribe(() => { - this.hasPermission = expectedPermissions.some((permission) => - this.store.hasPermission(permission) - ); - }); - this.store.selectedOrganization$ - .pipe(first(), untilDestroyed(this)) - .subscribe((organization) => { - if (organization) { - this.organizationInvitesAllowed = - organization.invitesAllowed; - } - }); - if (this.organizationInvitesAllowed && this.hasPermission) { - return true; - } - - this.router.navigate(['/']); - return false; - } +export function inviteGuard(route: ActivatedRouteSnapshot) { + const store = inject(Store) + const router = inject(Router) + const expectedPermissions: PermissionsEnum[] = route.data.expectedPermissions + return combineLatest([ + store.userRolePermissions$.pipe( + first(), + map(() => expectedPermissions.some((permission) => store.hasPermission(permission))) + ), + store.selectedOrganization$.pipe( + first(), + map((organization) => organization?.invitesAllowed) + ) + ]).pipe( + map(([hasPermission, invitesAllowed]) => invitesAllowed && hasPermission), + tap((allowed) => allowed || router.navigate(['/'])) + ) } diff --git a/apps/cloud/src/app/@core/theme/index.ts b/apps/cloud/src/app/@core/theme/index.ts index 07cafaf15..e115dedd0 100644 --- a/apps/cloud/src/app/@core/theme/index.ts +++ b/apps/cloud/src/app/@core/theme/index.ts @@ -1,3 +1,4 @@ export * from './selector.service' export * from './theme.service' export * from './icons' +export * from './translate' \ No newline at end of file diff --git a/apps/cloud/src/app/@core/theme/translate.ts b/apps/cloud/src/app/@core/theme/translate.ts new file mode 100644 index 000000000..f1764cdb5 --- /dev/null +++ b/apps/cloud/src/app/@core/theme/translate.ts @@ -0,0 +1,85 @@ +import { HttpClient } from '@angular/common/http' +import en from '@angular/common/locales/en' +import localeZhExtra from '@angular/common/locales/extra/zh-Hans' +import zh from '@angular/common/locales/zh' +import localeZh from '@angular/common/locales/zh-Hans' +import { ZhHans as AuthZhHans, ZhHant as AuthZhHant } from '@metad/cloud/auth' +import { ZhHans as IAppZhHans, ZhHant as IAppZhHant } from '@metad/cloud/indicator-market/i18n' +import { registerLocaleData as nxRegisterLocaleData, zhHans as CoreZhHans, zhHant as CoreZhHant } from '@metad/core' +import { ZhHans, ZhHant } from '@metad/ocap-angular/i18n' +import { ZhHans as StoryZhHans, ZhHant as StoryZhHant } from '@metad/story/i18n' +import { MissingTranslationHandler, MissingTranslationHandlerParams } from '@ngx-translate/core' +import { TranslateHttpLoader } from '@ngx-translate/http-loader' +import { } from '@metad/core' +import { Observable, map } from 'rxjs' +import { LanguagesEnum } from '../types' +import { registerLocaleData } from '@angular/common' +import { enUS, zhCN, zhHK } from 'date-fns/locale' + + +export const LOCALE_DEFAULT = LanguagesEnum.SimplifiedChinese +registerLocaleData(localeZh, LOCALE_DEFAULT, localeZhExtra) +registerLocaleData(zh) +registerLocaleData(en) +nxRegisterLocaleData(CoreZhHans, LanguagesEnum.SimplifiedChinese) +nxRegisterLocaleData(CoreZhHant, LanguagesEnum.TraditionalChinese) + +class CustomTranslateHttpLoader extends TranslateHttpLoader { + getTranslation(lang: string): Observable { + let ocapTranslates = {} + switch (lang) { + case LanguagesEnum.Chinese: + case LanguagesEnum.SimplifiedChinese: + ocapTranslates = { + ...ZhHans, + ...CoreZhHans, + ...StoryZhHans, + ...AuthZhHans, + ...IAppZhHans + } + break + case LanguagesEnum.TraditionalChinese: + ocapTranslates = { + ...ZhHant, + ...CoreZhHant, + ...StoryZhHant, + ...AuthZhHant, + ...IAppZhHant + } + break + default: + } + return super.getTranslation(lang).pipe( + map((t) => ({ + ...t, + ...ocapTranslates + })) + ) + } +} + +export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { + return new CustomTranslateHttpLoader(http, `./assets/i18n/`, '.json') +} + +export class MyMissingTranslationHandler implements MissingTranslationHandler { + handle(params: MissingTranslationHandlerParams) { + if (params.interpolateParams) { + return params.interpolateParams['Default'] || params.key + } + return params.key + } +} + +export function mapDateLocale(locale: string) { + switch (locale) { + case 'zh-CN': + case 'zh-Hans': + case 'zh': + return zhCN + case 'zh-Hant': + return zhHK + default: + return enUS + } +} \ No newline at end of file diff --git a/apps/cloud/src/app/@core/types.ts b/apps/cloud/src/app/@core/types.ts index 53a997269..1b5565e32 100644 --- a/apps/cloud/src/app/@core/types.ts +++ b/apps/cloud/src/app/@core/types.ts @@ -35,18 +35,10 @@ export enum RequestMethodEnum { export const LANGUAGES = [ { value: 'zh-CN', label: '简体中文' }, + { value: 'zh-Hant', label: '繁体中文' }, { value: 'en', label: 'English' } ] -// /** -// * @deprecated use in state project -// */ -// export enum ThemesEnum { -// default = 'default', -// dark = 'dark', -// thin = 'thin' -// } - export interface Group { id: string name: string diff --git a/apps/cloud/src/app/@shared/directives/index.ts b/apps/cloud/src/app/@shared/directives/index.ts new file mode 100644 index 000000000..c7c59904c --- /dev/null +++ b/apps/cloud/src/app/@shared/directives/index.ts @@ -0,0 +1,2 @@ +export * from './lazy-img.directive' +export * from './manage-entity-base' \ No newline at end of file diff --git a/apps/cloud/src/app/@shared/directives/manage-entity-base.ts b/apps/cloud/src/app/@shared/directives/manage-entity-base.ts new file mode 100644 index 000000000..280aac3db --- /dev/null +++ b/apps/cloud/src/app/@shared/directives/manage-entity-base.ts @@ -0,0 +1,52 @@ +import { effect, inject, signal } from '@angular/core' +import { ActivatedRoute, Router } from '@angular/router' +import { IBasePerTenantEntityModel } from '../../@core' +import { TranslationBaseComponent } from '../language/translation-base.component' + +/** + * Extends this class to use manage entity methods + */ +export abstract class ManageEntityBaseComponent< + T extends IBasePerTenantEntityModel = IBasePerTenantEntityModel +> extends TranslationBaseComponent { + protected readonly router = inject(Router) + protected readonly route = inject(ActivatedRoute) + + openedLinks = signal([]) + currentLink = signal(null) + + constructor() { + super() + + effect( + () => { + if (this.currentLink()) { + const links = this.openedLinks() + const index = links.findIndex((item) => item.id === this.currentLink().id) + if (index > -1) { + if (links[index] !== this.currentLink()) { + this.openedLinks.set([...links.slice(0, index), this.currentLink(), ...links.slice(index + 1)]) + } + } else { + this.openedLinks.set([...links, this.currentLink()]) + } + } + }, + { allowSignalWrites: true } + ) + } + + trackByEntityId(index: number, item: T) { + return item?.id + } + + setCurrentLink(link: T) { + this.currentLink.set(link) + } + + removeOpenedLink(link: T) { + this.currentLink.set(null) + this.openedLinks.set(this.openedLinks().filter((item) => item.id !== link.id)) + this.router.navigate(['.'], { relativeTo: this.route }) + } +} 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 e69de29bb..38f3ef31e 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 @@ -0,0 +1,3 @@ +:host { + @apply w-full; +} \ No newline at end of file diff --git a/apps/cloud/src/app/@shared/index.ts b/apps/cloud/src/app/@shared/index.ts index 91b6b75fa..c347a2a65 100644 --- a/apps/cloud/src/app/@shared/index.ts +++ b/apps/cloud/src/app/@shared/index.ts @@ -6,7 +6,7 @@ export * from './timer' export * from './language/language-selector' export * from './status-bar/status-bar.component' export * from './story/index' -export * from './directives/lazy-img.directive' +export * from './directives/' export * from './copilot/index' export * from './upload/upload.component' export * from './certification/index' @@ -14,4 +14,4 @@ export * from './tag/index' export * from './form-fields/index' export * from './organization/index' export * from './project/index' -export * from './language/translation-base.component' \ No newline at end of file +export * from './language/translation-base.component' diff --git a/apps/cloud/src/app/@shared/invite/forms/email-invite-form/email-invite-form.component.ts b/apps/cloud/src/app/@shared/invite/forms/email-invite-form/email-invite-form.component.ts index f27f7484e..5a96deaf1 100644 --- a/apps/cloud/src/app/@shared/invite/forms/email-invite-form/email-invite-form.component.ts +++ b/apps/cloud/src/app/@shared/invite/forms/email-invite-form/email-invite-form.component.ts @@ -131,23 +131,23 @@ export class EmailInviteFormComponent extends TranslationBaseComponent implement renderInvitationExpiryOptions() { this.invitationExpiryOptions = [ { - label: this.getTranslation('INVITE_PAGE.INVITATION_EXPIRATION_OPTIONS.DAY', { Default: '1 Day' }), + label: this.getTranslation('PAC.INVITE_PAGE.INVITATION_EXPIRATION_OPTIONS.DAY', { Default: '1 Day' }), value: InvitationExpirationEnum.DAY }, { - label: this.getTranslation('INVITE_PAGE.INVITATION_EXPIRATION_OPTIONS.WEEK', { Default: '1 Week' }), + label: this.getTranslation('PAC.INVITE_PAGE.INVITATION_EXPIRATION_OPTIONS.WEEK', { Default: '1 Week' }), value: InvitationExpirationEnum.WEEK }, { - label: this.getTranslation('INVITE_PAGE.INVITATION_EXPIRATION_OPTIONS.TWO_WEEK', { Default: '2 Week' }), + label: this.getTranslation('PAC.INVITE_PAGE.INVITATION_EXPIRATION_OPTIONS.TWO_WEEK', { Default: '2 Week' }), value: InvitationExpirationEnum.TWO_WEEK }, { - label: this.getTranslation('INVITE_PAGE.INVITATION_EXPIRATION_OPTIONS.MONTH', { Default: '1 Month' }), + label: this.getTranslation('PAC.INVITE_PAGE.INVITATION_EXPIRATION_OPTIONS.MONTH', { Default: '1 Month' }), value: InvitationExpirationEnum.MONTH }, { - label: this.getTranslation('INVITE_PAGE.INVITATION_EXPIRATION_OPTIONS.NEVER', { Default: 'Never' }), + label: this.getTranslation('PAC.INVITE_PAGE.INVITATION_EXPIRATION_OPTIONS.NEVER', { Default: 'Never' }), value: InvitationExpirationEnum.NEVER } ] diff --git a/apps/cloud/src/app/@shared/invite/invite-mutation/invite-mutation.component.ts b/apps/cloud/src/app/@shared/invite/invite-mutation/invite-mutation.component.ts index 1276f6e82..83f705b5e 100644 --- a/apps/cloud/src/app/@shared/invite/invite-mutation/invite-mutation.component.ts +++ b/apps/cloud/src/app/@shared/invite/invite-mutation/invite-mutation.component.ts @@ -1,21 +1,19 @@ import { DragDropModule } from '@angular/cdk/drag-drop' -import { Component, Input, ViewChild } from '@angular/core' +import { Component, Input, ViewChild, inject } from '@angular/core' import { FormsModule } from '@angular/forms' import { MatButtonModule } from '@angular/material/button' import { MatDialogModule, MatDialogRef } from '@angular/material/dialog' import { InvitationTypeEnum } from '@metad/contracts' import { ButtonGroupDirective } from '@metad/ocap-angular/core' import { MtxButtonModule } from '@ng-matero/extensions/button' -import { UntilDestroy } from '@ngneat/until-destroy' import { TranslateModule } from '@ngx-translate/core' -import { InviteService } from '@metad/cloud/state' import { getErrorMessage } from '../../../@core' import { ToastrService } from '../../../@core/services' import { EmailInviteFormComponent } from '../forms' import { InviteFormsModule } from '../forms/invite-forms.module' import { TranslationBaseComponent } from '../../language/translation-base.component' -@UntilDestroy({ checkProperties: true }) + @Component({ standalone: true, imports: [ @@ -34,6 +32,9 @@ import { TranslationBaseComponent } from '../../language/translation-base.compon styleUrls: ['./invite-mutation.component.scss'] }) export class InviteMutationComponent extends TranslationBaseComponent { + private readonly toastrService = inject(ToastrService) + private readonly _dialogRef = inject(MatDialogRef) + /* * Getter & Setter for InvitationTypeEnum */ @@ -48,14 +49,6 @@ export class InviteMutationComponent extends TranslationBaseComponent { @ViewChild('emailInviteForm') emailInviteForm: EmailInviteFormComponent - constructor( - private readonly toastrService: ToastrService, - private readonly inviteService: InviteService, - private _dialogRef: MatDialogRef - ) { - super() - } - async onApply() { try { const result = await this.emailInviteForm.saveInvites() @@ -64,6 +57,8 @@ export class InviteMutationComponent extends TranslationBaseComponent { ...result, Default: `Invites ${result.total}, ignored ${result.ignored}` }) + + this._dialogRef.close(result) } catch (err) { this.toastrService.success(getErrorMessage(err)) } diff --git a/apps/cloud/src/app/@shared/language/language-selector/language-selector.component.html b/apps/cloud/src/app/@shared/language/language-selector/language-selector.component.html index 1eee60962..e8751dcff 100644 --- a/apps/cloud/src/app/@shared/language/language-selector/language-selector.component.html +++ b/apps/cloud/src/app/@shared/language/language-selector/language-selector.component.html @@ -1,9 +1,7 @@ - - {{ 'PAC.KEY_WORDS.Language' | translate: {Default: "Language"} }} - - - {{ language.name }} - - - - + + + diff --git a/apps/cloud/src/app/@shared/language/language-selector/language-selector.component.ts b/apps/cloud/src/app/@shared/language/language-selector/language-selector.component.ts index dbb1f3f1e..174aec77d 100644 --- a/apps/cloud/src/app/@shared/language/language-selector/language-selector.component.ts +++ b/apps/cloud/src/app/@shared/language/language-selector/language-selector.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, Input, Output, EventEmitter, forwardRef, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, Input, Output, EventEmitter, forwardRef, ChangeDetectorRef, signal, computed } from '@angular/core'; import { ILanguage } from '@metad/contracts'; import { TranslateModule } from '@ngx-translate/core'; import { LanguagesService, Store } from '../../../@core'; @@ -6,10 +6,10 @@ import { filter, tap } from 'rxjs/operators'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { CommonModule } from '@angular/common'; -import { MatFormFieldAppearance, MatFormFieldModule } from '@angular/material/form-field'; -import { MatSelectModule } from '@angular/material/select'; +import { MatFormFieldAppearance } from '@angular/material/form-field'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { TranslationBaseComponent } from '../translation-base.component'; +import { NgmSelectComponent } from '@metad/ocap-angular/common'; @UntilDestroy({ checkProperties: true }) @Component({ @@ -19,9 +19,8 @@ import { TranslationBaseComponent } from '../translation-base.component'; FormsModule, TranslateModule, - MatFormFieldModule, - MatSelectModule, - MatProgressSpinnerModule + MatProgressSpinnerModule, + NgmSelectComponent ], selector: 'pac-language-selector', templateUrl: './language-selector.component.html', @@ -35,11 +34,14 @@ import { TranslationBaseComponent } from '../translation-base.component'; ] }) export class LanguageSelectorComponent extends TranslationBaseComponent implements OnInit { - languages: ILanguage[]; + languages = signal([]) + // languages: ILanguage[]; loading: boolean; onChange: any = () => { } onTouch: any = () => { } + languagesOptions = computed(() => this.languages().map((language: ILanguage) => ({key: language.code, caption: language.name}))) + @Input() appearance: MatFormFieldAppearance /* @@ -179,21 +181,21 @@ export class LanguageSelectorComponent extends TranslationBaseComponent implemen async getAllLanguages() { const { items } = await this.languagesService.getAllLanguages(); - this.languages = items; + this.languages.set(items) } checkPreFilledLanguage() { if (!this.selectedLanguageCode) { return; } - if (this.languages?.length > 0) { + if (this.languages()?.length > 0) { const selectedLanguage = this.getLanguageByCode(this.selectedLanguageCode); this.onChangeLanguage(selectedLanguage); } } getLanguageByCode(code: ILanguage['code']) { - return this.languages.find( + return this.languages().find( (language: ILanguage) => code === language.code ); } diff --git a/apps/cloud/src/app/@theme/header/settings/settings.component.html b/apps/cloud/src/app/@theme/header/settings/settings.component.html new file mode 100644 index 000000000..20f5c4ab3 --- /dev/null +++ b/apps/cloud/src/app/@theme/header/settings/settings.component.html @@ -0,0 +1,34 @@ + \ No newline at end of file diff --git a/apps/cloud/src/app/@theme/header/settings/settings.component.ts b/apps/cloud/src/app/@theme/header/settings/settings.component.ts index 938fa4163..28805ddba 100644 --- a/apps/cloud/src/app/@theme/header/settings/settings.component.ts +++ b/apps/cloud/src/app/@theme/header/settings/settings.component.ts @@ -6,77 +6,40 @@ import { MatFormFieldModule } from '@angular/material/form-field' import { MatIconModule } from '@angular/material/icon' import { MatSelectModule } from '@angular/material/select' import { Router } from '@angular/router' +import { NgmSelectComponent } from '@metad/ocap-angular/common' import { DensityDirective } from '@metad/ocap-angular/core' -import { UntilDestroy } from '@ngneat/until-destroy' +import { DisplayBehaviour } from '@metad/ocap-core' import { TranslateModule } from '@ngx-translate/core' import { LANGUAGES, Store } from '../../../@core' import { UserPipe } from '../../../@shared' -@UntilDestroy({ checkProperties: true }) @Component({ - standalone: true, - imports: [ - CommonModule, - MatFormFieldModule, - FormsModule, - MatSelectModule, - MatIconModule, - MatButtonModule, - TranslateModule, - DensityDirective, - UserPipe - ], - selector: 'pac-header-settings', - template: ``, + standalone: true, + imports: [ + CommonModule, + MatFormFieldModule, + FormsModule, + MatSelectModule, + MatIconModule, + MatButtonModule, + TranslateModule, + DensityDirective, + UserPipe, + NgmSelectComponent + ], + selector: 'pac-header-settings', + templateUrl: './settings.component.html' }) export class HeaderSettingsComponent { languages = LANGUAGES + DisplayBehaviour = DisplayBehaviour public readonly isAuthenticated$ = this.store.user$ preferredLanguage$ = this.store.preferredLanguage$ constructor(private store: Store, private router: Router) {} - onLanguageSelect({ value: language }): void { + onLanguageSelect(language): void { this.store.preferredLanguage = language } onProfile() { diff --git a/apps/cloud/src/app/_app.component.scss b/apps/cloud/src/app/_app.component.scss new file mode 100644 index 000000000..9d119e10f --- /dev/null +++ b/apps/cloud/src/app/_app.component.scss @@ -0,0 +1,32 @@ +@import './features/home/_home'; + +.nx-theme-dark, .dark { + --ngm-card-bg-color: theme(colors.bluegray.800); + --ngm-card-border-color: theme(colors.bluegray.700); +} + +body, .light { + --ngm-card-bg-color: theme(colors.white); + --ngm-card-border-color: theme(colors.gray.100); +} + +// popper +.ngxp__container.ngxp__animation { + @apply p-0 shadow-none z-10; + background-color: var(--ngm-card-bg-color); + border-color: var(--ngm-card-border-color); + + .ngxp__inner { + @apply shadow-lg border-0 border-slate-200 overflow-hidden rounded-lg border-t-0; + } + .ngxp__arrow::before { + @apply shadow-md; + background-color: var(--ngm-card-bg-color); + } + + &[data-popper-placement="bottom-end"] { + .ngxp__arrow { + right: 12px; + } + } +} diff --git a/apps/cloud/src/app/app.component.ts b/apps/cloud/src/app/app.component.ts index 66fcef553..c89132b71 100644 --- a/apps/cloud/src/app/app.component.ts +++ b/apps/cloud/src/app/app.component.ts @@ -1,14 +1,17 @@ import { Platform } from '@angular/cdk/platform' import { DOCUMENT } from '@angular/common' import { ChangeDetectionStrategy, Component, Inject, OnInit, Renderer2 } from '@angular/core' +import { DateFnsAdapter, MAT_DATE_FNS_FORMATS } from '@angular/material-date-fns-adapter' +import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core' import { MatIconRegistry } from '@angular/material/icon' import { DomSanitizer, Title } from '@angular/platform-browser' -import { TranslateService } from '@ngx-translate/core' import { ThemesEnum } from '@metad/cloud/state' +import { nonNullable } from '@metad/core' +import { TranslateService } from '@ngx-translate/core' import { NGXLogger } from 'ngx-logger' import { combineLatest } from 'rxjs' -import { filter, map, tap } from 'rxjs/operators' -import { ICONS, PACThemeService, Store, UpdateService } from './@core' +import { filter, map } from 'rxjs/operators' +import { ICONS, LanguagesService, PACThemeService, Store, UpdateService, mapDateLocale } from './@core' import { AppService } from './app.service' @@ -16,7 +19,14 @@ import { AppService } from './app.service' changeDetection: ChangeDetectionStrategy.OnPush, selector: 'pac-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'] + styleUrls: ['./app.component.scss'], + providers: [ + { + provide: DateAdapter, + useClass: DateFnsAdapter + }, + { provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FNS_FORMATS } + ] }) export class AppComponent implements OnInit { constructor( @@ -24,6 +34,7 @@ export class AppComponent implements OnInit { public readonly appService: AppService, public readonly updateService: UpdateService, private readonly themeService: PACThemeService, + private readonly languagesService: LanguagesService, private translate: TranslateService, private logger: NGXLogger, @Inject(DOCUMENT) @@ -33,15 +44,17 @@ export class AppComponent implements OnInit { private domSanitizer: DomSanitizer, private platform: Platform, private title: Title, + private _adapter: DateAdapter ) { translate.setDefaultLang('en') // the lang to use, if the lang isn't available, it will use the current loader to get them translate.use(this.store.preferredLanguage || navigator.language || 'en') this.document.documentElement.lang = translate.currentLang - this.store.preferredLanguage$.pipe(filter(value => !!value)).subscribe((language) => { + this.store.preferredLanguage$.pipe(filter(nonNullable)).subscribe((language) => { this.translate.use(language) this.document.documentElement.lang = language + this._adapter.setLocale(mapDateLocale(language)) }) this.translate.stream('PAC.Title').subscribe((title) => this.title.setTitle(title)) @@ -54,10 +67,8 @@ export class AppComponent implements OnInit { ngOnInit() { combineLatest([ this.appService.isMobile$, - this.store.preferredTheme$.pipe( - map((theme) => `nx-theme-${theme ?? ThemesEnum.default}`)) - ]) - .subscribe(([isMobile, theme]) => { + this.store.preferredTheme$.pipe(map((theme) => `nx-theme-${theme ?? ThemesEnum.default}`)) + ]).subscribe(([isMobile, theme]) => { // for body const body = this.document.getElementsByTagName('body')[0] const bodyThemeRemove = Array.from(body.classList).filter((item: string) => item.includes('-theme')) @@ -68,12 +79,11 @@ export class AppComponent implements OnInit { this.renderer.addClass(body, value) }) - if (isMobile && (this.platform.IOS || this.platform.ANDROID) ) { + if (isMobile && (this.platform.IOS || this.platform.ANDROID)) { this.renderer.addClass(body, 'mobile') } else { body.classList.remove('mobile') } }) } - } diff --git a/apps/cloud/src/app/app.module.ts b/apps/cloud/src/app/app.module.ts index ab4773fec..e746f0d0b 100644 --- a/apps/cloud/src/app/app.module.ts +++ b/apps/cloud/src/app/app.module.ts @@ -1,30 +1,24 @@ import { PlatformModule } from '@angular/cdk/platform' -import { registerLocaleData } from '@angular/common' -import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http' -import en from '@angular/common/locales/en' -import localeZhExtra from '@angular/common/locales/extra/zh-Hans' -import zh from '@angular/common/locales/zh' -import localeZh from '@angular/common/locales/zh-Hans' -import { APP_INITIALIZER, ErrorHandler, LOCALE_ID, NgModule } from '@angular/core' +import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http' +import { APP_INITIALIZER, LOCALE_ID, NgModule } from '@angular/core' import { ReactiveFormsModule } from '@angular/forms' import { MatSnackBarModule } from '@angular/material/snack-bar' import { BrowserModule, HammerModule } from '@angular/platform-browser' import { BrowserAnimationsModule } from '@angular/platform-browser/animations' -import { Router, RouteReuseStrategy } from '@angular/router' +import { RouteReuseStrategy } from '@angular/router' import { ServiceWorkerModule } from '@angular/service-worker' import { Ability, PureAbility } from '@casl/ability' import { AbilityModule } from '@casl/angular' -import { NxCoreModule, registerLocaleData as nxRegisterLocaleData, zhHans } from '@metad/core' -import * as Sentry from "@sentry/angular" +import { NxCoreModule } from '@metad/core' import { LoggerModule, NgxLoggerLevel } from 'ngx-logger' import { MarkdownModule } from 'ngx-markdown' import { NgxPermissionsModule } from 'ngx-permissions' -import { environment } from '../environments/environment' import { APIInterceptor, AppInitService, AppRouteReuseStrategy, CoreModule, + LOCALE_DEFAULT, LanguageInterceptor, TenantInterceptor, TokenInterceptor, @@ -42,12 +36,6 @@ function detectSubjectType(subject) { return subject[TYPE_KEY] } -const LOCALE = 'zh-Hans' -registerLocaleData(localeZh, LOCALE, localeZhExtra) -registerLocaleData(zh) -registerLocaleData(en) -nxRegisterLocaleData(zhHans, LOCALE) - @NgModule({ declarations: [AppComponent], imports: [ @@ -68,7 +56,7 @@ nxRegisterLocaleData(zhHans, LOCALE) level: NgxLoggerLevel.WARN, serverLogLevel: NgxLoggerLevel.ERROR, colorScheme: ['purple', 'teal', 'gray', 'gray', 'red', 'red', 'red'], - enableSourceMaps: true, + enableSourceMaps: true }), NxCoreModule.forRoot(), AbilityModule, @@ -85,7 +73,7 @@ nxRegisterLocaleData(zhHans, LOCALE) UpdateService, { provide: LOCALE_ID, - useValue: LOCALE + useValue: LOCALE_DEFAULT }, { provide: RouteReuseStrategy, @@ -120,7 +108,7 @@ nxRegisterLocaleData(zhHans, LOCALE) multi: true }, { provide: Ability, useValue: new Ability([], { detectSubjectType }) }, - { provide: PureAbility, useExisting: Ability }, + { provide: PureAbility, useExisting: Ability } // { // provide: ErrorHandler, diff --git a/apps/cloud/src/app/features/_features-theme.scss b/apps/cloud/src/app/features/_features-theme.scss index ae203ade1..90aed8a81 100644 --- a/apps/cloud/src/app/features/_features-theme.scss +++ b/apps/cloud/src/app/features/_features-theme.scss @@ -259,23 +259,6 @@ $sidebar-collapsed-width: 40px; } } - .ngxp__container.ngxp__animation { - @apply p-0 border-transparent shadow-none bg-transparent z-10; - - .ngxp__inner { - // background-color: mat.get-color-from-palette($background, card); - @apply shadow-lg border-0 border-slate-200 overflow-hidden rounded-lg border-t-0; - } - .ngxp__arrow::before { - @apply shadow-md bg-slate-100; - } - - &[data-popper-placement="bottom-end"] { - .ngxp__arrow { - right: 12px; - } - } - } .pac-toolbar-search { .mat-mdc-input-element { diff --git a/apps/cloud/src/app/features/home/_home.scss b/apps/cloud/src/app/features/home/_home.scss new file mode 100644 index 000000000..2a65f5447 --- /dev/null +++ b/apps/cloud/src/app/features/home/_home.scss @@ -0,0 +1,23 @@ +.pac-home__content { + .pac-home__gridster-item { + background: transparent; + + .pac-home__widget-actions { + position: absolute; + right: -30px; + top: 0; + opacity: 0; + visibility: hidden; + display: flex; + flex-direction: column; + } + + &:hover { + z-index: 1000 !important; + .pac-home__widget-actions { + opacity: 1; + visibility: visible; + } + } + } +} diff --git a/apps/cloud/src/app/features/home/dashboard/dashboard.component.html b/apps/cloud/src/app/features/home/dashboard/dashboard.component.html index 7d7d729d3..83249568d 100644 --- a/apps/cloud/src/app/features/home/dashboard/dashboard.component.html +++ b/apps/cloud/src/app/features/home/dashboard/dashboard.component.html @@ -40,10 +40,10 @@

{{ 'PAC.MENU.HOME.HELLO' | translate: {Default: "Hello"} }}
🟢 - - {{ 'PAC.MENU.HOME.HaveSemanticModels' | translate: { - Default: 'Have ' + quickGuides.model.quantity + ' semantic models', - quantity: quickGuides.model.quantity + + {{quickGuides.model.quantity}} + {{ 'PAC.KEY_WORDS.SemanticModels' | translate: { + Default: 'Semantic Models', } }} @@ -60,11 +60,9 @@

{{ 'PAC.MENU.HOME.HELLO' | translate: {Default: "Hello"} }} @@ -80,11 +78,9 @@

{{ 'PAC.MENU.HOME.HELLO' | translate: {Default: "Hello"} }} diff --git a/apps/cloud/src/app/features/home/dashboard/dashboard.component.scss b/apps/cloud/src/app/features/home/dashboard/dashboard.component.scss index 5b95218bf..5913a63ea 100644 --- a/apps/cloud/src/app/features/home/dashboard/dashboard.component.scss +++ b/apps/cloud/src/app/features/home/dashboard/dashboard.component.scss @@ -44,28 +44,6 @@ gridster { height: 100%; } -.pac-home__gridster-item { - background: transparent; - - .pac-home__widget-actions { - position: absolute; - right: -30px; - top: 0; - opacity: 0; - visibility: hidden; - display: flex; - flex-direction: column; - } - - &:hover { - z-index: 1000 !important; - .pac-home__widget-actions { - opacity: 1; - visibility: visible; - } - } -} - .pac-home__assets-empty { height: 280px; text-align: center; diff --git a/apps/cloud/src/app/features/home/dashboard/dashboard.component.ts b/apps/cloud/src/app/features/home/dashboard/dashboard.component.ts index 0fc4742fe..348b057d8 100644 --- a/apps/cloud/src/app/features/home/dashboard/dashboard.component.ts +++ b/apps/cloud/src/app/features/home/dashboard/dashboard.component.ts @@ -22,6 +22,7 @@ import { import { AbilityActions, FeedsService, + OrganizationDemoNetworkEnum, OrganizationsService, PermissionsEnum, ROUTE_ANIMATIONS_ELEMENTS, @@ -235,7 +236,9 @@ export class DashboardComponent extends TranslationBaseComponent implements OnIn } this.creatingDemo = true try { - await firstValueFrom(this.organizationsService.demo(this.store.organizationId)) + await firstValueFrom(this.organizationsService.demo(this.store.organizationId, { + source: OrganizationDemoNetworkEnum.aliyun + })) this.toastrService.success('PAC.MENU.HOME.GenerateSamples', { Default: 'Generate samples' }) this.quickGuides.sample.complete = true this.store.selectedOrganization = { diff --git a/apps/cloud/src/app/features/home/story-widget/story-widget.component.html b/apps/cloud/src/app/features/home/story-widget/story-widget.component.html index 035bdb430..d5d9fd2c8 100644 --- a/apps/cloud/src/app/features/home/story-widget/story-widget.component.html +++ b/apps/cloud/src/app/features/home/story-widget/story-widget.component.html @@ -1,9 +1,6 @@ - +
- {{error | json}} -
+ {{ error | json }} +

\ No newline at end of file diff --git a/apps/cloud/src/app/features/home/story-widget/story-widget.component.ts b/apps/cloud/src/app/features/home/story-widget/story-widget.component.ts index 5ed9e0d53..35a00e8ea 100644 --- a/apps/cloud/src/app/features/home/story-widget/story-widget.component.ts +++ b/apps/cloud/src/app/features/home/story-widget/story-widget.component.ts @@ -1,10 +1,11 @@ -import { Component, Input, inject } from '@angular/core' +import { Component, Input, computed, inject } from '@angular/core' +import { toSignal } from '@angular/core/rxjs-interop' import { WidgetsService, convertStoryResult, convertStoryWidgetResult } from '@metad/cloud/state' import { WasmAgentService } from '@metad/ocap-angular/wasm-agent' import { AgentType } from '@metad/ocap-core' import { omit } from 'lodash-es' import { BehaviorSubject, EMPTY } from 'rxjs' -import { catchError, filter, map, shareReplay, switchMap, tap } from 'rxjs/operators' +import { catchError, filter, switchMap } from 'rxjs/operators' import { registerWasmAgentModel } from '../../../@core' @Component({ @@ -27,38 +28,40 @@ export class StoryWidgetFeedComponent { } private id$ = new BehaviorSubject(null) - public readonly widget$ = this.id$.pipe( - filter((value) => !!value), - switchMap((id) => - this.widgetsService - .getOne(id, [ - 'point', - 'point.story', - 'point.story.points', - 'createdBy', - // 'point.story.model', - // 'point.story.model.indicators', - // 'point.story.model.dataSource', - // 'point.story.model.dataSource.type' + public readonly widget = toSignal( + this.id$.pipe( + filter((value) => !!value), + switchMap((id) => + this.widgetsService + .getOne(id, [ + 'point', + 'point.story', + 'point.story.points', + 'createdBy', + // 'point.story.model', + // 'point.story.model.indicators', + // 'point.story.model.dataSource', + // 'point.story.model.dataSource.type' - 'point.story.models', - 'point.story.models.dataSource', - 'point.story.models.dataSource.type', - 'point.story.models.indicators' - ]) - .pipe( - catchError((err) => { - this.error$.next(err.error) - return EMPTY - }) - ) - ), - shareReplay(1) + 'point.story.models', + 'point.story.models.dataSource', + 'point.story.models.dataSource.type', + 'point.story.models.indicators' + ]) + .pipe( + catchError((err) => { + this.error$.next(err.error) + return EMPTY + }) + ) + ) + ) ) - public readonly story$ = this.widget$.pipe( - map((widget) => { - return convertStoryResult({ + public readonly story = computed(() => { + const widget = this.widget() + if (widget) { + const story = convertStoryResult({ ...widget.point.story, points: [ { @@ -68,21 +71,23 @@ export class StoryWidgetFeedComponent { } ] }) - }), - tap((story) => { + story.models?.forEach((model) => { if (model.agentType === AgentType.Wasm) { registerWasmAgentModel(this.wasmAgent, model) } }) - }) - ) - public readonly _widget$ = this.widget$.pipe( - map((widget) => { + return story + } + }) + + public readonly _widget = computed(() => { + const widget = this.widget() + if (widget) { return convertStoryWidgetResult(widget) - }) - ) + } + }) public error$ = new BehaviorSubject(null) } diff --git a/apps/cloud/src/app/features/indicator/market/market.component.html b/apps/cloud/src/app/features/indicator/market/market.component.html index 22fa6ab84..d897d309d 100644 --- a/apps/cloud/src/app/features/indicator/market/market.component.html +++ b/apps/cloud/src/app/features/indicator/market/market.component.html @@ -45,6 +45,12 @@ [(ngModel)]="types" > +
+ + +
([]) + public certificationsControl = new FormControl() public readonly tags$ = this.tagService.getAll('indicator') public readonly index$ = new BehaviorSubject(1) @@ -95,7 +98,7 @@ export class MarketComponent { private readonly permissionApprovals$ = this.refreshApproval$.pipe( switchMap(() => this.permissionApprovalService.getMy()), map(({ items }) => items), - untilDestroyed(this), + takeUntilDestroyed(), shareReplay(1) ) // 所有的公开指标 @@ -155,7 +158,7 @@ export class MarketComponent { return indicators }), - untilDestroyed(this), + takeUntilDestroyed(), shareReplay(1) ) @@ -211,10 +214,14 @@ export class MarketComponent { return indicators }), switchMap((indicators) => this.types$.pipe(map((types) => indicators.filter((indicator) => types.length ? types.includes(indicator.type) : true)))), + switchMap((indicators) => this.certificationsControl.valueChanges.pipe( + startWith(null), + map((certification) => indicators.filter((indicator) => certification?.length ? certification.includes(indicator.certification?.id) : true))) + ), switchMap((indicators) => this.selectedTagNames$.pipe(map((tags) => indicators.filter((indicator) => { return tags.length === 0 || tags.every((tag) => find(indicator.tags, (item) => item.name === tag)) })))), - untilDestroyed(this), + takeUntilDestroyed(), shareReplay(1) ) @@ -237,6 +244,15 @@ export class MarketComponent { }), ) + public readonly certifications = toSignal(this.certificationService.getAll().pipe( + map((items) => items.map((item) => ({ + key: item.id, + value: item.id, + caption: item.name, + color: 'green' + }))) + )) + onPageIndexChange(index) { this.index$.next(index) } diff --git a/apps/cloud/src/app/features/indicator/viewer/viewer.component.html b/apps/cloud/src/app/features/indicator/viewer/viewer.component.html index 191444598..46c1ae357 100644 --- a/apps/cloud/src/app/features/indicator/viewer/viewer.component.html +++ b/apps/cloud/src/app/features/indicator/viewer/viewer.component.html @@ -1,189 +1,193 @@ -
- - -
-
- {{ 'PAC.INDICATOR.REGISTER.NAME' | translate }}: -
-
- {{indicator.name}} -
-
- -
-
- {{ 'PAC.INDICATOR.REGISTER.Code' | translate: {Default: 'Code'} }}: +
- -
-
-
- {{ 'PAC.INDICATOR.VIEWER.BASIC_INFORMATION' | translate: {Default: 'Basic information'} }} -
-
-
- -
- {{ 'PAC.INDICATOR.REGISTER.BUSINESS_AREA' | translate }}: -
-
- {{indicator.businessArea?.name}} -
- -
- {{ 'PAC.INDICATOR.REGISTER.UNIT' | translate }}: -
-
- {{indicator.unit}} -
- -
- {{ 'PAC.INDICATOR.REGISTER.CREATED_BY' | translate }}: -
-
- {{indicator.createdBy | createdBy}} -
- -
- {{ 'PAC.INDICATOR.REGISTER.PRINCIPAL' | translate }}: -
-
- {{indicator.principal}} -
- -
- {{ 'PAC.INDICATOR.REGISTER.Certification' | translate: {Default: 'Certification'} }}: -
-
- - {{indicator.certification.name}} - -
- -
- {{ 'PAC.INDICATOR.REGISTER.VALIDITY' | translate }}: -
-
- {{indicator.validity}} -
- -
- {{ 'PAC.INDICATOR.REGISTER.STATUS' | translate }}: -
-
- -
- -
- {{ 'PAC.INDICATOR.REGISTER.Visible' | translate: {Default: 'Visible'} }}: -
-
- -
- -
- {{ 'PAC.INDICATOR.REGISTER.Tags' | translate: {Default: 'Tags'} }}: -
-
- -
+ + + +
+ +
- {{ 'PAC.INDICATOR.REGISTER.BUSINESS' | translate }}: + {{ 'PAC.INDICATOR.REGISTER.NAME' | translate }}:
-
- {{indicator.business}} +
+ {{indicator.name}}
-
-
-
- {{ 'PAC.INDICATOR.VIEWER.MODEL_INFORMATION' | translate: {Default: 'Model information'} }} -
-
-
- -
- {{ 'PAC.INDICATOR.REGISTER.MODEL' | translate }}: -
- - -
- {{ 'PAC.INDICATOR.REGISTER.ENTITY' | translate }}: -
-
- {{indicator.entity}} -
- -
- {{ 'PAC.INDICATOR.REGISTER.TYPE' | translate }}: -
-
- -
- -
- {{ 'PAC.INDICATOR.REGISTER.MEASURE' | translate }}: -
-
- {{indicator.options?.measure}} -
- -
- {{ 'PAC.INDICATOR.REGISTER.Aggregator' | translate: {Default: 'Aggregator'} }}: -
-
- {{indicator.options?.aggregator}} -
- -
- {{ 'PAC.INDICATOR.REGISTER.FORMULA' | translate }}: -
-
- {{indicator.options?.formula}} -
- -
- {{ 'PAC.INDICATOR.REGISTER.DIMENSIONS' | translate }}: -
-
- {{indicator.options?.dimensions}} -
- +
- {{ 'PAC.INDICATOR.REGISTER.FILTERS' | translate }}: + {{ 'PAC.INDICATOR.REGISTER.Code' | translate: {Default: 'Code'} }}:
-
- +
+ {{indicator.code}}
-
+ + + + + {{ 'PAC.INDICATOR.VIEWER.BASIC_INFORMATION' | translate: {Default: 'Basic information'} }} + + + +
+
+ {{ 'PAC.INDICATOR.REGISTER.BUSINESS_AREA' | translate }}: +
+
+ {{indicator.businessArea?.name}} +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.UNIT' | translate }}: +
+
+ {{indicator.unit}} +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.CREATED_BY' | translate }}: +
+
+ {{indicator.createdBy | createdBy}} +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.PRINCIPAL' | translate }}: +
+
+ {{indicator.principal}} +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.Certification' | translate: {Default: 'Certification'} }}: +
+
+ + {{indicator.certification.name}} + +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.VALIDITY' | translate }}: +
+
+ {{indicator.validity}} +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.STATUS' | translate }}: +
+
+ +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.Visible' | translate: {Default: 'Visible'} }}: +
+
+ +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.Tags' | translate: {Default: 'Tags'} }}: +
+
+ +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.BUSINESS' | translate }}: +
+
+ {{indicator.business}} +
+ +
+
+
+ + + + {{ 'PAC.INDICATOR.VIEWER.MODEL_INFORMATION' | translate: {Default: 'Model information'} }} + + + +
+
+ {{ 'PAC.INDICATOR.REGISTER.MODEL' | translate }}: +
+ + +
+ {{ 'PAC.INDICATOR.REGISTER.ENTITY' | translate }}: +
+
+ {{indicator.entity}} +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.TYPE' | translate }}: +
+
+ +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.MEASURE' | translate }}: +
+
+ {{indicator.options?.measure}} +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.Aggregator' | translate: {Default: 'Aggregator'} }}: +
+
+ {{indicator.options?.aggregator}} +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.FORMULA' | translate }}: +
+
+ {{indicator.options?.formula}} +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.DIMENSIONS' | translate }}: +
+
+ {{indicator.options?.dimensions}} +
+ +
+ {{ 'PAC.INDICATOR.REGISTER.FILTERS' | translate }}: +
+
+ +
+
+
+
diff --git a/apps/cloud/src/app/features/indicator/viewer/viewer.component.scss b/apps/cloud/src/app/features/indicator/viewer/viewer.component.scss index 6e6d25280..16fd50f81 100644 --- a/apps/cloud/src/app/features/indicator/viewer/viewer.component.scss +++ b/apps/cloud/src/app/features/indicator/viewer/viewer.component.scss @@ -1,6 +1,3 @@ :host { - flex: 1; - overflow-y: auto; - overflow-x: hidden; - max-width: 100%; + @apply flex-1 max-w-full flex flex-col overflow-y-auto overflow-x-hidden; } diff --git a/apps/cloud/src/app/features/indicator/viewer/viewer.component.ts b/apps/cloud/src/app/features/indicator/viewer/viewer.component.ts index 57ca2356d..e6e06a75b 100644 --- a/apps/cloud/src/app/features/indicator/viewer/viewer.component.ts +++ b/apps/cloud/src/app/features/indicator/viewer/viewer.component.ts @@ -1,16 +1,17 @@ -import { Component, OnInit, inject } from '@angular/core' +import { CommonModule } from '@angular/common' +import { Component, inject } from '@angular/core' +import { toSignal } from '@angular/core/rxjs-interop' +import { FormsModule } from '@angular/forms' import { ActivatedRoute, Router, RouterModule } from '@angular/router' import { IndicatorsService } from '@metad/cloud/state' +import { NxSelectionModule } from '@metad/components/selection' +import { TranslateModule, TranslateService } from '@ngx-translate/core' +import formatRelative from 'date-fns/formatRelative' import { isNil, negate } from 'lodash-es' import { distinctUntilChanged, filter, map, startWith, switchMap } from 'rxjs/operators' import { AbilityActions, getDateLocale } from '../../../@core' -import { IndicatorTypeComponent } from '../../../@shared/indicator' -import { CommonModule } from '@angular/common' import { CreatedByPipe, MaterialModule, TagViewerComponent } from '../../../@shared' -import { TranslateModule, TranslateService } from '@ngx-translate/core' -import { FormsModule } from '@angular/forms' -import { NxSelectionModule } from '@metad/components/selection' -import formatRelative from 'date-fns/formatRelative' +import { IndicatorTypeComponent } from '../../../@shared/indicator' @Component({ standalone: true, @@ -20,7 +21,7 @@ import formatRelative from 'date-fns/formatRelative' FormsModule, MaterialModule, TranslateModule, - + CreatedByPipe, NxSelectionModule, IndicatorTypeComponent, @@ -30,29 +31,31 @@ import formatRelative from 'date-fns/formatRelative' templateUrl: './viewer.component.html', styleUrls: ['./viewer.component.scss'] }) -export class ViewerComponent implements OnInit { +export class ViewerComponent { AbilityActions = AbilityActions public readonly translateService = inject(TranslateService) - - public readonly indicator$ = this._route.paramMap.pipe( - startWith(this._route.snapshot.paramMap), - map((paramMap) => paramMap.get('id')), - filter(negate(isNil)), - distinctUntilChanged(), - switchMap((id) => this.indicatorsService.getById(id, ['model', 'businessArea', 'createdBy', 'certification'])), - map((indicator) => ({ - ...indicator, - validity: formatRelative(new Date(indicator.validity), new Date(), { locale: getDateLocale(this.translateService.currentLang) }), - } as any)) - ) + private indicatorsService = inject(IndicatorsService) + private _route = inject(ActivatedRoute) + private _router = inject(Router) - constructor( - private indicatorsService: IndicatorsService, - private _route: ActivatedRoute, - private _router: Router - ) {} - - ngOnInit() {} + public readonly indicator = toSignal( + this._route.paramMap.pipe( + startWith(this._route.snapshot.paramMap), + map((paramMap) => paramMap.get('id')), + filter(negate(isNil)), + distinctUntilChanged(), + switchMap((id) => this.indicatorsService.getById(id, ['model', 'businessArea', 'createdBy', 'certification'])), + map( + (indicator) => + ({ + ...indicator, + validity: formatRelative(new Date(indicator.validity), new Date(), { + locale: getDateLocale(this.translateService.currentLang) + }) + } as any) + ) + ) + ) edit(id: string) { this._router.navigate(['../../edit/', id], { relativeTo: this._route }) diff --git a/apps/cloud/src/app/features/project/indicators/my/my.component.html b/apps/cloud/src/app/features/project/indicators/all/all.component.html similarity index 96% rename from apps/cloud/src/app/features/project/indicators/my/my.component.html rename to apps/cloud/src/app/features/project/indicators/all/all.component.html index 223ddc85e..363a1eca1 100644 --- a/apps/cloud/src/app/features/project/indicators/my/my.component.html +++ b/apps/cloud/src/app/features/project/indicators/all/all.component.html @@ -1,4 +1,5 @@
diff --git a/apps/cloud/src/app/features/project/indicators/all/all.component.scss b/apps/cloud/src/app/features/project/indicators/all/all.component.scss new file mode 100644 index 000000000..b38f13e75 --- /dev/null +++ b/apps/cloud/src/app/features/project/indicators/all/all.component.scss @@ -0,0 +1,3 @@ +:host { + @apply w-full overflow-hidden flex-1 max-w-full flex flex-col p-4; +} \ No newline at end of file diff --git a/apps/cloud/src/app/features/project/indicators/my/my.component.ts b/apps/cloud/src/app/features/project/indicators/all/all.component.ts similarity index 93% rename from apps/cloud/src/app/features/project/indicators/my/my.component.ts rename to apps/cloud/src/app/features/project/indicators/all/all.component.ts index 17872e041..ffd0f9441 100644 --- a/apps/cloud/src/app/features/project/indicators/my/my.component.ts +++ b/apps/cloud/src/app/features/project/indicators/all/all.component.ts @@ -27,11 +27,11 @@ import { ProjectIndicatorsComponent } from '../indicators.component' AppearanceDirective, NxTableModule ], - selector: 'pac-indicator-my', - templateUrl: './my.component.html', - styleUrls: ['./my.component.scss'] + selector: 'pac-indicator-all', + templateUrl: './all.component.html', + styleUrls: ['./all.component.scss'] }) -export class MyIndicatorComponent implements OnDestroy { +export class AllIndicatorComponent implements OnDestroy { private projectComponent = inject(ProjectComponent) private indicatorsComponent = inject(ProjectIndicatorsComponent) diff --git a/apps/cloud/src/app/features/project/indicators/approvals/approvals.component.scss b/apps/cloud/src/app/features/project/indicators/approvals/approvals.component.scss index 7dc610e40..809713427 100644 --- a/apps/cloud/src/app/features/project/indicators/approvals/approvals.component.scss +++ b/apps/cloud/src/app/features/project/indicators/approvals/approvals.component.scss @@ -1,3 +1,3 @@ :host { - @apply flex-1 max-w-full overflow-hidden flex flex-col; + @apply flex-1 w-full max-w-full overflow-hidden flex flex-col p-4; } diff --git a/apps/cloud/src/app/features/project/indicators/indicators.component.html b/apps/cloud/src/app/features/project/indicators/indicators.component.html index 324232101..283bd7739 100644 --- a/apps/cloud/src/app/features/project/indicators/indicators.component.html +++ b/apps/cloud/src/app/features/project/indicators/indicators.component.html @@ -1,6 +1,6 @@ -
-
-

+
+
+

{{ 'PAC.Project.ManageIndicators' | translate: {Default: "Manage Indicators"} }}

@@ -8,7 +8,7 @@

(change)="handleUploadChange($event)" (click)="fileUpload.value=null;">
- -

-

diff --git a/apps/cloud/src/app/features/project/indicators/register/register.component.scss b/apps/cloud/src/app/features/project/indicators/register/register.component.scss index b761d93a6..0845bc75f 100644 --- a/apps/cloud/src/app/features/project/indicators/register/register.component.scss +++ b/apps/cloud/src/app/features/project/indicators/register/register.component.scss @@ -1,5 +1,5 @@ :host { - @apply overflow-auto flex-1 max-w-full flex flex-col; + @apply overflow-auto flex-1 w-full max-w-full flex flex-col; } .pac-indicator-register__form.pac-page__body { diff --git a/apps/cloud/src/app/features/project/indicators/register/register.component.ts b/apps/cloud/src/app/features/project/indicators/register/register.component.ts index 973f9d12d..1fce299b8 100644 --- a/apps/cloud/src/app/features/project/indicators/register/register.component.ts +++ b/apps/cloud/src/app/features/project/indicators/register/register.component.ts @@ -1,5 +1,5 @@ import { CommonModule } from '@angular/common' -import { ChangeDetectorRef, Component, HostListener, inject, Optional, ViewChild } from '@angular/core' +import { ChangeDetectorRef, Component, HostListener, inject, OnDestroy, Optional, ViewChild } from '@angular/core' import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { MatDialog } from '@angular/material/dialog' import { ActivatedRoute, Router, RouterModule } from '@angular/router' @@ -20,6 +20,7 @@ import { MaterialModule, userLabel } from '../../../../@shared' import { ProjectComponent } from '../../project.component' import { exportIndicator } from '../../types' import { IndicatorRegisterFormComponent } from '../register-form/register-form.component' +import { ProjectIndicatorsComponent } from '../indicators.component' // AOA : array of array type AOA = any[][] @@ -47,8 +48,9 @@ type AOA = any[][] styleUrls: ['./register.component.scss'], providers: [] }) -export class IndicatorRegisterComponent extends TranslationBaseComponent { +export class IndicatorRegisterComponent extends TranslationBaseComponent implements OnDestroy { private projectComponent = inject(ProjectComponent) + private indicatorsComponent? = inject(ProjectIndicatorsComponent, {optional: true}) @ViewChild('register_form') registerForm: IndicatorRegisterFormComponent @@ -71,6 +73,11 @@ export class IndicatorRegisterComponent extends TranslationBaseComponent { public readonly indicator$ = this._route.paramMap.pipe( startWith(this._route.snapshot.paramMap), map((paramMap) => paramMap.get('id')), + tap((id) => { + if (id === 'new') { + this.indicatorsComponent?.setCurrentLink({id: 'new'} as Indicator) + } + }), filter((id) => !isNil(id) && id !== 'new'), distinctUntilChanged(), switchMap((id) => { @@ -128,6 +135,7 @@ export class IndicatorRegisterComponent extends TranslationBaseComponent { delay(300) ).subscribe((indicator) => { this.registerForm.formGroup.markAsPristine() + this.indicatorsComponent?.setCurrentLink(indicator) }) constructor( private indicatorsService: IndicatorsService, @@ -157,10 +165,11 @@ export class IndicatorRegisterComponent extends TranslationBaseComponent { indicator = await firstValueFrom(this.indicatorsService.create(indicator)) this.loading = false - if (indicator.id) { + if (this.indicator.id) { this.toastrService.success('PAC.INDICATOR.REGISTER.SaveIndicator', { Default: 'Save Indicator' }) } else { this.toastrService.success('PAC.INDICATOR.REGISTER.CreateIndicator', { Default: 'Create Indicator' }) + this.indicatorsComponent?.replaceNewIndicator(indicator) } await this.projectComponent.refreshIndicators() @@ -234,4 +243,8 @@ export class IndicatorRegisterComponent extends TranslationBaseComponent { this.onSubmit() } } + + ngOnDestroy(): void { + this.indicatorsComponent?.setCurrentLink(null) + } } diff --git a/apps/cloud/src/app/features/project/members/members.component.html b/apps/cloud/src/app/features/project/members/members.component.html index 5ba9a02d3..1f577a479 100644 --- a/apps/cloud/src/app/features/project/members/members.component.html +++ b/apps/cloud/src/app/features/project/members/members.component.html @@ -7,7 +7,7 @@ [user]="project?.owner">
- - - - - \ No newline at end of file + [active]="rla2.isActive" + > + {{ 'PAC.KEY_WORDS.Password' | translate: {Default: 'Password'} }} + + +
+ + + + diff --git a/apps/cloud/src/app/features/setting/account/account.component.scss b/apps/cloud/src/app/features/setting/account/account.component.scss index ef3ec0dee..e12c20894 100644 --- a/apps/cloud/src/app/features/setting/account/account.component.scss +++ b/apps/cloud/src/app/features/setting/account/account.component.scss @@ -1,3 +1,3 @@ :host { - @apply flex flex-col flex-1 max-w-full items-center gap-4; + @apply flex flex-col flex-1 max-w-full items-stretch; } diff --git a/apps/cloud/src/app/features/setting/account/account.component.ts b/apps/cloud/src/app/features/setting/account/account.component.ts index 982f329ac..d5851d34a 100644 --- a/apps/cloud/src/app/features/setting/account/account.component.ts +++ b/apps/cloud/src/app/features/setting/account/account.component.ts @@ -1,27 +1,30 @@ import { CommonModule } from '@angular/common' -import { Component } from '@angular/core' +import { Component, inject } from '@angular/core' +import { toSignal } from '@angular/core/rxjs-interop' +import { MatDividerModule } from '@angular/material/divider' import { MatTabsModule } from '@angular/material/tabs' import { RouterModule } from '@angular/router' -import { UntilDestroy } from '@ngneat/until-destroy' import { TranslateModule } from '@ngx-translate/core' -import { IUser, Store } from '../../../@core' +import { Store } from '../../../@core' import { UserAvatarEditorComponent, UserPipe } from '../../../@shared' -@UntilDestroy({ checkProperties: true }) @Component({ - standalone: true, - selector: 'pac-account', - templateUrl: './account.component.html', - styleUrls: ['./account.component.scss'], - imports: [CommonModule, MatTabsModule, TranslateModule, RouterModule, UserPipe, UserAvatarEditorComponent] + standalone: true, + selector: 'pac-account', + templateUrl: './account.component.html', + styleUrls: ['./account.component.scss'], + imports: [ + CommonModule, + MatTabsModule, + MatDividerModule, + TranslateModule, + RouterModule, + UserPipe, + UserAvatarEditorComponent + ] }) export class PACAccountComponent { - user: IUser + private readonly store = inject(Store) - private _userSub = this.store.user$.subscribe((user) => { - this.user = user - }) - constructor( - private readonly store: Store, - ) {} + public readonly user = toSignal(this.store.user$) } diff --git a/apps/cloud/src/app/features/setting/business-area/area-info-form/area-info-form.component.html b/apps/cloud/src/app/features/setting/business-area/area-info-form/area-info-form.component.html new file mode 100644 index 000000000..2a8dc3959 --- /dev/null +++ b/apps/cloud/src/app/features/setting/business-area/area-info-form/area-info-form.component.html @@ -0,0 +1,11 @@ +
+ +
+ +
+ +
\ No newline at end of file diff --git a/apps/cloud/src/app/features/setting/business-area/area-info-form/area-info-form.component.ts b/apps/cloud/src/app/features/setting/business-area/area-info-form/area-info-form.component.ts index 72590edf5..79b9261e6 100644 --- a/apps/cloud/src/app/features/setting/business-area/area-info-form/area-info-form.component.ts +++ b/apps/cloud/src/app/features/setting/business-area/area-info-form/area-info-form.component.ts @@ -1,67 +1,48 @@ -import { Component, inject } from '@angular/core' -import { toSignal } from '@angular/core/rxjs-interop' -import { FormGroup } from '@angular/forms' -import { pick } from '@metad/ocap-core' -import { UntilDestroy } from '@ngneat/until-destroy' +import { Component, effect, inject } from '@angular/core' +import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms' import { BusinessAreasService, ToastrService } from '@metad/cloud/state' -import { FORMLY_W_1_2 } from '@metad/formly' -import { TranslationBaseComponent } from 'apps/cloud/src/app/@shared' -import { firstValueFrom, map } from 'rxjs' -import { BusinessAreaComponent } from '../business-area/business-area.component' -import { BusinessAreasComponent } from '../business-areas/areas.component' +import { NgmCommonModule } from '@metad/ocap-angular/common' +import { pick } from '@metad/ocap-core' +import { TranslateModule } from '@ngx-translate/core' +import { MaterialModule, TranslationBaseComponent } from 'apps/cloud/src/app/@shared' +import { firstValueFrom } from 'rxjs' +import { EditBusinessAreaComponent } from '../business-area/business-area.component' -@UntilDestroy({ checkProperties: true }) @Component({ + standalone: true, selector: 'pac-area-info-form', - template: ` - - - ` + templateUrl: './area-info-form.component.html', + imports: [MaterialModule, TranslateModule, ReactiveFormsModule, NgmCommonModule] }) export class BusinessAreaInfoFormComponent extends TranslationBaseComponent { private readonly businessAreasService = inject(BusinessAreasService) - private readonly businessAreaComponent = inject(BusinessAreaComponent) - private readonly businessAreasComponent = inject(BusinessAreasComponent) + private readonly businessAreaComponent = inject(EditBusinessAreaComponent) private readonly _toastrService = inject(ToastrService) //Fields for the form - public form = new FormGroup({}) - model = {} as any - - fields = toSignal( - this.translateService.stream('PAC.BUSINESS_AREA.BASIC_INFO_FORM', { Default: {} }).pipe( - map((TRANSLATE) => { - return [ - { - className: FORMLY_W_1_2, - key: 'name', - type: 'input', - props: { - label: TRANSLATE?.Name ?? 'Name', - placeholder: '' - } - } - ] - }) - ) - ) - - private _businessAreaSub = this.businessAreaComponent.businessArea$.subscribe((value) => { - this.form.patchValue(value) - this.model = value + public form = new FormGroup({ + id: new FormControl(null), + name: new FormControl(null) }) + get model() { + return this.form.value + } + + constructor() { + super() - onFormChange(model) { - // + effect(() => { + this.form.patchValue(this.businessAreaComponent.businessArea()) + this.form.markAsPristine() + }, {allowSignalWrites: true}) } async save() { try { await firstValueFrom(this.businessAreasService.update(this.model.id, pick(this.model, 'name'))) - this.businessAreasComponent.refresh() + this.businessAreaComponent.refresh() this._toastrService.success('PAC.BUSINESS_AREA.Update', { Default: 'Update' }) + this.form.markAsPristine() } catch (err) { this._toastrService.error('PAC.BUSINESS_AREA.Update', '', { Default: 'Update' }) } diff --git a/apps/cloud/src/app/features/setting/business-area/area-users/area-users.component.html b/apps/cloud/src/app/features/setting/business-area/area-users/area-users.component.html index 669eaabe2..70a7169db 100644 --- a/apps/cloud/src/app/features/setting/business-area/area-users/area-users.component.html +++ b/apps/cloud/src/app/features/setting/business-area/area-users/area-users.component.html @@ -1,6 +1,6 @@
- +
+
+
+ + +
+ + + + + + + +
+

+ {{ 'PAC.ACTIONS.CREATE' | translate: {Default: "Create"} }} {{ 'PAC.KEY_WORDS.BUSINESS_AREA' | translate: {Default: "Business Area"} }} +

+
+ + + + + + +
+ + +
+
+
\ No newline at end of file diff --git a/apps/cloud/src/app/features/setting/business-area/business-area.component.scss b/apps/cloud/src/app/features/setting/business-area/business-area.component.scss new file mode 100644 index 000000000..294754f5d --- /dev/null +++ b/apps/cloud/src/app/features/setting/business-area/business-area.component.scss @@ -0,0 +1,3 @@ +:host { + @apply flex-1 flex flex-col justify-start items-stretch overflow-hidden; +} diff --git a/apps/cloud/src/app/features/setting/business-area/business-area.component.ts b/apps/cloud/src/app/features/setting/business-area/business-area.component.ts new file mode 100644 index 000000000..0d5f19a09 --- /dev/null +++ b/apps/cloud/src/app/features/setting/business-area/business-area.component.ts @@ -0,0 +1,96 @@ +import { CommonModule } from '@angular/common' +import { Component, ElementRef, TemplateRef, ViewChild, effect, inject, signal } from '@angular/core' +import { FormsModule, ReactiveFormsModule } from '@angular/forms' +import { MatDialog } from '@angular/material/dialog' +import { ActivatedRoute, Router } from '@angular/router' +import { BusinessAreasService } from '@metad/cloud/state' +import { NgmCommonModule } from '@metad/ocap-angular/common' +import { TranslateModule } from '@ngx-translate/core' +import { firstValueFrom } from 'rxjs' +import { IBusinessArea, routeAnimations } from '../../../@core' +import { MaterialModule, SharedModule } from '../../../@shared' + +@Component({ + standalone: true, + selector: 'pac-business-area', + templateUrl: './business-area.component.html', + styleUrls: ['./business-area.component.scss'], + animations: [routeAnimations], + imports: [ + SharedModule, + CommonModule, + FormsModule, + ReactiveFormsModule, + TranslateModule, + MaterialModule, + NgmCommonModule + ] +}) +export class BusinessAreaComponent { + private router = inject(Router) + private _route = inject(ActivatedRoute) + private _dialog = inject(MatDialog) + private businessAreasStore = inject(BusinessAreasService) + + @ViewChild('createTempl') private createTempl: TemplateRef + + openedBusinessAreas = signal([]) + currentBusinessArea = signal(null) + parentId = '' + name = '' + constructor() { + effect( + () => { + if (this.currentBusinessArea()) { + const businessAreas = this.openedBusinessAreas() + const index = businessAreas.findIndex((item) => item.id === this.currentBusinessArea().id) + if (index > -1) { + if (businessAreas[index] !== this.currentBusinessArea()) { + this.openedBusinessAreas.set([ + ...businessAreas.slice(0, index), + this.currentBusinessArea(), + ...businessAreas.slice(index + 1) + ]) + } + } else { + this.openedBusinessAreas.set([...businessAreas, this.currentBusinessArea()]) + } + } + }, + { allowSignalWrites: true } + ) + } + + trackById(index: number, item: IBusinessArea) { + return item?.id + } + + async addGroup(parent?: IBusinessArea) { + this.parentId = parent?.id + this.name = null + const name = await firstValueFrom( + this._dialog.open(this.createTempl, { panelClass: 'nx-dialog-container' }).afterClosed() + ) + + if (name) { + return await firstValueFrom( + this.businessAreasStore.create({ + name, + parentId: this.parentId + }) + ) + } + + return null + } + + setCurrentBusinessArea(businessArea: IBusinessArea) { + this.currentBusinessArea.set(businessArea) + } + + removeOpenedArea(businessArea: IBusinessArea) { + this.currentBusinessArea.set(null) + this.openedBusinessAreas.set(this.openedBusinessAreas().filter((item) => item.id !== businessArea.id)) + this.router.navigate(['.'], { relativeTo: this._route }) + } +} diff --git a/apps/cloud/src/app/features/setting/business-area/business-area.module.ts b/apps/cloud/src/app/features/setting/business-area/business-area.module.ts index 425283363..68cf9f9c2 100644 --- a/apps/cloud/src/app/features/setting/business-area/business-area.module.ts +++ b/apps/cloud/src/app/features/setting/business-area/business-area.module.ts @@ -1,46 +1,11 @@ -import { A11yModule } from '@angular/cdk/a11y' import { CommonModule } from '@angular/common' import { NgModule } from '@angular/core' -import { FormsModule, ReactiveFormsModule } from '@angular/forms' -import { TreeTableModule } from '@metad/ocap-angular/common' -import { OcapCoreModule } from '@metad/ocap-angular/core' -import { FormlyModule } from '@ngx-formly/core' -import { TranslateModule } from '@ngx-translate/core' -import { NxTableModule } from '@metad/components/table' -import { SharedModule, UserProfileInlineComponent } from '../../../@shared' -import { InlineSearchComponent } from '../../../@shared/form-fields' -import { BusinessAreaInfoFormComponent } from './area-info-form/area-info-form.component' -import { BusinessAreaUsersComponent } from './area-users/area-users.component' import { BusinessAreasRoutingModule } from './business-area-routing.module' -import { BusinessAreaComponent } from './business-area/business-area.component' -import { BusinessAreasComponent } from './business-areas/areas.component' @NgModule({ - imports: [ - A11yModule, - SharedModule, - CommonModule, - FormsModule, - ReactiveFormsModule, - BusinessAreasRoutingModule, - TranslateModule, - FormlyModule, - - InlineSearchComponent, - NxTableModule, - UserProfileInlineComponent, - - // OCAP Modules - OcapCoreModule, - TreeTableModule - ], - exports: [BusinessAreasComponent, BusinessAreaComponent, BusinessAreaUsersComponent], - declarations: [ - BusinessAreasComponent, - BusinessAreaComponent, - BusinessAreaUsersComponent, - BusinessAreaInfoFormComponent - ], + imports: [CommonModule, BusinessAreasRoutingModule], + exports: [], + declarations: [], providers: [] }) export class BusinessAreaModule {} diff --git a/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.html b/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.html index c3be52588..0ac34677c 100644 --- a/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.html +++ b/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.html @@ -1,32 +1,32 @@
{{ 'PAC.MENU.EDIT_BUSINESS_AREA' | translate: {Default: "Edit Business Area"} }} - {{ name$ | async }} + {{ name() }}
- + -
- -
+ + + + diff --git a/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.scss b/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.scss index c3e49e68a..53d90966f 100644 --- a/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.scss +++ b/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.scss @@ -1,5 +1,3 @@ :host { - flex: 1; - max-width: 100%; - padding: 1rem; + @apply flex-1 w-full max-w-full p-4 flex flex-col gap-4; } diff --git a/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.ts b/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.ts index 7484c7eb9..b5f88986e 100644 --- a/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.ts +++ b/apps/cloud/src/app/features/setting/business-area/business-area/business-area.component.ts @@ -1,18 +1,29 @@ -import { Component, OnInit } from '@angular/core' +import { Component, OnDestroy, computed, effect, inject } from '@angular/core' +import { toSignal } from '@angular/core/rxjs-interop' import { ActivatedRoute, Router } from '@angular/router' -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy' import { BusinessAreasService, BusinessType } from '@metad/cloud/state' -import { distinctUntilChanged, filter, map, shareReplay, startWith, switchMap } from 'rxjs' +import { TranslateModule } from '@ngx-translate/core' +import { MaterialModule } from 'apps/cloud/src/app/@shared' +import { BehaviorSubject, distinctUntilChanged, filter, map, startWith, switchMap } from 'rxjs' +import { BusinessAreaInfoFormComponent } from '../area-info-form/area-info-form.component' +import { BusinessAreaUsersComponent } from '../area-users/area-users.component' +import { BusinessAreaComponent } from '../business-area.component' -@UntilDestroy() @Component({ - selector: 'pac-business-area', + standalone: true, + selector: 'pac-edit-business-area', templateUrl: './business-area.component.html', - styleUrls: ['./business-area.component.scss'] + styleUrls: ['./business-area.component.scss'], + imports: [MaterialModule, TranslateModule, BusinessAreaInfoFormComponent, BusinessAreaUsersComponent] }) -export class BusinessAreaComponent implements OnInit { +export class EditBusinessAreaComponent implements OnDestroy { BUSINESS_AREA_TYPE = BusinessType + private route = inject(ActivatedRoute) + private router = inject(Router) + private businessAreasService = inject(BusinessAreasService) + private businessAreaComponent = inject(BusinessAreaComponent) + public readonly businessAreaId$ = this.route.params.pipe( startWith(this.route.snapshot.params), map((params) => params?.id), @@ -20,18 +31,32 @@ export class BusinessAreaComponent implements OnInit { distinctUntilChanged() ) - public readonly businessArea$ = this.businessAreaId$.pipe( - switchMap((id) => this.businessAreasService.getById(id)), - untilDestroyed(this), - shareReplay(1) + private readonly refresh$ = new BehaviorSubject(null) + + public readonly businessArea = toSignal( + this.businessAreaId$.pipe( + switchMap((id) => this.refresh$.pipe(switchMap(() => this.businessAreasService.getById(id)))) + ) ) - public readonly name$ = this.businessArea$.pipe(map((businessArea) => businessArea?.name)) - constructor( - private route: ActivatedRoute, - private router: Router, - private businessAreasService: BusinessAreasService - ) {} + public readonly name = computed(() => this.businessArea()?.name) + + constructor() { + effect( + () => { + if (this.businessArea()) { + this.businessAreaComponent.setCurrentBusinessArea(this.businessArea()) + } + }, + { allowSignalWrites: true } + ) + } + + refresh() { + this.refresh$.next() + } - ngOnInit(): void {} + ngOnDestroy(): void { + this.businessAreaComponent.setCurrentBusinessArea(null) + } } diff --git a/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.html b/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.html index b424c6ffd..e07c71556 100644 --- a/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.html +++ b/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.html @@ -1,16 +1,5 @@ -
-
-
- -
-
- - +
- - -
{{name}} @@ -52,28 +38,3 @@
- - -
-

- {{ 'PAC.ACTIONS.CREATE' | translate: {Default: "Create"} }} {{ 'PAC.KEY_WORDS.BUSINESS_AREA' | translate: {Default: "Business Area"} }} -

-
- - - - {{ 'PAC.KEY_WORDS.NAME' | translate: {Default: 'Name'} }} - - - - -
- - -
-
-
diff --git a/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.scss b/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.scss index 5bcdd7767..8626accca 100644 --- a/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.scss +++ b/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.scss @@ -1,11 +1,7 @@ :host { - @apply w-full flex flex-col sm:flex-row; + @apply flex-1 w-full flex flex-col sm:flex-row p-4; } -.pac-page__body { - flex: 1; - padding-top: 0; -} .emoji-loader { position: absolute; } diff --git a/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.ts b/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.ts index 5c5e92147..5881dc479 100644 --- a/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.ts +++ b/apps/cloud/src/app/features/setting/business-area/business-areas/areas.component.ts @@ -1,69 +1,76 @@ -import { Component, ElementRef, OnInit, TemplateRef, ViewChild } from '@angular/core' +import { CommonModule } from '@angular/common' +import { Component, inject } from '@angular/core' +import { takeUntilDestroyed } from '@angular/core/rxjs-interop' +import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { MatDialog } from '@angular/material/dialog' -import { DisplayDensity } from '@metad/ocap-angular/core' -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy' import { BusinessAreasService } from '@metad/cloud/state' import { ConfirmDeleteComponent } from '@metad/components/confirm' +import { TreeTableModule } from '@metad/ocap-angular/common' +import { DisplayDensity, OcapCoreModule } from '@metad/ocap-angular/core' +import { TranslateModule } from '@ngx-translate/core' +import { InlineSearchComponent, MaterialModule, SharedModule } from 'apps/cloud/src/app/@shared' import { BehaviorSubject, firstValueFrom } from 'rxjs' import { shareReplay, switchMap, tap } from 'rxjs/operators' -import { IBusinessArea, ToastrService } from '../../../../@core/index' +import { IBusinessArea, ToastrService, routeAnimations } from '../../../../@core/index' +import { BusinessAreaComponent } from '../business-area.component' -@UntilDestroy() @Component({ + standalone: true, selector: 'pac-business-areas', templateUrl: './areas.component.html', - styleUrls: ['./areas.component.scss'] + styleUrls: ['./areas.component.scss'], + animations: [routeAnimations], + imports: [ + MaterialModule, + SharedModule, + CommonModule, + FormsModule, + ReactiveFormsModule, + TranslateModule, + + InlineSearchComponent, + + // OCAP Modules + OcapCoreModule, + TreeTableModule + ] }) -export class BusinessAreasComponent implements OnInit { +export class BusinessAreasComponent { DisplayDensity = DisplayDensity + private readonly businessAreaComponent = inject(BusinessAreaComponent) + loading = false private refresh$ = new BehaviorSubject(null) public readonly groupTree$ = this.refresh$.pipe( tap(() => (this.loading = true)), switchMap(() => this.businessAreasStore.getGroupsTree()), tap(() => (this.loading = false)), - untilDestroyed(this), + takeUntilDestroyed(), shareReplay(1) ) - @ViewChild('createTempl') private createTempl: TemplateRef - - parentId: string - name: string constructor( private businessAreasStore: BusinessAreasService, private readonly _toastrService: ToastrService, private _dialog: MatDialog ) {} - ngOnInit(): void {} - async addGroup(parent?: IBusinessArea) { - this.parentId = parent?.id - this.name = null - const name = await firstValueFrom( - this._dialog.open(this.createTempl, { panelClass: 'nx-dialog-container' }).afterClosed() - ) - - if (name) { - await firstValueFrom( - this.businessAreasStore.create({ - name, - parentId: this.parentId - }) - ) - + const area = await this.businessAreaComponent.addGroup(parent) + if (area) { this.refresh$.next() } } async deleteBusinessArea(item: IBusinessArea) { - const cofirm = await firstValueFrom(this._dialog.open(ConfirmDeleteComponent, {data: {value: item.name}}).afterClosed()) + const cofirm = await firstValueFrom( + this._dialog.open(ConfirmDeleteComponent, { data: { value: item.name } }).afterClosed() + ) if (!cofirm) { return } - + try { await firstValueFrom(this.businessAreasStore.delete(item.id)) this._toastrService.success('PAC.BUSINESS_AREA.Delete', { Default: 'Delete' }) diff --git a/apps/cloud/src/app/features/setting/certification/certification.component.html b/apps/cloud/src/app/features/setting/certification/certification.component.html index b81ec5503..12b4b685b 100644 --- a/apps/cloud/src/app/features/setting/certification/certification.component.html +++ b/apps/cloud/src/app/features/setting/certification/certification.component.html @@ -1,78 +1,97 @@ -
- {{ 'PAC.KEY_WORDS.Certification' | translate: {Default: 'Certification'} }} -
-
- {{ 'PAC.KEY_WORDS.DigitalAssetCertificationTypes' | translate: {Default: 'Digital Asset Certification Types'} }} -
- -
-
- +
+
+
+
{{ 'PAC.KEY_WORDS.Certification' | translate: {Default: 'Certification'} }}
+
{{ 'PAC.KEY_WORDS.DigitalAssetCertificationTypes' | translate: {Default: 'Digital Asset Certification Types'} }}
+
+ +
+
+ +
+
-
-
-
- - - - {{ certification.name }} - - - {{ certification.description }} - - + +
+ - -
- - -
-
- -
+ +
+
+ + + + {{ certification.name }} + + + {{ certification.description }} + + + + + + -
-
- {{ 'PAC.ACTIONS.Edit' | translate: {Default: 'Edit'} }} + +
+ + +
+
+
-
- - {{ 'PAC.KEY_WORDS.Name' | translate: {Default: 'Name'} }} - - - - {{ 'PAC.KEY_WORDS.Description' | translate: {Default: 'Description'} }} - - +
+
+ {{ 'PAC.ACTIONS.Edit' | translate: {Default: 'Edit'} }} +
+ + + {{ 'PAC.KEY_WORDS.Name' | translate: {Default: 'Name'} }} + + - - + + {{ 'PAC.KEY_WORDS.Description' | translate: {Default: 'Description'} }} + + -
- - -
- - + + + +
+ + +
+ + +
-
+ diff --git a/apps/cloud/src/app/features/setting/certification/certification.component.ts b/apps/cloud/src/app/features/setting/certification/certification.component.ts index 21dfcb597..f698771f8 100644 --- a/apps/cloud/src/app/features/setting/certification/certification.component.ts +++ b/apps/cloud/src/app/features/setting/certification/certification.component.ts @@ -10,7 +10,7 @@ import { UsersService } from '@metad/cloud/state' import { ConfirmDeleteComponent } from '@metad/components/confirm' import { BehaviorSubject, catchError, firstValueFrom, from, map, switchMap } from 'rxjs' import { CertificationService, ICertification, ToastrService } from '../../../@core' -import { MaterialModule, UserProfileInlineComponent, userLabel } from '../../../@shared' +import { MaterialModule, SharedModule, UserProfileInlineComponent, userLabel } from '../../../@shared' @UntilDestroy({ checkProperties: true }) @Component({ @@ -19,6 +19,7 @@ import { MaterialModule, UserProfileInlineComponent, userLabel } from '../../../ templateUrl: './certification.component.html', styleUrls: ['./certification.component.scss'], imports: [ + SharedModule, CommonModule, TranslateModule, MaterialModule, diff --git a/apps/cloud/src/app/features/setting/certification/certification.module.ts b/apps/cloud/src/app/features/setting/certification/certification.module.ts index 20ba35eb2..a5d08d1fa 100644 --- a/apps/cloud/src/app/features/setting/certification/certification.module.ts +++ b/apps/cloud/src/app/features/setting/certification/certification.module.ts @@ -1,11 +1,8 @@ import { NgModule } from '@angular/core' -import { FormsModule, ReactiveFormsModule } from '@angular/forms' -import { TranslateModule } from '@ngx-translate/core' -import { MaterialModule } from '../../../@shared' import { CertificationRoutingModule } from './certification-routing.module' @NgModule({ - imports: [CertificationRoutingModule, TranslateModule, MaterialModule, FormsModule, ReactiveFormsModule], + imports: [CertificationRoutingModule], declarations: [], providers: [] }) diff --git a/apps/cloud/src/app/features/setting/copilot/copilot.component.html b/apps/cloud/src/app/features/setting/copilot/copilot.component.html index d5aced20c..37429e367 100644 --- a/apps/cloud/src/app/features/setting/copilot/copilot.component.html +++ b/apps/cloud/src/app/features/setting/copilot/copilot.component.html @@ -1,5 +1,5 @@ -
- {{ 'PAC.Copilot.AICopilot' | translate: {Default: 'AI Copilot'} }} +
+
{{ 'PAC.Copilot.AICopilot' | translate: {Default: 'AI Copilot'} }}
- {{ 'PAC.MENU.Custom SMTP' | translate: {Default: "Custom SMTP"} }} -
+
+
{{ 'PAC.MENU.Custom SMTP' | translate: {Default: "Custom SMTP"} }}
- - -
- + + manage_accounts + {{ 'PAC.MENU.Tenant' | translate: {Default: "Tenant"} }} + + + corporate_fare + {{ 'PAC.MENU.Organization' | translate: {Default: "Organization"} }} + + {{ organiztionName$ | async }} + +
+ + + + + \ No newline at end of file diff --git a/apps/cloud/src/app/features/setting/data-sources/data-sources.component.html b/apps/cloud/src/app/features/setting/data-sources/data-sources.component.html index 1a3a73360..5a2fcea5c 100644 --- a/apps/cloud/src/app/features/setting/data-sources/data-sources.component.html +++ b/apps/cloud/src/app/features/setting/data-sources/data-sources.component.html @@ -1,15 +1,19 @@ -
-
- +
+
{{ 'PAC.KEY_WORDS.DATA_SOURCE' | translate: {Default: "Data Source"} }}
+ +
+
+ +
-
+
diff --git a/apps/cloud/src/app/features/setting/email-templates/email-templates.component.html b/apps/cloud/src/app/features/setting/email-templates/email-templates.component.html index 5d2f76d76..892ac6773 100644 --- a/apps/cloud/src/app/features/setting/email-templates/email-templates.component.html +++ b/apps/cloud/src/app/features/setting/email-templates/email-templates.component.html @@ -1,85 +1,82 @@ -
-

- {{ 'PAC.MENU.ForOrganization' | translate: {Default: "For Organization"} }}: - {{ organization?.name }} -

+
+ +
+
{{ 'PAC.MENU.Email Template' | translate: {Default: "Email Template"} }}
+
{{ 'PAC.MENU.ForOrganization' | translate: {Default: "For Organization"} }}: + {{ organization?.name }}
+
-
- - - +
+ + - - - {{ 'PAC.KEY_WORDS.TemplateName' | translate: {Default: "Template Name"} }} - - - - {{name}} - - - + -
- -
+
+
+
-
-
-
-

{{ 'PAC.KEY_WORDS.Subject' | translate: {Default: "Subject"} }}

- -
+
+
+
+

{{ 'PAC.KEY_WORDS.Subject' | translate: {Default: "Subject"} }}

+ +
-
-

{{ 'PAC.KEY_WORDS.EmailBody' | translate: {Default: "Email Body"} }}

- -
+
+

{{ 'PAC.KEY_WORDS.EmailBody' | translate: {Default: "Email Body"} }}

+
+
-
-
- {{ 'PAC.KEY_WORDS.Subject' | translate: {Default: "Subject"} }}: -
-
+
+
+ {{ 'PAC.KEY_WORDS.Subject' | translate: {Default: "Subject"} }}: +
+
-
-

{{ 'PAC.KEY_WORDS.EmailBody' | translate: {Default: "Email Body"} }}

-
-
-
+
+

{{ 'PAC.KEY_WORDS.EmailBody' | translate: {Default: "Email Body"} }}

+
+
-
+ +
diff --git a/apps/cloud/src/app/features/setting/email-templates/email-templates.component.scss b/apps/cloud/src/app/features/setting/email-templates/email-templates.component.scss index 2efb1a522..1b39e3efb 100644 --- a/apps/cloud/src/app/features/setting/email-templates/email-templates.component.scss +++ b/apps/cloud/src/app/features/setting/email-templates/email-templates.component.scss @@ -4,9 +4,6 @@ flex-direction: column; } -.ngm-button-group { - .mat-form-field, - pac-language-selector { - margin-top: -0.5rem; - } -} +.pac-page-header { + @apply flex flex-row items-center justify-between; +} \ No newline at end of file diff --git a/apps/cloud/src/app/features/setting/email-templates/email-templates.component.ts b/apps/cloud/src/app/features/setting/email-templates/email-templates.component.ts index cd73e9c6c..ac3706d49 100644 --- a/apps/cloud/src/app/features/setting/email-templates/email-templates.component.ts +++ b/apps/cloud/src/app/features/setting/email-templates/email-templates.component.ts @@ -1,221 +1,192 @@ -import { - AfterViewInit, - ChangeDetectorRef, - Component, - OnDestroy, - SecurityContext, -} from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; -import { - EmailTemplateNameEnum, - IOrganization, - LanguagesEnum, - LanguagesMap -} from '@metad/contracts'; -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; -import { isEqual } from 'lodash-es'; -import { combineLatest, Subject } from 'rxjs'; -import { debounceTime, distinctUntilChanged, filter, tap } from 'rxjs/operators'; -import { EmailTemplateService, Store, ToastrService } from '../../../@core/services'; -import { TranslationBaseComponent } from '../../../@shared'; - -@UntilDestroy({ checkProperties: true }) +import { AfterViewInit, ChangeDetectorRef, Component, OnDestroy, SecurityContext } from '@angular/core' +import { FormBuilder, FormGroup, Validators } from '@angular/forms' +import { DomSanitizer, SafeHtml } from '@angular/platform-browser' +import { EmailTemplateNameEnum, IOrganization, LanguagesEnum, LanguagesMap } from '@metad/contracts' +import { ISelectOption } from '@metad/ocap-angular/core' +import { isEqual } from 'lodash-es' +import { Subject, combineLatest } from 'rxjs' +import { debounceTime, distinctUntilChanged, filter, tap } from 'rxjs/operators' +import { EmailTemplateService, Store, ToastrService } from '../../../@core/services' +import { TranslationBaseComponent } from '../../../@shared' +import { takeUntilDestroyed } from '@angular/core/rxjs-interop' + + @Component({ - templateUrl: './email-templates.component.html', - styleUrls: ['./email-templates.component.scss'] + templateUrl: './email-templates.component.html', + styleUrls: ['./email-templates.component.scss'] }) -export class EmailTemplatesComponent - extends TranslationBaseComponent - implements AfterViewInit, OnDestroy { - - previewEmail: SafeHtml; - previewSubject: SafeHtml; - organization: IOrganization; - - templateNames: string[] = Object.values(EmailTemplateNameEnum); - subject$: Subject = new Subject(); - - readonly form: FormGroup = EmailTemplatesComponent.buildForm(this.fb); - static buildForm(fb: FormBuilder): FormGroup { - return fb.group({ - name: [EmailTemplateNameEnum.WELCOME_USER], - languageCode: [LanguagesEnum.English], - subject: ['', [Validators.required, Validators.maxLength(60)]], - mjml: ['', Validators.required] - }); - } - - private _templateSub = this.subject$ - .pipe( - debounceTime(500), - tap(() => this.getTemplate()), - untilDestroyed(this) - ) - .subscribe(); - private _selectedOrganizationSub = combineLatest([this.store.selectedOrganization$, this.store.preferredLanguage$]) - .pipe( - distinctUntilChanged(isEqual), - filter(([organization, language]) => !!language), - tap(([organization, language]) => { - this.organization = organization; - this.form.patchValue({ languageCode: LanguagesMap[language] ?? language }); - }), - tap(() => this.subject$.next(true)), - untilDestroyed(this) - ) - .subscribe(); - constructor( - private readonly sanitizer: DomSanitizer, - private readonly store: Store, - private readonly fb: FormBuilder, - private readonly toastrService: ToastrService, - private readonly emailTemplateService: EmailTemplateService, - private _cdr: ChangeDetectorRef - ) { - super(); - } - - ngAfterViewInit() { - this.form.get('subject').valueChanges.pipe(debounceTime(1000), distinctUntilChanged()).subscribe((value) => { - this.onSubjectChange(value) - }) - this.form.get('mjml').valueChanges.pipe(debounceTime(1000), distinctUntilChanged()).subscribe((value) => { - this.onEmailChange(value) - }) - - // this.themeService - // .getJsTheme() - // .pipe(untilDestroyed(this)) - // .subscribe( - // ({ - // name - // }: { - // name: 'dark' | 'cosmic' | 'corporate' | 'default'; - // }) => { - // switch (name) { - // case 'dark': - // case 'cosmic': - // this.emailEditor.setTheme('tomorrow_night'); - // this.subjectEditor.setTheme('tomorrow_night'); - // break; - // default: - // this.emailEditor.setTheme('sqlserver'); - // this.subjectEditor.setTheme('sqlserver'); - // break; - // } - // } - // ); - - const editorOptions = { - enableBasicAutocompletion: true, - enableLiveAutocompletion: true, - printMargin: false, - showLineNumbers: true, - tabSize: 2 - }; - - // this.emailEditor.getEditor().setOptions(editorOptions); - // this.subjectEditor - // .getEditor() - // .setOptions({ ...editorOptions, maxLines: 2 }); - } - - async getTemplate() { - - try { - const { tenantId } = this.store.user; - const { id: organizationId } = this.organization ?? {} - const { - languageCode = LanguagesEnum.English, - name = EmailTemplateNameEnum.WELCOME_USER - } = this.form.value; - const result = await this.emailTemplateService.getTemplate({ - languageCode, - name, - organizationId, - tenantId - }) - - this.form.patchValue({ - subject: result.subject, - mjml: result.template, - }) - this.form.markAsPristine() - const { - html: email - } = await this.emailTemplateService.generateTemplatePreview( - result.template - ); - const { - html: subject - } = await this.emailTemplateService.generateTemplatePreview( - result.subject - ); - this.previewEmail = this.sanitizer.bypassSecurityTrustHtml(email); - - this.previewSubject = this.sanitizer.sanitize( - SecurityContext.HTML, - subject - ); - } catch (error) { - this.form.patchValue({ - subject: '', - mjml: '', - }) - this.form.markAsPristine() - this.toastrService.danger(error); - } - } - - async onSubjectChange(code: string) { - // this.form.get('subject').setValue(code); - const { - html - } = await this.emailTemplateService.generateTemplatePreview(code); - this.previewSubject = this.sanitizer.bypassSecurityTrustHtml(html); - this._cdr.detectChanges() - } - - async onEmailChange(code: string) { - // this.form.get('mjml').setValue(code); - const { - html - } = await this.emailTemplateService.generateTemplatePreview(code); - this.previewEmail = this.sanitizer.bypassSecurityTrustHtml(html); - this._cdr.detectChanges() - } - - selectedLanguage(event) { - this.form.patchValue({ - languageCode: event.code - }); - } - - async submitForm() { - try { - const { tenantId } = this.store.user; - const { id: organizationId } = this.organization ?? {}; - await this.emailTemplateService.saveEmailTemplate({ - ...this.form.value, - organizationId, - tenantId - }); - - this.form.markAsPristine() - this._cdr.detectChanges() - - this.toastrService.success('TOASTR.MESSAGE.EMAIL_TEMPLATE_SAVED', { - templateName: this.getTranslation( - 'EMAIL_TEMPLATES_PAGE.TEMPLATE_NAMES.' + - this.form.get('name').value - ), - Default: 'Email Template saved' - }) - } catch (error) { - this.toastrService.danger(error) - } - } - - ngOnDestroy() {} +export class EmailTemplatesComponent extends TranslationBaseComponent implements AfterViewInit, OnDestroy { + previewEmail: SafeHtml + previewSubject: SafeHtml + organization: IOrganization + + templateNames: ISelectOption[] = Object.values(EmailTemplateNameEnum).map((name) => ({ key: name, caption: name })) + subject$: Subject = new Subject() + + readonly form: FormGroup = EmailTemplatesComponent.buildForm(this.fb) + static buildForm(fb: FormBuilder): FormGroup { + return fb.group({ + name: [EmailTemplateNameEnum.WELCOME_USER], + languageCode: [LanguagesEnum.English], + subject: ['', [Validators.required, Validators.maxLength(60)]], + mjml: ['', Validators.required] + }) + } + + private _templateSub = this.subject$ + .pipe( + debounceTime(500), + tap(() => this.getTemplate()), + takeUntilDestroyed() + ) + .subscribe() + private _selectedOrganizationSub = combineLatest([this.store.selectedOrganization$, this.store.preferredLanguage$]) + .pipe( + distinctUntilChanged(isEqual), + filter(([organization, language]) => !!language), + tap(([organization, language]) => { + this.organization = organization + this.form.patchValue({ languageCode: LanguagesMap[language] ?? language }) + }), + tap(() => this.subject$.next(true)), + takeUntilDestroyed() + ) + .subscribe() + constructor( + private readonly sanitizer: DomSanitizer, + private readonly store: Store, + private readonly fb: FormBuilder, + private readonly toastrService: ToastrService, + private readonly emailTemplateService: EmailTemplateService, + private _cdr: ChangeDetectorRef + ) { + super() + } + + ngAfterViewInit() { + this.form + .get('subject') + .valueChanges.pipe(debounceTime(1000), distinctUntilChanged()) + .subscribe((value) => { + this.onSubjectChange(value) + }) + this.form + .get('mjml') + .valueChanges.pipe(debounceTime(1000), distinctUntilChanged()) + .subscribe((value) => { + this.onEmailChange(value) + }) + + // this.themeService + // .getJsTheme() + // .pipe(untilDestroyed(this)) + // .subscribe( + // ({ + // name + // }: { + // name: 'dark' | 'cosmic' | 'corporate' | 'default'; + // }) => { + // switch (name) { + // case 'dark': + // case 'cosmic': + // this.emailEditor.setTheme('tomorrow_night'); + // this.subjectEditor.setTheme('tomorrow_night'); + // break; + // default: + // this.emailEditor.setTheme('sqlserver'); + // this.subjectEditor.setTheme('sqlserver'); + // break; + // } + // } + // ); + + const editorOptions = { + enableBasicAutocompletion: true, + enableLiveAutocompletion: true, + printMargin: false, + showLineNumbers: true, + tabSize: 2 + } + + // this.emailEditor.getEditor().setOptions(editorOptions); + // this.subjectEditor + // .getEditor() + // .setOptions({ ...editorOptions, maxLines: 2 }); + } + + async getTemplate() { + try { + const { tenantId } = this.store.user + const { id: organizationId } = this.organization ?? {} + const { languageCode = LanguagesEnum.English, name = EmailTemplateNameEnum.WELCOME_USER } = this.form.value + const result = await this.emailTemplateService.getTemplate({ + languageCode, + name, + organizationId, + tenantId + }) + + this.form.patchValue({ + subject: result.subject, + mjml: result.template + }) + this.form.markAsPristine() + const { html: email } = await this.emailTemplateService.generateTemplatePreview(result.template) + const { html: subject } = await this.emailTemplateService.generateTemplatePreview(result.subject) + this.previewEmail = this.sanitizer.bypassSecurityTrustHtml(email) + + this.previewSubject = this.sanitizer.sanitize(SecurityContext.HTML, subject) + } catch (error) { + this.form.patchValue({ + subject: '', + mjml: '' + }) + this.form.markAsPristine() + this.toastrService.danger(error) + } + } + + async onSubjectChange(code: string) { + // this.form.get('subject').setValue(code); + const { html } = await this.emailTemplateService.generateTemplatePreview(code) + this.previewSubject = this.sanitizer.bypassSecurityTrustHtml(html) + this._cdr.detectChanges() + } + + async onEmailChange(code: string) { + // this.form.get('mjml').setValue(code); + const { html } = await this.emailTemplateService.generateTemplatePreview(code) + this.previewEmail = this.sanitizer.bypassSecurityTrustHtml(html) + this._cdr.detectChanges() + } + + selectedLanguage(event) { + this.form.patchValue({ + languageCode: event.code + }) + } + + async submitForm() { + try { + const { tenantId } = this.store.user + const { id: organizationId } = this.organization ?? {} + await this.emailTemplateService.saveEmailTemplate({ + ...this.form.value, + organizationId, + tenantId + }) + + this.form.markAsPristine() + this._cdr.detectChanges() + + this.toastrService.success('TOASTR.MESSAGE.EMAIL_TEMPLATE_SAVED', { + templateName: this.getTranslation('EMAIL_TEMPLATES_PAGE.TEMPLATE_NAMES.' + this.form.get('name').value), + Default: 'Email Template saved' + }) + } catch (error) { + this.toastrService.danger(error) + } + } + + ngOnDestroy() {} } diff --git a/apps/cloud/src/app/features/setting/email-templates/email-templates.module.ts b/apps/cloud/src/app/features/setting/email-templates/email-templates.module.ts index dd724095a..8e31f24ea 100644 --- a/apps/cloud/src/app/features/setting/email-templates/email-templates.module.ts +++ b/apps/cloud/src/app/features/setting/email-templates/email-templates.module.ts @@ -7,6 +7,7 @@ import { MonacoEditorModule } from 'ngx-monaco-editor'; import { LanguageSelectorComponent, MaterialModule, SharedModule } from '../../../@shared'; import { EmailTemplatesRoutingModule } from './email-templates-routing.module'; import { EmailTemplatesComponent } from './email-templates.component'; +import { NgmSelectComponent } from '@metad/ocap-angular/common'; @NgModule({ @@ -20,10 +21,12 @@ import { EmailTemplatesComponent } from './email-templates.component'; SharedModule, MaterialModule, - ButtonGroupDirective, LanguageSelectorComponent, - - MonacoEditorModule.forRoot() + + MonacoEditorModule.forRoot(), + + ButtonGroupDirective, + NgmSelectComponent ], providers: [], declarations: [EmailTemplatesComponent] diff --git a/apps/cloud/src/app/features/setting/features/features.component.html b/apps/cloud/src/app/features/setting/features/features.component.html index 3cd7196ab..78023da7e 100644 --- a/apps/cloud/src/app/features/setting/features/features.component.html +++ b/apps/cloud/src/app/features/setting/features/features.component.html @@ -1,9 +1,9 @@ -
-

- {{ 'PAC.MENU.MANAGE_FEATURES' | translate: {Default: "Manage Features"} }} -

+
+
{{ 'PAC.MENU.MANAGE_FEATURES' | translate: {Default: "Manage Features"} }}
-
+ -
- -
+ + + \ No newline at end of file diff --git a/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization-settings/edit-organization-main/edit-organization-main.component.ts b/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization-settings/edit-organization-main/edit-organization-main.component.ts index 77d8d6d6a..b7dbfb90f 100644 --- a/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization-settings/edit-organization-main/edit-organization-main.component.ts +++ b/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization-settings/edit-organization-main/edit-organization-main.component.ts @@ -1,16 +1,16 @@ -import { ChangeDetectorRef, Component, inject } from '@angular/core' +import { Component, effect, inject } from '@angular/core' import { UntypedFormGroup } from '@angular/forms' import { Router } from '@angular/router' import { IOrganization } from '@metad/contracts' -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy' +import { getErrorMessage } from '@metad/core' import { FormlyFieldConfig } from '@ngx-formly/core' import { TranslateService } from '@ngx-translate/core' -import { getErrorMessage } from '@metad/core' import { firstValueFrom } from 'rxjs' import { OrganizationsService, ToastrService } from '../../../../../../@core' import { EditOrganizationComponent } from '../../edit-organization.component' +import { FORMLY_ROW, FORMLY_W_1_2 } from '@metad/story/designer' + -@UntilDestroy({ checkProperties: true }) @Component({ selector: 'pac-edit-org-main', templateUrl: './edit-organization-main.component.html', @@ -27,95 +27,112 @@ export class EditOrganizationMainComponent { public editOrganizationComponent: EditOrganizationComponent, private readonly router: Router, private readonly organizationService: OrganizationsService, - readonly translateService: TranslateService, - private readonly cdr: ChangeDetectorRef - ) {} + readonly translateService: TranslateService + ) { + effect(() => { + const org = this.editOrganizationComponent.organization() + if (org) { + this.form.patchValue(org) + this.model = { ...org } + } + }) + } handleImageUploadError(event: any) {} ngOnInit(): void { - this.editOrganizationComponent.organization$.pipe(untilDestroyed(this)).subscribe((org) => { - this.form.patchValue(org) - this.model = { ...org } - }) - + const className = FORMLY_W_1_2 this.translateService.get('PAC.ORGANIZATIONS_PAGE.Organization').subscribe((Organization) => { this.fields = [ { - key: 'name', - type: 'input', - props: { - label: Organization?.Name ?? 'Name', - placeholder: Organization?.OrganizationName ?? 'Organization Name', - appearance: 'fill' - } - }, - { - key: 'isDefault', - type: 'toggle', - props: { - label: Organization?.IsDefault ?? 'Is Default', - placeholder: Organization?.SetAsDefault ?? 'Set as Default' - } - }, - { - key: 'isActive', - type: 'toggle', - props: { - label: Organization?.IsActive ?? 'Is Active', - placeholder: Organization?.ActiveOrganization ?? 'Active Organization' - } - }, - { - key: 'profile_link', - type: 'input', - props: { - label: Organization?.ProfileLink ?? 'Profile Link', - appearance: 'fill' - } - }, - { - key: 'officialName', - type: 'input', - props: { - label: Organization?.OfficialName ?? 'Official Name', - appearance: 'fill' - } - }, - { - key: 'short_description', - type: 'textarea', - props: { - label: Organization?.ShortDescription ?? 'Short Description', - appearance: 'fill', - autosize: true - } - }, - { - key: 'website', - type: 'input', - props: { - label: Organization?.Website ?? 'Website', - appearance: 'fill' - } - }, - { - key: 'invitesAllowed', - type: 'toggle', - props: { - label: Organization?.InvitesAllowed ?? 'Invites Allowed', - placeholder: Organization?.EnableInvitesAllowed ?? 'Enable Invites Allowed' - } - }, - { - key: 'inviteExpiryPeriod', - type: 'input', - props: { - label: Organization?.InviteExpiryPeriod ?? 'Invite Expiry Period', - placeholder: Organization?.InviteExpiryPeriod ?? 'Invite Expiry Period (in Days)', - type: 'number', - appearance: 'fill' - } + fieldGroupClassName: FORMLY_ROW, + fieldGroup: [ + { + className, + key: 'name', + type: 'input', + props: { + label: Organization?.Name ?? 'Name', + placeholder: Organization?.OrganizationName ?? 'Organization Name', + appearance: 'fill' + } + }, + { + className, + key: 'isDefault', + type: 'toggle', + props: { + label: Organization?.IsDefault ?? 'Is Default', + placeholder: Organization?.SetAsDefault ?? 'Set as Default' + } + }, + { + className, + key: 'isActive', + type: 'toggle', + props: { + label: Organization?.IsActive ?? 'Is Active', + placeholder: Organization?.ActiveOrganization ?? 'Active Organization' + } + }, + { + className, + key: 'profile_link', + type: 'input', + props: { + label: Organization?.ProfileLink ?? 'Profile Link', + appearance: 'fill' + } + }, + { + className, + key: 'officialName', + type: 'input', + props: { + label: Organization?.OfficialName ?? 'Official Name', + appearance: 'fill' + } + }, + { + className, + key: 'short_description', + type: 'textarea', + props: { + label: Organization?.ShortDescription ?? 'Short Description', + appearance: 'fill', + autosize: true + } + }, + { + className, + key: 'website', + type: 'input', + props: { + label: Organization?.Website ?? 'Website', + appearance: 'fill' + } + }, + { + className, + key: 'invitesAllowed', + type: 'toggle', + props: { + label: Organization?.InvitesAllowed ?? 'Invites Allowed', + placeholder: Organization?.EnableInvitesAllowed ?? 'Enable Invites Allowed' + } + }, + { + className, + key: 'inviteExpiryPeriod', + type: 'input', + props: { + label: Organization?.InviteExpiryPeriod ?? 'Invite Expiry Period', + placeholder: Organization?.InviteExpiryPeriod ?? 'Invite Expiry Period (in Days)', + type: 'number', + appearance: 'fill' + } + } + ] } ] }) diff --git a/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.html b/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.html index 3a5d115e8..ed91999ed 100644 --- a/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.html +++ b/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.html @@ -1,28 +1,33 @@ -
-

- {{ 'PAC.KEY_WORDS.ORGANIZATION' | translate: {Default: 'Organization'} }} {{ selectedOrg?.name }} -

+ + + {{ 'PAC.KEY_WORDS.ORGANIZATION' | translate: {Default: 'Organization'} }} + + +
+ +
{{ selectedOrg?.name }}
+
+
+
-
- -
- -
- - + + + {{ 'PAC.ORGANIZATIONS_PAGE.Organization.DEMO' | translate: {Default: "Demo"} }} + + +
+ +
+
+
diff --git a/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.scss b/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.scss index 99d9031dc..dcbe168d1 100644 --- a/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.scss +++ b/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.scss @@ -1,5 +1,3 @@ :host { - display: flex; - flex-direction: column; - flex: 1; + @apply w-full flex-1 flex flex-col gap-4 p-4; } \ No newline at end of file diff --git a/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.ts b/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.ts index cafeb753b..f1b91130b 100644 --- a/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.ts +++ b/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.ts @@ -1,22 +1,43 @@ -import { Component, OnDestroy, OnInit } from '@angular/core' -import { ActivatedRoute, Router } from '@angular/router' -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy' -import { TranslateService } from '@ngx-translate/core' +import { Component, effect, inject } from '@angular/core' +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop' +import { FormsModule, ReactiveFormsModule } from '@angular/forms' +import { ActivatedRoute } from '@angular/router' import { IOrganization } from '@metad/contracts' -import { filter, map, shareReplay, switchMap } from 'rxjs/operators' -import { EmployeesService, OrganizationsService, PermissionsEnum, Store } from '../../../../@core' +import { nonBlank } from '@metad/core' +import { TranslateService } from '@ngx-translate/core' +import { MaterialModule, OrgAvatarComponent, OrgAvatarEditorComponent, SharedModule } from 'apps/cloud/src/app/@shared' +import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators' +import { OrganizationsService, Store } from '../../../../@core' +import { OrganizationsComponent } from '../organizations.component' +import { EditOrganizationSettingsModule } from './edit-organization-settings/edit-organization-settings.module' +import { OrganizationDemoComponent } from '../organization-demo/organization-demo.component' + -@UntilDestroy({ checkProperties: true }) @Component({ + standalone: true, templateUrl: './edit-organization.component.html', - styleUrls: ['./edit-organization.component.scss'] + styleUrls: ['./edit-organization.component.scss'], + imports: [ + SharedModule, + MaterialModule, + FormsModule, + ReactiveFormsModule, + OrgAvatarEditorComponent, + OrgAvatarComponent, + EditOrganizationSettingsModule, + OrganizationDemoComponent + ] }) -export class EditOrganizationComponent implements OnInit { +export class EditOrganizationComponent { + private readonly organizationsComponent = inject(OrganizationsComponent) - public readonly organization$ = this.route.params.pipe( - map((params) => params.id), - switchMap((id) => this.organizationsService.getById(id, null, ['tags'])), - shareReplay(1) + public readonly organization = toSignal( + this.route.params.pipe( + map((params) => params.id), + distinctUntilChanged(), + filter(nonBlank), + switchMap((id) => this.organizationsService.getById(id, null, ['tags'])) + ) ) selectedOrg: IOrganization @@ -24,50 +45,34 @@ export class EditOrganizationComponent implements OnInit { employeesCount: number params: any + private orgSub = this.store.selectedOrganization$ + .pipe( + filter((organization) => !!organization), + takeUntilDestroyed() + ) + .subscribe((organization) => { + this.setSelectedOrg(organization) + }) constructor( - private router: Router, private route: ActivatedRoute, private organizationsService: OrganizationsService, - private employeesService: EmployeesService, private store: Store, readonly translateService: TranslateService - ) {} - - async ngOnInit() { - this.organization$.pipe(untilDestroyed(this)).subscribe((organization) => { - this.setSelectedOrg(organization) + ) { + effect(() => { + if (this.organization()) { + this.setSelectedOrg(this.organization()) + } }) - - this.store.selectedOrganization$ - .pipe( - filter((organization) => !!organization), - untilDestroyed(this) - ) - .subscribe((organization) => { - this.setSelectedOrg(organization) - }) } - setSelectedOrg(selectedOrg) { + setSelectedOrg(selectedOrg: IOrganization) { this.store.selectedEmployee = null this.selectedOrg = selectedOrg this.store.selectedOrganization = this.selectedOrg this.store.organizationId = this.selectedOrg.id this.selectedOrgFromHeader = this.selectedOrg - } - // canEditPublicPage() { - // return this.store.hasPermission(PermissionsEnum.PUBLIC_PAGE_EDIT) - // } - - // private async loadEmployeesCount() { - // const { tenantId } = this.store.user - // const { total } = await firstValueFrom( - // this.employeesService.getAll([], { - // organizationId: this.selectedOrg.id, - // tenantId - // }) - // ) - // this.employeesCount = total - // } + this.organizationsComponent.setCurrentLink(this.selectedOrg) + } } diff --git a/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.html b/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.html index 504a09095..f78ebf4ee 100644 --- a/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.html +++ b/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.html @@ -1,3 +1,16 @@ - \ No newline at end of file +
+ + + GitHub + Aliyun oss + +
+ + + diff --git a/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.scss b/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.scss index 1b0fcd370..31fb81987 100644 --- a/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.scss +++ b/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.scss @@ -1,3 +1,3 @@ :host { - padding: 1.5rem; + @apply flex flex-col gap-2 p-4; } diff --git a/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.ts b/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.ts index 73a25d41d..f4d7d1b04 100644 --- a/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.ts +++ b/apps/cloud/src/app/features/setting/organizations/organization-demo/organization-demo.component.ts @@ -1,39 +1,47 @@ -import { Component } from '@angular/core' -import { UntilDestroy } from '@ngneat/until-destroy' -import { OrganizationsService, ToastrService } from 'apps/cloud/src/app/@core' -import { TranslationBaseComponent } from 'apps/cloud/src/app/@shared' -import { catchError, concatMap, EMPTY, Observable, tap, withLatestFrom } from 'rxjs' +import { CommonModule } from '@angular/common' +import { Component, inject, signal } from '@angular/core' +import { FormControl } from '@angular/forms' +import { TranslateModule } from '@ngx-translate/core' +import { + OrganizationDemoNetworkEnum, + OrganizationsService, + ToastrService, + getErrorMessage +} from 'apps/cloud/src/app/@core' +import { MaterialModule, SharedModule, TranslationBaseComponent } from 'apps/cloud/src/app/@shared' +import { firstValueFrom } from 'rxjs' import { EditOrganizationComponent } from '../edit-organization/edit-organization.component' -import { effectAction } from '@metad/ocap-angular/core' -@UntilDestroy({ checkProperties: true }) @Component({ + standalone: true, + selector: 'pac-organization-demo', templateUrl: './organization-demo.component.html', - styleUrls: ['./organization-demo.component.scss'] + styleUrls: ['./organization-demo.component.scss'], + imports: [CommonModule, SharedModule, MaterialModule, TranslateModule] }) export class OrganizationDemoComponent extends TranslationBaseComponent { - constructor( - public editOrganizationComponent: EditOrganizationComponent, - private orgsService: OrganizationsService, - private readonly _toastrService: ToastrService - ) { - super() - } + OrganizationDemoNetworkEnum = OrganizationDemoNetworkEnum + + public editOrganizationComponent = inject(EditOrganizationComponent) + private orgsService = inject(OrganizationsService) + private readonly _toastrService = inject(ToastrService) + + source = new FormControl(OrganizationDemoNetworkEnum.github) - readonly generate = effectAction((origin$: Observable) => { - return origin$.pipe( - withLatestFrom(this.editOrganizationComponent.organization$), - concatMap(([, org]) => { - return this.orgsService.demo(org.id).pipe( - catchError((err) => { - this._toastrService.error('PAC.NOTES.ORGANIZATIONS.DEMO_GENERATE_ERROR') - return EMPTY - }) - ) - }), - tap(() => { - this._toastrService.success('PAC.NOTES.ORGANIZATIONS.DEMO_GENERATED') - }) - ) - }) + private readonly organization = this.editOrganizationComponent.organization + public readonly loading = signal(false) + public readonly generated = signal(false) + + async generate() { + try { + this.loading.set(true) + await firstValueFrom(this.orgsService.demo(this.organization().id, {source: this.source.value})) + this._toastrService.success('PAC.NOTES.ORGANIZATIONS.DEMO_GENERATED', { Default: 'Demo generated' }) + this.loading.set(false) + this.generated.set(true) + } catch (err) { + this._toastrService.error(getErrorMessage(err)) + this.loading.set(false) + } + } } diff --git a/apps/cloud/src/app/features/setting/organizations/organizations-routing.module.ts b/apps/cloud/src/app/features/setting/organizations/organizations-routing.module.ts index 2df84c6ba..971aa32fb 100644 --- a/apps/cloud/src/app/features/setting/organizations/organizations-routing.module.ts +++ b/apps/cloud/src/app/features/setting/organizations/organizations-routing.module.ts @@ -2,11 +2,9 @@ import { NgModule } from '@angular/core' import { RouterModule, Routes } from '@angular/router' import { NgxPermissionsGuard } from 'ngx-permissions' import { PermissionsEnum } from '../../../@core' -import { EditOrganizationMainComponent } from './edit-organization/edit-organization-settings/edit-organization-main/edit-organization-main.component' -import { EditOrganizationSettingsModule } from './edit-organization/edit-organization-settings/edit-organization-settings.module' import { EditOrganizationComponent } from './edit-organization/edit-organization.component' -import { OrganizationDemoComponent } from './organization-demo/organization-demo.component' import { OrganizationsComponent } from './organizations.component' +import { AllOrganizationsComponent } from './organizations/organizations.component' export function redirectTo() { return '/dashboard' @@ -28,45 +26,62 @@ const routes: Routes = [ organization: false, date: false } - } - }, - { - path: 'edit/:id', - component: EditOrganizationComponent, - canActivate: [NgxPermissionsGuard], - data: { - permissions: { - only: [PermissionsEnum.ALL_ORG_EDIT], - redirectTo - } }, children: [ { - path: '', - redirectTo: 'main', - pathMatch: 'full' - }, - { - path: 'main', - component: EditOrganizationMainComponent, + path: ':id', + component: EditOrganizationComponent, + canActivate: [NgxPermissionsGuard], data: { - selectors: { - project: false, - employee: false, - date: false + permissions: { + only: [PermissionsEnum.ALL_ORG_EDIT], + redirectTo } } }, { - path: 'demo', - component: OrganizationDemoComponent + path: '', + component: AllOrganizationsComponent } ] } + // { + // path: 'edit/:id', + // component: EditOrganizationComponent, + // canActivate: [NgxPermissionsGuard], + // data: { + // permissions: { + // only: [PermissionsEnum.ALL_ORG_EDIT], + // redirectTo + // } + // }, + // children: [ + // { + // path: '', + // redirectTo: 'main', + // pathMatch: 'full' + // }, + // { + // path: 'main', + // component: EditOrganizationMainComponent, + // data: { + // selectors: { + // project: false, + // employee: false, + // date: false + // } + // } + // }, + // { + // path: 'demo', + // component: OrganizationDemoComponent + // } + // ] + // }, ] @NgModule({ - imports: [RouterModule.forChild(routes), EditOrganizationSettingsModule], + imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class OrganizationsRoutingModule {} diff --git a/apps/cloud/src/app/features/setting/organizations/organizations.component.html b/apps/cloud/src/app/features/setting/organizations/organizations.component.html index 5499a8f13..a495537ff 100644 --- a/apps/cloud/src/app/features/setting/organizations/organizations.component.html +++ b/apps/cloud/src/app/features/setting/organizations/organizations.component.html @@ -1,60 +1,37 @@ -
-
- {{ 'PAC.MENU.MANAGE_ORGANIZATIONS' | translate: {Default: "Manage Organizations"} }} +
+
+
{{ 'PAC.MENU.MANAGE_ORGANIZATIONS' | translate: {Default: "Manage Organizations"} }}
+ +
+ +
-
- -
-
- - + +
+ - -
- \ No newline at end of file + + + diff --git a/apps/cloud/src/app/features/setting/organizations/organizations.component.scss b/apps/cloud/src/app/features/setting/organizations/organizations.component.scss index 4b24fffdb..a97cd30ed 100644 --- a/apps/cloud/src/app/features/setting/organizations/organizations.component.scss +++ b/apps/cloud/src/app/features/setting/organizations/organizations.component.scss @@ -1,6 +1,5 @@ :host { - flex: 1; - max-width: 100%; + @apply flex-1 max-w-full flex flex-col items-stretch justify-start; } .pac-page__body.pac-organizations__content { diff --git a/apps/cloud/src/app/features/setting/organizations/organizations.component.ts b/apps/cloud/src/app/features/setting/organizations/organizations.component.ts index 7201b32b6..83d0f7063 100644 --- a/apps/cloud/src/app/features/setting/organizations/organizations.component.ts +++ b/apps/cloud/src/app/features/setting/organizations/organizations.component.ts @@ -1,21 +1,19 @@ import { SelectionModel } from '@angular/cdk/collections' import { Component } from '@angular/core' import { MatDialog } from '@angular/material/dialog' -import { Router } from '@angular/router' -import { UntilDestroy } from '@ngneat/until-destroy' import { ConfirmDeleteComponent } from '@metad/components/confirm' import { BehaviorSubject, firstValueFrom, map, shareReplay, switchMap } from 'rxjs' import { IOrganization, OrganizationsService, ToastrService } from '../../../@core' -import { TranslationBaseComponent } from '../../../@shared' +import { ManageEntityBaseComponent } from '../../../@shared' import { OrganizationMutationComponent } from './organization-mutation/organization-mutation.component' -@UntilDestroy({ checkProperties: true }) + @Component({ selector: 'pac-organizations', templateUrl: './organizations.component.html', styleUrls: ['./organizations.component.scss'] }) -export class OrganizationsComponent extends TranslationBaseComponent { +export class OrganizationsComponent extends ManageEntityBaseComponent { private refresh$ = new BehaviorSubject(null) public readonly organizations$ = this.refresh$.pipe( switchMap(() => this.organizationsService.getAll().pipe(map(({ items }) => items))), @@ -26,7 +24,6 @@ export class OrganizationsComponent extends TranslationBaseComponent { constructor( private readonly organizationsService: OrganizationsService, - private readonly router: Router, private readonly _dialog: MatDialog, private _toastrService: ToastrService ) { diff --git a/apps/cloud/src/app/features/setting/organizations/organizations.module.ts b/apps/cloud/src/app/features/setting/organizations/organizations.module.ts index 34ba7963c..6b2f2573b 100644 --- a/apps/cloud/src/app/features/setting/organizations/organizations.module.ts +++ b/apps/cloud/src/app/features/setting/organizations/organizations.module.ts @@ -3,8 +3,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormlyMatToggleModule } from '@ngx-formly/material/toggle' import { NxTableModule } from '@metad/components/table' import { OrgAvatarComponent, OrgAvatarEditorComponent, SharedModule } from '../../../@shared' -import { EditOrganizationComponent } from './edit-organization/edit-organization.component' -import { OrganizationDemoComponent } from './organization-demo/organization-demo.component' import { OrganizationMutationComponent } from './organization-mutation/organization-mutation.component' import { OrganizationStepFormComponent } from './organization-step-form/organization-step-form.component' import { OrganizationsRoutingModule } from './organizations-routing.module' @@ -23,10 +21,8 @@ import { OrganizationsComponent } from './organizations.component' ], declarations: [ OrganizationsComponent, - EditOrganizationComponent, OrganizationStepFormComponent, OrganizationMutationComponent, - OrganizationDemoComponent ], providers: [] }) diff --git a/apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.html b/apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.html new file mode 100644 index 000000000..3dac1eaec --- /dev/null +++ b/apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.html @@ -0,0 +1,50 @@ +
+ +
+ + + + + + +
+ + + +
+
diff --git a/apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.scss b/apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.scss new file mode 100644 index 000000000..b41c95953 --- /dev/null +++ b/apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.scss @@ -0,0 +1,3 @@ +:host { + @apply flex-1 w-full max-w-full flex flex-col items-stretch justify-start; +} diff --git a/apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.ts b/apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.ts new file mode 100644 index 000000000..686641486 --- /dev/null +++ b/apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.ts @@ -0,0 +1,96 @@ +import { SelectionModel } from '@angular/cdk/collections' +import { CommonModule } from '@angular/common' +import { Component } from '@angular/core' +import { MatDialog } from '@angular/material/dialog' +import { Router, RouterModule } from '@angular/router' +import { ConfirmDeleteComponent } from '@metad/components/confirm' +import { NxTableModule } from '@metad/components/table' +import { TranslateModule } from '@ngx-translate/core' +import { BehaviorSubject, firstValueFrom, map, shareReplay, switchMap } from 'rxjs' +import { IOrganization, OrganizationsService, ToastrService } from '../../../../@core' +import { MaterialModule, OrgAvatarComponent, TranslationBaseComponent } from '../../../../@shared' +import { OrganizationMutationComponent } from '../organization-mutation/organization-mutation.component' + +@Component({ + standalone: true, + selector: 'pac-all-organizations', + templateUrl: './organizations.component.html', + styleUrls: ['./organizations.component.scss'], + imports: [CommonModule, MaterialModule, TranslateModule, RouterModule, NxTableModule, OrgAvatarComponent] +}) +export class AllOrganizationsComponent extends TranslationBaseComponent { + private refresh$ = new BehaviorSubject(null) + public readonly organizations$ = this.refresh$.pipe( + switchMap(() => this.organizationsService.getAll().pipe(map(({ items }) => items))), + shareReplay(1) + ) + + public readonly selection = new SelectionModel() + + constructor( + private readonly organizationsService: OrganizationsService, + private readonly router: Router, + private readonly _dialog: MatDialog, + private _toastrService: ToastrService + ) { + super() + } + + checkSelected(org: IOrganization) { + return this.selection.isSelected(org.id) + } + + toggle(org: IOrganization) { + this.selection.toggle(org.id) + } + + editOrganization(id) { + this.router.navigate(['/settings/organizations/', id]) + } + + async addOrganization() { + const org = await firstValueFrom(this._dialog.open(OrganizationMutationComponent).afterClosed()) + if (org) { + try { + await firstValueFrom(this.organizationsService.create(org)) + this._toastrService.success('NOTES.ORGANIZATIONS.ADD_NEW_ORGANIZATION', { Default: 'Add New Organization' }) + this.refresh$.next() + } catch (err) { + this._toastrService.error(err) + } + } + } + + async deleteOrganization(id: string) { + const organizations = await firstValueFrom(this.organizations$) + const organization = organizations.find((item) => item.id === id) + const information = await firstValueFrom( + this.getTranslation('PAC.NOTES.ORGANIZATIONS.DELETE_CONFIRM', { + Default: 'Confirm to delete the org from server?' + }) + ) + const confirm = await firstValueFrom( + this._dialog + .open(ConfirmDeleteComponent, { + data: { + value: organization?.name, + information + } + }) + .afterClosed() + ) + + if (confirm) { + try { + await firstValueFrom(this.organizationsService.delete(organization.id)) + this._toastrService.success('PAC.NOTES.ORGANIZATIONS.DELETE_ORGANIZATION', { + Default: `Organization '{{ name }}' was removed`, + name: organization.name + }) + this.refresh$.next() + } catch (err) { + this._toastrService.error(err) + } + } + } +} diff --git a/apps/cloud/src/app/features/setting/roles/roles.component.html b/apps/cloud/src/app/features/setting/roles/roles.component.html index 7616846fd..8b57ffb51 100644 --- a/apps/cloud/src/app/features/setting/roles/roles.component.html +++ b/apps/cloud/src/app/features/setting/roles/roles.component.html @@ -1,30 +1,37 @@ - - +
+ -
+ +
+
+ + +
-
-

+
+

{{ 'PAC.MENU.Roles.General' | translate: {Default: 'General'} }}

@@ -39,8 +46,8 @@

-
-

+
+

{{ 'PAC.MENU.Roles.Administration' | translate: {Default: 'Administration'} }}

@@ -57,3 +64,7 @@

+ + + + \ No newline at end of file diff --git a/apps/cloud/src/app/features/setting/roles/roles.component.scss b/apps/cloud/src/app/features/setting/roles/roles.component.scss index 2dbd0419c..f3390fa55 100644 --- a/apps/cloud/src/app/features/setting/roles/roles.component.scss +++ b/apps/cloud/src/app/features/setting/roles/roles.component.scss @@ -6,16 +6,10 @@ } -.pac-page__body.pac-settings-roles__body { - padding: 24px; - overflow: auto; -} - :host::ng-deep { .mat-mdc-list-item.mdc-list-item:not(.mdc-list-item--disabled) { @apply hover:bg-gray-100; } - .mdc-list-item__primary-text { @apply w-full flex items-center h-10; diff --git a/apps/cloud/src/app/features/setting/settings.component.scss b/apps/cloud/src/app/features/setting/settings.component.scss new file mode 100644 index 000000000..1b173e402 --- /dev/null +++ b/apps/cloud/src/app/features/setting/settings.component.scss @@ -0,0 +1,14 @@ +:host { + @apply bg-white; + display: flex; + flex: 1; + flex-direction: row; + max-width: 100%; + overflow: auto; +} +.pac-nav__router { + display: flex; + /* max-height: calc(100% - 37px); */ + overflow-y: auto; + overflow-x: hidden; +} \ No newline at end of file diff --git a/apps/cloud/src/app/features/setting/settings.component.ts b/apps/cloud/src/app/features/setting/settings.component.ts index d97da75cc..ae07ec534 100644 --- a/apps/cloud/src/app/features/setting/settings.component.ts +++ b/apps/cloud/src/app/features/setting/settings.component.ts @@ -6,7 +6,7 @@ import { AnalyticsPermissionsEnum, FeatureEnum, PermissionsEnum, RolesEnum, Stor @Component({ selector: 'pac-settings', template: ` -
+
@@ -30,28 +30,12 @@ import { AnalyticsPermissionsEnum, FeatureEnum, PermissionsEnum, RolesEnum, Stor
`, - styles: [ - ` - :host { - display: flex; - flex: 1; - flex-direction: row; - max-width: 100%; - overflow: auto; - } - .pac-nav__router { - display: flex; - max-height: calc(100% - 37px); - overflow-y: auto; - overflow-x: hidden; - } - ` - ], + styleUrls: ['./settings.component.scss'], animations: [routeAnimations], changeDetection: ChangeDetectionStrategy.OnPush }) diff --git a/apps/cloud/src/app/features/setting/tenant/settings/settings.component.ts b/apps/cloud/src/app/features/setting/tenant/settings/settings.component.ts index a33bd3afe..46b834eb4 100644 --- a/apps/cloud/src/app/features/setting/tenant/settings/settings.component.ts +++ b/apps/cloud/src/app/features/setting/tenant/settings/settings.component.ts @@ -11,7 +11,7 @@ interface ItemData { @Component({ selector: 'pac-tenant-settings', templateUrl: 'settings.component.html', - styles: [':host {display: block;}'] + styles: [':host {display: block; width: 100%; padding: 1rem;}'] }) export class SettingsComponent implements OnInit { i = 0 diff --git a/apps/cloud/src/app/features/setting/tenant/tenant.component.html b/apps/cloud/src/app/features/setting/tenant/tenant.component.html index 76e5076f0..5ee8f8caf 100644 --- a/apps/cloud/src/app/features/setting/tenant/tenant.component.html +++ b/apps/cloud/src/app/features/setting/tenant/tenant.component.html @@ -1,8 +1,9 @@ -
-
- {{ 'PAC.MENU.MANAGE_TENANT' | translate: {Default: "Manage Tenant"} }} -
-
+ + + + + @@ -43,8 +55,12 @@ - - - \ No newline at end of file + +
+ {{ 'PAC.Users.NoMoreOrganizations' | translate: { Default: 'No more organizations can be added' } }} +
+ diff --git a/apps/cloud/src/app/features/setting/users/organizations/organizations.component.ts b/apps/cloud/src/app/features/setting/users/organizations/organizations.component.ts index 3eb302e86..a15b586ed 100644 --- a/apps/cloud/src/app/features/setting/users/organizations/organizations.component.ts +++ b/apps/cloud/src/app/features/setting/users/organizations/organizations.component.ts @@ -1,46 +1,53 @@ import { Component } from '@angular/core' import { MatDialog } from '@angular/material/dialog' -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy' import { ConfirmDeleteComponent } from '@metad/components/confirm' -import { TranslationBaseComponent } from 'apps/cloud/src/app/@shared' +import { MaterialModule, SharedModule, TranslationBaseComponent, UserProfileInlineComponent } from 'apps/cloud/src/app/@shared' import { differenceWith } from 'lodash-es' import { BehaviorSubject, combineLatest, firstValueFrom } from 'rxjs' import { map, shareReplay, switchMap } from 'rxjs/operators' import { IOrganization, OrganizationsService, ToastrService, UsersOrganizationsService } from '../../../../@core' import { PACEditUserComponent } from '../edit-user/edit-user.component' +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop' +import { NxTableModule } from '@metad/components/table' + -@UntilDestroy({checkProperties: true}) @Component({ + standalone: true, selector: 'pac-user-organizations', templateUrl: 'organizations.component.html', styles: [ ` :host { + width: 100%; display: flex; flex-direction: column; } ` + ], + imports: [ + SharedModule, + MaterialModule, + NxTableModule, + UserProfileInlineComponent ] }) export class PACUserOrganizationsComponent extends TranslationBaseComponent { - public readonly user$ = this.userComponent.user$ - private readonly refresh$ = new BehaviorSubject(null) public readonly userOrganizations$ = combineLatest([this.userComponent.userId$, this.refresh$]).pipe( switchMap(([userId]) => this.userOrganizationsService.getAll(['user', 'organization'], { userId })), map(({ items }) => items), - untilDestroyed(this), + takeUntilDestroyed(), shareReplay(1) ) - public readonly organizations$ = combineLatest([ + public readonly organizations = toSignal(combineLatest([ this.organizationsService.getAll([]).pipe(map(({ items }) => items)), this.userOrganizations$ ]).pipe( map(([organizations, userOrganizations]) => { return differenceWith(organizations, userOrganizations, (arrVal, othVal) => arrVal.id === othVal.organizationId) }) - ) + )) constructor( private readonly userComponent: PACEditUserComponent, @@ -53,7 +60,7 @@ export class PACUserOrganizationsComponent extends TranslationBaseComponent { } async addOrg(org: IOrganization) { - const user = await firstValueFrom(this.user$) + const user = this.userComponent.user() if (user) { try { await firstValueFrom( diff --git a/apps/cloud/src/app/features/setting/users/user-basic/user-basic.component.html b/apps/cloud/src/app/features/setting/users/user-basic/user-basic.component.html index 0b1ccef5e..6320d76f6 100644 --- a/apps/cloud/src/app/features/setting/users/user-basic/user-basic.component.html +++ b/apps/cloud/src/app/features/setting/users/user-basic/user-basic.component.html @@ -1,7 +1,21 @@ - - + + +
+ manage_accounts + {{ 'PAC.MENU.USER.BASIC' | translate: {Default: "Basic"} }} +
+
+ +
+ + +
+
- + + + +
diff --git a/apps/cloud/src/app/features/setting/users/user-basic/user-basic.component.ts b/apps/cloud/src/app/features/setting/users/user-basic/user-basic.component.ts index 93b67fefb..bd1efee69 100644 --- a/apps/cloud/src/app/features/setting/users/user-basic/user-basic.component.ts +++ b/apps/cloud/src/app/features/setting/users/user-basic/user-basic.component.ts @@ -1,29 +1,32 @@ -import { Component, Input, OnInit } from '@angular/core' +import { Component, Input, OnInit, effect } from '@angular/core' +import { ActivatedRoute } from '@angular/router' +import { UsersService } from '@metad/cloud/state' import { IUserUpdateInput, LanguagesEnum } from '@metad/contracts' -import { TranslationBaseComponent, CreatedByPipe } from '../../../../@shared' +import { NgmCommonModule } from '@metad/ocap-angular/common' +import { UserFormsModule } from 'apps/cloud/src/app/@shared/user/forms' import { ToastrService, User } from '../../../../@core' +import { CreatedByPipe, MaterialModule, SharedModule, TranslationBaseComponent } from '../../../../@shared' import { PACEditUserComponent } from '../edit-user/edit-user.component' -import { UsersService } from '@metad/cloud/state' -import { ActivatedRoute } from '@angular/router' -import { takeUntilDestroyed } from '@angular/core/rxjs-interop' - @Component({ + standalone: true, selector: 'pac-user-basic', templateUrl: 'user-basic.component.html', - styles: [`:host { - display: flex; - flex-direction: column; - max-width: 700px; - align-items: flex-start; - margin: auto; - }`] + styles: [ + ` + :host { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + } + ` + ], + imports: [SharedModule, MaterialModule, NgmCommonModule, UserFormsModule] }) export class UserBasicComponent extends TranslationBaseComponent implements OnInit { @Input() allowRoleChange: boolean - public readonly user$ = this.userComponent.user$ - user: User constructor( private readonly userComponent: PACEditUserComponent, @@ -33,8 +36,8 @@ export class UserBasicComponent extends TranslationBaseComponent implements OnIn ) { super() - this.user$.pipe(takeUntilDestroyed()).subscribe((user) => { - this.user = user as User + effect(() => { + this.user = this.userComponent.user() as User }) } @@ -51,7 +54,7 @@ export class UserBasicComponent extends TranslationBaseComponent implements OnIn lastName, tags, preferredLanguage: preferredLanguage as LanguagesEnum, - imageUrl, + imageUrl } if (password) { @@ -70,7 +73,7 @@ export class UserBasicComponent extends TranslationBaseComponent implements OnIn try { await this.userService.update(this.user.id, request).then(() => { - this._toastrService.success(`PAC.NOTES.USERS.USER_UPDATED`, {name: (new CreatedByPipe()).transform(this.user)}) + this._toastrService.success(`PAC.NOTES.USERS.USER_UPDATED`, { name: new CreatedByPipe().transform(this.user) }) }) } catch (error) {} } diff --git a/apps/cloud/src/app/features/setting/users/user-routing.module.ts b/apps/cloud/src/app/features/setting/users/user-routing.module.ts index 1b92e8131..a8051ce6b 100644 --- a/apps/cloud/src/app/features/setting/users/user-routing.module.ts +++ b/apps/cloud/src/app/features/setting/users/user-routing.module.ts @@ -1,12 +1,13 @@ import { NgModule } from '@angular/core' import { RouterModule, Routes } from '@angular/router' import { PermissionsEnum } from '@metad/contracts' -import { InviteGuard } from '../../../@core/guards' +import { inviteGuard } from '../../../@core/guards' import { PACEditUserComponent } from './edit-user/edit-user.component' import { ManageUserInviteComponent } from './manage-user-invite/manage-user-invite.component' import { PACUserOrganizationsComponent } from './organizations/organizations.component' import { UserBasicComponent } from './user-basic/user-basic.component' import { PACUsersComponent } from './users.component' +import { ManageUserComponent } from './manage-user/manage-user.component' const routes: Routes = [ { @@ -29,19 +30,6 @@ const routes: Routes = [ } ] }, - - { - path: 'invites', - component: ManageUserInviteComponent, - canActivate: [InviteGuard], - data: { - title: 'Settings/User/Invites', - expectedPermissions: [ - PermissionsEnum.ORG_INVITE_EDIT, - PermissionsEnum.ORG_INVITE_VIEW - ] - } - }, { path: '', component: PACUsersComponent, @@ -49,9 +37,28 @@ const routes: Routes = [ title: 'Settings/User', }, children: [ + { + path: '', + component: ManageUserComponent + }, + { + path: 'invites', + component: ManageUserInviteComponent, + canActivate: [inviteGuard], + data: { + title: 'Settings/User/Invites', + expectedPermissions: [ + PermissionsEnum.ORG_INVITE_EDIT, + PermissionsEnum.ORG_INVITE_VIEW + ] + } + }, { path: ':id', - component: PACEditUserComponent + component: PACEditUserComponent, + data: { + title: 'Settings/User/Edit' + }, } ] }, diff --git a/apps/cloud/src/app/features/setting/users/user.module.ts b/apps/cloud/src/app/features/setting/users/user.module.ts index 90abda476..6135080dd 100644 --- a/apps/cloud/src/app/features/setting/users/user.module.ts +++ b/apps/cloud/src/app/features/setting/users/user.module.ts @@ -1,40 +1,9 @@ import { NgModule } from '@angular/core' -import { ButtonGroupDirective, OcapCoreModule } from '@metad/ocap-angular/core' -import { MtxCheckboxGroupModule } from '@ng-matero/extensions/checkbox-group' -import { NxTableModule } from '@metad/components/table' -import { InviteGuard } from '../../../@core/guards' -import { MaterialModule, SharedModule, UserProfileInlineComponent } from '../../../@shared' -import { UserFormsModule } from '../../../@shared/user/forms' -import { PACEditUserComponent } from './edit-user/edit-user.component' -import { ManageUserInviteComponent } from './manage-user-invite/manage-user-invite.component' -import { PACUserOrganizationsComponent } from './organizations/organizations.component' -import { UserBasicComponent } from './user-basic/user-basic.component' import { UserRoutingModule } from './user-routing.module' -import { PACUsersComponent } from './users.component' -import { InlineSearchComponent } from '../../../@shared/form-fields' @NgModule({ - declarations: [ - PACUsersComponent, - PACEditUserComponent, - UserBasicComponent, - PACUserOrganizationsComponent, - ManageUserInviteComponent - ], - providers: [InviteGuard], - imports: [ - UserRoutingModule, - SharedModule, - MaterialModule, - UserFormsModule, - // Standard components - ButtonGroupDirective, - NxTableModule, - MtxCheckboxGroupModule, - InlineSearchComponent, - // OCAP Modules - OcapCoreModule, - UserProfileInlineComponent - ] + declarations: [], + providers: [], + imports: [UserRoutingModule] }) export class UserModule {} diff --git a/apps/cloud/src/app/features/setting/users/users.component.html b/apps/cloud/src/app/features/setting/users/users.component.html index eea369ba3..e93b8bbac 100644 --- a/apps/cloud/src/app/features/setting/users/users.component.html +++ b/apps/cloud/src/app/features/setting/users/users.component.html @@ -1,90 +1,57 @@ - - -
- -
- - -
- - +
+
+
+
{{ 'PAC.MENU.MANAGE_USERS' | translate: {Default: 'Manage Users'} }}
+
{{ 'PAC.MENU.ManageUsersAndInvites' | translate: {Default: 'Manage Users & Invites'} }}
- + +
-
-
- - -
- -
- - {{ user | user }} - - - - {{user.role.name}} - -
{{user.email}}
-
-
- - -
-
-
- +
+ - - - - - - - + + + diff --git a/apps/cloud/src/app/features/setting/users/users.component.scss b/apps/cloud/src/app/features/setting/users/users.component.scss index 2c3e5df0d..f9f81de9c 100644 --- a/apps/cloud/src/app/features/setting/users/users.component.scss +++ b/apps/cloud/src/app/features/setting/users/users.component.scss @@ -1,16 +1,3 @@ :host { - @apply flex-1 flex flex-col items-end justify-start; -} - -.pac-sketch-card.mdc-card { - - .mat-mdc-card-subtitle { - margin-bottom: 0; - } - - .mat-chip-list { - display: inline-block; - margin: 0 5px; - vertical-align: middle; - } + @apply flex-1 flex flex-col items-stretch justify-start; } diff --git a/apps/cloud/src/app/features/setting/users/users.component.ts b/apps/cloud/src/app/features/setting/users/users.component.ts index 2bc08ebd7..386f425cb 100644 --- a/apps/cloud/src/app/features/setting/users/users.component.ts +++ b/apps/cloud/src/app/features/setting/users/users.component.ts @@ -1,79 +1,80 @@ -import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core' +import { ChangeDetectionStrategy, Component, ViewChild, effect, inject, signal } from '@angular/core' import { MatDialog } from '@angular/material/dialog' -import { Router } from '@angular/router' -import { Store, UsersService } from '@metad/cloud/state' -import { ConfirmDeleteComponent } from '@metad/components/confirm' -import { includes } from 'lodash-es' -import { BehaviorSubject, firstValueFrom, map, startWith, switchMap } from 'rxjs' -import { Group, IUser, RolesEnum, routeAnimations, ROUTE_ANIMATIONS_ELEMENTS, ToastrService } from '../../../@core/index' +import { ActivatedRoute, Router } from '@angular/router' +import { Store } from '@metad/cloud/state' +import { Subject, firstValueFrom, map } from 'rxjs' +import { Group, IUser, ROUTE_ANIMATIONS_ELEMENTS, routeAnimations } from '../../../@core/index' +import { MaterialModule, SharedModule, UserMutationComponent, userLabel } from '../../../@shared' import { InviteMutationComponent } from '../../../@shared/invite' -import { userLabel } from '../../../@shared/pipes' -import { UserMutationComponent } from '../../../@shared/user' import { TranslationBaseComponent } from '../../../@shared/language/translation-base.component' + @Component({ + standalone: true, selector: 'pac-users', templateUrl: './users.component.html', styleUrls: ['./users.component.scss'], animations: [routeAnimations], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [SharedModule, MaterialModule] }) -export class PACUsersComponent extends TranslationBaseComponent { +export class PACUsersComponent extends TranslationBaseComponent { routeAnimationsElements = ROUTE_ANIMATIONS_ELEMENTS + userLabel = userLabel private readonly store = inject(Store) - private userService = inject(UsersService) private router = inject(Router) + private _route = inject(ActivatedRoute) private _dialog = inject(MatDialog) - private toastrService = inject(ToastrService) - ROLES = Object.keys(RolesEnum) - roles$ = new BehaviorSubject([]) - get roles() { - return this.roles$.value - } - set roles(value) { - this.roles$.next(value) + openedLinks = signal([]) + currentLink = signal(null) + + public readonly organizationName$ = this.store.selectedOrganization$.pipe(map((org) => org?.name)) + + public readonly invitedEvent = new Subject() + + constructor() { + super() + + effect( + () => { + if (this.currentLink()) { + const links = this.openedLinks() + const index = links.findIndex((item) => item.id === this.currentLink().id) + if (index > -1) { + if (links[index] !== this.currentLink()) { + this.openedLinks.set([...links.slice(0, index), this.currentLink(), ...links.slice(index + 1)]) + } + } else { + this.openedLinks.set([...links, this.currentLink()]) + } + } + }, + { allowSignalWrites: true } + ) } - user = 'A' - private search$ = new BehaviorSubject('') - get search() { - return this.search$.value + + trackById(index: number, item: T) { + return item?.id } - set search(value) { - this.search$.next(value) + + setCurrentLink(link: T) { + this.currentLink.set(link) } - private refresh$ = new BehaviorSubject(null) - public readonly users$ = this.refresh$.pipe( - switchMap(() => this.userService.getAll(['role'])), - switchMap((users) => this.roles$.pipe(map((roles) => roles?.length ? users.filter((user) => includes(roles, user.role.name)) : users))), - switchMap((users) => { - return this.search$.pipe( - startWith(this.search), - map((text: string) => { - text = text?.toLowerCase() - return text - ? users.filter( - (user) => - user.name?.toLowerCase().includes(text) || - user.lastName?.toLowerCase().includes(text) || - user.firstName?.toLowerCase().includes(text) || - user.email?.toLowerCase().includes(text) - ) - : users - }) - ) - }) - ) - public readonly organizationName$ = this.store.selectedOrganization$.pipe(map((org) => org?.name)) + removeOpenedLink(link: T) { + this.currentLink.set(null) + this.openedLinks.set(this.openedLinks().filter((item) => item.id !== link.id)) + this.router.navigate(['.'], { relativeTo: this._route }) + } checkChange(e: boolean): void { console.log(e) } navUser(user: IUser) { - this.router.navigate(['/settings/users/edit/', user.id]) + this.router.navigate(['/settings/users/', user.id]) } navGroup(group: Group) { @@ -81,40 +82,25 @@ export class PACUsersComponent extends TranslationBaseComponent { } manageInvites() { - this.router.navigate(['/settings/users/invites/']); - } - - async add() { - const user = await firstValueFrom(this._dialog - .open(UserMutationComponent, { data: { isAdmin: true } }) - .afterClosed() - ) - if (user) { - this.refresh$.next() - } + this.router.navigate(['/settings/users/invites/']) } async invite() { - const user = await firstValueFrom(this._dialog.open(InviteMutationComponent,).afterClosed()) + const result = await firstValueFrom(this._dialog.open(InviteMutationComponent).afterClosed()) + + // 成功邀请人数 + if (result?.total) { + this.invitedEvent.next() + this.router.navigate(['invites'], { relativeTo: this._route }) + } } - /** - * 对比下面函数的写法 - */ - async remove(user: IUser) { - const confirm = await firstValueFrom(this._dialog.open(ConfirmDeleteComponent, { data: {value: userLabel(user)} }).afterClosed()) - if (confirm) { - try { - await firstValueFrom(this.userService.delete(user.id, user)) - this.toastrService.success('PAC.NOTES.USERS.UserDelete', { - name: userLabel(user) - }) - this.refresh$.next() - } catch (err) { - this.toastrService.error('PAC.NOTES.USERS.UserDelete', '', { - name: userLabel(user) - }) - } + async addUser() { + const result = await firstValueFrom( + this._dialog.open(UserMutationComponent, { data: { isAdmin: true } }).afterClosed() + ) + if (result?.user) { + this.router.navigate(['.', result.user.id], { relativeTo: this._route }) } } } diff --git a/apps/cloud/src/app/features/story/save-as-template/save-as-template.component.html b/apps/cloud/src/app/features/story/save-as-template/save-as-template.component.html index bc35e482b..124090b3c 100644 --- a/apps/cloud/src/app/features/story/save-as-template/save-as-template.component.html +++ b/apps/cloud/src/app/features/story/save-as-template/save-as-template.component.html @@ -64,26 +64,28 @@ {{ 'Story.Template.Preview' | translate: {Default: "Preview"} }} -
- - - -
- -
- {{error}} +
+
+ + + +
+ + + {{error}} +
diff --git a/apps/cloud/src/app/features/story/save-as-template/save-as-template.component.ts b/apps/cloud/src/app/features/story/save-as-template/save-as-template.component.ts index 7029a9095..835bc28a4 100644 --- a/apps/cloud/src/app/features/story/save-as-template/save-as-template.component.ts +++ b/apps/cloud/src/app/features/story/save-as-template/save-as-template.component.ts @@ -5,7 +5,7 @@ import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angula import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog' import { AppearanceDirective, ButtonGroupDirective, DensityDirective } from '@metad/ocap-angular/core' import { ChartAnnotation, DataSettings, isNil, omit, omitBy, pick } from '@metad/ocap-core' -import { TranslateModule } from '@ngx-translate/core' +import { TranslateModule, TranslateService } from '@ngx-translate/core' import { NX_STORY_STORE, NxStoryStore, Story, StoryPoint, StoryPointState } from '@metad/story/core' import { firstValueFrom } from 'rxjs' import { @@ -45,6 +45,7 @@ export class SaveAsTemplateComponent { private readonly storyTemplateService = inject(StoryTemplateService) private readonly screenshotService = inject(ScreenshotService) private readonly toastrService = inject(ToastrService) + private readonly translate = inject(TranslateService) file: File imagePreview: string | ArrayBuffer | null = null @@ -88,8 +89,9 @@ export class SaveAsTemplateComponent { const reader = new FileReader() reader.onload = () => { const result = reader.result as String; - if (result.length > 2**21) { // Note: 2*2**20 = 2**21 = 2MB - this.error = 'File exceeds the maximum size 2MB' + // File size check (There is an error) + if (result.length > 3*(2**20)) { // Note: 2*2**20 = 2MB + this.error = `${this.translate.instant('Story.Template.PreviewExceedsMaximum', {Default: 'File exceeds the maximum size'})} 2MB` this.file = null } else { this.imagePreview = reader.result @@ -148,6 +150,7 @@ export class SaveAsTemplateComponent { deletePreview() { this.file = null this.imagePreview = null + this.error = null this.formGroup.patchValue({ previewId: null, thumbnail: null }) } } diff --git a/apps/cloud/src/app/features/story/story-details/story-details.component.html b/apps/cloud/src/app/features/story/story-details/story-details.component.html index ed1fb43d4..dcc0df9eb 100644 --- a/apps/cloud/src/app/features/story/story-details/story-details.component.html +++ b/apps/cloud/src/app/features/story/story-details/story-details.component.html @@ -117,45 +117,6 @@ - {{ 'Story.StoryDetails.DISPLAY_AS_FULLSCREEN' | translate: {Default: "Display as Fullscreen"} }} @@ -174,6 +135,10 @@
Image Preview +
+ {{error}} +
+ + + +
+
+ +
+ +
+
+ {{ 'PAC.MENU.HOME.Trending' | translate: {Default: "Trending"} }} +
+
+
+ {{ 'PAC.KEY_WORDS.SortBy' | translate: {Default: 'Sort By'} }}: +
+ + + {{ 'PAC.KEY_WORDS.Visits' | translate: {Default: 'Visits'} }} + + + {{ 'PAC.KEY_WORDS.UpdatedDate' | translate: {Default: 'Updated Date'} }} + + + +
+
+ +
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
\ No newline at end of file diff --git a/apps/cloud/src/app/public/trending/trending.component.scss b/apps/cloud/src/app/public/trending/trending.component.scss index e69de29bb..6a51f3912 100644 --- a/apps/cloud/src/app/public/trending/trending.component.scss +++ b/apps/cloud/src/app/public/trending/trending.component.scss @@ -0,0 +1,8 @@ +:host { + flex: 1; + max-width: 100%; + height: 100%; + display: flex; + flex-direction: column; + overflow: auto; +} diff --git a/apps/cloud/src/app/public/trending/trending.componnet.ts b/apps/cloud/src/app/public/trending/trending.componnet.ts index 059f50dc4..0271a42d6 100644 --- a/apps/cloud/src/app/public/trending/trending.componnet.ts +++ b/apps/cloud/src/app/public/trending/trending.componnet.ts @@ -1,12 +1,122 @@ -import { Component } from '@angular/core' -import { UntilDestroy } from '@ngneat/until-destroy' +import { DragDropModule } from '@angular/cdk/drag-drop' +import { CommonModule } from '@angular/common' +import { ChangeDetectorRef, Component, effect, inject, signal } from '@angular/core' +import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms' +import { MatButtonToggleModule } from '@angular/material/button-toggle' +import { RouterModule } from '@angular/router' +import { NgmCommonModule } from '@metad/ocap-angular/common' +import { effectAction } from '@metad/ocap-angular/core' +import { IntersectionObserverModule } from '@ng-web-apis/intersection-observer' +import { TranslateModule } from '@ngx-translate/core' +import { StoriesService } from '@metad/cloud/state' +import { debounceTime, distinctUntilChanged, switchMap, tap } from 'rxjs' +import { StoryCardComponent } from '../../@shared' +import { IStory, listAnimation } from '../../@core' +import { MatButtonModule } from '@angular/material/button' + -@UntilDestroy({ checkProperties: true }) @Component({ + standalone: true, + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + DragDropModule, + RouterModule, + IntersectionObserverModule, + MatButtonToggleModule, + MatButtonModule, + + TranslateModule, + NgmCommonModule, + + StoryCardComponent + ], selector: 'pac-public-trending', - templateUrl: './trending.component.html', - styleUrls: ['./trending.component.scss'] + templateUrl: 'trending.component.html', + styleUrls: ['trending.component.scss'], + animations: [listAnimation] }) export class TrendingComponent { - + private readonly storiesService = inject(StoriesService) + private readonly _cdr = inject(ChangeDetectorRef) + + searchControl = new FormControl() + get highlight() { + return this.searchControl.value + } + + public trends = [] + private pageSize = 10 + private currentPage = 0 + private loading = false + public done = false + + public get orderType() { + return this._orderType() + } + set orderType(value) { + this._orderType.set(value) + } + private readonly _orderType = signal<'visits' | 'update'>('visits') + + private searchSub = this.searchControl.valueChanges.pipe(distinctUntilChanged(), debounceTime(500)).subscribe(() => { + this.currentPage = 0 + this.trends = [] + this.done = false + this.loadTrends() + }) + + constructor() { + effect(() => { + if (this._orderType()) { + this.currentPage = 0 + this.trends = [] + this.done = false + this.loadTrends() + } + }) + } + + trackById(index: number, item: IStory) { + return item.id + } + + loadTrends = effectAction((origin$) => { + return origin$.pipe( + switchMap(() => { + this.loading = true + return this.storiesService + .getTrends( + { take: this.pageSize, skip: this.currentPage * this.pageSize, orderType: this.orderType }, + this.highlight + ) + .pipe( + tap({ + next: (result) => { + this.trends = [...this.trends, ...result.items] + this.currentPage++ + if (result.items.length < this.pageSize || this.currentPage * this.pageSize >= result.total) { + this.done = true + } + }, + error: (err) => { + this.loading = false + this._cdr.detectChanges() + }, + complete: () => { + this.loading = false + this._cdr.detectChanges() + } + }) + ) + }) + ) + }) + + onIntersection() { + if (!this.loading) { + this.loadTrends() + } + } } diff --git a/apps/cloud/src/assets/i18n/en-US.json b/apps/cloud/src/assets/i18n/en-US.json index f8bbc7523..d7da1b269 100644 --- a/apps/cloud/src/assets/i18n/en-US.json +++ b/apps/cloud/src/assets/i18n/en-US.json @@ -124,6 +124,14 @@ "STATUS": "Status" } }, + "Languages": { + "en": "English", + "en-US": "US English", + "zh": "Chinese", + "zh-CN": "Chinese", + "zh-Hans": "Simplied Chinese", + "zh-Hant": "Traditional Chinese" + }, "title": { "short": "Analytics Cloud" }, @@ -292,7 +300,8 @@ "ORG_JOB_MATCHING_VIEW": "View Job Matching", "TENANT_SETTINGS": "Tenant Settings", "ACCESS_DELETE_ACCOUNT": "Access Delete Account", - "ACCESS_DELETE_ALL_DATA": "Access Delete All Data" + "ACCESS_DELETE_ALL_DATA": "Access Delete All Data", + "ORG_DEMO_EDIT": "Edit Organization Demo" } } }, @@ -437,10 +446,5 @@ "VALUE_HELP": { "TITLE": "Set Filters for '{{value}}'" } - }, - "FORMLY": { - "PROPERTY_SELECT": { - "REFERENCE_LINE": "Reference Line" - } } } diff --git a/apps/cloud/src/assets/i18n/en.json b/apps/cloud/src/assets/i18n/en.json index 0561bfd90..d7da1b269 100644 --- a/apps/cloud/src/assets/i18n/en.json +++ b/apps/cloud/src/assets/i18n/en.json @@ -300,7 +300,8 @@ "ORG_JOB_MATCHING_VIEW": "View Job Matching", "TENANT_SETTINGS": "Tenant Settings", "ACCESS_DELETE_ACCOUNT": "Access Delete Account", - "ACCESS_DELETE_ALL_DATA": "Access Delete All Data" + "ACCESS_DELETE_ALL_DATA": "Access Delete All Data", + "ORG_DEMO_EDIT": "Edit Organization Demo" } } }, diff --git a/apps/cloud/src/assets/i18n/zh-CN.json b/apps/cloud/src/assets/i18n/zh-CN.json index 7322a6692..a1c1a624c 100644 --- a/apps/cloud/src/assets/i18n/zh-CN.json +++ b/apps/cloud/src/assets/i18n/zh-CN.json @@ -152,7 +152,12 @@ "CalculatedFormula": "计算公式", "Visits": "访问量", "UpdatedDate": "更新日期", - "SortBy": "排序" + "SortBy": "排序", + "Role&Permissions": "角色 & 权限", + "SemanticModels": "语义模型", + "Stories": "故事", + "Indicators": "指标", + "IndicatorMarket": "指标市场" }, "MENU": { "Certification": "认证", @@ -198,7 +203,7 @@ "InviteUsers": "邀请用户", "Authentication": "用户认证", "UserSettings": "用户设置", - + "ManageUsersAndInvites": "管理用户和邀请", "ORGANIZATIONS": "组织", "FEATURES": "功能", "USERS": "用户", @@ -301,7 +306,7 @@ "INDICATOR": { "REGISTER_INDICATOR": "注册指标", "BATCH_UPLOAD": "批量上传", - "DOWNLOAD_TEMPLATE": "下载模板", + "DownloadAsTemplate": "下载为模板", "INDICATOR_MARKET": "指标市场", "INDICATOR_MARKET_DESC": "浏览指标,申请指标权限" }, @@ -545,7 +550,8 @@ "Import": "导入", "Indicators": "指标", "Types": "类型", - "IndicatorMarket": "指标市场" + "IndicatorMarket": "指标市场", + "Certifications": "认证" }, "MODEL": { "ModelOverview": "语义模型概览", @@ -907,6 +913,7 @@ } }, "BUSINESS_AREA": { + "All": "所有", "BASIC": "基本属性", "Delete": "删除", "Update": "更新", @@ -952,6 +959,28 @@ "Open": "查看" } }, + "INVITE_PAGE": { + "ForOrganization": "为组织", + "INVITATION_EXPIRATION_OPTIONS": { + "DAY": "一日", + "WEEK": "一周", + "TWO_WEEK": "两周", + "MONTH": "一月", + "NEVER": "永不" + }, + "Email": "邮箱", + "Role": "角色", + "InvitedBy": "邀请人", + "CreatedAt": "创建时间", + "Expires": "过期时间", + "Action": "操作", + "Status": "状态", + "STATUS": { + "INVITED": "邀请中", + "ACCEPTED": "已接受", + "EXPIRED": "过期" + } + }, "Header": { "Organization": { "AllOrg": "所有组织" @@ -1178,8 +1207,11 @@ "en-US": "美国英文", "zh": "中文", "zh-CN": "中文", - "zh-Hans": "中文简体", - "zh-Hant": "中文繁体" + "zh-Hans": "简体中文", + "zh-Hant": "繁体中文" + }, + "Users": { + "NoMoreOrganizations": "没有更多的组织可添加" }, "title": { "short": "分析云" @@ -1325,16 +1357,19 @@ "SMS_GATEWAY_VIEW": "View SMS Gateway", "CUSTOM_SMTP_VIEW": "View Custom SMTP", "IMPORT_EXPORT_VIEW": "View Import/Export", - "ORG_JOB_EMPLOYEE_VIEW": "View Job Employees", - "ORG_JOB_MATCHING_VIEW": "View Job Matching", + "ORG_JOB_EMPLOYEE_VIEW": "查看任务员工", + "ORG_JOB_MATCHING_VIEW": "查看任务匹配", "TENANT_SETTINGS": "租户设置表", - "ACCESS_DELETE_ACCOUNT": "Access Delete Account", - "ACCESS_DELETE_ALL_DATA": "Access Delete All Data" + "ACCESS_DELETE_ACCOUNT": "访问删除账号", + "ACCESS_DELETE_ALL_DATA": "访问删除所有数据", + "ORG_DEMO_EDIT": "维护组织演示样例" }, "Organization": { + "AllOrganizations": "所有组织", "MAIN": "主属性", "DEMO": "演示数据", "GENERATE_DEMO": "生成演示数据", + "RegenerateDemo": "重新生成演示数据", "TotalEmployees": "总员工数", "BasicInfo": "基础信息", "OtherInfo": "其他信息", @@ -1351,7 +1386,8 @@ "ProfileLink": "主页链接", "OfficialName": "组织全称", "ShortDescription": "组织简介", - "Website": "网站链接" + "Website": "网站链接", + "SelectDataNetwork": "选择数据网络" } } }, @@ -2813,27 +2849,7 @@ "ROLE": "选择角色" } }, - "INVITE_PAGE": { - "INVITATION_EXPIRATION_OPTIONS": { - "DAY": "一日", - "WEEK": "一周", - "TWO_WEEK": "两周", - "MONTH": "一月", - "NEVER": "永不" - }, - "Email": "邮箱", - "Role": "角色", - "InvitedBy": "邀请人", - "CreatedAt": "创建时间", - "Expires": "过期时间", - "Action": "操作", - "Status": "状态", - "STATUS": { - "INVITED": "邀请中", - "ACCEPTED": "已接受", - "EXPIRED": "过期" - } - }, + "EMAIL_TEMPLATES_PAGE": { "TEMPLATE_NAMES": { "password": "密码重置", diff --git a/apps/cloud/src/assets/i18n/zh-Hans.json b/apps/cloud/src/assets/i18n/zh-Hans.json new file mode 100644 index 000000000..a1c1a624c --- /dev/null +++ b/apps/cloud/src/assets/i18n/zh-Hans.json @@ -0,0 +1,2880 @@ +{ + "MENU": { + "TENANT": "集团", + "ORGANIZATION": "公司", + "DASHBOARD": "仪表盘", + "INDICATOR": "指标", + "INDICATOR_MARKET": "市场", + "INDICATOR_APP": "指标应用", + "INDICATOR_REGISTER": "注册", + "INDICATOR_GROUPS": "组", + "INDICATOR_MY": "我的", + "INSIGHT": "洞察", + "INSIGHT_VIEWER": "洞察", + "INSIGHT_ADMIN": "管理", + "STORY_MODEL": "模型", + "STORY": "故事", + "USERS": "用户" + }, + "PAC": { + "Title": "元数分析云", + "KEY_WORDS": { + "Ask": "提问", + "Certification": "认证", + "DigitalAssetCertificationTypes": "数字资产认证类型", + "Owner": "所有者", + "Query": "查询", + "Story": "故事", + "SemanticModel": "语义模型", + "SuggestingPrompts": "正在建议提示语", + "SelectSemanticModel": "选择语义模型", + "Project": "项目", + "BusinessArea": "业务域", + "Logo": "标识", + "StoryPoint": "故事点", + "ADD": "添加", + "ACTION": "操作", + "Apply": "应用", + "BUSINESS_AREA": "业务域", + "CACHE": "缓存", + "CODE": "代码", + "CREATED_AT": "创建时间", + "CreatedAt": "创建时间", + "CREATED_BY": "创建人", + "Cancel": "取消", + "CLOSE_ALL": "关闭所有", + "Cube": "多维数据集", + "Tags": "标签", + "DATA": "数据", + "DATA_SOURCE": "数据源", + "DATA_SOURCES": "数据源", + "DELETE": "删除", + "DIMENSIONS": "维度", + "DIMENSION": "维度", + "EDIT": "编辑", + "EXPORT": "导出", + "GENERAL": "常规", + "GROUP": "组", + "HIERARCHY": "层次结构", + "INDICATOR": "指标", + "LEVELS": "层级", + "MANAGE": "管理", + "MODEL": "模型", + "MODEL_TYPE": "模型类型", + "MODIFY": "修改", + "NAME": "名称", + "VALUE": "值", + "NOTIFICATION_DESTINATION": "通知目标地", + "OVERVIEW": "概览", + "PREFERENCES": "首选项", + "REMOVE": "删除", + "SEMANTIC_MODEL": "语义模型", + "STORY": "故事", + "TYPE": "类型", + "USER": "用户", + "UPDATED_BY": "修改人", + "UPDATED_AT": "修改时间", + "VIEW": "视图", + "VARIABLES": "变量", + "WORKSPACE": "工作空间", + "WORD_WRAP": "换行", + "Reset": "重置", + "RENAME": "重命名", + "SUCCEED": "成功", + "ROLE": "角色", + "PERMISSION": "权限", + "TENANT": "租户", + "ORGANIZATION": "组织", + "SEARCH": "搜索", + "COMFORT": "舒适", + "COMPACT": "紧凑", + "SETTINGS": "设置", + "IndicatorApp": "指标应用", + "SELECT": "选择", + "CURRENCY": "币种", + "STATUS": "状态", + "SAVE": "保存", + "Refresh": "刷新", + "Management": "管理", + "User": "用户", + "Users": "用户", + "Action": "操作", + "Roles": "角色", + "Search": "搜索", + "Member": "成员", + "Name": "名称", + "CreatedBy": "创建人", + "Cubes": "多维数据集", + "Formula": "公式", + "Confirm": "确定", + "Dimension": "维度", + "Dimensions": "维度", + "Measures": "度量", + "CalculatedMembers": "计算成员", + "Caption": "标签", + "Description": "描述", + "Role": "角色", + "Model": "模型", + "CreateBy": "创建人", + "Actions": "操作", + "Active": "启用", + "EmailTemplates": "邮件模板", + "TemplateName": "模板名称", + "Language": "语言", + "Subject": "主题", + "EmailBody": "邮件正文", + "Indicator": "指标", + "IndicatorGroup": "指标组", + "PermissionType": "权限类型", + "Approve": "同意", + "Refuse": "拒绝", + "Authorization": "授权", + "Compact": "紧凑", + "Username": "用户名", + "Password": "密码", + "Type": "类型", + "None": "无", + "Clear": "清空", + "Format": "美化", + "ShortcutKey": "快捷键", + "Minute": "分钟", + "Off": "关闭", + "AutoRefresh": "自动刷新", + "Error": "错误", + "CurrentPassword": "当前密码", + "NewPassword": "新密码", + "ConfirmPassword": "确认密码", + "Save": "保存", + "Profile": "配置", + "UpdatedAt": "更新于", + "NoData": "无数据", + "Copilot": "副驾驶", + "CalculatedFormula": "计算公式", + "Visits": "访问量", + "UpdatedDate": "更新日期", + "SortBy": "排序", + "Role&Permissions": "角色 & 权限", + "SemanticModels": "语义模型", + "Stories": "故事", + "Indicators": "指标", + "IndicatorMarket": "指标市场" + }, + "MENU": { + "Certification": "认证", + "Copilot": "副驾驶", + "Dashboard": "仪表板", + "Semantic Model": "语义模型", + "Story": "故事", + "Indicator": "指标", + "Indicator Market": "指标市场", + "Indicator Register": "指标注册", + "My Indicator": "我的指标", + "Indicator App": "指标应用", + "Settings": "设置", + "General": "通用", + "Account": "账号", + "User": "用户", + "Datasource": "数据源", + "Business Area": "业务域", + "Role & Permission": "角色 & 权限", + "Feature": "功能", + "Email Template": "邮件模板", + "Custom SMTP": "自定义 SMTP", + "AGENT": "代理", + "LOCAL_AGENT": "本地代理", + "WASM_DB": "WASM 数据库", + "Attributes": "属性", + "CALCULATION": "计算", + "CALCULATED_MEMBERS": "计算成员", + "DIMENSIONS": "维度", + "ENTITY": "实体", + "MANUAL_REFRESH": "手动刷新", + "MEMBERS": "成员", + "MEASURES": "度量", + "PREVIEW": "预览", + "QL_LAB": "查询", + "RUN": "执行", + "RUN_BY_SELECTION": "执行选中语句", + "RESULTS": "结果", + "SHARED_DIMENSIONS": "公共维度", + "STORY_LIST": "故事", + "STRUCTURE": "结构", + "AddUsers": "添加用户", + "InviteUsers": "邀请用户", + "Authentication": "用户认证", + "UserSettings": "用户设置", + "ManageUsersAndInvites": "管理用户和邀请", + "ORGANIZATIONS": "组织", + "FEATURES": "功能", + "USERS": "用户", + "LOCAL_AGENT_STATUS": "本地代理状态", + "ENABLED_PERMISSIONS": "角色启用的权限", + "MANAGE_USERS": "管理用户", + "MANAGE_ROLES": "管理角色 & 权限", + "MANAGE_FEATURES": "管理功能模块", + "MANAGE_ORGANIZATIONS": "管理组织", + "MANAGE_TENANT": "管理租户", + "EDIT_USER": "维护用户", + "EDIT_BUSINESS_AREA": "编辑业务域", + "MY_ACCOUNT": "我的账号", + "ForOrganization": "为组织", + "ManageCustomSmtp": "维护自定义 SMTP", + "Tenant": "租户", + "Organization": "组织", + "Today": "今天", + "Catalog": "目录", + "Trending": "热门", + "Insights": "洞察", + "Home": "首页", + "Project": "项目", + "Indicators": "指标", + "Data Sources": "数据源", + + "HOME": { + "TODAY": "今天", + "Catalog": "目录", + "Trending": "热门", + "Insight": "洞察", + "MyCatalog": "我的目录", + "HELLO": "你好", + "SEARCH": "搜索", + "AskaQuestion": "询问一个问题", + "Recents": "最近访问", + "StoryRanking": "故事排名", + "All": "所有", + "My": "我的", + "GenerateSamples": "生成演示样例", + "RegenerateSamples": "重新生成演示样例", + "GeneratingSamples": "正在生成演示样例", + "NoRelevantDigitalAssets": "未找到相关数字资产", + "ExploreASampleStory": "浏览一个故事样例", + "CreateYourFirstSemanticModel": "创建第一个语义模型", + "HaveSemanticModels": "拥有 {{quantity}} 个语义模型", + "CreateYourFirstStory": "创建第一个故事", + "HaveStories": "拥有 {{quantity}} 个故事", + "CreateYourFirstIndicator": "创建第一个指标", + "HaveIndicators": "拥有 {{quantity}} 个指标", + "UpdateLayout": "更新布局" + }, + "USER": { + "BASIC": "基本属性" + }, + "TENANT": { + "TITLE": "租户", + "SETTINGS": "设置", + "DEMO": "演示数据" + }, + "MODEL": { + "CREATE_MODEL": "创建语义模型", + "SELECT_DATASOURCE": "选择数据源", + "SELECT_CATALOG": "选择目录", + "BASIC_INFO": "基本信息", + "USE_MDX": "使用 MDX 建模", + "MY": "我的", + "ALL": "所有", + "SELECT_DATASOURCE_COLUMNS": { + "Name": "名称", + "Type": "类型", + "Protocol": "协议", + "UseLocalAgent": "使用本地代理" + }, + "CATALOG_COLUMNS": { + "Name": "名称", + "Type": "类型", + "Label": "描述" + } + }, + "STORY": { + "SELECT_BUSINESS_AREA": "选择业务域", + "SELECT_SEMANTIC_MODEL": "选择语义模型", + "STORY_NAME": "名称", + "INPUT_UNIQUE_NAME": "输入唯一名称", + "ALL": "全部", + "FAVORITES": "收藏", + "WhatIsTheName": "故事叫什么名称", + "Description": "描述", + "DescriptionPlaceholder": "可选,故事的详细描述", + "Model": "模型", + "StoryBusinessArea": "应该放在哪个业务域内" + }, + "STATUS_BAR": { + "TITLE": "状态栏", + "ERROR_LOG": "错误日志", + "NOTIFICATION": "通知", + "ClearAuthentication": "清除用户认证" + }, + "INDICATOR": { + "REGISTER_INDICATOR": "注册指标", + "BATCH_UPLOAD": "批量上传", + "DownloadAsTemplate": "下载为模板", + "INDICATOR_MARKET": "指标市场", + "INDICATOR_MARKET_DESC": "浏览指标,申请指标权限" + }, + "GENERAL": { + "TITLE": "通用", + "LANGUAGE": "语言", + "LANGUAGE_PLACEHOLDER": "选择语言", + "THEME": "主题" + }, + "DATA_SOURCES": { + "TYPE_SELECTION": "选择类型", + "CONFIGURATION": "配置", + "NAME": "名称", + "NAME_REQUIRED": "名称必输", + "USE_LOCAL_AGENT": "使用本地代理", + "DONE": "完成", + "AuthType": "授权方式", + "AuthType_None": "无", + "AuthType_Basic": "基本身份验证" + }, + "Roles": { + "General": "通用", + "Administration": "管理员" + } + }, + "USERS_PAGE": { + "ADD_USER": "添加用户" + }, + "ACTIONS": { + "Add": "添加", + "Cancel": "取消", + "New": "新建", + "Release": "发布", + "Open": "打开", + "Upload": "上传", + "Remove": "删除", + "APPLY": "应用", + "CreateIndicator": "创建指标", + "ADD_CALCULATED_MEMBER": "新增计算成员", + "CREATE_STORY": "创建故事", + "COPY": "复制", + "CREATE": "创建", + "CANCEL": "取消", + "SUBMIT": "提交", + "DELETE_SELECTED_ENTITY": "删除当前实体", + "Download": "下载", + "Delete": "删除", + "FORMAT_DOCUMENT": "格式化文档", + "FORMAT_SELECTION": "格式化选中部分", + "NEW": "新建", + "NEW_HIERARCHY": "新建层次结构", + "REDO": "重做", + "REFRESH_DATA_SOURCE_SCHEMA": "刷新数据源纲要", + "REMOVE_CURRENT_HIERARCHY": "删除当前层次结构", + "REMOVE_CURRENT_LEVEL": "删除当前层级", + "SAVE": "保存", + "SHARE": "分享", + "UPLOAD": "上传", + "UNDO": "撤销", + "CLEAR": "清空", + "CLEAR_CACHE": "清空缓存", + "DOWNLOAD_AGENT": "下载代理", + "ADD": "添加", + "INVITE": "邀请", + "PREVIOUS": "上一步", + "NEXT": "下一步", + "CONFIRM_DELETE": "确认从服务器上删除此记录?", + "PING": "测试连接", + "CreateStory": "📖创建故事", + "CreateModel": "创建模型", + "Edit": "编辑", + "Generate": "生成演示数据", + "ManageInvites": "管理邀请", + "Save": "保存", + "Validate": "验证", + "Connect": "连接", + "Uploading": "上传中", + "Search": "搜索", + "Copy": "复制", + "NewTag": "新建标签", + "Duplicate": "复制" + }, + "MESSAGE": { + "MAIN_ORGANIZATION_UPDATED": "组织更新成功", + "USER_ORGANIZATION_ADDED": "用户组织添加成功", + "USER_ORGANIZATION_REMOVED": "用户组织删除成功", + "LocalAgentOffline": "本地代理离线", + "NameAlreadyExist": "名称已存在", + "Required": "必输", + "Update": "更新", + "StoryRunWithWasmModelOnMobileWarn": "在移动端上分析 WASM 模型可能会有性能限制,谨慎使用", + "PasswordChange": "密码修改", + "NewVersionUpdate": "已获取新版本。现在更新?", + "CreateStoryWidgetSuccess": "创建故事部件成功", + "CreateDataSource": "创建数据源", + "ConfirmExitDirtyData": "有未保存数据, 确认退出吗?", + "Sure": "确定" + }, + "NOTES": { + "ORGANIZATIONS": { + "DELETE_CONFIRM": "确定从服务器上删除此组织?", + "DELETE_ORGANIZATION": "组织'{{name}}'删除成功", + "DEMO_GENERATE_ERROR": "演示数据生成错误", + "DEMO_GENERATED": "演示数据生成" + }, + "ROLES": { + "PERMISSION_UPDATED": "角色'{{name}}'更新成功", + "RoleCreate": "角色创建", + "RoleDelete": "角色删除" + }, + "USERS": { + "UserDelete": "用户'{{name}}'删除", + "USER_DELETED": "用户'{{name}}'删除成功", + "USER_UPDATED": "用户'{{name}}'更新" + }, + "TENANT": { + "DEMO_GENERATED": "演示数据生成" + }, + "STORY": { + "STORY_DELETED": "故事'{{name}}'删除", + "UPLOAD_FILETYPE_ERROR": "上传文件类型", + "READ_FILE": "读取文件内容", + "STORY_UPLOAD": "故事上传" + } + }, + "TOASTR": { + "TITLE": { + "SUCCESS": "成功", + "ERROR": "错误" + }, + "Updating": "{{value}}更新中。。。", + "UpdateDone": "{{value}}更新完成" + }, + "INDICATOR": { + "REGISTER": { + "Code": "编码", + "CODE": "编码", + "CODE_PLACEHOLDER": "指标唯一编码", + "NAME": "名称", + "NAME_PLACEHOLDER": "指标名称", + "BUSINESS_AREA": "业务域", + "BUSINESS_AREA_PLACEHOLDER": "选择所属业务域", + "IsActive": "激活", + "AvailableInApplication": "指标应用适用", + "Visible": "是否可见", + "Visibility": "可见性", + "UNIT": "单位", + "UNIT_PLACEHOLDER": "度量单位", + "CREATED_BY": "创建人", + "CREATED_AT": "创建时间", + "PRINCIPAL": "负责人", + "Certification": "认证", + "PRINCIPAL_PLACEHOLDER": "业务负责人", + "AUTHENTICATION": "认证流程", + "AUTHENTICATION_PLACEHOLDER": "选择认证流程", + "BUSINESS": "业务口径", + "BUSINESS_PLACEHOLDER": "业务口径详细描述", + "VALIDITY": "有效期", + "VALIDITY_PLACEHOLDER": "有效期至", + "MODEL": "语义模型", + "MODEL_PLACEHOLDER": "选择语义模型", + "ENTITY": "模型实体", + "ENTITY_PLACEHOLDER": "选择模型实体", + "TYPE": "类型", + "TYPE_PLACEHOLDER": "选择指标类型", + "TYPE_BASIC": "基础指标", + "TYPE_DERIVE": "衍生指标", + "FORMULA": "计算公式", + "FORMULA_PLACEHOLDER": "指标计算公式", + "MEASURE": "度量", + "MEASURE_PLACEHOLDER": "选择度量字段", + "DIMENSIONS": "自由维度", + "DIMENSIONS_PLACEHOLDER": "选择自由维度", + "FILTERS": "筛选条件", + "STATUS": "状态", + "BASIC_INFO": "基础信息", + "MODEL_INFO": "模型信息", + "IndicatorsBulkCreate": "指标批量创建", + "New": "新建", + "SaveIndicator": "保存指标", + "CreateIndicator": "创建指标", + "RestrictiveCondition": "限定条件", + "Aggregator": "聚合类型", + "Calendar": "日历维度", + "Tags": "标签", + "IndicatorNotFound": "指标未找到", + "DeleteIndicator": "删除指标" + }, + "MARKET": { + "REQUEST": "申请", + "RequestBusinessArea": "申请业务域", + "RequestIndicator": "申请指标", + "Tags": "标签", + "Types": "类型" + }, + "MY_INDICATORS": { + "TITLE": "我的指标", + "EXPORT": "导出", + "REGISTER": "注册", + "MY": "我的", + "ALL": "全部", + "Approvals": "审批" + }, + "VIEWER": { + "MARKET": "市场", + "EDIT": "编辑", + "REGISTER": "注册", + "DELETE": "删除", + "BASIC_INFORMATION": "基础信息", + "MODEL_INFORMATION": "模型信息" + }, + "Indicator Name": "指标名称", + "Indicator Code": "指标编码", + "Business Area": "业务域", + "Authentication": "认证流程", + "Business": "业务口径", + "Principal": "业务负责人", + "Validity": "有效期", + "Type": "类型", + "Model": "语义模型", + "Entity": "多维数据集", + "Filters": "限定条件", + "RestrictiveCondition": "限定条件", + "Free Dimensions": "自由维度", + "Measure": "度量", + "Formula": "计算公式", + "Unit": "单位", + "EditFormula": "为 {{name}} 编辑计算公式", + "Close": "关闭", + "Reset": "重置", + "Authorization": "授权", + "IndicatorTemplateFileName": "指标模版", + "PermissionRequested": "权限已申请", + "PermissionApproved": "权限已批准", + "PermissionRefused": "申请被拒绝", + "DeleteIndicator": "删除指标", + "All": "所有", + "Derivative": "衍生指标", + "Basic": "基础指标", + "IndicatorFormula": "指标计算公式", + "Import": "导入", + "Indicators": "指标", + "Types": "类型", + "IndicatorMarket": "指标市场", + "Certifications": "认证" + }, + "MODEL": { + "ModelOverview": "语义模型概览", + "SharedDimensions": "公共维度", + "Cubes": "多维数据集", + "VirtualCubes": "虚拟数据集", + "Stories": "故事", + "Roles": "角色", + "Members": "成员", + "ClearServerCache": "清空服务端缓存", + "Type": "类型", + "DataSource": "数据源", + "CreatedBy": "创建人", + "UpdatedBy": "修改人", + "Actions": "操作", + "Name": "名称", + "Indicators": "指标", + "IndicatorCode": "指标编码", + "Reset": "重置", + "QueryName": "查询的简短名称", + "CreateQuery": "创建查询", + "QueryBaseModelPlaceholder": "想要查询哪个模型空间", + "ModelName": "模型的名称", + "ModelOwner": "模型拥有者", + "TransferOwnership": "转移所有权", + "ModelMembers": "模型成员", + "DescriptionPlaceholder": "可选,语义模型的详细描述", + "UploadModel": "上载模型", + "SaveAsDefaultCube": "保存为默认数据集", + + "QUERY": { + "TITLE": "查询", + "SaveAsModel": "另存为模型", + "SaveAsDBInit": "另存为数据库初始化脚本", + "TableSchema": "表结构", + "New": "新建查询", + "TotalRecords": "总记录数", + "PreviewTop1000": "最大预览 1000 条", + "CopilotPlaceholder": "提出问题或请求,输入 CTRL + Enter 发送", + "CopilotName": "查询实验室", + "EditorActions": { + "Nl2SQL": "自然语言转SQL", + "Explain": "解释", + "Optimize": "优化" + } + }, + "TOASTR": { + "MODEL_UPDATE": "模型更新", + "ModelSave": "模型保存", + "ModelCreate": "创建模型", + "ModelUpload": "上传模型", + "ModelDelete": "删除模型", + "DeleteModelPermanently": "永久删除此模型" + }, + "MODEL": { + "Entities": "实体", + "TITLE": "模型", + "TABLES": "数据表", + "Preferences": "首选项", + "New": "新建", + "NewTable": "新建表", + "UploadTable": "上传表", + "RefreshSchema": "刷新元数据", + "Name": "名称", + "Description": "描述", + "DescriptionPlaceholder": "语义模型的详细描述", + "DataSource": "数据源", + "DataCatalog": "数据目录", + "Enable": "启用", + "EnableServerCache": "启用服务端缓存", + "CacheExpires": "缓存时间", + "CacheExpiresSecond": "缓存时长(秒)", + "Language": "语言", + "LanguageContext": "选择语言上下文", + "Auto": "自动", + "Expose": "暴露", + "EnableExposeXMLA": "启用 XMLA 接口", + "CreateStory": "创建故事", + "Visibility": "可见性", + "Visibility_Public": "公开", + "Visibility_Secret": "秘密", + "Visibility_Private": "私有", + "RemoveDBInitScript": "删除数据库初始化脚本", + "CopilotDefaultPrompts": [ + "将表创建为立方体", + "将表创建为维度" + ], + "CopilotName": "建模" + }, + "CREATE_ENTITY": { + "CREATE_ENTITY": "创建模型实体", + "TYPE": "类型", + "SELECT_TYPE": "选择类型", + "CUBE": "多维数据集", + "DIMENSION": "维度", + "VirtualCube": "虚拟数据集", + "NAME": "名称", + "INPUT_NAME": "输入名称", + "LABEL": "标签", + "INPUT_LABEL": "输入标签", + "TABLE": "表", + "PICK_ONE_TABLE": "选择一个表", + "CUBE_TABLE": "立方体的表", + "Field": "字段", + "Measure": "度量", + "AssociatedDimension": "关联维度", + "PrimaryKey": "主键", + "Visible": "可见", + "Caption": "标签" + }, + "CREATE_TABLE": { + "TITLE": "添加表", + "Name": "名称", + "Type": "类型", + "Url": "链接", + "Delimiter": "分隔符", + "AddFile": "添加文件", + "DataPreview": "数据预览", + "InputTableName": "输入表名称", + "HasHeader": "第一行是标题", + "DefaultDelimiter": "默认:,", + "DragandDropFile": "拖拽上传文件", + "Or": "或", + "BrowseForFile": "浏览文件" + }, + "ENTITY": { + "NewDimension": "新建维度", + "NewMeasure": "新建度量", + "NewCalculatedMember": "新建计算成员", + "CALCULATION": { + "ROWS": "行", + "COLUMNS": "列", + "FILTERS": "过滤器", + "Refresh": "刷新", + "Pivot": "旋转轴" + }, + "LeftKey": "左键", + "RightKey": "右键", + "Equal": "等于", + "OnekeyGeneration": "一键生成", + "OnekeyGenerateModel": "根据表字段划分一键生成模型", + "SourceFields": "源字段", + "OnekeySync": "一键同步", + "OnekeySyncModel": "根据源模型定义一键同步模型", + "AllVisible": "所有可见", + "SelectAll": "全选", + "ConfirmOverwriteCube": "数据集已存在配置,确认覆盖?", + "PleaseSelectFields": "请选择字段!" + }, + "DIMENSION": { + "Levels": "层级", + "DimensionTables": "维度表", + "DataPreview": "数据预览", + "Count": "计数", + "EditAttributes": "编辑属性", + "SameLevelAlreadyExists": "相同层级已存在" + }, + "UPLOAD": { + "Title": "上传数据文件", + "Files": "文件", + "Preview": "预览", + "Key": "键", + "Import": "导入", + "Done": "完成", + "ImportMethod": "导入方式", + "Cover": "覆盖", + "Append": "追加", + "Merge": "合并", + "Uploaded": "已上传", + "Records": "条记录", + "Preview50": "预览前 50 条记录", + "UploadText": "点击选择或拖拽文件到此区域进行上传", + "UploadHint": "支持单个或批量文件上传" + }, + "SCHEMA": { + "COMMON": { + "DATA": "数据", + "Table": "表", + "FactTable": "事实表", + "SQLExpression": { + "Dialect": "方言", + "Content": "值" + }, + "TITLE": "多维数据集", + "Modeling": "建模", + "Role": "角色", + "Name": "名称", + "Label": "标签", + "Value": "值", + "Column": "字段", + "Description": "描述", + "ForeignKey": "外键", + "ParentChild": "父子层级关系", + "Semantics": "语义", + "Semantic": "语义类型", + "Formatter": "格式化", + "Dimension": "维度", + "Hierarchy": "层次结构", + "Visible": "是否显示", + "DataType": "数据类型", + "Property": "属性", + "KeyExpression": "键表达式", + "NameExpression": "名称表达式", + "CaptionExpression": "说明表达式", + "OrdinalExpression": "顺序表达式", + "ParentExpression": "父字段表达式", + "Enabled": "启用", + "Cache": "缓存", + "Caption": "标签", + "None": "无", + "Unit": "单位", + "Decimal": "小数位" + }, + "CUBE": { + "TITLE": "多维数据集", + "Modeling": "建模", + "Name": "名称", + "Label": "标签", + "Table": "表", + "DefaultMeasure": "默认度量" + }, + "DimensionUsage": { + "Title": "共享维度" + }, + "DIMENSION": { + "TITLE": "维度", + "Modeling": "建模", + "Name": "名称", + "Label": "标签", + "DimensionType": "维度类型", + "DefaultHierarchy": "默认层次结构", + "KeyExpression": "键表达式", + "SQLExpression": { + "Dialect": "方言", + "Content": "值" + }, + "CaptionColumn": "文本字段", + "Column": "维度表主键", + "ForeignKey": "事实表外键" + }, + "HIERARCHY": { + "TITLE": "层次结构", + "Modeling": "建模", + "Name": "名称", + "Label": "标签", + "DimensionTable": "维度表", + "TableName": "表名", + "HasAll": "有 All 成员", + "AllMemberName": "All 成员名称", + "AllMemberCaption": "All 成员标签", + "AllLevelName": "All 层级名称", + "PrimaryKey": "主键", + "PrimaryKeyTable": "主键表", + "JoinTable": "关联表", + "Table": "表", + "LeftKey": "左键", + "RightKey": "右键", + "RightAlias": "右表别名", + "DefaultMember": "默认成员" + }, + "LEVEL": { + "Level": "层级", + "Modeling": "建模", + "Name": "名称", + "Label": "标签", + "Property": "属性", + "PropertyExpression": "属性表达式", + "Dialect": "方言", + "Content": "值", + "Column": "字段", + "Type": "值类型", + "Type_Null": "无", + "Type_String": "字符串", + "Type_Integer": "整数", + "Type_Numeric": "数值", + "Type_Boolean": "布尔", + "Type_Date": "日期", + "Type_Time": "时间", + "Type_Timestamp": "时间戳", + "UniqueMembers": "成员唯一", + "NameColumn": "名称字段", + "CaptionColumn": "说明字段", + "OrdinalColumn": "顺序字段", + "ParentColumn": "父级字段", + "ChildColumn": "子字段", + "NullParentValue": "父字段空", + "TimeLevelType": "层级时间类型", + "Table": "表", + "HideMemberIf": "隐藏成员", + "ClosureTable": "闭合表", + "KeyExpression": "键表达式", + "CaptionExpression": "说明表达式", + "ParentChild": "父子层级关系", + "Semantics": "语义", + "SQLExpression": { + "Dialect": "方言", + "Content": "值" + } + }, + "CALCULATED_MEMBER": { + "Title": "计算成员", + "Formula": "公式", + "Parent": "父级成员", + "SolveOrder": "求解次序" + }, + "MEASURE": { + "Title": "度量", + "Aggregator": "聚合类型", + "FormatString": "格式化", + "MeasureExpression": "度量表达式", + "FORMATTING": { + "Title": "数据格式", + "ShortNumber": "缩写数字", + "DecimalFormatter": "数字格式化", + "Unit": "单位" + } + } + }, + "AccessControl": { + "Title": "访问控制", + "Name": "名称", + "NewRole": "新建角色", + "RoleCreate": "角色创建", + "Cubes": "多维数据集", + "Access": "访问控制", + "Overview": "访问控制概览", + "RolesManage": "角色管理", + "UsersManage": "用户管理", + "RoleOverview": "角色概览", + "DefaultAccess": "默认访问", + "Access_all": "所有", + "Access_all_dimensions": "所有维度", + "Access_custom": "自定义", + "Access_none": "无", + "RollupPolicy": "汇总策略", + "RollupPolicy_full": "全部", + "RollupPolicy_partial": "部分", + "RollupPolicy_hidden": "隐藏", + "TopLevel": "最高层级", + "BottomLevel": "最低层级", + "Roles": "角色", + "Type": "类型", + "SingleRole": "标准角色", + "UnionRole": "复合角色", + "DimensionHierarchyAlreadyExists": "维度或层次结构已存在!", + "MemberAlreadyExists": "成员已存在!", + "MeasureAlreadyExists": "度量已存在!", + "DragandDropAddDimension": "拖放以添加维度" + }, + "VirtualCube": { + "VirtualCube": "虚拟多维数据集", + "CubeUsages": "使用的多维数据集", + "NewCalculatedMember": "新建计算成员", + "IgnoreUnrelatedDimensions": "忽略不相关维度", + "SharedDimension": "共享维度", + "CubeAlreadyExists": "多维数据集已存在!", + "DimensionAlreadyExists": "维度已存在!", + "MeasureAlreadyExists": "度量已存在!" + } + }, + "BUSINESS_AREA": { + "All": "所有", + "BASIC": "基本属性", + "Delete": "删除", + "Update": "更新", + "RemoveUser": "删除用户", + "BASIC_INFO_FORM": { + "Name": "名称" + }, + "BusinessAreaRole": { + "Modeler": "编辑者", + "Viewer": "查看者" + } + }, + "SHARED": { + "USER_BASIC": { + "firstName": "名 (可选)", + "lastName": "姓 (可选)", + "Username": "用户名", + "Email": "邮箱", + "Passwrod": "密码", + "RepeatPasswrod": "重复密码", + "Role": "角色", + "PreferredLanguage": "首选语言", + "ImageURL": "图片链接 (可选)" + }, + "User": { + "NameEmail": "名称,邮箱" + }, + "SMTP": { + "Host": "域名", + "Port": "端口", + "Secure": "安全", + "Username": "用户名", + "Password": "密码", + "True": "是", + "False": "否" + }, + "Assets": { + "RecentlyViewed": "最近访问", + "NoRelevantDigitalAssets": "未找到相关数字资产" + }, + "StoryCard": { + "LastUpdated": "最后更新", + "Open": "查看" + } + }, + "INVITE_PAGE": { + "ForOrganization": "为组织", + "INVITATION_EXPIRATION_OPTIONS": { + "DAY": "一日", + "WEEK": "一周", + "TWO_WEEK": "两周", + "MONTH": "一月", + "NEVER": "永不" + }, + "Email": "邮箱", + "Role": "角色", + "InvitedBy": "邀请人", + "CreatedAt": "创建时间", + "Expires": "过期时间", + "Action": "操作", + "Status": "状态", + "STATUS": { + "INVITED": "邀请中", + "ACCEPTED": "已接受", + "EXPIRED": "过期" + } + }, + "Header": { + "Organization": { + "AllOrg": "所有组织" + } + }, + "DataSources": { + "Schema": { + "Host": "主机", + "Port": "端口号", + "Path": "路径", + "Username": "用户名", + "Password": "密码", + "Database Name": "数据库名", + "Use SSL": "使用加密连接", + "CA certificate": "CA 证书", + "Client certificate": "客户端证书", + "Client key": "客户端密钥", + "Disable reject cert": "禁用证书验证", + "ApiHost": "接口主机", + "ApiPort": "接口端口号", + "Catalog": "目录", + "Database": "数据库", + "Version": "版本" + } + }, + "Story": { + "EditStory": "编辑故事", + "DuplicateStory": "复印故事", + "DownloadStory": "下载故事", + "AutoRefresh": "自动刷新", + "RemoveBookmark": "取消收藏", + "Bookmark": "收藏", + "Fullscreen": "全屏", + "ExitFullscreen": "退出全屏", + "Released": "已发布", + "Draft": "草稿", + "ConfirmChangingReleasedStory": "故事已经发布,确认再次编辑吗", + "GlobalFilterBar": "全局过滤器", + "BorderImageSlice": "边框切片", + "Shadow": "阴影", + "ShadowOffsetX": "偏移 X", + "ShadowOffsetY": "偏移 Y", + "ShadowBlur": "模糊", + "ShadowSpread": "扩展", + "PresetImages": "预设图片", + "StoryStyles": "故事样式", + "Padding": "内边距", + "BorderRadius": "边框半径", + "BackgroundColor": "背景颜色", + "BackgroundImage": "背景图片", + "BorderImage": "边框图片", + "Border": "边框", + "BorderWidth": "边框宽度", + "BorderStyle": "边框样式", + "PresetBackgroundImages": "预设背景图片", + "Color": "颜色", + "TextAlign": "文本对齐", + "FontSize": "字体大小", + "FontFamily": "字体", + "FontWeight": "字重", + "ChooseFontFamily": "选择字体", + "ChooseFontWeight": "选择字重", + "CustomImages": "自定义图片", + "GlobalStyles": "全局样式", + "Transform": "变换", + "TransformOrigin": "变换原点", + "BackgroundSize": "背景大小", + "BackgroundRepeat": "背景重复", + "BoxShadow": "盒子阴影", + "TextShadow": "文本阴影", + "BackdropFilter": "背景滤镜", + "Filter": "滤镜", + "Opacity": "透明度" + }, + "Project": { + "Project": "项目", + "NewProject": "新建项目", + "Certifications": "认证", + "AddCertification": "添加认证", + "RemoveCertification": "移除认证", + "CertificationAlreadyAdded": "认证已添加", + "DefaultProject": "默认", + "Name": "名称", + "WhatIsTheName": "你的项目名称", + "Description": "描述", + "DescriptionPlaceholder": "你的项目描述", + "DefaultCollection": "默认", + "Home": "首页", + "Bookmarks": "收藏夹", + "Collection": "工作集", + "Collections": "工作集", + "CollectionName": "名称", + "WhatIsTheCollectionName": "你工作集的名称", + "CollectionPlaceholder": "应该放在哪个工作集内", + "MoveToCollection": "移动到工作集", + "SemanticModels": "语义模型", + "Members": "成员", + "Create": "创建", + "NewCollection": "新建集", + "RemoveCollection": "删除集", + "NewStory": "新建故事", + "Release": "发布", + "Rerelease": "重新发布", + "Archive": "下线", + "ConfirmArchiveStory": "确定要下线此故事吗?", + "MoveTo": "移动到", + "Copy": "复制", + "CopyStory": "复制故事", + "Remove": "删除", + "AddModel": "添加模型", + "RemoveModel": "删除模型", + "RemoveBookmark": "取消收藏", + "ParentCollection": "父集", + "RecentUpdates": "最近更新", + "ClicktoUpload": "点击上传", + "OrDragandDrop": "或者拖放", + "StoryJsonFile": "故事 JSON 文件", + "ProjectMembers": "项目成员", + "Inner": "内部", + "Public": "公开", + "StoryReleased": "故事发布", + "ProjectOwner": "项目所有者", + "TransferOwnership": "转移所有权", + "CreateStory": "创建故事", + "Manage": "管理", + "DeleteProject": "删除项目", + "ConfirmDelete": "确定删除", + "AddModels": "添加语义模型", + "ManageIndicators": "管理指标", + "Indicators": "指标", + "Templates": "模板", + "AddSemanticModels": "添加语义模型", + "New": "新建", + "Files": "文件" + }, + "Certification": { + "Certification": "认证", + "UpdateCertification": "更新认证", + "DeleteCertification": "删除认证", + "CreateCertification": "创建认证" + }, + "Copilot": { + "Copilot": "Copilot", + "AICopilot": "AI 副驾驶", + "EnableCopilot": "启用 Copilot", + "GetYourApiKey": "获取你的 API Key", + "ProvideOpenaiApiKey": "请提供 Openai API Key?", + "Provider": "提供商", + "YourAIPairProgrammer": "你的 AI 配对程序员!", + "LetYourAIPairProgrammerEdits": "让你的 AI 配对程序员修改一下!", + "SelectSomeCode": "选择代码,让你的 AI 配对程序员修改一下!", + "ThinkingHard": "努力思考中...", + "StopGenerating": "停止生成", + "ClearMessages": "清空消息", + "CharacterLength": "字数", + "Resubmit": "重新提交", + "Model": "模型", + "Options": "选项", + "UseSystemPrompt": "使用系统提示", + "ExamplesOfPrompts": "提示语示例", + "APIKey": "API 密钥", + "APIHost": "API 主机", + "Prompts": { + "Set story theme dark": "设置故事暗黑主题", + "Set story gradient background color sense of technology": "设置故事背景为科技感渐变色", + "Set widget transparent background": "设置部件透明背景", + "Chart series set line smooth": "图形系列设定线平滑", + "Chart series set bar max width 20, rounded, shadow": "图形系列设定条形图最大宽度 20,圆角,阴影", + "Chart series add average mark line": "图形系列添加平均标记线", + "Chart category axis line width 2, show axis tick": "图形分类轴线宽度 2,显示轴线刻度", + "Data analysis": "分析数据" + } + }, + "Home": { + "Insight": { + "CreateSemanticModelForUse": "添加到故事:创建语义模型后才能使用", + "AddWidgetToStoryTitle": "将部件添加到故事" + } + }, + "ApprovalPolicy": { + "BUSINESS_AREA": "业务域", + "INDICATOR": "指标" + }, + "Onboarding": { + "Welcome": "欢迎使用 Metad 分析平台", + "WelcomeInfo": "看起来一切都正常。 现在让我们认识您,连接到你的数据,并开始为您寻找一些答案!", + "LetGetStarted": "让我们开始吧", + "FeelStuck": "如果您感到困惑", + "OurGuide": "我们的入门指南", + "ClickAway": "只需一次点击即可获得", + "WhatsPreferredLanguage": "您更喜欢哪种语言?", + "PreferredLanguageDescription": "这种语言将会被用于Metad分析平台中,并且将会是新用户的默认语言。", + "Next": "下一步", + "WhatCallYou": "我们应该怎么称呼您", + "CompanyTeamName": "公司或组织名称", + "CreateAPassword": "创建一个密码", + "Email": "邮箱", + "FirstName": "名", + "LastName": "姓", + "Minlength": "最小长度", + "Actuallength": "实际长度", + "ConfirmYourPassword": "确认密码", + "PasswordMustMatch": "密码不一致", + "WantGenerateDemo": "是否想要生成演示数据", + "GenerateDemoDescription": "系统将从服务器链接上下载演示数据文件,并将数据导入至系统数据库中,然后创建相应的演示样例", + "Skip": "跳过", + "Generate": "生成", + "Retry": "重试", + "AddYourData": "添加您的数据", + "ReadyExploringYourData": "准备好开始探索您的数据了吗?在下面添加它吧。", + "NotReadySample": "还没有准备好?跳过并玩玩我们的示例吧。", + "DisplayName": "显示名称", + "NameRequired": "名称不能为空", + "AddDataLater": "我稍后添加我的数据", + "ConnectDatabase": "连接数据库", + "Done": "完成", + "AllSetup": "您已经设置好了!", + "TakeMetoMetadAnalyticsPlatform": "带我去 Metad 分析平台", + "SelectNetwork": "选择所需网络", + "GenerateDemoSuccess": "演示数据和样例生成成功!" + }, + "Languages": { + "en": "英文", + "en-US": "美国英文", + "zh": "中文", + "zh-CN": "中文", + "zh-Hans": "简体中文", + "zh-Hant": "繁体中文" + }, + "Users": { + "NoMoreOrganizations": "没有更多的组织可添加" + }, + "title": { + "short": "分析云" + }, + "menu": { + "home": "主页", + "settings": "设置", + "login": "登录/注册", + "profile": "简况", + "logout": "退出", + "connection": "连接", + "create": { + "title": "创建", + "story": "故事", + "model": "模型" + }, + "browse": { + "title": "浏览", + "story": "故事" + }, + "xmla": { + "designer": "查询设计器" + }, + "security": "安全" + }, + "settings": { + "title": "设置", + "language": "语言", + "theme": "主题" + }, + "connection": { + "menu": { + "data-sources": "数据源", + "connections": "系统连接" + } + }, + + "ORGANIZATIONS_PAGE": { + "PERMISSIONS": { + "ADMIN_DASHBOARD_VIEW": "查看 Admin 仪表盘", + "ORG_COPILOT_EDIT": "配置 Copilot", + "MODELS_VIEW": "查看模型", + "MODELS_EDIT": "编辑模型", + "STORIES_VIEW": "查看故事看板", + "STORIES_EDIT": "编辑故事看板", + "BUSINESS_AREA_VIEW": "查看业务域", + "BUSINESS_AREA_EDIT": "编辑业务域", + "INDICATOR_VIEW": "查看指标", + "INDICATOR_MARTKET_VIEW": "查看指标应用", + "INDICATOR_EDIT": "编辑指标", + "INSIGHT_VIEW": "查看洞察", + "INSIGHT_EDIT": "编辑洞察", + "SUBSCRIPTION_VIEW": "查看订阅", + "SUBSCRIPTION_EDIT": "编辑订阅", + "ORG_PAYMENT_VIEW": "View Payments", + "ORG_PAYMENT_ADD_EDIT": "Create/Edit/Delete Payments", + "ORG_EXPENSES_VIEW": "View All Expenses", + "ORG_EXPENSES_EDIT": "Create/Edit/Delete Expenses", + "EMPLOYEE_EXPENSES_VIEW": "View All Employee Expenses", + "EMPLOYEE_EXPENSES_EDIT": "Create/Edit/Delete Employee Expenses", + "ORG_INCOMES_EDIT": "Create/Edit/Delete Incomes", + "ORG_INCOMES_VIEW": "View All Incomes", + "ORG_PROPOSALS_EDIT": "Create/Edit/Delete Proposals Register", + "ORG_PROPOSALS_VIEW": "View Proposals Page", + "ORG_PROPOSAL_TEMPLATES_VIEW": "View Proposal Templates Page", + "ORG_PROPOSAL_TEMPLATES_EDIT": "Create/Edit/Delete Proposal Templates", + "ORG_TIME_OFF_VIEW": "View Time Off Page", + "ORG_EMPLOYEES_VIEW": "View Organization Employees", + "ORG_EMPLOYEES_EDIT": "Create/Edit/Delete Organization Employees", + "ORG_CANDIDATES_VIEW": "View Organization Candidates", + "ORG_CANDIDATES_EDIT": "Create/Edit/Delete Organization Candidates", + "ORG_USERS_VIEW": "View Organization Users", + "ORG_USERS_EDIT": "Create/Edit/Delete Organization Users", + "ORG_INVITE_VIEW": "View Organization Invites", + "ORG_INVITE_EDIT": "Create/Resend/Delete Invites", + "ORG_CANDIDATES_DOCUMENTS_VIEW": "View All Candidates Documents", + "ORG_CANDIDATES_TASK_EDIT": "Create/Edit Task", + "ORG_CANDIDATES_INTERVIEW_EDIT": "Create/Edit Interview", + "ORG_INVENTORY_PRODUCT_EDIT": "Management Product", + "ORG_TAGS_EDIT": "Create/Edit/Delete Tags", + "ORG_CANDIDATES_FEEDBACK_EDIT": "Create/Edit/Delete Candidate Feedback", + "ALL_ORG_VIEW": "View All Organizations", + "ALL_ORG_EDIT": "Create/Edit/Delete All Organizations", + "POLICY_VIEW": "View Time Off Policy", + "POLICY_EDIT": "Edit Time Off Policy", + "CHANGE_SELECTED_EMPLOYEE": "Change Selected Employee", + "CHANGE_SELECTED_CANDIDATE": "Change Selected Candidate", + "CHANGE_SELECTED_ORGANIZATION": "Change Selected Organization", + "CHANGE_ROLES_PERMISSIONS": "Change Roles & Permissions", + "ACCESS_PRIVATE_PROJECTS": "Access Private Projects", + "TIMESHEET_EDIT_TIME": "Edit Time in Timesheet", + "SUPER_ADMIN_EDIT": "Edit Super Admin Users", + "INVOICES_VIEW": "View Invoices", + "INVOICES_EDIT": "Edit Invoices Add", + "ESTIMATES_VIEW": "View Estimates", + "ESTIMATES_EDIT": "Edit Estimates Add", + "EDIT_SALES_PIPELINES": "Edit Sales Pipelines", + "VIEW_SALES_PIPELINES": "View Sales Pipelines", + "APPROVALS_POLICY_EDIT": "Edit Approvals Policy", + "APPROVALS_POLICY_VIEW": "View Approvals Policy", + "REQUEST_APPROVAL_EDIT": "Edit Approval Request", + "REQUEST_APPROVAL_VIEW": "View Approval Request", + "ORG_CANDIDATES_INTERVIEWERS_EDIT": "Create/Edit Interviewers", + "VIEW_ALL_EMAILS": "View All Emails", + "VIEW_ALL_EMAIL_TEMPLATES": "View All Emails Templates", + "ORG_HELP_CENTER_EDIT": "Edit Organization Help Center", + "PUBLIC_PAGE_EDIT": "Edit Organization Public Page", + "CAN_APPROVE_TIMESHEET": "Approve Timesheet", + "EVENT_TYPES_VIEW": "View Event Types", + "TIME_OFF_EDIT": "Edit Time Off", + "ORG_INVENTORY_VIEW": "View Organization Inventory", + "INVENTORY_GALLERY_VIEW": "View Inventory Gallery", + "INVENTORY_GALLERY_EDIT": "Edit Inventory Gallery", + "ORG_EQUIPMENT_VIEW": "View Organization Equipment", + "ORG_EQUIPMENT_EDIT": "Edit Organization Equipment", + "ORG_EQUIPMENT_SHARING_VIEW": "View Organization Equipment Sharing", + "ORG_EQUIPMENT_SHARING_EDIT": "Edit Organization Equipment Sharing", + "EQUIPMENT_MAKE_REQUEST": "Request Make Equipment Make", + "EQUIPMENT_APPROVE_REQUEST": "Request Approve Equipment", + "ORG_PRODUCT_TYPES_VIEW": "View Organization Product Types", + "ORG_PRODUCT_TYPES_EDIT": "Edit Organization Product Types", + "ORG_PRODUCT_CATEGORIES_VIEW": "View Organization Product Categories", + "ORG_PRODUCT_CATEGORIES_EDIT": "Edit Organization Product Categories", + "VIEW_ALL_ACCOUNTING_TEMPLATES": "View All Accounting Templates", + "GROUPS": { + "GENERAL": "General", + "ADMINISTRATION": "Administration" + }, + "ONLY_ADMIN": "These permissions are read-only and enabled only for admin", + "INSUFFICIENT": "You do not have sufficient permissions. The following permissions are missing:", + "ORG_SPRINT_EDIT": "Create/Edit Sprints", + "ORG_SPRINT_VIEW": "View Sprints", + "ORG_PROJECT_EDIT": "Create/Edit Projects", + "ORG_CONTACT_EDIT": "Create/Edit Contacts", + "ORG_CONTACT_VIEW": "View Contacts", + "ORG_TEAM_EDIT": "Create/Edit Teams", + "ORG_CONTRACT_EDIT": "Create/Edit Contracts", + "TIME_TRACKER": "Access Time Tracker", + "TENANT_ADD_EXISTING_USER": "Tenant Add User To Organization", + "INTEGRATION_VIEW": "View Integrations", + "FILE_STORAGE_VIEW": "View File Storage", + "PAYMENT_GATEWAY_VIEW": "View Payment Gateway", + "SMS_GATEWAY_VIEW": "View SMS Gateway", + "CUSTOM_SMTP_VIEW": "View Custom SMTP", + "IMPORT_EXPORT_VIEW": "View Import/Export", + "ORG_JOB_EMPLOYEE_VIEW": "查看任务员工", + "ORG_JOB_MATCHING_VIEW": "查看任务匹配", + "TENANT_SETTINGS": "租户设置表", + "ACCESS_DELETE_ACCOUNT": "访问删除账号", + "ACCESS_DELETE_ALL_DATA": "访问删除所有数据", + "ORG_DEMO_EDIT": "维护组织演示样例" + }, + "Organization": { + "AllOrganizations": "所有组织", + "MAIN": "主属性", + "DEMO": "演示数据", + "GENERATE_DEMO": "生成演示数据", + "RegenerateDemo": "重新生成演示数据", + "TotalEmployees": "总员工数", + "BasicInfo": "基础信息", + "OtherInfo": "其他信息", + "Name": "名称", + "OrganizationName": "组织名称", + "IsDefault": "默认", + "SetAsDefault": "设置为默认组织", + "IsActive": "启用", + "ActiveOrganization": "激活组织", + "DefaultValueDateType": "默认日期类型", + "InvitesAllowed": "允许邀请", + "InviteExpiryPeriod": "邀请过期时间(天)", + "EnableInvitesAllowed": "启用邀请用户", + "ProfileLink": "主页链接", + "OfficialName": "组织全称", + "ShortDescription": "组织简介", + "Website": "网站链接", + "SelectDataNetwork": "选择数据网络" + } + } + }, + "AUTH": { + "APP_NAME": "分析云", + "LOGIN": { + "ACCOUNT": "账号", + "USERNAME": "用户名/邮箱", + "PASSWORD": "密码", + "REMEMBER": "记住", + "FORGOT-PASSWORD": "忘记密码", + "SIGNUP": "没有账号-注册", + "SUBMIT": "登录", + "FEISHU": "飞书", + "DINGTALK": "钉钉", + "GITHUB": "Github" + }, + "REGISTER": { + "REGISTER": "注册", + "EMAIL": "邮箱", + "PASSWORD": "密码", + "CONFIRM_PASSWORD": "确认密码", + "SIGN-IN": "已有账号-登录", + "SUBMIT": "注册" + } + }, + "STORY": { + "COMMON": { + "APPLY": "应用", + "RESET": "重置", + "CANCEL": "取消", + "CONFIRM": "确定", + "CLEAR": "清空", + "SEARCH": "搜索" + }, + "WIDGET": { + "MENU": { + "LINKED_ANALYSIS": "关联分析", + "COPY": "复制", + "COPY_TO": "复制到", + "DUPLICATE": "复印", + "ADD": "添加", + "FULLSCREEN": "全屏", + "EXIT_FULLSCREEN": "退出全屏", + "NAVIGATE": "转到", + "FOCUS": "聚焦", + "PIN": "固定到主屏幕", + "SUBSCRIPTIONS": "订阅", + "ALERTS": "预警", + "SHARE": "分享", + "REFRESH": "刷新", + "REMOVE": "删除", + "NEW_RESPONSIVE_PAGE": "新响应页面", + "NEW_CANVAS_PAGE": "新画布页面" + } + }, + "WIDGETS": { + + "FilterBar": { + "Query": "查询" + }, + "AccountingStatement": { + "Unit": "单位" + } + }, + "DESIGNER": { + "SUBMIT": "提交", + "CANCEL": "取消", + "DELETE": "删除" + } + + }, + "STORY_DESIGNER": { + "BUILDER_TITLE": "构建", + "STYLING_TITLE": "样式", + "COMMON": { + "Appearance": "外观", + "Float_Label": "浮动标签", + "Display_Density": "显示密度", + "Label": "标签", + "Placeholder": "占位符", + "Widget": "组件", + "OPTIONS": "设置", + "DensityComfortable": "舒适", + "DensityCosy": "适中", + "DensityCompact": "紧凑", + "Title": "标题", + "Autocomplete": "自动补全", + "ControlType": "控制器类型", + "ControlOptions": "控制器选项", + "SelectionType": "值类型", + "SingleValue": "单值", + "MultiValue": "多值", + "SingleInterval": "单间隔", + "SingleRange": "单区间", + "MaxTagCount": "最大标签数量", + "AutoActiveFirst": "自动激活第一选项", + "Searchable": "可搜索", + "CascadingEffect": "级联过滤", + "Granularity": "时间粒度", + "GranularitySequence": "粒度序列", + "TimeFormatter": "时间格式", + "DefaultTimeFunction": "默认时间函数", + "DefaultTime": "默认时间", + "Single": "单值", + "TreeSelect": "树状选择", + "FlatSelect": "平铺选择", + "DropDownList": "下拉选择", + "Auto": "自动" + }, + "BUILDER": { + "COMMON": { + "Title": "标题", + "Options": "设置", + "initialHierarchyLevel": "初始展示层级", + "None": "默认", + "Display_Density": "显示密度", + "DensityComfortable": "舒适", + "DensityCosy": "适中", + "DensityCompact": "紧凑" + }, + "TITLE": "标题", + "SemanticModel": "语义模型", + "Entity": "模型实体", + "CALCULATED_MEMBER": "计算成员", + "DATA": "数据", + "DATA_SETTINGS": "数据配置", + "DATA_SOURCE": "数据源", + "ENTITY_SET": "模型", + "COMPONENT_TYPE": "组件类型", + "MODELING": "建模", + "NAME": "名称", + "LABEL": "标签", + "SELECTION_VARIANT": "选择条件", + "SELECT_OPTIONS": "过滤器", + "PRESENTATION_VARIANT": "展示变式", + "TOP": "前", + "SORT_BY": "排序", + "BY_FIELD": "字段", + "DRILL_DOWN": "下钻维度", + "DATE": {}, + "SELECTION_FIELDS_ANNOTATION": { + "DIMENSIONS": "维度" + }, + "FILTER_BAR": { + "TITLE": "过滤器栏", + "OPTIONS": "设置", + "LIVE_MODE": "实时查询", + "CascadingEffect": "级联联动", + "CascadingType": "级联类型", + "CascadingType_Default": "默认", + "CascadingType_InTurn": "从前到后", + "CascadingType_All": "所有", + "EnableToday": "启用当前时间输入" + }, + "WIDGET": { + "ANALYTICAL_CARD": "分析卡片", + "ACCOUNTING_STATEMENT": "财务报表", + "INDICATOR_CARD": "指标卡片", + "TABSET": "选项卡" + }, + "CHART": { + "DIMENSIONS": "维度", + "MEASURES": "度量", + "RealTimeLinkedAnalysis": "实时联动分析", + "DisableContextMenu": "禁用上下文菜单", + "ShowDataButton": "显示数据按钮", + "HideHeader": "隐藏标题栏", + "HideDataDownload": "隐藏数据下载", + "HideScreenshot": "隐藏截图", + "MaximumLimit": "最大数据量限制", + "DigitInfo": "数字格式", + "TrellisHorizontal": "格子横向个数", + "UniversalTransition": "全局过渡动画", + "CustomLogic": "自定义逻辑", + "Color": "颜色", + "Enabled": "启用", + "ShowDecal": "显示贴花", + "Decals": "贴花图案", + "Options": "选项", + "ChartSettings": "图形配置", + "ChartVariants": "图形变体", + "ReferenceLine": { + "Title": "创建参考线", + "ReferenceLine": "参考线", + "removeLabel": "删除", + "Label": "名称", + "Type": "展示类型", + "MarkLine": "标记线", + "MarkPoint": "标记点", + "ValueType": "值类型", + "Fixed": "固定", + "Dynamic": "动态", + "Value": "值", + "Aggregation": "聚合类型", + "Min": "最小值", + "Max": "最大值", + "Average": "平均值", + "Median": "中位数" + } + }, + "SELECTION_PRESENTATION_VARIANTS": { + "TITLE": "选择展示变式" + }, + "Filter": { + "Autocomplete": "自动补全", + "InitialLevel": "初始层级", + "VirtualScroll": "虚拟滚动", + "Multiple": "多选", + "Searchable": "可搜索", + "MaxTagCount": "最大标签数量", + "AutoActiveFirst": "自动激活第一选项", + "USER_DEFINED_DATA": "用户自定义数据", + "Value": "值", + "Label": "标签", + "PanelWidth": "下拉面板宽度" + }, + "IndicatorCard": { + "Options": "指标配置", + "Alias": "指标别名", + "Indicator": "指标", + "IndicatorType": "类型", + "YoYType": "同比类型", + "DisabledYoy": "禁用同比", + "DisabledTrend": "禁用趋势图", + "DigitsInfo": "数字格式", + "Indicators": "明细指标", + "LookBack": "回顾期间数" + }, + + "IFrame": { + "SRC": "src" + }, + "AccountingStatement": { + "Options": "配置", + "TableName": "表名称", + "Denominator": "缩放因子", + "DenominatorUnit": "缩放后单位", + "MeasuresOptions": "度量设置", + "Measure": "度量", + "PeriodFunctionsCURRENT": "当期", + "PeriodFunctionsYTD": "年累计", + "PeriodFunctionsPYSM": "去年同期", + "PeriodFunctionsMPM": "上期", + "PeriodFunctionsYOY": "同比", + "PeriodFunctionsMOM": "环比", + "ColumnName": "列名", + "IsRatio": "比率", + "IsSemanticColor": "语义颜色", + "ReverseSemanticColor": "反转颜色", + "Indicators": "指标列表配置", + "Indicator": "指标", + "IndicatorAlias": "别名", + "GroupName": "分组名", + "DigitsInfo": "数字格式", + "DigitsUnit": "数字单位", + "IsItalic": "斜体", + "IsUnderline": "下划线" + } + }, + "STYLING": { + "CSS": { + "BACKGROUND": { + "TITLE": "背景", + "BackgroundColor": "背景颜色", + "Background": "背景", + "BackgroundImage": "背景图片", + "BackgroundPosition": "背景位置", + "BackgroundSize": "背景大小", + "BackgroundRepeat": "背景重复", + "BackdropFilter": "背景滤镜", + "Opacity": "不透明度", + "BackgroundAttachment": "背景附着", + "None": "无" + }, + "BOX": { + "TITLE": "盒子", + "BoxShadow": "盒子阴影", + "BorderWidth": "边框大小", + "BorderColor": "边框颜色", + "BorderRadius": "边框半径", + "BorderStyle": "边框样式" + }, + "LAYOUT": { + "TITLE": "布局", + "Padding": "填充空白", + "Margin": "边缘空白", + "Overflow": "溢出" + }, + "SIZE": { + "TITLE": "大小", + "Width": "宽度", + "Height": "高度", + "MinWidth": "最小宽度", + "MinHeight": "最小高度", + "MaxWidth": "最大宽度", + "MaxHeight": "最大高度" + }, + "FONT": { + "TITLE": "字体", + "None": "无", + "FontSize": "字体大小", + "FontColor": "字体颜色", + "FontFamily": "字体", + "FontStyle": "字体样式", + "FontWeight": "字重", + "TextDecoration": "文本装饰", + "TextAlign": "文本对齐", + "TextDecoration_Overline": "上划线", + "TextDecoration_Underline": "下划线", + "TextDecoration_LineThrough": "删除线", + "TextAlign_Left": "左对齐", + "TextAlign_Center": "居中", + "TextAlign_Right": "右对齐", + "TextAlign_Top": "顶端对齐", + "TextAlign_Middle": "垂直居中", + "TextAlign_Bottom": "底对齐", + "FontWeight_Bold": "加粗", + "FontWeight_Lighter": "细化", + "FontWeight_Normal": "正常", + "FontStyle_Italic": "斜体 Italic", + "FontStyle_Oblique": "斜体 Oblique", + "FontStyle_Normal": "正常", + "FontFamily_Song": "宋体" + } + }, + + "CANVAS": { + "TITLE": "画布" + }, + + "STORY_PAGE": { + "PAGE_SIZE": "页面大小", + "DefaultBackground": "预设背景", + "Dynamic": "动态", + "Fixed": "固定", + "ContinuousHeight": "连续的高度", + "PresetBackground": "预设背景", + "PageType": "类型" + }, + + "ECHARTS": { + "Common": { + "Align": "对齐", + "Show": "显示", + "LEFT": "左侧距离", + "TOP": "上侧距离", + "RIGHT": "右侧距离", + "BOTTOM": "下侧距离", + "Opacity": "不透明度", + "Color": "颜色", + "ColorJSONPlaceholder": "JSON 格式的颜色", + "BorderWidth": "边框宽度", + "BorderColor": "边框颜色", + "BorderRadius": "边框半径", + "BorderStyle": "边框样式", + "BorderType": "边框类型", + "BorderJoin": "边框连接", + "BorderCap": "边框帽", + "BorderMiterLimit": "边框斜接限制", + "UniversalTransition": "全局过渡动画", + "Label": "标签", + "Position": "位置", + "Left": "左", + "Right": "右", + "Top": "上", + "Bottom": "下", + "Silent": "静默", + "Cursor": "光标", + "Cursor_Auto": "自动", + "Cursor_Pointer": "指针", + "Cursor_Move": "移动", + "ColorBy": "按着色", + "ColorBy_Auto": "自动", + "ColorBy_SameSeries": "相同系列", + "ColorBy_DataItems": "数据项", + "SeriesLayoutBy": "数据布局", + "Auto": "自动", + "Column": "列", + "Row": "行", + "SelectedMode": "选择模式", + "SelectedMode_None": "无", + "SelectedMode_Single": "单选", + "SelectedMode_Multiple": "多选", + "SelectedMode_False": "禁用", + "SelectedMode_Series": "系列", + "Formatter": "格式化", + "Rotate": "旋转", + "Enabled": "启用", + "Width": "宽度", + "Height": "高度", + "Disabled": "禁用", + "Orient": "方向", + "Horizontal": "横向", + "Vertical": "纵向", + "None": "无", + "Padding": "填充空白", + "Radius": "半径", + "Symbol": "符号", + "SymbolSize": "符号大小", + "SymbolRotate": "符号旋转", + "SymbolOffset": "符号位移", + "Stack": "堆积", + "TextAlign": { + "Title": "文本对齐", + "Auto": "自动", + "Left": "靠左", + "Right": "靠右", + "Center": "居中" + }, + "Name": "名称", + "LegendHoverLink": "图例联动高亮", + "Position_Auto": "自动", + "Position_Left": "靠左", + "Position_Right": "靠右", + "Position_Top": "靠上", + "Position_Bottom": "靠下", + "Position_Middle": "居中", + "Position_Center": "居中" + }, + "Global": { + "Title": "全局", + "DarkMode": "暗黑模式", + "BackgroundColor": "背景颜色", + "Animation": "动画", + "AnimationThreshold": "动画阈值", + "AnimationDuration": "动画时间", + "AnimationEasing": "动画函数", + "AnimationDelay": "动画延迟", + "AnimationDurationUpdate": "更新动画时间", + "AnimationEasingUpdate": "更新动画函数", + "AnimationDelayUpdate": "更新动画延迟" + }, + "SHADOW": { + "SHADOW_BLUR": "阴影模糊", + "SHADOW_COLOR": "阴影颜色", + "SHADOW_OFFSETX": "水平偏移", + "SHADOW_OFFSETY": "垂直偏移" + }, + "CATEGORY_AXIS": { + "TITLE": "分类轴", + "SHOW": "是否显示", + "Position": "位置", + "Offset": "偏移", + "ShowName": "显示名称", + "Name": "名称", + "NameLocation": "名称位置", + "NameGap": "名称间隔", + "NameRotate": "名称旋转", + "Inverse": "倒转", + "BoundaryGap": "边界差", + "Min": "最小值", + "Max": "最大值", + "Silent": "静默" + }, + "VALUE_AXIS": { + "TITLE": "值轴", + "SHOW": "是否显示", + "SplitNumber": "分割数", + "ValueScale": "自动范围", + "Min": "最小值", + "Max": "最大值" + }, + "Axis": { + "Title": "轴", + "Name": "名称", + "NameLocation": "名称位置", + "NameGap": "名称间隙", + "NameRotate": "名称旋转", + "MinorSplitLine": "次分割线", + "AxisTick": { + "Title": "轴刻度", + "Show": "显示", + "AlignWithLabel": "与标签对齐", + "Interval": "间隔", + "Inside": "在内侧", + "Length": "长度" + }, + "MinorTick": { + "Title": "次刻度", + "Show": "显示", + "SplitNumber": "分格数", + "Length": "长度" + } + }, + "SingleAxis": { + "Title": "单轴" + }, + "XAXIS_STYLE": { + "XAXIS": "x 轴", + "SHOW": "显示", + "NAME_LOCATION": "坐标轴名称显示位置", + "NAME_TEXT_STYLE": "坐标轴名称的文字样式", + "COLOR": "坐标轴名称的颜色", + "AXIS_LINE": "坐标轴轴线相关设置", + "AXIS_LINE_COLOR": "坐标轴线线的颜色", + "AXIS_LABEL": "坐标轴刻度标签的相关设置", + "AXISLABEL_ALIGN": "文字水平对齐方式", + "AXISLABEL_VERTICALALIGN": "文字垂直对齐方式", + "AXIS_TYPE": "坐标轴类型", + "AXIS_GRID_AREA_SEPARATOR": "坐标轴grid区域分隔线", + "SHOW_SEPARATOR_LINES": "是否显示分割线", + "SEPARATOR_LINE_STYLE": "分隔线样式", + "SEPARATOR_COLOR": "分割线颜色" + }, + "YAXIS_STYLE": { + "YAXIS": "y 轴", + "SHOW": "显示", + "NAME_LOCATION": "坐标轴名称显示位置", + "NAME_TEXT_STYLE": "坐标轴名称的文字样式", + "COLOR": "坐标轴名称的颜色", + "AXIS_LINE": "坐标轴轴线相关设置", + "AXIS_LINE_COLOR": "坐标轴线线的颜色", + "AXIS_LABEL": "坐标轴刻度标签的相关设置", + "AXISLABEL_ALIGN": "文字水平对齐方式", + "AXISLABEL_VERTICALALIGN": "文字垂直对齐方式", + "AXIS_GRID_AREA_SEPARATOR": "坐标轴grid区域分隔线", + "SHOW_SEPARATOR_LINES": "是否显示分割线", + "SEPARATOR_LINE_STYLE": "分隔线样式", + "SEPARATOR_COLOR": "分割线颜色" + }, + "AxisLine": { + "Title": "轴线", + "OnZero": "在零" + }, + "AxisLabel": { + "Title": "轴标签", + "Interval": "间隔", + "Inside": "内部", + "Rotate": "旋转", + "ShowMinLabel": "显示最小标签", + "ShowMaxLabel": "显示最大标签", + "HideOverlap": "隐藏重叠", + "Overflow": "溢出", + "Overflow_Null": "无", + "Overflow_Truncate": "截断", + "Overflow_Break": "间断", + "Overflow_BreakAll": "间断所有" + }, + "AxisPointer": { + "Title": "轴指针", + "Show": "显示", + "Type": "类型", + "Snap": "对齐", + "Handle": { + "Title": "手柄", + "Show": "显示", + "Type": "类型" + } + }, + "GRID": { + "GRID": "网格", + "SHOW": "是否显示", + "CONTAIN_LABEL": "是否包含刻度标签", + "BACKGROUND_COLOR": "背景颜色", + "BORDER_COLOR": "边框颜色", + "BORDER_WIDTH": "边框粗细" + }, + "LEGEND": { + "TITLE": "图例", + "LEGEND_TYPE": "类型", + "WIDTH": "宽度", + "HEIGHT": "高度", + "LEGEND_LEFT": "左侧的距离", + "LEGEND_TOP": "上侧的距离", + "LEGEND_RIGHT": "右侧的距离", + "LEGEND_BOTTOM": "下侧的距离", + "LEGEND_ORIENT": "布局朝向", + "Align": "对齐", + "Align_Auto": "自动", + "Align_Left": "左对齐", + "Align_Right": "右对齐", + "ItemGap": "元素间距", + "ItemWidth": "元素宽度", + "ItemHeight": "元素高度", + "InactiveColor": "非激活颜色", + "InactiveBorderColor": "非激活边框颜色", + "InactiveBorderWidth": "非激活边框宽度", + "IconSymbol": "图标符号", + "TextStyle": "文字样式" + }, + "TOOLTIP": { + "TITLE": "提示框", + "TOOLTIP_SHOW": "是否显示", + "TOOLTIP_TRIGGER": "触发类型", + "AXIS_POINTER": "坐标轴指示器配置项", + "AXIS_POINTER_TYPE": "指示器类型", + "ShowContent": "显示内容", + "Trigger": "触发", + "AppendToBody": "追加到 HTML Body", + "AxisPointer": "轴指针", + "Type": "类型", + "Axis": "轴", + "Snap": "快照", + "AlwaysShowContent": "永远显示", + "TriggerOn": "触发条件", + "ShowDelay": "延迟显示", + "HideDelay": "延迟隐藏", + "Enterable": "鼠标进入", + "Confine": "限制在图表的区域内", + "ClassName": "CSS 类", + "TransitionDuration": "移动动画时间", + "Position": "位置", + "BackgroundColor": "背景颜色", + "BorderColor": "边框颜色", + "BorderWidth": "边框宽度", + "Padding": "内边距", + "Order": "排列顺序", + "TextStyle": "文本样式", + "ExtraCssText": "附加样式" + }, + "TEXT": { + "TEXTSTYLE": "全局的字体样式", + "TEXTSTYLE_COLOR": "文字的颜色", + "TEXTSTYLE_FONTSTYLE": "文字字体的风格", + "TEXTSTYLE_FONTWEIGHT": "文字字体的粗细", + "TEXTSTYLE_FONTSIZE": "文字的字体大小" + }, + "DATAZOOM_STYLE": { + "None": "无", + "DATAZOOM": "数据缩放", + "ORIENT": "布局方式", + "ORIENT_HORIZONTAL": "水平", + "ORIENT_VERTICAL": "竖直", + "DATAZOOM_TYPE": "类型", + "FILTER_MODE": "过滤模式", + "START": "起始", + "END": "结束", + "START_VALUE": "起始数值", + "END_VALUE": "结束数值", + "YAXIS_INDEX": "控制的 Y 轴", + "MIN_SPAN": "窗口最小值", + "MAX_SPAN": "窗口最大值", + "ZOOM_LOCK": "锁定窗口大小", + "Type_none": "无", + "Type_inside": "内置", + "Type_slider": "滑动条", + "Type_sliderInside": "内置+滑动条", + "RangeMode": "范围模式", + "MinValueSpan": "最小实际值", + "MaxValueSpan": "最大实际值", + "Throttle": "刷新频率", + "PreventDefaultMouseMove": "阻止默认的鼠标移动", + "MouseMode_true": "不按功能键", + "MouseMode_false": "不触发", + "MouseMode_shift": "按住 SHIFT 触发", + "MouseMode_ctrl": "按住 CTRL 触发", + "MouseMode_alt": "按住 ALT 触发", + "zoomOnMouseWheel": "鼠标滚动缩放", + "moveOnMouseMove": "鼠标移动移动", + "moveOnMouseWheel": "鼠标滚动移动" + }, + "SERIE_STYLE": { + "TITLE": "系列统一属性", + "SERIES": "Echarts系列", + "SERIES_TYPE": "Echarts系列类型", + "ITEMS_TYLE": "图形样式", + "GRADIENT_STYLE": "渐变类型", + "LINESTYLE": "线条样式", + "LINEAR_X0": "线性渐变X0参数", + "LINEAR_Y0": "线性渐变Y0参数", + "RADIAL_R": "径向渐变半径参数", + "LINEAR_X2": "线性渐变X2参数", + "LINEAR_Y2": "线性渐变Y2参数", + "LINEWIDTH": "线宽", + "LINE_TYPE": "线的类型", + "LINESHADOW_BLUR": "图形阴影的模糊大小", + "LINESHADOW_COLOR": "阴影颜色", + "LINESHADOW_OFFSETX": "阴影水平方向上的偏移距离", + "LINESHAODW_OFFSETY": "阴影垂直方向上的偏移距离", + "SMOOTH": "是否平滑曲线显示", + "COLOR_STOPS": "渐变颜色参数", + "OFFSET": "0-100%的颜色", + "COLOR": "颜色", + "ITEMSTYLEBORDER_COLOR": "图形的描边颜色", + "ITEMSTYLEBORDER_WIDTH": "描边线宽", + "ITEMSTYLEBORDER_TYPE": "描边类型", + "ITEMSTYLESHADOW_BLUR": "图形阴影的模糊大小", + "ITEMSTYLESHADOW_COLOR": "阴影颜色", + "ITEMSTYLE_OPCITY": "图形透明度", + "BORDER_RADIUS": "柱状图圆角半径", + "BAR_WIDTH": "柱条的宽度", + "EMPHASIS_STYLE": "Emphasis 样式", + "TEXT_LABEL": "文本标签", + "IS_LABEL": "是否显示标签", + "GRAPHIC_STYLE": "图形样式", + "GRAPHIC_COLOR": "图形颜色", + "STROKE_COLOR": "描边颜色", + "STROKE_WIDTH": "描边宽度", + "GRAPHIC_SHADOW": "图形阴影", + "SHADOW_COLOR": "阴影颜色", + "SHADOW_OFFSET_X": "阴影水平偏移量", + "SHADOW_OFFSET_Y": "阴影垂直偏移量", + "OPACITY": "不透明度", + "ROSETYPE": "是否展示成南丁格尔图", + "PIE_RADIUS": "饼图半径", + "AREA_STYLE": "区域填充样式", + "SHADOW_BLUR": "阴影模糊大小", + "ITEM_STYLE": { + "TITLE": "单个体样式", + "OPACITY": "不透明度" + }, + + "LABEL": { + "TITLE": "标签" + }, + "LabelLine": { + "Title": "标签线" + } + }, + "EMPHASIS": { + "TITLE": "高亮样式", + "DISABLED": "禁用", + "FOCUS": "聚焦", + "BlurScope": "模糊范围", + "BlurScope_None": "无", + "BlurScope_CoordinateSystem": "坐标系统", + "BlurScope_Series": "系列", + "BlurScope_Global": "全局", + "Focus_None": "无", + "Focus_Self": "自己", + "Focus_Series": "系列", + "Focus_Adjacency": "相邻", + "Scale": "缩放", + "ScaleSize": "缩放大小" + }, + "ITEM_STYLE": { + "TITLE": "单个体样式", + "OPACITY": "不透明度" + }, + "GLOBAL_COLORS": { + "TITLE": "全局颜色", + "ColorList": "颜色序列", + "Color": "颜色" + }, + "ARIA": { + "TITLE": "辅助增强", + "ShowDecal": "显示贴花", + "Decals": "贴花图案" + }, + "SeriesStyle": { + "Title": "系列属性", + "HasAll":"有 All 成员", + "FunnelAlign": "漏斗对齐", + "BoundaryGap": "边界间隙" + }, + "DDD": { + "GridTitle": "3D网格", + "BoxWidth": "宽度", + "BoxHeight": "高度", + "BoxDepth": "深度", + "Light": "光线", + "BarSeriesTitle": "系列属性", + "Shading": "明暗法", + "Environment": "环境贴图", + "PostEffect": "后处理特效", + "TemporalSuperSampling": "分帧超采样", + "Enable": "启用", + "ViewControl": "视角控制", + "BevelSize": "倒角尺寸", + "BevelSmoothness": "倒角圆润度", + "Stack": "堆叠", + "StackStrategy": "堆叠策略", + "MinHeight": "最小高度", + "Silent": "不响应", + "Label": "标签", + "ItemStyle": "元素样式", + "Show": "显示", + "Distance": "距离", + "Formatter": "格式", + "TextStyle": "文本样式", + "Emphasis": "高亮", + "BlendMode": "混合模式" + }, + "Select": { + "Title": "选中样式" + }, + "MarkLine": { + "Title": "标记线", + "LineStyle": "线样式" + }, + "VisualMap": { + "Title": "可视映射", + "RemoveLabel": "删除", + "Type": "类型", + "Piecewise": "分段", + "Continuous": "连续", + "Show": "显示", + "Realtime": "实时", + "Calculable": "可计算", + "Controller": "控制器", + "InRange": "范围内的", + "OutofRange": "范围外的", + "Text": "描述", + "SymbolSize": "符号大小", + "ColorLightness": "颜色亮度", + "Inverse": "倒转", + "Min": "最小值", + "Max": "最大值", + "Range": "预选中范围", + "SplitNumber": "分割数量", + "Precision": "数字精度", + "Pieces": "分段", + "ShowLabel": "显示标签", + "ItemSymbol": "元素符号", + "ItemGap": "元素间距" + }, + "Calendar": { + "Title": "日历", + "ItemStyle": "元素样式", + "CellSize": "单元格大小" + }, + "SplitLine": { + "Title": "分割线", + "Show": "显示", + "LineStyle": "线样式", + "Interval": "间隔" + }, + "SplitArea": { + "Title": "分割区域", + "Show": "显示", + "AreaStyle": "区域样式", + "Interval": "间隔" + }, + "LineStyle": { + "Title": "线样式", + "Color": "颜色", + "Width": "宽度", + "Type": "类型", + "None": "无", + "Solid": "实线", + "Dashed": "虚线", + "Dotted": "点虚线" + }, + "ItemStyle": { + "Title": "元素样式" + }, + "Text": { + "TextBorderColor": "文本边框颜色", + "TextBorderWidth": "文本边框宽度", + "TextBorderType": "文本边框类型", + "TextBorderDashOffset": "文本边框横线偏移量", + "TextShadowColor": "文本阴影颜色", + "TextShadowBlur": "文本阴影模糊", + "TextShadowOffsetX": "文本阴影偏移X", + "TextShadowOffsetY": "文本阴影偏移Y", + "Overflow": "溢出", + "Overflow_Null": "无", + "Overflow_Truncate": "截断", + "Overflow_Break": "间断", + "Overflow_BreakAll": "间断所有", + "Ellipsis": "省略", + "Align": "对齐", + "Align_Auto": "自动", + "Align_Left": "左", + "Align_Center": "中", + "Align_Right": "右", + "Color": "文本颜色", + "FontStyle": "文本样式", + "FontStyle_Auto": "自动", + "FontStyle_Normal": "正常", + "FontStyle_Italic": "倾斜 Italic", + "FontStyle_Oblique": "倾斜 Oblique", + "FontWeight": "字重", + "FontFamily": "字体", + "FontSize": "字体大小", + "LineHeight": "行高", + "VerticalAlign": "垂直对齐", + "VerticalAlign_Auto": "自动", + "VerticalAlign_Top": "顶部", + "VerticalAlign_Middle": "居中", + "VerticalAlign_Bottom": "底部", + "RichText": "富文本" + }, + "Geo": { + "Title": "地理组件", + "Center": "中心", + "Aggregator": "聚合函数", + "AspectScale": "长宽比", + "BoundingCoords": "地图范围", + "NameProperty": "GeoJSON 属性名称", + "ShowLegendSymbol": "显示图例标识", + "Zoom": "缩放比例" + }, + "Title": { + "Title": "标题", + "Text": "主文本", + "Link": "主链接", + "SubText": "附文本", + "SubLink": "附链接", + "Left": "左侧", + "Top": "上侧", + "Right": "右侧", + "Bottom": "下侧" + }, + "Bar": { + "BarWidth": "宽度", + "BarMaxWidth": "最大宽度", + "BarMinWidth": "最小宽度", + "BarMinHeight": "最小高度", + "BarMinAngle": "最小角度", + "BarGap": "间距", + "BarCategoryGap": "类别间距", + "ShowBackground": "显示背景", + "Background": "背景", + "RoundCap": "圆帽" + }, + "Line": { + "ShowSymbol": "显示符号", + "ShowAllSymbol": "显示所有符号", + "Smooth": "平滑", + "Stack": "堆积", + "Step": "分步", + "AreaStyle": "面积样式", + "Origin": "源" + }, + "Tree": { + "SeriesStyle": { + "Title": "系列样式", + "Layout": "布局方式", + "Orthogonal": "直角", + "Radial": "雷达", + "Orient": "方位", + "EdgeShape": "边缘形状", + "EdgeForkPosition": "边缘分叉位置", + "InitialTreeDepth": "初始显示深度", + "Leaves": "叶子" + } + }, + "Pie": { + "RoseType": "玫瑰类型", + "Center": "中心", + "Radius": "半径", + "MinShowLabelAngle": "最小显示标签角度", + "Clockwise": "顺时针方向", + "StartAngle": "开始角度", + "MinAngle": "最小显示角度", + "SelectedOffset": "选中偏移", + "AlignTo": "对齐方式", + "AlignTo_none": "默认", + "AlignTo_labelLine": "线末端对齐", + "AlignTo_edge": "文字对齐", + "EdgeDistance": "文字边距", + "BleedMargin": "出血线大小", + "DistanceToLabelLine": "文字与线间距", + "PercentPrecision": "百分比精度", + "StillShowZeroSum": "零数据仍显示扇区", + "AvoidLabelOverlap": "防止标签重叠" + }, + "Sankey": { + "HasAll": "有 All 成员", + "NodeWidth": "节点宽度", + "NodeGap": "节点间隙", + "NodeAlign": "节点对齐", + "LayoutIterations": "布局迭代", + "Draggable": "可拖拽", + "LineStyle": "线样式", + "Curveness": "平滑", + "Label": "标签", + "LevelsOptions": "层级属性" + }, + "Treemap": { + "HasAll": "有 All 成员", + "LeafDepth": "叶子深度", + "DrillDownIcon": "下钻符号", + "ColorAlpha": "颜色α", + "ColorSaturation": "色彩饱和度", + "ColorMappingBy": "颜色映射", + "VisibleMin": "最小显示", + "ChildrenVisibleMin": "子级最小显示", + "UpperLabel": "上级标签", + "VisualMin": "最小可视", + "VisualMax": "最大可视", + "LevelsOptions": "层级属性", + "GapWidth": "间隙宽度", + "DragRoam": "拖拽漫游", + "DragRoam_default": "默认", + "DragRoam_false": "关闭", + "DragRoam_scale": "缩放", + "DragRoam_move": "平移", + "DragRoam_all": "缩放和平移" + }, + "Sunburst": { + "Label": "标签", + "Rotate": "旋转", + "MinAngle": "最小显示角度", + "NodeClick": "节点点击", + "LevelsOptions": "层级属性" + }, + "Polar": { + "Title": "极坐标" + }, + "Heatmap": { + "DateFormatter": "日期格式" + }, + "Label": { + "Title": "标签" + }, + "LabelLine": { + "ShowAbove": "图形上方", + "Smooth": "平滑", + "FirstLength": "第一段的长度", + "SecondLength": "第二段的长度", + "MinTurnAngle": "最小转弯角度", + "MaxSurfaceAngle": "最大表面角度" + }, + "LabelLayout": { + "Title": "标签布局", + "HideOverlap": "隐藏重叠", + "MoveOverlap": "挪动防止重叠", + "MoveOverlap_none": "无", + "MoveOverlap_shiftX": "水平依次位移", + "MoveOverlap_shiftY": "垂直依次位移" + }, + "Waterfall": { + "Accumulate": "累计" + } + } + } + }, + "COMPONENTS": { + "COMMON": { + "APPLY": "应用", + "Apply": "应用", + "Confirm": "确定", + "RESET": "重置", + "CANCEL": "取消", + "CONFIRM": "确定", + "CLEAR": "清空", + "SEARCH": "搜索", + "ADD": "添加", + "VALUE": "值", + "LABEL": "标签", + "None": "无", + "DIMENSION_MEASURE": "维度/度量", + "Parameter": "参数", + "Measure Control": "度量控制", + "Measure": "度量", + "Calculation": "计算", + "Dimension": "维度", + "Hierarchy": "层次结构", + "Level": "层级", + "Measure Group": "度量组", + "Indicator": "指标", + "Calendar": "日历", + "Address.Country": "国家", + "DisplayBehaviour": "显示行为", + "DisplayBehaviour_Auto": "自动", + "DisplayBehaviour_Description": "描述", + "DisplayBehaviour_DescriptionID": "描述+编码", + "DisplayBehaviour_IDDescription": "编码+描述", + "DisplayBehaviour_IDOnly": "编码" + }, + "ENTITY": { + "MEASURE": "度量", + "SELECT_DIMENSION": "选择维度", + "MeasureFormatting": "度量格式", + "ShortNumber": "缩写数字", + "Decimals": "小数位", + "Unit": "单位", + "UseUnderlyingUnit": "使用模型单位", + "DigitsInfo": "数字格式" + }, + "PROPERTY": { + "PARAMETER": "参数", + "PARAMETERS": "参数", + "MEASURE": "度量", + "MEASURES": "度量", + "MeasureGroup": "度量组", + "INDICATORS": "指标", + "CREATE_PARAMETER": "创建参数", + "EditParameter": "编辑参数", + "CALCULATIONS": "计算度量", + "DIMENSION": "维度", + "DIMENSIONS": "维度", + "ADD_DIMENSION": "添加维度", + "MEMBERS": "成员", + "HIERARCHY": "层次结构", + "ADD_PARAMETER_MEMBER": "添加成员", + "MEASURE_CONTROLS": "度量控制", + "CREATE_CALCULATION": "创建计算", + "CREATE_MEASURE_CONTROL": "创建度量控制", + "REFERENCE_LINE": "参考线", + "Input": "输入", + "Select": "选择", + "Dimensions": "维度", + "Name": "名称", + "NameRequired": "名称必输或已存在", + "Caption": "标签", + "Value": "值", + "DefaultValue": "默认值", + "ValueType": "值类型", + "DisplayAs": "显示为", + "Label": "文本字段", + "Formatter": "格式设置", + "EditFormula": "编辑公式", + "UnbookedData": "无成员数据", + "ZeroSuppression": "清零", + "PropertyList": "属性列表", + "DisplayHierarchy": "包含父级层级", + "CreateParameter": "创建参数", + "CurrentMember": "当前成员", + "PreviousNMember": "之前第 N 个成员", + "NextNMember": "之后第 N 个成员", + "ParallelMember": "平行成员", + "AncestorMember": "祖先成员", + "SelectByMembers": "选择成员", + "NewCalculationInputControl": "新建计算输入", + "NthMember": "值 / 第 N 个", + "IsDefault": "默认", + "Default": "默认", + "Auto": "自动", + "Description and ID": "名称+ID", + "Description Only": "名称", + "ID Only": "ID", + "Description": "描述", + "Order": "排序", + "None": "无", + "Order_ASC": "正序", + "Order_DESC": "倒序", + "Dimension": "维度", + "AvailableMembers": "可用成员" + }, + "CALCULATION": { + "TITLE": "计算编辑器", + "TYPE": "类型", + "Name": "名称", + "NameRequired": "名称必输或已存在", + "Caption": "标签", + "FUNCTIONS": "函数", + "DIMENSION_MEMBERS": "维度成员", + "CALCULATED_MEMBERS": "计算成员", + "PARAMETERS": "参数", + "CALCULATED_MEASURE": "计算公式", + "RESTRICTED_MEASURE": "受限度量", + "VARIANCE_MEASURE": "差值度量", + "AGGREGATION": "聚合", + "DIMENSION_TO_MEASURE": "维度转度量", + "MEASURE_CONTROL": "度量控制", + "PROPERTIES": "属性", + "OPERATION": "运算", + "VALUE": "值", + "AGGREGATION_DIMENSIONS": "聚合维度", + "ADD_DIMENSION": "添加维度", + "SELECTION_CONTEXT": "选择上下文", + "ENABLE_CONSTANT_SELECTION": "启用常量选择", + "EDIT_FORMULA": "编辑公式", + "UseConditionalAggregation": "使用条件聚合", + "ConditionalDimensions": "条件维度", + "ExcludeConditions": "排除条件", + "Compare": "比", + "To": "较", + "BaseDimension": "基准维度", + + "SetNoDataasZero": "将无数据当作零", + "CalculateasPercentage": "计算为百分比", + "DirectDivide": "直接除", + "AbsoluteBaseValue": "绝对化基值", + "DivideBy": "除以", + "CompareValueA": "比 (A)", + "ToValueB": "较 (B)", + "Measure": "度量", + "RestrictiveConditions": "限定条件", + "ConstantSelectionTootip": "锁定限定条件维度成员,使其不会被用户上下文切片器所覆盖", + "Dimension": "维度", + "MeasureSelectOptions": "度量选择选项", + "ConditionalAggregation": "条件聚合", + "Unit": "单位", + "Formulas": "公式", + "MeasureSelectPlaceholder": "选择或新建一个度量" + }, + "MeasureSelect": { + "EditCalculationMeasure": "编辑计算度量", + "NewCalculationMeasure": "新建计算度量" + }, + "VALUE_HELP": { + "TITLE": "为{{value}}设置过滤器", + "AVAILABLE_MEMBERS": "可选成员", + "DISPLAY_BEHAVIOUR": "显示形式", + "SHOW_HIERARCHY": "显示层级", + "PRESENTATION": "展现形式", + "SHOW_UNBOOKED_MEMBERS": "显示空成员", + "SHOW_ONLY_LEAVES": "只显示叶子成员", + "EXCLUDE_SELECTED_MEMBERS": "排除选中成员", + "CLEAR_SELECTION": "清空选择", + "SELECTED_MEMBERS": "选中成员", + "TREE_SELECTION_MODE": "选择模式", + "EDIT_FORMULA": "编辑公式", + "FUNCTIONS": "函数", + "CONDITIONS": "条件", + "OPERATORS": "操作符", + "DIMENSION_MEMBERS": "维度成员", + "CALCULATED_MEMBERS": "计算成员" + }, + "SELECTION": { + "Slicers": "切片器", + "AdvancedFilter": "组合切片器", + "CombinationSlicer": "组合切片器", + "AdvancedSlicer": "高级切片器", + "DimensionMembers": "维度成员", + "TimeRanges": "动态时间范围", + "OnContext": "基于", + "SLICERS_BAR": { + "TITLE": "过滤器" + }, + "ADVANCED_SLICER": { + "TITLE": "高级切片器", + "CONTEXT": "上下文", + "OPERATOR": "操作符", + "ENABLE_OTHER": "汇总其它项", + "VALUE": "值", + "VALUE_FROM": "从", + "VALUE_TO": "至", + "MEASURE": "度量", + "MeasureSelectPlaceholder": "选择或新建一个度量" + }, + "SLICER": { + "ADVANCED_SLICER": "高级切片器", + "ADVANCED_FILTER": "组合切片器" + }, + "DateFunctions": { + "SYSTEMTIME": "系统时间", + "TODAY": "今天" + } + }, + "DATE_PICKER": { + "Date": "日期", + "Year": "年", + "Quarter": "季", + "Month": "月", + "Week": "周", + "Day": "日", + "From": "从", + "To": "至" + }, + "TIME_FILTER": { + "SET_DATE_RANGE": "为 {{property}} 设置时间区间", + "CURRENT_DATE": "当前日期", + "SYSTEM_DATE": "系统时间", + "USER_CURRENT_DATE": "用户当前时间", + "ADD_TIME_RANGE": "添加时间区间", + "RANGE": "区间", + "RANGE_TYPE": "区间类型", + "RANGE_TYPE_STANDARD": "标准", + "RANGE_TYPE_OFFSET": "偏移", + "GRANULARITY": "粒度", + "YEAR": "年", + "QUARTER": "季度", + "MONTH": "月", + "WEEK": "周", + "DAY": "日", + "LOOK_BACK": "回顾", + "LOOK_AHEAD": "展望", + "CURRENT_PERIOD": "当前时间", + "FORMATTER": "格式", + "OFFSET_DIRECTION": "偏移方向", + "OFFSET_AMOUNT": "偏移量", + "SETTINGS_FOR_USERS": "为用户设置", + "ALLOW_MODIFY_SELECTIONS": "允许查看者修改选择", + "SELECTION_TYPE": "选择类型", + "SELECTION_TYPE_MULTIPLE": "多选", + "SELECTION_TYPE_SINGLE": "单选", + "TODAY": "当前期间", + "Year": "年", + "Quarter": "季度", + "Month": "月", + "Week": "周", + "Day": "日" + }, + "COUNTDOWN_CONFIRMATION": { + "CONFIRM": "确认", + "WAS": "秒", + "ENABLED": "启用", + "DISABLED": "停用", + "WAIT_UNTIL_RELOAD": "等待直至重新加载" + }, + "CONFIRM": { + "DELETE": "确定删除", + "INPUT_UNIQUE_VALUE": "输入唯一值", + "NAME": "名称" + }, + "SINGLE_SELECTION_TABLE": { + "SEARCH": "搜索", + "SELECT": "选择" + }, + "MEMBER_CONTROL": { + "LABEL_ID": "名称 / 键" + }, + "EDITOR": { + "EDIT": "编辑" + }, + "AdvancedFilter": { + "Title": "组合切片器", + "AND": "且", + "OR": "或", + "GROUP": "组合", + "Operator": "操作符", + "Value": "值", + "Condition": "条件", + "AddGroup": "\"且\"组合", + "OrGroup": "\"或\"组合", + "EndGroup": "结束组合", + "DeleteGroup": "删除组合", + "Tips": "使用 且/或 创建条件组合" + }, + "Table": { + "firstPageLabel": "第一", + "itemsPerPageLabel": "每页", + "lastPageLabel": "最后", + "nextPageLabel": "下一页", + "previousPageLabel": "上一页", + "rangeLabel0": "页 1 共 1", + "pageLabel": "页", + "ofLabel": "共" + } + }, + "FORMLY": { + "COMMON": { + "ADD": "添加", + "Apply": "应用", + "Cancel": "取消", + "Search": "搜索", + "Options": "配置", + "Clear": "清空" + }, + "PROPERTY_SELECT": { + "REFERENCE_LINE": "参考线", + "None": "默认", + "Category": "类别", + "Category2": "类别2", + "Group": "分组", + "Stacked": "堆积", + "Color": "颜色", + "Trellis": "格子", + "Axis1": "轴1", + "Axis2": "轴2", + "Axis3": "轴3", + "Size": "大小", + "Lightness": "明度", + "SizeLightness": "大小和明度", + "Tooltip": "提示信息", + "Bar": "柱形", + "Line": "线形", + "Scatter": "散点", + "Pattern": "图案", + "Palette": "调色板", + "Invert": "反转", + "Role": "角色", + "Shape": "形状", + "Style": "样式", + "ChartOptions": "图形属性", + "ChartAttributes": "图形属性", + "BarChart": "条形图", + "Colors": "颜色" + }, + "TABLE": { + "Action": "操作", + "Open": "打开", + "AddRow": "新增", + "Options": "配置" + }, + "CHART": { + "ChartType": "图形类型", + "CustomCode": "自定义代码", + "AutomaticallyGenerateCode": "根据注释自动生成代码", + "None": "无", + "Horizontal": "横向", + "Vertical": "纵向", + "Doughnut": "环形图", + "Doughnut2": "细环形图", + "Nightingale": "南丁格尔", + "Nightingale2": "南丁格尔2", + "Polar": "极坐标", + "Comparison": "比较", + "Pie": "饼图", + "Bar": "柱图", + "Waterfall": "瀑布图", + "Map": "地理", + "Histogram": "直方图", + "Trend": "趋势", + "Line": "线图", + "Line2": "纵向线图", + "Area": "面积图", + "AreaStacked": "堆积面积图", + "Theme River": "河流图", + "ThemeRiver": "河流图", + "Correlation": "相关", + "Scatterplot": "散点图", + "Scatter": "散点图", + "Bubble": "气泡图", + "Cluster Bubble": "集群气泡图", + "Packed Bubble": "包气泡图", + "Radial Scatter": "雷达散点图", + "Distribution": "分布", + "Heat Map": "热点图", + "Heatmap": "热点图", + "Box plot": "盒须图", + "Boxplot": "盒须图", + "Tree": "树图", + "Tree Map": "矩阵树图", + "Treemap": "矩阵树图", + "Sunburst": "旭日图", + "Sankey": "桑基图", + "Radar": "雷达图", + "Reverse": "反向", + "Funnel": "漏斗图", + "Calendar": "日历", + "Radial": "雷达", + "3D": "三维", + "Geo": "地理", + "Custom": "自定义", + "GeoMap": "地理图", + "MapName": "地图名称", + "MapUrl": "地理文件链接", + "MapProjection": "地图投影", + "IsTopoJSON": "是 TopoJSON 格式", + "FeatureObjectNames": "Feature 对象名称", + "Bar 3D": "三维柱形", + "Bar3D": "三维柱形", + "Line 3D": "三维线图", + "Line3D": "三维线图", + "Scatter 3D": "三维散点", + "Scatter3D": "三维散点", + "Column": "柱条形图", + "ColumnStacked": "堆积柱条形图", + "BarStacked": "堆积条形图", + "BarPolar": "极坐标条形图", + "BatPolarBackground": "极坐标有背景条形图", + "Combination": "组合图", + "BarTrellis": "柱形图矩阵", + "Ask": "提问", + "ChartName": "图形名称" + }, + "Select": { + "UnableLoadOptionList": "无法加载可选项" + }, + "SemanticModel": { + "Label": "语义模型" + }, + "Sort": { + "Label": "排序字段" + } + }, + "PANGOLIN": { + "CORE": { + "WIDGET": { + "Rank": "排名", + "Top": "前" + } + } + }, + "FORM": { + "LABELS": { + "EMAILS": "邮箱", + "ROLE": "角色", + "INVITATION_EXPIRATION": "邀请过期" + }, + "PLACEHOLDERS": { + "ROLE": "选择角色" + } + }, + + "EMAIL_TEMPLATES_PAGE": { + "TEMPLATE_NAMES": { + "password": "密码重置", + "welcome-user": "欢迎用户", + "invite-user": "邀请用户", + "TEMPLATE_NAMES": "模板名称" + } + }, + "TOASTR": { + "TITLE": { + "SUCCESS": "成功" + }, + "MESSAGE": { + "ERRORS": "错误", + "INVITES_DELETE": "删除邀请 {{email}}", + "INVITES_RESULT": "成功邀请 {{total}} 人, 忽略 {{ignored}} 人", + "EMAIL_TEMPLATE_SAVED": "邮件模板保存", + "CUSTOM_SMTP_UPDATED": "自定义 SMTP 更新" + } + }, + "The name is required": "名称必输", + "Must be unique from the table name": "不能与表名重复", + "Initializing": "初始化中", + "offline": "离线", + "online": "在线", + "loading": "加载中", + "error": "错误" +} diff --git a/apps/cloud/src/assets/i18n/zh-Hant.json b/apps/cloud/src/assets/i18n/zh-Hant.json new file mode 100644 index 000000000..8ede8f645 --- /dev/null +++ b/apps/cloud/src/assets/i18n/zh-Hant.json @@ -0,0 +1,2880 @@ +{ + "MENU": { + "TENANT": "集團", + "ORGANIZATION": "公司", + "DASHBOARD": "儀錶盤", + "INDICATOR": "指標", + "INDICATOR_MARKET": "市場", + "INDICATOR_APP": "指標應用", + "INDICATOR_REGISTER": "註冊", + "INDICATOR_GROUPS": "組", + "INDICATOR_MY": "我的", + "INSIGHT": "洞察", + "INSIGHT_VIEWER": "洞察", + "INSIGHT_ADMIN": "管理", + "STORY_MODEL": "模型", + "STORY": "故事", + "USERS": "用戶" + }, + "PAC": { + "Title": "元數分析雲", + "KEY_WORDS": { + "Ask": "提問", + "Certification": "認證", + "DigitalAssetCertificationTypes": "數字資產認證類型", + "Owner": "所有者", + "Query": "查詢", + "Story": "故事", + "SemanticModel": "語義模型", + "SuggestingPrompts": "正在建議提示語", + "SelectSemanticModel": "選擇語義模型", + "Project": "項目", + "BusinessArea": "業務域", + "Logo": "標識", + "StoryPoint": "故事點", + "ADD": "添加", + "ACTION": "操作", + "Apply": "應用", + "BUSINESS_AREA": "業務域", + "CACHE": "緩存", + "CODE": "代碼", + "CREATED_AT": "創建時間", + "CreatedAt": "創建時間", + "CREATED_BY": "創建人", + "Cancel": "取消", + "CLOSE_ALL": "關閉所有", + "Cube": "多維數據集", + "Tags": "標籤", + "DATA": "數據", + "DATA_SOURCE": "數據源", + "DATA_SOURCES": "數據源", + "DELETE": "刪除", + "DIMENSIONS": "維度", + "DIMENSION": "維度", + "EDIT": "編輯", + "EXPORT": "導出", + "GENERAL": "常規", + "GROUP": "組", + "HIERARCHY": "層次結構", + "INDICATOR": "指標", + "LEVELS": "層級", + "MANAGE": "管理", + "MODEL": "模型", + "MODEL_TYPE": "模型類型", + "MODIFY": "修改", + "NAME": "名稱", + "VALUE": "值", + "NOTIFICATION_DESTINATION": "通知目標地", + "OVERVIEW": "概覽", + "PREFERENCES": "首選項", + "REMOVE": "刪除", + "SEMANTIC_MODEL": "語義模型", + "STORY": "故事", + "TYPE": "類型", + "USER": "用戶", + "UPDATED_BY": "修改人", + "UPDATED_AT": "修改時間", + "VIEW": "視圖", + "VARIABLES": "變量", + "WORKSPACE": "工作空間", + "WORD_WRAP": "換行", + "Reset": "重置", + "RENAME": "重命名", + "SUCCEED": "成功", + "ROLE": "角色", + "PERMISSION": "權限", + "TENANT": "租戶", + "ORGANIZATION": "組織", + "SEARCH": "搜索", + "COMFORT": "舒適", + "COMPACT": "緊湊", + "SETTINGS": "設置", + "IndicatorApp": "指標應用", + "SELECT": "選擇", + "CURRENCY": "幣種", + "STATUS": "狀態", + "SAVE": "保存", + "Refresh": "刷新", + "Management": "管理", + "User": "用戶", + "Users": "用戶", + "Action": "操作", + "Roles": "角色", + "Search": "搜索", + "Member": "成員", + "Name": "名稱", + "CreatedBy": "創建人", + "Cubes": "多維數據集", + "Formula": "公式", + "Confirm": "確定", + "Dimension": "維度", + "Dimensions": "維度", + "Measures": "度量", + "CalculatedMembers": "計算成員", + "Caption": "標籤", + "Description": "描述", + "Role": "角色", + "Model": "模型", + "CreateBy": "創建人", + "Actions": "操作", + "Active": "啟用", + "EmailTemplates": "郵件模板", + "TemplateName": "模板名稱", + "Language": "語言", + "Subject": "主題", + "EmailBody": "郵件正文", + "Indicator": "指標", + "IndicatorGroup": "指標組", + "PermissionType": "權限類型", + "Approve": "同意", + "Refuse": "拒絕", + "Authorization": "授權", + "Compact": "緊湊", + "Username": "用戶名", + "Password": "密碼", + "Type": "類型", + "None": "無", + "Clear": "清空", + "Format": "美化", + "ShortcutKey": "快捷鍵", + "Minute": "分鐘", + "Off": "關閉", + "AutoRefresh": "自動刷新", + "Error": "錯誤", + "CurrentPassword": "當前密碼", + "NewPassword": "新密碼", + "ConfirmPassword": "確認密碼", + "Save": "保存", + "Profile": "配置", + "UpdatedAt": "更新於", + "NoData": "無數據", + "Copilot": "副駕駛", + "CalculatedFormula": "計算公式", + "Visits": "訪問量", + "UpdatedDate": "更新日期", + "SortBy": "排序", + "Role&Permissions": "角色 & 權限", + "SemanticModels": "語義模型", + "Stories": "故事", + "Indicators": "指標", + "IndicatorMarket": "指標市場" + }, + "MENU": { + "Certification": "認證", + "Copilot": "副駕駛", + "Dashboard": "儀錶板", + "Semantic Model": "語義模型", + "Story": "故事", + "Indicator": "指標", + "Indicator Market": "指標市場", + "Indicator Register": "指標註冊", + "My Indicator": "我的指標", + "Indicator App": "指標應用", + "Settings": "設置", + "General": "通用", + "Account": "賬號", + "User": "用戶", + "Datasource": "數據源", + "Business Area": "業務域", + "Role & Permission": "角色 & 權限", + "Feature": "功能", + "Email Template": "郵件模板", + "Custom SMTP": "自定義 SMTP", + "AGENT": "代理", + "LOCAL_AGENT": "本地代理", + "WASM_DB": "WASM 數據庫", + "Attributes": "屬性", + "CALCULATION": "計算", + "CALCULATED_MEMBERS": "計算成員", + "DIMENSIONS": "維度", + "ENTITY": "實體", + "MANUAL_REFRESH": "手動刷新", + "MEMBERS": "成員", + "MEASURES": "度量", + "PREVIEW": "預覽", + "QL_LAB": "查詢", + "RUN": "執行", + "RUN_BY_SELECTION": "執行選中語句", + "RESULTS": "結果", + "SHARED_DIMENSIONS": "公共維度", + "STORY_LIST": "故事", + "STRUCTURE": "結構", + "AddUsers": "添加用戶", + "InviteUsers": "邀請用戶", + "Authentication": "用戶認證", + "UserSettings": "用戶設置", + "ManageUsersAndInvites": "管理用戶和邀請", + "ORGANIZATIONS": "組織", + "FEATURES": "功能", + "USERS": "用戶", + "LOCAL_AGENT_STATUS": "本地代理狀態", + "ENABLED_PERMISSIONS": "角色啟用的權限", + "MANAGE_USERS": "管理用戶", + "MANAGE_ROLES": "管理角色 & 權限", + "MANAGE_FEATURES": "管理功能模塊", + "MANAGE_ORGANIZATIONS": "管理組織", + "MANAGE_TENANT": "管理租戶", + "EDIT_USER": "維護用戶", + "EDIT_BUSINESS_AREA": "編輯業務域", + "MY_ACCOUNT": "我的賬號", + "ForOrganization": "為組織", + "ManageCustomSmtp": "維護自定義 SMTP", + "Tenant": "租戶", + "Organization": "組織", + "Today": "今天", + "Catalog": "目錄", + "Trending": "熱門", + "Insights": "洞察", + "Home": "首頁", + "Project": "項目", + "Indicators": "指標", + "Data Sources": "數據源", + + "HOME": { + "TODAY": "今天", + "Catalog": "目錄", + "Trending": "熱門", + "Insight": "洞察", + "MyCatalog": "我的目錄", + "HELLO": "你好", + "SEARCH": "搜索", + "AskaQuestion": "詢問一個問題", + "Recents": "最近訪問", + "StoryRanking": "故事排名", + "All": "所有", + "My": "我的", + "GenerateSamples": "生成演示樣例", + "RegenerateSamples": "重新生成演示樣例", + "GeneratingSamples": "正在生成演示樣例", + "NoRelevantDigitalAssets": "未找到相關數字資產", + "ExploreASampleStory": "瀏覽一個故事樣例", + "CreateYourFirstSemanticModel": "創建第一個語義模型", + "HaveSemanticModels": "擁有 {{quantity}} 個語義模型", + "CreateYourFirstStory": "創建第一個故事", + "HaveStories": "擁有 {{quantity}} 個故事", + "CreateYourFirstIndicator": "創建第一個指標", + "HaveIndicators": "擁有 {{quantity}} 個指標", + "UpdateLayout": "更新布局" + }, + "USER": { + "BASIC": "基本屬性" + }, + "TENANT": { + "TITLE": "租戶", + "SETTINGS": "設置", + "DEMO": "演示數據" + }, + "MODEL": { + "CREATE_MODEL": "創建語義模型", + "SELECT_DATASOURCE": "選擇數據源", + "SELECT_CATALOG": "選擇目錄", + "BASIC_INFO": "基本信息", + "USE_MDX": "使用 MDX 建模", + "MY": "我的", + "ALL": "所有", + "SELECT_DATASOURCE_COLUMNS": { + "Name": "名稱", + "Type": "類型", + "Protocol": "協議", + "UseLocalAgent": "使用本地代理" + }, + "CATALOG_COLUMNS": { + "Name": "名稱", + "Type": "類型", + "Label": "描述" + } + }, + "STORY": { + "SELECT_BUSINESS_AREA": "選擇業務域", + "SELECT_SEMANTIC_MODEL": "選擇語義模型", + "STORY_NAME": "名稱", + "INPUT_UNIQUE_NAME": "輸入唯一名稱", + "ALL": "全部", + "FAVORITES": "收藏", + "WhatIsTheName": "故事叫什麼名稱", + "Description": "描述", + "DescriptionPlaceholder": "可選,故事的詳細描述", + "Model": "模型", + "StoryBusinessArea": "應該放在哪個業務域內" + }, + "STATUS_BAR": { + "TITLE": "狀態欄", + "ERROR_LOG": "錯誤日誌", + "NOTIFICATION": "通知", + "ClearAuthentication": "清除用戶認證" + }, + "INDICATOR": { + "REGISTER_INDICATOR": "註冊指標", + "BATCH_UPLOAD": "批量上傳", + "DownloadAsTemplate": "下載為模板", + "INDICATOR_MARKET": "指標市場", + "INDICATOR_MARKET_DESC": "瀏覽指標,申請指標權限" + }, + "GENERAL": { + "TITLE": "通用", + "LANGUAGE": "語言", + "LANGUAGE_PLACEHOLDER": "選擇語言", + "THEME": "主題" + }, + "DATA_SOURCES": { + "TYPE_SELECTION": "選擇類型", + "CONFIGURATION": "配置", + "NAME": "名稱", + "NAME_REQUIRED": "名稱必輸", + "USE_LOCAL_AGENT": "使用本地代理", + "DONE": "完成", + "AuthType": "授權方式", + "AuthType_None": "無", + "AuthType_Basic": "基本身份驗證" + }, + "Roles": { + "General": "通用", + "Administration": "管理員" + } + }, + "USERS_PAGE": { + "ADD_USER": "添加用戶" + }, + "ACTIONS": { + "Add": "添加", + "Cancel": "取消", + "New": "新建", + "Release": "發布", + "Open": "打開", + "Upload": "上傳", + "Remove": "刪除", + "APPLY": "應用", + "CreateIndicator": "創建指標", + "ADD_CALCULATED_MEMBER": "新增計算成員", + "CREATE_STORY": "創建故事", + "COPY": "複製", + "CREATE": "創建", + "CANCEL": "取消", + "SUBMIT": "提交", + "DELETE_SELECTED_ENTITY": "刪除當前實體", + "Download": "下載", + "Delete": "刪除", + "FORMAT_DOCUMENT": "格式化文檔", + "FORMAT_SELECTION": "格式化選中部分", + "NEW": "新建", + "NEW_HIERARCHY": "新建層次結構", + "REDO": "重做", + "REFRESH_DATA_SOURCE_SCHEMA": "刷新數據源綱要", + "REMOVE_CURRENT_HIERARCHY": "刪除當前層次結構", + "REMOVE_CURRENT_LEVEL": "刪除當前層級", + "SAVE": "保存", + "SHARE": "分享", + "UPLOAD": "上傳", + "UNDO": "撤銷", + "CLEAR": "清空", + "CLEAR_CACHE": "清空緩存", + "DOWNLOAD_AGENT": "下載代理", + "ADD": "添加", + "INVITE": "邀請", + "PREVIOUS": "上一步", + "NEXT": "下一步", + "CONFIRM_DELETE": "確認從服務器上刪除此記錄?", + "PING": "測試連接", + "CreateStory": "📖創建故事", + "CreateModel": "創建模型", + "Edit": "編輯", + "Generate": "生成演示數據", + "ManageInvites": "管理邀請", + "Save": "保存", + "Validate": "驗證", + "Connect": "連接", + "Uploading": "上傳中", + "Search": "搜索", + "Copy": "複製", + "NewTag": "新建標籤", + "Duplicate": "複製" + }, + "MESSAGE": { + "MAIN_ORGANIZATION_UPDATED": "組織更新成功", + "USER_ORGANIZATION_ADDED": "用戶組織添加成功", + "USER_ORGANIZATION_REMOVED": "用戶組織刪除成功", + "LocalAgentOffline": "本地代理離線", + "NameAlreadyExist": "名稱已存在", + "Required": "必輸", + "Update": "更新", + "StoryRunWithWasmModelOnMobileWarn": "在移動端上分析 WASM 模型可能會有性能限制,謹慎使用", + "PasswordChange": "密碼修改", + "NewVersionUpdate": "已獲取新版本。現在更新?", + "CreateStoryWidgetSuccess": "創建故事部件成功", + "CreateDataSource": "創建數據源", + "ConfirmExitDirtyData": "有未保存數據, 確認退出嗎?", + "Sure": "確定" + }, + "NOTES": { + "ORGANIZATIONS": { + "DELETE_CONFIRM": "確定從服務器上刪除此組織?", + "DELETE_ORGANIZATION": "組織'{{name}}'刪除成功", + "DEMO_GENERATE_ERROR": "演示數據生成錯誤", + "DEMO_GENERATED": "演示數據生成" + }, + "ROLES": { + "PERMISSION_UPDATED": "角色'{{name}}'更新成功", + "RoleCreate": "角色創建", + "RoleDelete": "角色刪除" + }, + "USERS": { + "UserDelete": "用戶'{{name}}'刪除", + "USER_DELETED": "用戶'{{name}}'刪除成功", + "USER_UPDATED": "用戶'{{name}}'更新" + }, + "TENANT": { + "DEMO_GENERATED": "演示數據生成" + }, + "STORY": { + "STORY_DELETED": "故事'{{name}}'刪除", + "UPLOAD_FILETYPE_ERROR": "上傳文件類型", + "READ_FILE": "讀取文件內容", + "STORY_UPLOAD": "故事上傳" + } + }, + "TOASTR": { + "TITLE": { + "SUCCESS": "成功", + "ERROR": "錯誤" + }, + "Updating": "{{value}}更新中。。。", + "UpdateDone": "{{value}}更新完成" + }, + "INDICATOR": { + "REGISTER": { + "Code": "編碼", + "CODE": "編碼", + "CODE_PLACEHOLDER": "指標唯一編碼", + "NAME": "名稱", + "NAME_PLACEHOLDER": "指標名稱", + "BUSINESS_AREA": "業務域", + "BUSINESS_AREA_PLACEHOLDER": "選擇所屬業務域", + "IsActive": "激活", + "AvailableInApplication": "指標應用適用", + "Visible": "是否可見", + "Visibility": "可見性", + "UNIT": "單位", + "UNIT_PLACEHOLDER": "度量單位", + "CREATED_BY": "創建人", + "CREATED_AT": "創建時間", + "PRINCIPAL": "負責人", + "Certification": "認證", + "PRINCIPAL_PLACEHOLDER": "業務負責人", + "AUTHENTICATION": "認證流程", + "AUTHENTICATION_PLACEHOLDER": "選擇認證流程", + "BUSINESS": "業務口徑", + "BUSINESS_PLACEHOLDER": "業務口徑詳細描述", + "VALIDITY": "有效期", + "VALIDITY_PLACEHOLDER": "有效期至", + "MODEL": "語義模型", + "MODEL_PLACEHOLDER": "選擇語義模型", + "ENTITY": "模型實體", + "ENTITY_PLACEHOLDER": "選擇模型實體", + "TYPE": "類型", + "TYPE_PLACEHOLDER": "選擇指標類型", + "TYPE_BASIC": "基礎指標", + "TYPE_DERIVE": "衍生指標", + "FORMULA": "計算公式", + "FORMULA_PLACEHOLDER": "指標計算公式", + "MEASURE": "度量", + "MEASURE_PLACEHOLDER": "選擇度量字段", + "DIMENSIONS": "自由維度", + "DIMENSIONS_PLACEHOLDER": "選擇自由維度", + "FILTERS": "篩選條件", + "STATUS": "狀態", + "BASIC_INFO": "基礎信息", + "MODEL_INFO": "模型信息", + "IndicatorsBulkCreate": "指標批量創建", + "New": "新建", + "SaveIndicator": "保存指標", + "CreateIndicator": "創建指標", + "RestrictiveCondition": "限定條件", + "Aggregator": "聚合類型", + "Calendar": "日曆維度", + "Tags": "標籤", + "IndicatorNotFound": "指標未找到", + "DeleteIndicator": "刪除指標" + }, + "MARKET": { + "REQUEST": "申請", + "RequestBusinessArea": "申請業務域", + "RequestIndicator": "申請指標", + "Tags": "標籤", + "Types": "類型" + }, + "MY_INDICATORS": { + "TITLE": "我的指標", + "EXPORT": "導出", + "REGISTER": "註冊", + "MY": "我的", + "ALL": "全部", + "Approvals": "審批" + }, + "VIEWER": { + "MARKET": "市場", + "EDIT": "編輯", + "REGISTER": "註冊", + "DELETE": "刪除", + "BASIC_INFORMATION": "基礎信息", + "MODEL_INFORMATION": "模型信息" + }, + "Indicator Name": "指標名稱", + "Indicator Code": "指標編碼", + "Business Area": "業務域", + "Authentication": "認證流程", + "Business": "業務口徑", + "Principal": "業務負責人", + "Validity": "有效期", + "Type": "類型", + "Model": "語義模型", + "Entity": "多維數據集", + "Filters": "限定條件", + "RestrictiveCondition": "限定條件", + "Free Dimensions": "自由維度", + "Measure": "度量", + "Formula": "計算公式", + "Unit": "單位", + "EditFormula": "為 {{name}} 編輯計算公式", + "Close": "關閉", + "Reset": "重置", + "Authorization": "授權", + "IndicatorTemplateFileName": "指標模版", + "PermissionRequested": "權限已申請", + "PermissionApproved": "權限已批准", + "PermissionRefused": "申請被拒絕", + "DeleteIndicator": "刪除指標", + "All": "所有", + "Derivative": "衍生指標", + "Basic": "基礎指標", + "IndicatorFormula": "指標計算公式", + "Import": "導入", + "Indicators": "指標", + "Types": "類型", + "IndicatorMarket": "指標市場", + "Certifications": "認證" + }, + "MODEL": { + "ModelOverview": "語義模型概覽", + "SharedDimensions": "公共維度", + "Cubes": "多維數據集", + "VirtualCubes": "虛擬數據集", + "Stories": "故事", + "Roles": "角色", + "Members": "成員", + "ClearServerCache": "清空服務端緩存", + "Type": "類型", + "DataSource": "數據源", + "CreatedBy": "創建人", + "UpdatedBy": "修改人", + "Actions": "操作", + "Name": "名稱", + "Indicators": "指標", + "IndicatorCode": "指標編碼", + "Reset": "重置", + "QueryName": "查詢的簡短名稱", + "CreateQuery": "創建查詢", + "QueryBaseModelPlaceholder": "想要查詢哪個模型空間", + "ModelName": "模型的名稱", + "ModelOwner": "模型擁有者", + "TransferOwnership": "轉移所有權", + "ModelMembers": "模型成員", + "DescriptionPlaceholder": "可選,語義模型的詳細描述", + "UploadModel": "上載模型", + "SaveAsDefaultCube": "保存為默認數據集", + + "QUERY": { + "TITLE": "查詢", + "SaveAsModel": "另存為模型", + "SaveAsDBInit": "另存為數據庫初始化腳本", + "TableSchema": "表結構", + "New": "新建查詢", + "TotalRecords": "總記錄數", + "PreviewTop1000": "最大預覽 1000 條", + "CopilotPlaceholder": "提出問題或請求,輸入 CTRL + Enter 發送", + "CopilotName": "查詢實驗室", + "EditorActions": { + "Nl2SQL": "自然語言轉SQL", + "Explain": "解釋", + "Optimize": "優化" + } + }, + "TOASTR": { + "MODEL_UPDATE": "模型更新", + "ModelSave": "模型保存", + "ModelCreate": "創建模型", + "ModelUpload": "上傳模型", + "ModelDelete": "刪除模型", + "DeleteModelPermanently": "永久刪除此模型" + }, + "MODEL": { + "Entities": "實體", + "TITLE": "模型", + "TABLES": "數據表", + "Preferences": "首選項", + "New": "新建", + "NewTable": "新建表", + "UploadTable": "上傳表", + "RefreshSchema": "刷新元數據", + "Name": "名稱", + "Description": "描述", + "DescriptionPlaceholder": "語義模型的詳細描述", + "DataSource": "數據源", + "DataCatalog": "數據目錄", + "Enable": "啟用", + "EnableServerCache": "啟用服務端緩存", + "CacheExpires": "緩存時間", + "CacheExpiresSecond": "緩存時長(秒)", + "Language": "語言", + "LanguageContext": "選擇語言上下文", + "Auto": "自動", + "Expose": "暴露", + "EnableExposeXMLA": "啟用 XMLA 接口", + "CreateStory": "創建故事", + "Visibility": "可見性", + "Visibility_Public": "公開", + "Visibility_Secret": "秘密", + "Visibility_Private": "私有", + "RemoveDBInitScript": "刪除數據庫初始化腳本", + "CopilotDefaultPrompts": [ + "將表創建為立方體", + "將表創建為維度" + ], + "CopilotName": "建模" + }, + "CREATE_ENTITY": { + "CREATE_ENTITY": "創建模型實體", + "TYPE": "類型", + "SELECT_TYPE": "選擇類型", + "CUBE": "多維數據集", + "DIMENSION": "維度", + "VirtualCube": "虛擬數據集", + "NAME": "名稱", + "INPUT_NAME": "輸入名稱", + "LABEL": "標籤", + "INPUT_LABEL": "輸入標籤", + "TABLE": "表", + "PICK_ONE_TABLE": "選擇一個表", + "CUBE_TABLE": "立方體的表", + "Field": "字段", + "Measure": "度量", + "AssociatedDimension": "關聯維度", + "PrimaryKey": "主鍵", + "Visible": "可見", + "Caption": "標籤" + }, + "CREATE_TABLE": { + "TITLE": "添加表", + "Name": "名稱", + "Type": "類型", + "Url": "鏈接", + "Delimiter": "分隔符", + "AddFile": "添加文件", + "DataPreview": "數據預覽", + "InputTableName": "輸入表名稱", + "HasHeader": "第一行是標題", + "DefaultDelimiter": "默認:,", + "DragandDropFile": "拖拽上傳文件", + "Or": "或", + "BrowseForFile": "瀏覽文件" + }, + "ENTITY": { + "NewDimension": "新建維度", + "NewMeasure": "新建度量", + "NewCalculatedMember": "新建計算成員", + "CALCULATION": { + "ROWS": "行", + "COLUMNS": "列", + "FILTERS": "過濾器", + "Refresh": "刷新", + "Pivot": "旋轉軸" + }, + "LeftKey": "左鍵", + "RightKey": "右鍵", + "Equal": "等於", + "OnekeyGeneration": "一鍵生成", + "OnekeyGenerateModel": "根據表字段劃分一鍵生成模型", + "SourceFields": "源字段", + "OnekeySync": "一鍵同步", + "OnekeySyncModel": "根據源模型定義一鍵同步模型", + "AllVisible": "所有可見", + "SelectAll": "全選", + "ConfirmOverwriteCube": "數據集已存在配置,確認覆蓋?", + "PleaseSelectFields": "請選擇字段!" + }, + "DIMENSION": { + "Levels": "層級", + "DimensionTables": "維度表", + "DataPreview": "數據預覽", + "Count": "計數", + "EditAttributes": "編輯屬性", + "SameLevelAlreadyExists": "相同層級已存在" + }, + "UPLOAD": { + "Title": "上傳數據文件", + "Files": "文件", + "Preview": "預覽", + "Key": "鍵", + "Import": "導入", + "Done": "完成", + "ImportMethod": "導入方式", + "Cover": "覆蓋", + "Append": "追加", + "Merge": "合併", + "Uploaded": "已上傳", + "Records": "條記錄", + "Preview50": "預覽前 50 條記錄", + "UploadText": "點擊選擇或拖拽文件到此區域進行上傳", + "UploadHint": "支持單個或批量文件上傳" + }, + "SCHEMA": { + "COMMON": { + "DATA": "數據", + "Table": "表", + "FactTable": "事實表", + "SQLExpression": { + "Dialect": "方言", + "Content": "值" + }, + "TITLE": "多維數據集", + "Modeling": "建模", + "Role": "角色", + "Name": "名稱", + "Label": "標籤", + "Value": "值", + "Column": "字段", + "Description": "描述", + "ForeignKey": "外鍵", + "ParentChild": "父子層級關係", + "Semantics": "語義", + "Semantic": "語義類型", + "Formatter": "格式化", + "Dimension": "維度", + "Hierarchy": "層次結構", + "Visible": "是否顯示", + "DataType": "數據類型", + "Property": "屬性", + "KeyExpression": "鍵表達式", + "NameExpression": "名稱表達式", + "CaptionExpression": "說明表達式", + "OrdinalExpression": "順序表達式", + "ParentExpression": "父字段表達式", + "Enabled": "啟用", + "Cache": "緩存", + "Caption": "標籤", + "None": "無", + "Unit": "單位", + "Decimal": "小數位" + }, + "CUBE": { + "TITLE": "多維數據集", + "Modeling": "建模", + "Name": "名稱", + "Label": "標籤", + "Table": "表", + "DefaultMeasure": "默認度量" + }, + "DimensionUsage": { + "Title": "共享維度" + }, + "DIMENSION": { + "TITLE": "維度", + "Modeling": "建模", + "Name": "名稱", + "Label": "標籤", + "DimensionType": "維度類型", + "DefaultHierarchy": "默認層次結構", + "KeyExpression": "鍵表達式", + "SQLExpression": { + "Dialect": "方言", + "Content": "值" + }, + "CaptionColumn": "文本字段", + "Column": "維度表主鍵", + "ForeignKey": "事實表外鍵" + }, + "HIERARCHY": { + "TITLE": "層次結構", + "Modeling": "建模", + "Name": "名稱", + "Label": "標籤", + "DimensionTable": "維度表", + "TableName": "表名", + "HasAll": "有 All 成員", + "AllMemberName": "All 成員名稱", + "AllMemberCaption": "All 成員標籤", + "AllLevelName": "All 層級名稱", + "PrimaryKey": "主鍵", + "PrimaryKeyTable": "主鍵表", + "JoinTable": "關聯表", + "Table": "表", + "LeftKey": "左鍵", + "RightKey": "右鍵", + "RightAlias": "右表別名", + "DefaultMember": "默認成員" + }, + "LEVEL": { + "Level": "層級", + "Modeling": "建模", + "Name": "名稱", + "Label": "標籤", + "Property": "屬性", + "PropertyExpression": "屬性表達式", + "Dialect": "方言", + "Content": "值", + "Column": "字段", + "Type": "值類型", + "Type_Null": "無", + "Type_String": "字符串", + "Type_Integer": "整數", + "Type_Numeric": "數值", + "Type_Boolean": "布爾", + "Type_Date": "日期", + "Type_Time": "時間", + "Type_Timestamp": "時間戳", + "UniqueMembers": "成員唯一", + "NameColumn": "名稱字段", + "CaptionColumn": "說明字段", + "OrdinalColumn": "順序字段", + "ParentColumn": "父級字段", + "ChildColumn": "子字段", + "NullParentValue": "父字段空", + "TimeLevelType": "層級時間類型", + "Table": "表", + "HideMemberIf": "隱藏成員", + "ClosureTable": "閉合表", + "KeyExpression": "鍵表達式", + "CaptionExpression": "說明表達式", + "ParentChild": "父子層級關係", + "Semantics": "語義", + "SQLExpression": { + "Dialect": "方言", + "Content": "值" + } + }, + "CALCULATED_MEMBER": { + "Title": "計算成員", + "Formula": "公式", + "Parent": "父級成員", + "SolveOrder": "求解次序" + }, + "MEASURE": { + "Title": "度量", + "Aggregator": "聚合類型", + "FormatString": "格式化", + "MeasureExpression": "度量表達式", + "FORMATTING": { + "Title": "數據格式", + "ShortNumber": "縮寫數字", + "DecimalFormatter": "數字格式化", + "Unit": "單位" + } + } + }, + "AccessControl": { + "Title": "訪問控制", + "Name": "名稱", + "NewRole": "新建角色", + "RoleCreate": "角色創建", + "Cubes": "多維數據集", + "Access": "訪問控制", + "Overview": "訪問控制概覽", + "RolesManage": "角色管理", + "UsersManage": "用戶管理", + "RoleOverview": "角色概覽", + "DefaultAccess": "默認訪問", + "Access_all": "所有", + "Access_all_dimensions": "所有維度", + "Access_custom": "自定義", + "Access_none": "無", + "RollupPolicy": "匯總策略", + "RollupPolicy_full": "全部", + "RollupPolicy_partial": "部分", + "RollupPolicy_hidden": "隱藏", + "TopLevel": "最高層級", + "BottomLevel": "最低層級", + "Roles": "角色", + "Type": "類型", + "SingleRole": "標準角色", + "UnionRole": "複合角色", + "DimensionHierarchyAlreadyExists": "維度或層次結構已存在!", + "MemberAlreadyExists": "成員已存在!", + "MeasureAlreadyExists": "度量已存在!", + "DragandDropAddDimension": "拖放以添加維度" + }, + "VirtualCube": { + "VirtualCube": "虛擬多維數據集", + "CubeUsages": "使用的多維數據集", + "NewCalculatedMember": "新建計算成員", + "IgnoreUnrelatedDimensions": "忽略不相關維度", + "SharedDimension": "共享維度", + "CubeAlreadyExists": "多維數據集已存在!", + "DimensionAlreadyExists": "維度已存在!", + "MeasureAlreadyExists": "度量已存在!" + } + }, + "BUSINESS_AREA": { + "All": "所有", + "BASIC": "基本屬性", + "Delete": "刪除", + "Update": "更新", + "RemoveUser": "刪除用戶", + "BASIC_INFO_FORM": { + "Name": "名稱" + }, + "BusinessAreaRole": { + "Modeler": "編輯者", + "Viewer": "查看者" + } + }, + "SHARED": { + "USER_BASIC": { + "firstName": "名 (可選)", + "lastName": "姓 (可選)", + "Username": "用戶名", + "Email": "郵箱", + "Passwrod": "密碼", + "RepeatPasswrod": "重複密碼", + "Role": "角色", + "PreferredLanguage": "首選語言", + "ImageURL": "圖片鏈接 (可選)" + }, + "User": { + "NameEmail": "名稱,郵箱" + }, + "SMTP": { + "Host": "域名", + "Port": "端口", + "Secure": "安全", + "Username": "用戶名", + "Password": "密碼", + "True": "是", + "False": "否" + }, + "Assets": { + "RecentlyViewed": "最近訪問", + "NoRelevantDigitalAssets": "未找到相關數字資產" + }, + "StoryCard": { + "LastUpdated": "最後更新", + "Open": "查看" + } + }, + "INVITE_PAGE": { + "ForOrganization": "為組織", + "INVITATION_EXPIRATION_OPTIONS": { + "DAY": "一日", + "WEEK": "一周", + "TWO_WEEK": "兩周", + "MONTH": "一月", + "NEVER": "永不" + }, + "Email": "郵箱", + "Role": "角色", + "InvitedBy": "邀請人", + "CreatedAt": "創建時間", + "Expires": "過期時間", + "Action": "操作", + "Status": "狀態", + "STATUS": { + "INVITED": "邀請中", + "ACCEPTED": "已接受", + "EXPIRED": "過期" + } + }, + "Header": { + "Organization": { + "AllOrg": "所有組織" + } + }, + "DataSources": { + "Schema": { + "Host": "主機", + "Port": "端口號", + "Path": "路徑", + "Username": "用戶名", + "Password": "密碼", + "Database Name": "數據庫名", + "Use SSL": "使用加密連接", + "CA certificate": "CA 證書", + "Client certificate": "客戶端證書", + "Client key": "客戶端密鑰", + "Disable reject cert": "禁用證書驗證", + "ApiHost": "接口主機", + "ApiPort": "接口端口號", + "Catalog": "目錄", + "Database": "數據庫", + "Version": "版本" + } + }, + "Story": { + "EditStory": "編輯故事", + "DuplicateStory": "複印故事", + "DownloadStory": "下載故事", + "AutoRefresh": "自動刷新", + "RemoveBookmark": "取消收藏", + "Bookmark": "收藏", + "Fullscreen": "全屏", + "ExitFullscreen": "退出全屏", + "Released": "已發布", + "Draft": "草稿", + "ConfirmChangingReleasedStory": "故事已經發布,確認再次編輯嗎", + "GlobalFilterBar": "全局過濾器", + "BorderImageSlice": "邊框切片", + "Shadow": "陰影", + "ShadowOffsetX": "偏移 X", + "ShadowOffsetY": "偏移 Y", + "ShadowBlur": "模糊", + "ShadowSpread": "擴展", + "PresetImages": "預設圖片", + "StoryStyles": "故事樣式", + "Padding": "內邊距", + "BorderRadius": "邊框半徑", + "BackgroundColor": "背景顏色", + "BackgroundImage": "背景圖片", + "BorderImage": "邊框圖片", + "Border": "邊框", + "BorderWidth": "邊框寬度", + "BorderStyle": "邊框樣式", + "PresetBackgroundImages": "預設背景圖片", + "Color": "顏色", + "TextAlign": "文本對齊", + "FontSize": "字體大小", + "FontFamily": "字體", + "FontWeight": "字重", + "ChooseFontFamily": "選擇字體", + "ChooseFontWeight": "選擇字重", + "CustomImages": "自定義圖片", + "GlobalStyles": "全局樣式", + "Transform": "變換", + "TransformOrigin": "變換原點", + "BackgroundSize": "背景大小", + "BackgroundRepeat": "背景重複", + "BoxShadow": "盒子陰影", + "TextShadow": "文本陰影", + "BackdropFilter": "背景濾鏡", + "Filter": "濾鏡", + "Opacity": "透明度" + }, + "Project": { + "Project": "項目", + "NewProject": "新建項目", + "Certifications": "認證", + "AddCertification": "添加認證", + "RemoveCertification": "移除認證", + "CertificationAlreadyAdded": "認證已添加", + "DefaultProject": "默認", + "Name": "名稱", + "WhatIsTheName": "你的項目名稱", + "Description": "描述", + "DescriptionPlaceholder": "你的項目描述", + "DefaultCollection": "默認", + "Home": "首頁", + "Bookmarks": "收藏夾", + "Collection": "工作集", + "Collections": "工作集", + "CollectionName": "名稱", + "WhatIsTheCollectionName": "你工作集的名稱", + "CollectionPlaceholder": "應該放在哪個工作集內", + "MoveToCollection": "移動到工作集", + "SemanticModels": "語義模型", + "Members": "成員", + "Create": "創建", + "NewCollection": "新建集", + "RemoveCollection": "刪除集", + "NewStory": "新建故事", + "Release": "發布", + "Rerelease": "重新發布", + "Archive": "下線", + "ConfirmArchiveStory": "確定要下線此故事嗎?", + "MoveTo": "移動到", + "Copy": "複製", + "CopyStory": "複製故事", + "Remove": "刪除", + "AddModel": "添加模型", + "RemoveModel": "刪除模型", + "RemoveBookmark": "取消收藏", + "ParentCollection": "父集", + "RecentUpdates": "最近更新", + "ClicktoUpload": "點擊上傳", + "OrDragandDrop": "或者拖放", + "StoryJsonFile": "故事 JSON 文件", + "ProjectMembers": "項目成員", + "Inner": "內部", + "Public": "公開", + "StoryReleased": "故事發布", + "ProjectOwner": "項目所有者", + "TransferOwnership": "轉移所有權", + "CreateStory": "創建故事", + "Manage": "管理", + "DeleteProject": "刪除項目", + "ConfirmDelete": "確定刪除", + "AddModels": "添加語義模型", + "ManageIndicators": "管理指標", + "Indicators": "指標", + "Templates": "模板", + "AddSemanticModels": "添加語義模型", + "New": "新建", + "Files": "文件" + }, + "Certification": { + "Certification": "認證", + "UpdateCertification": "更新認證", + "DeleteCertification": "刪除認證", + "CreateCertification": "創建認證" + }, + "Copilot": { + "Copilot": "Copilot", + "AICopilot": "AI 副駕駛", + "EnableCopilot": "啟用 Copilot", + "GetYourApiKey": "獲取你的 API Key", + "ProvideOpenaiApiKey": "請提供 Openai API Key?", + "Provider": "提供商", + "YourAIPairProgrammer": "你的 AI 配對程序員!", + "LetYourAIPairProgrammerEdits": "讓你的 AI 配對程序員修改一下!", + "SelectSomeCode": "選擇代碼,讓你的 AI 配對程序員修改一下!", + "ThinkingHard": "努力思考中...", + "StopGenerating": "停止生成", + "ClearMessages": "清空消息", + "CharacterLength": "字數", + "Resubmit": "重新提交", + "Model": "模型", + "Options": "選項", + "UseSystemPrompt": "使用系統提示", + "ExamplesOfPrompts": "提示語示例", + "APIKey": "API 密鑰", + "APIHost": "API 主機", + "Prompts": { + "Set story theme dark": "設置故事暗黑主題", + "Set story gradient background color sense of technology": "設置故事背景為科技感漸變色", + "Set widget transparent background": "設置部件透明背景", + "Chart series set line smooth": "圖形系列設定線平滑", + "Chart series set bar max width 20, rounded, shadow": "圖形系列設定條形圖最大寬度 20,圓角,陰影", + "Chart series add average mark line": "圖形系列添加平均標記線", + "Chart category axis line width 2, show axis tick": "圖形分類軸線寬度 2,顯示軸線刻度", + "Data analysis": "分析數據" + } + }, + "Home": { + "Insight": { + "CreateSemanticModelForUse": "添加到故事:創建語義模型後才能使用", + "AddWidgetToStoryTitle": "將部件添加到故事" + } + }, + "ApprovalPolicy": { + "BUSINESS_AREA": "業務域", + "INDICATOR": "指標" + }, + "Onboarding": { + "Welcome": "歡迎使用 Metad 分析平台", + "WelcomeInfo": "看起來一切都正常。 現在讓我們認識您,連接到你的數據,並開始為您尋找一些答案!", + "LetGetStarted": "讓我們開始吧", + "FeelStuck": "如果您感到困惑", + "OurGuide": "我們的入門指南", + "ClickAway": "只需一次點擊即可獲得", + "WhatsPreferredLanguage": "您更喜歡哪種語言?", + "PreferredLanguageDescription": "這種語言將會被用於Metad分析平台中,並且將會是新用戶的默認語言。", + "Next": "下一步", + "WhatCallYou": "我們應該怎麼稱呼您", + "CompanyTeamName": "公司或組織名稱", + "CreateAPassword": "創建一個密碼", + "Email": "郵箱", + "FirstName": "名", + "LastName": "姓", + "Minlength": "最小長度", + "Actuallength": "實際長度", + "ConfirmYourPassword": "確認密碼", + "PasswordMustMatch": "密碼不一致", + "WantGenerateDemo": "是否想要生成演示數據", + "GenerateDemoDescription": "系統將從服務器鏈接上下載演示數據文件,並將數據導入至系統數據庫中,然後創建相應的演示樣例", + "Skip": "跳過", + "Generate": "生成", + "Retry": "重試", + "AddYourData": "添加您的數據", + "ReadyExploringYourData": "準備好開始探索您的數據了嗎?在下面添加它吧。", + "NotReadySample": "還沒有準備好?跳過並玩玩我們的示例吧。", + "DisplayName": "顯示名稱", + "NameRequired": "名稱不能為空", + "AddDataLater": "我稍後添加我的數據", + "ConnectDatabase": "連接數據庫", + "Done": "完成", + "AllSetup": "您已經設置好了!", + "TakeMetoMetadAnalyticsPlatform": "帶我去 Metad 分析平台", + "SelectNetwork": "選擇所需網絡", + "GenerateDemoSuccess": "演示數據和樣例生成成功!" + }, + "Languages": { + "en": "英文", + "en-US": "美國英文", + "zh": "中文", + "zh-CN": "中文", + "zh-Hans": "簡體中文", + "zh-Hant": "繁體中文" + }, + "Users": { + "NoMoreOrganizations": "沒有更多的組織可添加" + }, + "title": { + "short": "分析雲" + }, + "menu": { + "home": "主頁", + "settings": "設置", + "login": "登錄/註冊", + "profile": "簡況", + "logout": "退出", + "connection": "連接", + "create": { + "title": "創建", + "story": "故事", + "model": "模型" + }, + "browse": { + "title": "瀏覽", + "story": "故事" + }, + "xmla": { + "designer": "查詢設計器" + }, + "security": "安全" + }, + "settings": { + "title": "設置", + "language": "語言", + "theme": "主題" + }, + "connection": { + "menu": { + "data-sources": "數據源", + "connections": "系統連接" + } + }, + + "ORGANIZATIONS_PAGE": { + "PERMISSIONS": { + "ADMIN_DASHBOARD_VIEW": "查看 Admin 儀錶盤", + "ORG_COPILOT_EDIT": "配置 Copilot", + "MODELS_VIEW": "查看模型", + "MODELS_EDIT": "編輯模型", + "STORIES_VIEW": "查看故事看板", + "STORIES_EDIT": "編輯故事看板", + "BUSINESS_AREA_VIEW": "查看業務域", + "BUSINESS_AREA_EDIT": "編輯業務域", + "INDICATOR_VIEW": "查看指標", + "INDICATOR_MARTKET_VIEW": "查看指標應用", + "INDICATOR_EDIT": "編輯指標", + "INSIGHT_VIEW": "查看洞察", + "INSIGHT_EDIT": "編輯洞察", + "SUBSCRIPTION_VIEW": "查看訂閱", + "SUBSCRIPTION_EDIT": "編輯訂閱", + "ORG_PAYMENT_VIEW": "View Payments", + "ORG_PAYMENT_ADD_EDIT": "Create/Edit/Delete Payments", + "ORG_EXPENSES_VIEW": "View All Expenses", + "ORG_EXPENSES_EDIT": "Create/Edit/Delete Expenses", + "EMPLOYEE_EXPENSES_VIEW": "View All Employee Expenses", + "EMPLOYEE_EXPENSES_EDIT": "Create/Edit/Delete Employee Expenses", + "ORG_INCOMES_EDIT": "Create/Edit/Delete Incomes", + "ORG_INCOMES_VIEW": "View All Incomes", + "ORG_PROPOSALS_EDIT": "Create/Edit/Delete Proposals Register", + "ORG_PROPOSALS_VIEW": "View Proposals Page", + "ORG_PROPOSAL_TEMPLATES_VIEW": "View Proposal Templates Page", + "ORG_PROPOSAL_TEMPLATES_EDIT": "Create/Edit/Delete Proposal Templates", + "ORG_TIME_OFF_VIEW": "View Time Off Page", + "ORG_EMPLOYEES_VIEW": "View Organization Employees", + "ORG_EMPLOYEES_EDIT": "Create/Edit/Delete Organization Employees", + "ORG_CANDIDATES_VIEW": "View Organization Candidates", + "ORG_CANDIDATES_EDIT": "Create/Edit/Delete Organization Candidates", + "ORG_USERS_VIEW": "View Organization Users", + "ORG_USERS_EDIT": "Create/Edit/Delete Organization Users", + "ORG_INVITE_VIEW": "View Organization Invites", + "ORG_INVITE_EDIT": "Create/Resend/Delete Invites", + "ORG_CANDIDATES_DOCUMENTS_VIEW": "View All Candidates Documents", + "ORG_CANDIDATES_TASK_EDIT": "Create/Edit Task", + "ORG_CANDIDATES_INTERVIEW_EDIT": "Create/Edit Interview", + "ORG_INVENTORY_PRODUCT_EDIT": "Management Product", + "ORG_TAGS_EDIT": "Create/Edit/Delete Tags", + "ORG_CANDIDATES_FEEDBACK_EDIT": "Create/Edit/Delete Candidate Feedback", + "ALL_ORG_VIEW": "View All Organizations", + "ALL_ORG_EDIT": "Create/Edit/Delete All Organizations", + "POLICY_VIEW": "View Time Off Policy", + "POLICY_EDIT": "Edit Time Off Policy", + "CHANGE_SELECTED_EMPLOYEE": "Change Selected Employee", + "CHANGE_SELECTED_CANDIDATE": "Change Selected Candidate", + "CHANGE_SELECTED_ORGANIZATION": "Change Selected Organization", + "CHANGE_ROLES_PERMISSIONS": "Change Roles & Permissions", + "ACCESS_PRIVATE_PROJECTS": "Access Private Projects", + "TIMESHEET_EDIT_TIME": "Edit Time in Timesheet", + "SUPER_ADMIN_EDIT": "Edit Super Admin Users", + "INVOICES_VIEW": "View Invoices", + "INVOICES_EDIT": "Edit Invoices Add", + "ESTIMATES_VIEW": "View Estimates", + "ESTIMATES_EDIT": "Edit Estimates Add", + "EDIT_SALES_PIPELINES": "Edit Sales Pipelines", + "VIEW_SALES_PIPELINES": "View Sales Pipelines", + "APPROVALS_POLICY_EDIT": "Edit Approvals Policy", + "APPROVALS_POLICY_VIEW": "View Approvals Policy", + "REQUEST_APPROVAL_EDIT": "Edit Approval Request", + "REQUEST_APPROVAL_VIEW": "View Approval Request", + "ORG_CANDIDATES_INTERVIEWERS_EDIT": "Create/Edit Interviewers", + "VIEW_ALL_EMAILS": "View All Emails", + "VIEW_ALL_EMAIL_TEMPLATES": "View All Emails Templates", + "ORG_HELP_CENTER_EDIT": "Edit Organization Help Center", + "PUBLIC_PAGE_EDIT": "Edit Organization Public Page", + "CAN_APPROVE_TIMESHEET": "Approve Timesheet", + "EVENT_TYPES_VIEW": "View Event Types", + "TIME_OFF_EDIT": "Edit Time Off", + "ORG_INVENTORY_VIEW": "View Organization Inventory", + "INVENTORY_GALLERY_VIEW": "View Inventory Gallery", + "INVENTORY_GALLERY_EDIT": "Edit Inventory Gallery", + "ORG_EQUIPMENT_VIEW": "View Organization Equipment", + "ORG_EQUIPMENT_EDIT": "Edit Organization Equipment", + "ORG_EQUIPMENT_SHARING_VIEW": "View Organization Equipment Sharing", + "ORG_EQUIPMENT_SHARING_EDIT": "Edit Organization Equipment Sharing", + "EQUIPMENT_MAKE_REQUEST": "Request Make Equipment Make", + "EQUIPMENT_APPROVE_REQUEST": "Request Approve Equipment", + "ORG_PRODUCT_TYPES_VIEW": "View Organization Product Types", + "ORG_PRODUCT_TYPES_EDIT": "Edit Organization Product Types", + "ORG_PRODUCT_CATEGORIES_VIEW": "View Organization Product Categories", + "ORG_PRODUCT_CATEGORIES_EDIT": "Edit Organization Product Categories", + "VIEW_ALL_ACCOUNTING_TEMPLATES": "View All Accounting Templates", + "GROUPS": { + "GENERAL": "General", + "ADMINISTRATION": "Administration" + }, + "ONLY_ADMIN": "These permissions are read-only and enabled only for admin", + "INSUFFICIENT": "You do not have sufficient permissions. The following permissions are missing:", + "ORG_SPRINT_EDIT": "Create/Edit Sprints", + "ORG_SPRINT_VIEW": "View Sprints", + "ORG_PROJECT_EDIT": "Create/Edit Projects", + "ORG_CONTACT_EDIT": "Create/Edit Contacts", + "ORG_CONTACT_VIEW": "View Contacts", + "ORG_TEAM_EDIT": "Create/Edit Teams", + "ORG_CONTRACT_EDIT": "Create/Edit Contracts", + "TIME_TRACKER": "Access Time Tracker", + "TENANT_ADD_EXISTING_USER": "Tenant Add User To Organization", + "INTEGRATION_VIEW": "View Integrations", + "FILE_STORAGE_VIEW": "View File Storage", + "PAYMENT_GATEWAY_VIEW": "View Payment Gateway", + "SMS_GATEWAY_VIEW": "View SMS Gateway", + "CUSTOM_SMTP_VIEW": "View Custom SMTP", + "IMPORT_EXPORT_VIEW": "View Import/Export", + "ORG_JOB_EMPLOYEE_VIEW": "查看任務員工", + "ORG_JOB_MATCHING_VIEW": "查看任務匹配", + "TENANT_SETTINGS": "租戶設置表", + "ACCESS_DELETE_ACCOUNT": "訪問刪除賬號", + "ACCESS_DELETE_ALL_DATA": "訪問刪除所有數據", + "ORG_DEMO_EDIT": "維護組織演示樣例" + }, + "Organization": { + "AllOrganizations": "所有組織", + "MAIN": "主屬性", + "DEMO": "演示數據", + "GENERATE_DEMO": "生成演示數據", + "RegenerateDemo": "重新生成演示數據", + "TotalEmployees": "總員工數", + "BasicInfo": "基礎信息", + "OtherInfo": "其他信息", + "Name": "名稱", + "OrganizationName": "組織名稱", + "IsDefault": "默認", + "SetAsDefault": "設置為默認組織", + "IsActive": "啟用", + "ActiveOrganization": "激活組織", + "DefaultValueDateType": "默認日期類型", + "InvitesAllowed": "允許邀請", + "InviteExpiryPeriod": "邀請過期時間(天)", + "EnableInvitesAllowed": "啟用邀請用戶", + "ProfileLink": "主頁鏈接", + "OfficialName": "組織全稱", + "ShortDescription": "組織簡介", + "Website": "網站鏈接", + "SelectDataNetwork": "選擇數據網絡" + } + } + }, + "AUTH": { + "APP_NAME": "分析雲", + "LOGIN": { + "ACCOUNT": "賬號", + "USERNAME": "用戶名/郵箱", + "PASSWORD": "密碼", + "REMEMBER": "記住", + "FORGOT-PASSWORD": "忘記密碼", + "SIGNUP": "沒有賬號-註冊", + "SUBMIT": "登錄", + "FEISHU": "飛書", + "DINGTALK": "釘釘", + "GITHUB": "Github" + }, + "REGISTER": { + "REGISTER": "註冊", + "EMAIL": "郵箱", + "PASSWORD": "密碼", + "CONFIRM_PASSWORD": "確認密碼", + "SIGN-IN": "已有賬號-登錄", + "SUBMIT": "註冊" + } + }, + "STORY": { + "COMMON": { + "APPLY": "應用", + "RESET": "重置", + "CANCEL": "取消", + "CONFIRM": "確定", + "CLEAR": "清空", + "SEARCH": "搜索" + }, + "WIDGET": { + "MENU": { + "LINKED_ANALYSIS": "關聯分析", + "COPY": "複製", + "COPY_TO": "複製到", + "DUPLICATE": "複印", + "ADD": "添加", + "FULLSCREEN": "全屏", + "EXIT_FULLSCREEN": "退出全屏", + "NAVIGATE": "轉到", + "FOCUS": "聚焦", + "PIN": "固定到主屏幕", + "SUBSCRIPTIONS": "訂閱", + "ALERTS": "預警", + "SHARE": "分享", + "REFRESH": "刷新", + "REMOVE": "刪除", + "NEW_RESPONSIVE_PAGE": "新響應頁面", + "NEW_CANVAS_PAGE": "新畫布頁面" + } + }, + "WIDGETS": { + + "FilterBar": { + "Query": "查詢" + }, + "AccountingStatement": { + "Unit": "單位" + } + }, + "DESIGNER": { + "SUBMIT": "提交", + "CANCEL": "取消", + "DELETE": "刪除" + } + + }, + "STORY_DESIGNER": { + "BUILDER_TITLE": "構建", + "STYLING_TITLE": "樣式", + "COMMON": { + "Appearance": "外觀", + "Float_Label": "浮動標籤", + "Display_Density": "顯示密度", + "Label": "標籤", + "Placeholder": "占位符", + "Widget": "組件", + "OPTIONS": "設置", + "DensityComfortable": "舒適", + "DensityCosy": "適中", + "DensityCompact": "緊湊", + "Title": "標題", + "Autocomplete": "自動補全", + "ControlType": "控制器類型", + "ControlOptions": "控制器選項", + "SelectionType": "值類型", + "SingleValue": "單值", + "MultiValue": "多值", + "SingleInterval": "單間隔", + "SingleRange": "單區間", + "MaxTagCount": "最大標籤數量", + "AutoActiveFirst": "自動激活第一選項", + "Searchable": "可搜索", + "CascadingEffect": "級聯過濾", + "Granularity": "時間粒度", + "GranularitySequence": "粒度序列", + "TimeFormatter": "時間格式", + "DefaultTimeFunction": "默認時間函數", + "DefaultTime": "默認時間", + "Single": "單值", + "TreeSelect": "樹狀選擇", + "FlatSelect": "平鋪選擇", + "DropDownList": "下拉選擇", + "Auto": "自動" + }, + "BUILDER": { + "COMMON": { + "Title": "標題", + "Options": "設置", + "initialHierarchyLevel": "初始展示層級", + "None": "默認", + "Display_Density": "顯示密度", + "DensityComfortable": "舒適", + "DensityCosy": "適中", + "DensityCompact": "緊湊" + }, + "TITLE": "標題", + "SemanticModel": "語義模型", + "Entity": "模型實體", + "CALCULATED_MEMBER": "計算成員", + "DATA": "數據", + "DATA_SETTINGS": "數據配置", + "DATA_SOURCE": "數據源", + "ENTITY_SET": "模型", + "COMPONENT_TYPE": "組件類型", + "MODELING": "建模", + "NAME": "名稱", + "LABEL": "標籤", + "SELECTION_VARIANT": "選擇條件", + "SELECT_OPTIONS": "過濾器", + "PRESENTATION_VARIANT": "展示變式", + "TOP": "前", + "SORT_BY": "排序", + "BY_FIELD": "字段", + "DRILL_DOWN": "下鑽維度", + "DATE": {}, + "SELECTION_FIELDS_ANNOTATION": { + "DIMENSIONS": "維度" + }, + "FILTER_BAR": { + "TITLE": "過濾器欄", + "OPTIONS": "設置", + "LIVE_MODE": "實時查詢", + "CascadingEffect": "級聯聯動", + "CascadingType": "級聯類型", + "CascadingType_Default": "默認", + "CascadingType_InTurn": "從前到後", + "CascadingType_All": "所有", + "EnableToday": "啟用當前時間輸入" + }, + "WIDGET": { + "ANALYTICAL_CARD": "分析卡片", + "ACCOUNTING_STATEMENT": "財務報表", + "INDICATOR_CARD": "指標卡片", + "TABSET": "選項卡" + }, + "CHART": { + "DIMENSIONS": "維度", + "MEASURES": "度量", + "RealTimeLinkedAnalysis": "實時聯動分析", + "DisableContextMenu": "禁用上下文菜單", + "ShowDataButton": "顯示數據按鈕", + "HideHeader": "隱藏標題欄", + "HideDataDownload": "隱藏數據下載", + "HideScreenshot": "隱藏截圖", + "MaximumLimit": "最大數據量限制", + "DigitInfo": "數字格式", + "TrellisHorizontal": "格子橫向個數", + "UniversalTransition": "全局過渡動畫", + "CustomLogic": "自定義邏輯", + "Color": "顏色", + "Enabled": "啟用", + "ShowDecal": "顯示貼花", + "Decals": "貼花圖案", + "Options": "選項", + "ChartSettings": "圖形配置", + "ChartVariants": "圖形變體", + "ReferenceLine": { + "Title": "創建參考線", + "ReferenceLine": "參考線", + "removeLabel": "刪除", + "Label": "名稱", + "Type": "展示類型", + "MarkLine": "標記線", + "MarkPoint": "標記點", + "ValueType": "值類型", + "Fixed": "固定", + "Dynamic": "動態", + "Value": "值", + "Aggregation": "聚合類型", + "Min": "最小值", + "Max": "最大值", + "Average": "平均值", + "Median": "中位數" + } + }, + "SELECTION_PRESENTATION_VARIANTS": { + "TITLE": "選擇展示變式" + }, + "Filter": { + "Autocomplete": "自動補全", + "InitialLevel": "初始層級", + "VirtualScroll": "虛擬滾動", + "Multiple": "多選", + "Searchable": "可搜索", + "MaxTagCount": "最大標籤數量", + "AutoActiveFirst": "自動激活第一選項", + "USER_DEFINED_DATA": "用戶自定義數據", + "Value": "值", + "Label": "標籤", + "PanelWidth": "下拉麵板寬度" + }, + "IndicatorCard": { + "Options": "指標配置", + "Alias": "指標別名", + "Indicator": "指標", + "IndicatorType": "類型", + "YoYType": "同比類型", + "DisabledYoy": "禁用同比", + "DisabledTrend": "禁用趨勢圖", + "DigitsInfo": "數字格式", + "Indicators": "明細指標", + "LookBack": "回顧期間數" + }, + + "IFrame": { + "SRC": "src" + }, + "AccountingStatement": { + "Options": "配置", + "TableName": "表名稱", + "Denominator": "縮放因子", + "DenominatorUnit": "縮放後單位", + "MeasuresOptions": "度量設置", + "Measure": "度量", + "PeriodFunctionsCURRENT": "當期", + "PeriodFunctionsYTD": "年累計", + "PeriodFunctionsPYSM": "去年同期", + "PeriodFunctionsMPM": "上期", + "PeriodFunctionsYOY": "同比", + "PeriodFunctionsMOM": "環比", + "ColumnName": "列名", + "IsRatio": "比率", + "IsSemanticColor": "語義顏色", + "ReverseSemanticColor": "反轉顏色", + "Indicators": "指標列表配置", + "Indicator": "指標", + "IndicatorAlias": "別名", + "GroupName": "分組名", + "DigitsInfo": "數字格式", + "DigitsUnit": "數字單位", + "IsItalic": "斜體", + "IsUnderline": "下劃線" + } + }, + "STYLING": { + "CSS": { + "BACKGROUND": { + "TITLE": "背景", + "BackgroundColor": "背景顏色", + "Background": "背景", + "BackgroundImage": "背景圖片", + "BackgroundPosition": "背景位置", + "BackgroundSize": "背景大小", + "BackgroundRepeat": "背景重複", + "BackdropFilter": "背景濾鏡", + "Opacity": "不透明度", + "BackgroundAttachment": "背景附着", + "None": "無" + }, + "BOX": { + "TITLE": "盒子", + "BoxShadow": "盒子陰影", + "BorderWidth": "邊框大小", + "BorderColor": "邊框顏色", + "BorderRadius": "邊框半徑", + "BorderStyle": "邊框樣式" + }, + "LAYOUT": { + "TITLE": "布局", + "Padding": "填充空白", + "Margin": "邊緣空白", + "Overflow": "溢出" + }, + "SIZE": { + "TITLE": "大小", + "Width": "寬度", + "Height": "高度", + "MinWidth": "最小寬度", + "MinHeight": "最小高度", + "MaxWidth": "最大寬度", + "MaxHeight": "最大高度" + }, + "FONT": { + "TITLE": "字體", + "None": "無", + "FontSize": "字體大小", + "FontColor": "字體顏色", + "FontFamily": "字體", + "FontStyle": "字體樣式", + "FontWeight": "字重", + "TextDecoration": "文本裝飾", + "TextAlign": "文本對齊", + "TextDecoration_Overline": "上劃線", + "TextDecoration_Underline": "下劃線", + "TextDecoration_LineThrough": "刪除線", + "TextAlign_Left": "左對齊", + "TextAlign_Center": "居中", + "TextAlign_Right": "右對齊", + "TextAlign_Top": "頂端對齊", + "TextAlign_Middle": "垂直居中", + "TextAlign_Bottom": "底對齊", + "FontWeight_Bold": "加粗", + "FontWeight_Lighter": "細化", + "FontWeight_Normal": "正常", + "FontStyle_Italic": "斜體 Italic", + "FontStyle_Oblique": "斜體 Oblique", + "FontStyle_Normal": "正常", + "FontFamily_Song": "宋體" + } + }, + + "CANVAS": { + "TITLE": "畫布" + }, + + "STORY_PAGE": { + "PAGE_SIZE": "頁面大小", + "DefaultBackground": "預設背景", + "Dynamic": "動態", + "Fixed": "固定", + "ContinuousHeight": "連續的高度", + "PresetBackground": "預設背景", + "PageType": "類型" + }, + + "ECHARTS": { + "Common": { + "Align": "對齊", + "Show": "顯示", + "LEFT": "左側距離", + "TOP": "上側距離", + "RIGHT": "右側距離", + "BOTTOM": "下側距離", + "Opacity": "不透明度", + "Color": "顏色", + "ColorJSONPlaceholder": "JSON 格式的顏色", + "BorderWidth": "邊框寬度", + "BorderColor": "邊框顏色", + "BorderRadius": "邊框半徑", + "BorderStyle": "邊框樣式", + "BorderType": "邊框類型", + "BorderJoin": "邊框連接", + "BorderCap": "邊框帽", + "BorderMiterLimit": "邊框斜接限制", + "UniversalTransition": "全局過渡動畫", + "Label": "標籤", + "Position": "位置", + "Left": "左", + "Right": "右", + "Top": "上", + "Bottom": "下", + "Silent": "靜默", + "Cursor": "光標", + "Cursor_Auto": "自動", + "Cursor_Pointer": "指針", + "Cursor_Move": "移動", + "ColorBy": "按着色", + "ColorBy_Auto": "自動", + "ColorBy_SameSeries": "相同系列", + "ColorBy_DataItems": "數據項", + "SeriesLayoutBy": "數據布局", + "Auto": "自動", + "Column": "列", + "Row": "行", + "SelectedMode": "選擇模式", + "SelectedMode_None": "無", + "SelectedMode_Single": "單選", + "SelectedMode_Multiple": "多選", + "SelectedMode_False": "禁用", + "SelectedMode_Series": "系列", + "Formatter": "格式化", + "Rotate": "旋轉", + "Enabled": "啟用", + "Width": "寬度", + "Height": "高度", + "Disabled": "禁用", + "Orient": "方向", + "Horizontal": "橫向", + "Vertical": "縱向", + "None": "無", + "Padding": "填充空白", + "Radius": "半徑", + "Symbol": "符號", + "SymbolSize": "符號大小", + "SymbolRotate": "符號旋轉", + "SymbolOffset": "符號位移", + "Stack": "堆積", + "TextAlign": { + "Title": "文本對齊", + "Auto": "自動", + "Left": "靠左", + "Right": "靠右", + "Center": "居中" + }, + "Name": "名稱", + "LegendHoverLink": "圖例聯動高亮", + "Position_Auto": "自動", + "Position_Left": "靠左", + "Position_Right": "靠右", + "Position_Top": "靠上", + "Position_Bottom": "靠下", + "Position_Middle": "居中", + "Position_Center": "居中" + }, + "Global": { + "Title": "全局", + "DarkMode": "暗黑模式", + "BackgroundColor": "背景顏色", + "Animation": "動畫", + "AnimationThreshold": "動畫閾值", + "AnimationDuration": "動畫時間", + "AnimationEasing": "動畫函數", + "AnimationDelay": "動畫延遲", + "AnimationDurationUpdate": "更新動畫時間", + "AnimationEasingUpdate": "更新動畫函數", + "AnimationDelayUpdate": "更新動畫延遲" + }, + "SHADOW": { + "SHADOW_BLUR": "陰影模糊", + "SHADOW_COLOR": "陰影顏色", + "SHADOW_OFFSETX": "水平偏移", + "SHADOW_OFFSETY": "垂直偏移" + }, + "CATEGORY_AXIS": { + "TITLE": "分類軸", + "SHOW": "是否顯示", + "Position": "位置", + "Offset": "偏移", + "ShowName": "顯示名稱", + "Name": "名稱", + "NameLocation": "名稱位置", + "NameGap": "名稱間隔", + "NameRotate": "名稱旋轉", + "Inverse": "倒轉", + "BoundaryGap": "邊界差", + "Min": "最小值", + "Max": "最大值", + "Silent": "靜默" + }, + "VALUE_AXIS": { + "TITLE": "值軸", + "SHOW": "是否顯示", + "SplitNumber": "分割數", + "ValueScale": "自動範圍", + "Min": "最小值", + "Max": "最大值" + }, + "Axis": { + "Title": "軸", + "Name": "名稱", + "NameLocation": "名稱位置", + "NameGap": "名稱間隙", + "NameRotate": "名稱旋轉", + "MinorSplitLine": "次分割線", + "AxisTick": { + "Title": "軸刻度", + "Show": "顯示", + "AlignWithLabel": "與標籤對齊", + "Interval": "間隔", + "Inside": "在內側", + "Length": "長度" + }, + "MinorTick": { + "Title": "次刻度", + "Show": "顯示", + "SplitNumber": "分格數", + "Length": "長度" + } + }, + "SingleAxis": { + "Title": "單軸" + }, + "XAXIS_STYLE": { + "XAXIS": "x 軸", + "SHOW": "顯示", + "NAME_LOCATION": "坐標軸名稱顯示位置", + "NAME_TEXT_STYLE": "坐標軸名稱的文字樣式", + "COLOR": "坐標軸名稱的顏色", + "AXIS_LINE": "坐標軸軸線相關設置", + "AXIS_LINE_COLOR": "坐標軸線線的顏色", + "AXIS_LABEL": "坐標軸刻度標籤的相關設置", + "AXISLABEL_ALIGN": "文字水平對齊方式", + "AXISLABEL_VERTICALALIGN": "文字垂直對齊方式", + "AXIS_TYPE": "坐標軸類型", + "AXIS_GRID_AREA_SEPARATOR": "坐標軸grid區域分隔線", + "SHOW_SEPARATOR_LINES": "是否顯示分割線", + "SEPARATOR_LINE_STYLE": "分隔線樣式", + "SEPARATOR_COLOR": "分割線顏色" + }, + "YAXIS_STYLE": { + "YAXIS": "y 軸", + "SHOW": "顯示", + "NAME_LOCATION": "坐標軸名稱顯示位置", + "NAME_TEXT_STYLE": "坐標軸名稱的文字樣式", + "COLOR": "坐標軸名稱的顏色", + "AXIS_LINE": "坐標軸軸線相關設置", + "AXIS_LINE_COLOR": "坐標軸線線的顏色", + "AXIS_LABEL": "坐標軸刻度標籤的相關設置", + "AXISLABEL_ALIGN": "文字水平對齊方式", + "AXISLABEL_VERTICALALIGN": "文字垂直對齊方式", + "AXIS_GRID_AREA_SEPARATOR": "坐標軸grid區域分隔線", + "SHOW_SEPARATOR_LINES": "是否顯示分割線", + "SEPARATOR_LINE_STYLE": "分隔線樣式", + "SEPARATOR_COLOR": "分割線顏色" + }, + "AxisLine": { + "Title": "軸線", + "OnZero": "在零" + }, + "AxisLabel": { + "Title": "軸標籤", + "Interval": "間隔", + "Inside": "內部", + "Rotate": "旋轉", + "ShowMinLabel": "顯示最小標籤", + "ShowMaxLabel": "顯示最大標籤", + "HideOverlap": "隱藏重疊", + "Overflow": "溢出", + "Overflow_Null": "無", + "Overflow_Truncate": "截斷", + "Overflow_Break": "間斷", + "Overflow_BreakAll": "間斷所有" + }, + "AxisPointer": { + "Title": "軸指針", + "Show": "顯示", + "Type": "類型", + "Snap": "對齊", + "Handle": { + "Title": "手柄", + "Show": "顯示", + "Type": "類型" + } + }, + "GRID": { + "GRID": "網格", + "SHOW": "是否顯示", + "CONTAIN_LABEL": "是否包含刻度標籤", + "BACKGROUND_COLOR": "背景顏色", + "BORDER_COLOR": "邊框顏色", + "BORDER_WIDTH": "邊框粗細" + }, + "LEGEND": { + "TITLE": "圖例", + "LEGEND_TYPE": "類型", + "WIDTH": "寬度", + "HEIGHT": "高度", + "LEGEND_LEFT": "左側的距離", + "LEGEND_TOP": "上側的距離", + "LEGEND_RIGHT": "右側的距離", + "LEGEND_BOTTOM": "下側的距離", + "LEGEND_ORIENT": "布局朝向", + "Align": "對齊", + "Align_Auto": "自動", + "Align_Left": "左對齊", + "Align_Right": "右對齊", + "ItemGap": "元素間距", + "ItemWidth": "元素寬度", + "ItemHeight": "元素高度", + "InactiveColor": "非激活顏色", + "InactiveBorderColor": "非激活邊框顏色", + "InactiveBorderWidth": "非激活邊框寬度", + "IconSymbol": "圖標符號", + "TextStyle": "文字樣式" + }, + "TOOLTIP": { + "TITLE": "提示框", + "TOOLTIP_SHOW": "是否顯示", + "TOOLTIP_TRIGGER": "觸發類型", + "AXIS_POINTER": "坐標軸指示器配置項", + "AXIS_POINTER_TYPE": "指示器類型", + "ShowContent": "顯示內容", + "Trigger": "觸發", + "AppendToBody": "追加到 HTML Body", + "AxisPointer": "軸指針", + "Type": "類型", + "Axis": "軸", + "Snap": "快照", + "AlwaysShowContent": "永遠顯示", + "TriggerOn": "觸發條件", + "ShowDelay": "延遲顯示", + "HideDelay": "延遲隱藏", + "Enterable": "鼠標進入", + "Confine": "限制在圖表的區域內", + "ClassName": "CSS 類", + "TransitionDuration": "移動動畫時間", + "Position": "位置", + "BackgroundColor": "背景顏色", + "BorderColor": "邊框顏色", + "BorderWidth": "邊框寬度", + "Padding": "內邊距", + "Order": "排列順序", + "TextStyle": "文本樣式", + "ExtraCssText": "附加樣式" + }, + "TEXT": { + "TEXTSTYLE": "全局的字體樣式", + "TEXTSTYLE_COLOR": "文字的顏色", + "TEXTSTYLE_FONTSTYLE": "文字字體的風格", + "TEXTSTYLE_FONTWEIGHT": "文字字體的粗細", + "TEXTSTYLE_FONTSIZE": "文字的字體大小" + }, + "DATAZOOM_STYLE": { + "None": "無", + "DATAZOOM": "數據縮放", + "ORIENT": "布局方式", + "ORIENT_HORIZONTAL": "水平", + "ORIENT_VERTICAL": "豎直", + "DATAZOOM_TYPE": "類型", + "FILTER_MODE": "過濾模式", + "START": "起始", + "END": "結束", + "START_VALUE": "起始數值", + "END_VALUE": "結束數值", + "YAXIS_INDEX": "控制的 Y 軸", + "MIN_SPAN": "窗口最小值", + "MAX_SPAN": "窗口最大值", + "ZOOM_LOCK": "鎖定窗口大小", + "Type_none": "無", + "Type_inside": "內置", + "Type_slider": "滑動條", + "Type_sliderInside": "內置+滑動條", + "RangeMode": "範圍模式", + "MinValueSpan": "最小實際值", + "MaxValueSpan": "最大實際值", + "Throttle": "刷新頻率", + "PreventDefaultMouseMove": "阻止默認的鼠標移動", + "MouseMode_true": "不按功能鍵", + "MouseMode_false": "不觸發", + "MouseMode_shift": "按住 SHIFT 觸發", + "MouseMode_ctrl": "按住 CTRL 觸發", + "MouseMode_alt": "按住 ALT 觸發", + "zoomOnMouseWheel": "鼠標滾動縮放", + "moveOnMouseMove": "鼠標移動移動", + "moveOnMouseWheel": "鼠標滾動移動" + }, + "SERIE_STYLE": { + "TITLE": "系列統一屬性", + "SERIES": "Echarts系列", + "SERIES_TYPE": "Echarts系列類型", + "ITEMS_TYLE": "圖形樣式", + "GRADIENT_STYLE": "漸變類型", + "LINESTYLE": "線條樣式", + "LINEAR_X0": "線性漸變X0參數", + "LINEAR_Y0": "線性漸變Y0參數", + "RADIAL_R": "徑向漸變半徑參數", + "LINEAR_X2": "線性漸變X2參數", + "LINEAR_Y2": "線性漸變Y2參數", + "LINEWIDTH": "線寬", + "LINE_TYPE": "線的類型", + "LINESHADOW_BLUR": "圖形陰影的模糊大小", + "LINESHADOW_COLOR": "陰影顏色", + "LINESHADOW_OFFSETX": "陰影水平方向上的偏移距離", + "LINESHAODW_OFFSETY": "陰影垂直方向上的偏移距離", + "SMOOTH": "是否平滑曲線顯示", + "COLOR_STOPS": "漸變顏色參數", + "OFFSET": "0-100%的顏色", + "COLOR": "顏色", + "ITEMSTYLEBORDER_COLOR": "圖形的描邊顏色", + "ITEMSTYLEBORDER_WIDTH": "描邊線寬", + "ITEMSTYLEBORDER_TYPE": "描邊類型", + "ITEMSTYLESHADOW_BLUR": "圖形陰影的模糊大小", + "ITEMSTYLESHADOW_COLOR": "陰影顏色", + "ITEMSTYLE_OPCITY": "圖形透明度", + "BORDER_RADIUS": "柱狀圖圓角半徑", + "BAR_WIDTH": "柱條的寬度", + "EMPHASIS_STYLE": "Emphasis 樣式", + "TEXT_LABEL": "文本標籤", + "IS_LABEL": "是否顯示標籤", + "GRAPHIC_STYLE": "圖形樣式", + "GRAPHIC_COLOR": "圖形顏色", + "STROKE_COLOR": "描邊顏色", + "STROKE_WIDTH": "描邊寬度", + "GRAPHIC_SHADOW": "圖形陰影", + "SHADOW_COLOR": "陰影顏色", + "SHADOW_OFFSET_X": "陰影水平偏移量", + "SHADOW_OFFSET_Y": "陰影垂直偏移量", + "OPACITY": "不透明度", + "ROSETYPE": "是否展示成南丁格爾圖", + "PIE_RADIUS": "餅圖半徑", + "AREA_STYLE": "區域填充樣式", + "SHADOW_BLUR": "陰影模糊大小", + "ITEM_STYLE": { + "TITLE": "單個體樣式", + "OPACITY": "不透明度" + }, + + "LABEL": { + "TITLE": "標籤" + }, + "LabelLine": { + "Title": "標籤線" + } + }, + "EMPHASIS": { + "TITLE": "高亮樣式", + "DISABLED": "禁用", + "FOCUS": "聚焦", + "BlurScope": "模糊範圍", + "BlurScope_None": "無", + "BlurScope_CoordinateSystem": "坐標系統", + "BlurScope_Series": "系列", + "BlurScope_Global": "全局", + "Focus_None": "無", + "Focus_Self": "自己", + "Focus_Series": "系列", + "Focus_Adjacency": "相鄰", + "Scale": "縮放", + "ScaleSize": "縮放大小" + }, + "ITEM_STYLE": { + "TITLE": "單個體樣式", + "OPACITY": "不透明度" + }, + "GLOBAL_COLORS": { + "TITLE": "全局顏色", + "ColorList": "顏色序列", + "Color": "顏色" + }, + "ARIA": { + "TITLE": "輔助增強", + "ShowDecal": "顯示貼花", + "Decals": "貼花圖案" + }, + "SeriesStyle": { + "Title": "系列屬性", + "HasAll":"有 All 成員", + "FunnelAlign": "漏斗對齊", + "BoundaryGap": "邊界間隙" + }, + "DDD": { + "GridTitle": "3D網格", + "BoxWidth": "寬度", + "BoxHeight": "高度", + "BoxDepth": "深度", + "Light": "光線", + "BarSeriesTitle": "系列屬性", + "Shading": "明暗法", + "Environment": "環境貼圖", + "PostEffect": "後處理特效", + "TemporalSuperSampling": "分幀超採樣", + "Enable": "啟用", + "ViewControl": "視角控制", + "BevelSize": "倒角尺寸", + "BevelSmoothness": "倒角圓潤度", + "Stack": "堆疊", + "StackStrategy": "堆疊策略", + "MinHeight": "最小高度", + "Silent": "不響應", + "Label": "標籤", + "ItemStyle": "元素樣式", + "Show": "顯示", + "Distance": "距離", + "Formatter": "格式", + "TextStyle": "文本樣式", + "Emphasis": "高亮", + "BlendMode": "混合模式" + }, + "Select": { + "Title": "選中樣式" + }, + "MarkLine": { + "Title": "標記線", + "LineStyle": "線樣式" + }, + "VisualMap": { + "Title": "可視映射", + "RemoveLabel": "刪除", + "Type": "類型", + "Piecewise": "分段", + "Continuous": "連續", + "Show": "顯示", + "Realtime": "實時", + "Calculable": "可計算", + "Controller": "控制器", + "InRange": "範圍內的", + "OutofRange": "範圍外的", + "Text": "描述", + "SymbolSize": "符號大小", + "ColorLightness": "顏色亮度", + "Inverse": "倒轉", + "Min": "最小值", + "Max": "最大值", + "Range": "預選中範圍", + "SplitNumber": "分割數量", + "Precision": "數字精度", + "Pieces": "分段", + "ShowLabel": "顯示標籤", + "ItemSymbol": "元素符號", + "ItemGap": "元素間距" + }, + "Calendar": { + "Title": "日曆", + "ItemStyle": "元素樣式", + "CellSize": "單元格大小" + }, + "SplitLine": { + "Title": "分割線", + "Show": "顯示", + "LineStyle": "線樣式", + "Interval": "間隔" + }, + "SplitArea": { + "Title": "分割區域", + "Show": "顯示", + "AreaStyle": "區域樣式", + "Interval": "間隔" + }, + "LineStyle": { + "Title": "線樣式", + "Color": "顏色", + "Width": "寬度", + "Type": "類型", + "None": "無", + "Solid": "實線", + "Dashed": "虛線", + "Dotted": "點虛線" + }, + "ItemStyle": { + "Title": "元素樣式" + }, + "Text": { + "TextBorderColor": "文本邊框顏色", + "TextBorderWidth": "文本邊框寬度", + "TextBorderType": "文本邊框類型", + "TextBorderDashOffset": "文本邊框橫線偏移量", + "TextShadowColor": "文本陰影顏色", + "TextShadowBlur": "文本陰影模糊", + "TextShadowOffsetX": "文本陰影偏移X", + "TextShadowOffsetY": "文本陰影偏移Y", + "Overflow": "溢出", + "Overflow_Null": "無", + "Overflow_Truncate": "截斷", + "Overflow_Break": "間斷", + "Overflow_BreakAll": "間斷所有", + "Ellipsis": "省略", + "Align": "對齊", + "Align_Auto": "自動", + "Align_Left": "左", + "Align_Center": "中", + "Align_Right": "右", + "Color": "文本顏色", + "FontStyle": "文本樣式", + "FontStyle_Auto": "自動", + "FontStyle_Normal": "正常", + "FontStyle_Italic": "傾斜 Italic", + "FontStyle_Oblique": "傾斜 Oblique", + "FontWeight": "字重", + "FontFamily": "字體", + "FontSize": "字體大小", + "LineHeight": "行高", + "VerticalAlign": "垂直對齊", + "VerticalAlign_Auto": "自動", + "VerticalAlign_Top": "頂部", + "VerticalAlign_Middle": "居中", + "VerticalAlign_Bottom": "底部", + "RichText": "富文本" + }, + "Geo": { + "Title": "地理組件", + "Center": "中心", + "Aggregator": "聚合函數", + "AspectScale": "長寬比", + "BoundingCoords": "地圖範圍", + "NameProperty": "GeoJSON 屬性名稱", + "ShowLegendSymbol": "顯示圖例標識", + "Zoom": "縮放比例" + }, + "Title": { + "Title": "標題", + "Text": "主文本", + "Link": "主鏈接", + "SubText": "附文本", + "SubLink": "附鏈接", + "Left": "左側", + "Top": "上側", + "Right": "右側", + "Bottom": "下側" + }, + "Bar": { + "BarWidth": "寬度", + "BarMaxWidth": "最大寬度", + "BarMinWidth": "最小寬度", + "BarMinHeight": "最小高度", + "BarMinAngle": "最小角度", + "BarGap": "間距", + "BarCategoryGap": "類別間距", + "ShowBackground": "顯示背景", + "Background": "背景", + "RoundCap": "圓帽" + }, + "Line": { + "ShowSymbol": "顯示符號", + "ShowAllSymbol": "顯示所有符號", + "Smooth": "平滑", + "Stack": "堆積", + "Step": "分步", + "AreaStyle": "面積樣式", + "Origin": "源" + }, + "Tree": { + "SeriesStyle": { + "Title": "系列樣式", + "Layout": "布局方式", + "Orthogonal": "直角", + "Radial": "雷達", + "Orient": "方位", + "EdgeShape": "邊緣形狀", + "EdgeForkPosition": "邊緣分叉位置", + "InitialTreeDepth": "初始顯示深度", + "Leaves": "葉子" + } + }, + "Pie": { + "RoseType": "玫瑰類型", + "Center": "中心", + "Radius": "半徑", + "MinShowLabelAngle": "最小顯示標籤角度", + "Clockwise": "順時針方向", + "StartAngle": "開始角度", + "MinAngle": "最小顯示角度", + "SelectedOffset": "選中偏移", + "AlignTo": "對齊方式", + "AlignTo_none": "默認", + "AlignTo_labelLine": "線末端對齊", + "AlignTo_edge": "文字對齊", + "EdgeDistance": "文字邊距", + "BleedMargin": "出血線大小", + "DistanceToLabelLine": "文字與線間距", + "PercentPrecision": "百分比精度", + "StillShowZeroSum": "零數據仍顯示扇區", + "AvoidLabelOverlap": "防止標籤重疊" + }, + "Sankey": { + "HasAll": "有 All 成員", + "NodeWidth": "節點寬度", + "NodeGap": "節點間隙", + "NodeAlign": "節點對齊", + "LayoutIterations": "布局迭代", + "Draggable": "可拖拽", + "LineStyle": "線樣式", + "Curveness": "平滑", + "Label": "標籤", + "LevelsOptions": "層級屬性" + }, + "Treemap": { + "HasAll": "有 All 成員", + "LeafDepth": "葉子深度", + "DrillDownIcon": "下鑽符號", + "ColorAlpha": "顏色α", + "ColorSaturation": "色彩飽和度", + "ColorMappingBy": "顏色映射", + "VisibleMin": "最小顯示", + "ChildrenVisibleMin": "子級最小顯示", + "UpperLabel": "上級標籤", + "VisualMin": "最小可視", + "VisualMax": "最大可視", + "LevelsOptions": "層級屬性", + "GapWidth": "間隙寬度", + "DragRoam": "拖拽漫遊", + "DragRoam_default": "默認", + "DragRoam_false": "關閉", + "DragRoam_scale": "縮放", + "DragRoam_move": "平移", + "DragRoam_all": "縮放和平移" + }, + "Sunburst": { + "Label": "標籤", + "Rotate": "旋轉", + "MinAngle": "最小顯示角度", + "NodeClick": "節點點擊", + "LevelsOptions": "層級屬性" + }, + "Polar": { + "Title": "極坐標" + }, + "Heatmap": { + "DateFormatter": "日期格式" + }, + "Label": { + "Title": "標籤" + }, + "LabelLine": { + "ShowAbove": "圖形上方", + "Smooth": "平滑", + "FirstLength": "第一段的長度", + "SecondLength": "第二段的長度", + "MinTurnAngle": "最小轉彎角度", + "MaxSurfaceAngle": "最大表面角度" + }, + "LabelLayout": { + "Title": "標籤布局", + "HideOverlap": "隱藏重疊", + "MoveOverlap": "挪動防止重疊", + "MoveOverlap_none": "無", + "MoveOverlap_shiftX": "水平依次位移", + "MoveOverlap_shiftY": "垂直依次位移" + }, + "Waterfall": { + "Accumulate": "累計" + } + } + } + }, + "COMPONENTS": { + "COMMON": { + "APPLY": "應用", + "Apply": "應用", + "Confirm": "確定", + "RESET": "重置", + "CANCEL": "取消", + "CONFIRM": "確定", + "CLEAR": "清空", + "SEARCH": "搜索", + "ADD": "添加", + "VALUE": "值", + "LABEL": "標籤", + "None": "無", + "DIMENSION_MEASURE": "維度/度量", + "Parameter": "參數", + "Measure Control": "度量控制", + "Measure": "度量", + "Calculation": "計算", + "Dimension": "維度", + "Hierarchy": "層次結構", + "Level": "層級", + "Measure Group": "度量組", + "Indicator": "指標", + "Calendar": "日曆", + "Address.Country": "國家", + "DisplayBehaviour": "顯示行為", + "DisplayBehaviour_Auto": "自動", + "DisplayBehaviour_Description": "描述", + "DisplayBehaviour_DescriptionID": "描述+編碼", + "DisplayBehaviour_IDDescription": "編碼+描述", + "DisplayBehaviour_IDOnly": "編碼" + }, + "ENTITY": { + "MEASURE": "度量", + "SELECT_DIMENSION": "選擇維度", + "MeasureFormatting": "度量格式", + "ShortNumber": "縮寫數字", + "Decimals": "小數位", + "Unit": "單位", + "UseUnderlyingUnit": "使用模型單位", + "DigitsInfo": "數字格式" + }, + "PROPERTY": { + "PARAMETER": "參數", + "PARAMETERS": "參數", + "MEASURE": "度量", + "MEASURES": "度量", + "MeasureGroup": "度量組", + "INDICATORS": "指標", + "CREATE_PARAMETER": "創建參數", + "EditParameter": "編輯參數", + "CALCULATIONS": "計算度量", + "DIMENSION": "維度", + "DIMENSIONS": "維度", + "ADD_DIMENSION": "添加維度", + "MEMBERS": "成員", + "HIERARCHY": "層次結構", + "ADD_PARAMETER_MEMBER": "添加成員", + "MEASURE_CONTROLS": "度量控制", + "CREATE_CALCULATION": "創建計算", + "CREATE_MEASURE_CONTROL": "創建度量控制", + "REFERENCE_LINE": "參考線", + "Input": "輸入", + "Select": "選擇", + "Dimensions": "維度", + "Name": "名稱", + "NameRequired": "名稱必輸或已存在", + "Caption": "標籤", + "Value": "值", + "DefaultValue": "默認值", + "ValueType": "值類型", + "DisplayAs": "顯示為", + "Label": "文本字段", + "Formatter": "格式設置", + "EditFormula": "編輯公式", + "UnbookedData": "無成員數據", + "ZeroSuppression": "清零", + "PropertyList": "屬性列表", + "DisplayHierarchy": "包含父級層級", + "CreateParameter": "創建參數", + "CurrentMember": "當前成員", + "PreviousNMember": "之前第 N 個成員", + "NextNMember": "之後第 N 個成員", + "ParallelMember": "平行成員", + "AncestorMember": "祖先成員", + "SelectByMembers": "選擇成員", + "NewCalculationInputControl": "新建計算輸入", + "NthMember": "值 / 第 N 個", + "IsDefault": "默認", + "Default": "默認", + "Auto": "自動", + "Description and ID": "名稱+ID", + "Description Only": "名稱", + "ID Only": "ID", + "Description": "描述", + "Order": "排序", + "None": "無", + "Order_ASC": "正序", + "Order_DESC": "倒序", + "Dimension": "維度", + "AvailableMembers": "可用成員" + }, + "CALCULATION": { + "TITLE": "計算編輯器", + "TYPE": "類型", + "Name": "名稱", + "NameRequired": "名稱必輸或已存在", + "Caption": "標籤", + "FUNCTIONS": "函數", + "DIMENSION_MEMBERS": "維度成員", + "CALCULATED_MEMBERS": "計算成員", + "PARAMETERS": "參數", + "CALCULATED_MEASURE": "計算公式", + "RESTRICTED_MEASURE": "受限度量", + "VARIANCE_MEASURE": "差值度量", + "AGGREGATION": "聚合", + "DIMENSION_TO_MEASURE": "維度轉度量", + "MEASURE_CONTROL": "度量控制", + "PROPERTIES": "屬性", + "OPERATION": "運算", + "VALUE": "值", + "AGGREGATION_DIMENSIONS": "聚合維度", + "ADD_DIMENSION": "添加維度", + "SELECTION_CONTEXT": "選擇上下文", + "ENABLE_CONSTANT_SELECTION": "啟用常量選擇", + "EDIT_FORMULA": "編輯公式", + "UseConditionalAggregation": "使用條件聚合", + "ConditionalDimensions": "條件維度", + "ExcludeConditions": "排除條件", + "Compare": "比", + "To": "較", + "BaseDimension": "基準維度", + + "SetNoDataasZero": "將無數據當作零", + "CalculateasPercentage": "計算為百分比", + "DirectDivide": "直接除", + "AbsoluteBaseValue": "絕對化基值", + "DivideBy": "除以", + "CompareValueA": "比 (A)", + "ToValueB": "較 (B)", + "Measure": "度量", + "RestrictiveConditions": "限定條件", + "ConstantSelectionTootip": "鎖定限定條件維度成員,使其不會被用戶上下文切片器所覆蓋", + "Dimension": "維度", + "MeasureSelectOptions": "度量選擇選項", + "ConditionalAggregation": "條件聚合", + "Unit": "單位", + "Formulas": "公式", + "MeasureSelectPlaceholder": "選擇或新建一個度量" + }, + "MeasureSelect": { + "EditCalculationMeasure": "編輯計算度量", + "NewCalculationMeasure": "新建計算度量" + }, + "VALUE_HELP": { + "TITLE": "為{{value}}設置過濾器", + "AVAILABLE_MEMBERS": "可選成員", + "DISPLAY_BEHAVIOUR": "顯示形式", + "SHOW_HIERARCHY": "顯示層級", + "PRESENTATION": "展現形式", + "SHOW_UNBOOKED_MEMBERS": "顯示空成員", + "SHOW_ONLY_LEAVES": "只顯示葉子成員", + "EXCLUDE_SELECTED_MEMBERS": "排除選中成員", + "CLEAR_SELECTION": "清空選擇", + "SELECTED_MEMBERS": "選中成員", + "TREE_SELECTION_MODE": "選擇模式", + "EDIT_FORMULA": "編輯公式", + "FUNCTIONS": "函數", + "CONDITIONS": "條件", + "OPERATORS": "操作符", + "DIMENSION_MEMBERS": "維度成員", + "CALCULATED_MEMBERS": "計算成員" + }, + "SELECTION": { + "Slicers": "切片器", + "AdvancedFilter": "組合切片器", + "CombinationSlicer": "組合切片器", + "AdvancedSlicer": "高級切片器", + "DimensionMembers": "維度成員", + "TimeRanges": "動態時間範圍", + "OnContext": "基於", + "SLICERS_BAR": { + "TITLE": "過濾器" + }, + "ADVANCED_SLICER": { + "TITLE": "高級切片器", + "CONTEXT": "上下文", + "OPERATOR": "操作符", + "ENABLE_OTHER": "匯總其它項", + "VALUE": "值", + "VALUE_FROM": "從", + "VALUE_TO": "至", + "MEASURE": "度量", + "MeasureSelectPlaceholder": "選擇或新建一個度量" + }, + "SLICER": { + "ADVANCED_SLICER": "高級切片器", + "ADVANCED_FILTER": "組合切片器" + }, + "DateFunctions": { + "SYSTEMTIME": "系統時間", + "TODAY": "今天" + } + }, + "DATE_PICKER": { + "Date": "日期", + "Year": "年", + "Quarter": "季", + "Month": "月", + "Week": "周", + "Day": "日", + "From": "從", + "To": "至" + }, + "TIME_FILTER": { + "SET_DATE_RANGE": "為 {{property}} 設置時間區間", + "CURRENT_DATE": "當前日期", + "SYSTEM_DATE": "系統時間", + "USER_CURRENT_DATE": "用戶當前時間", + "ADD_TIME_RANGE": "添加時間區間", + "RANGE": "區間", + "RANGE_TYPE": "區間類型", + "RANGE_TYPE_STANDARD": "標準", + "RANGE_TYPE_OFFSET": "偏移", + "GRANULARITY": "粒度", + "YEAR": "年", + "QUARTER": "季度", + "MONTH": "月", + "WEEK": "周", + "DAY": "日", + "LOOK_BACK": "回顧", + "LOOK_AHEAD": "展望", + "CURRENT_PERIOD": "當前時間", + "FORMATTER": "格式", + "OFFSET_DIRECTION": "偏移方向", + "OFFSET_AMOUNT": "偏移量", + "SETTINGS_FOR_USERS": "為用戶設置", + "ALLOW_MODIFY_SELECTIONS": "允許查看者修改選擇", + "SELECTION_TYPE": "選擇類型", + "SELECTION_TYPE_MULTIPLE": "多選", + "SELECTION_TYPE_SINGLE": "單選", + "TODAY": "當前期間", + "Year": "年", + "Quarter": "季度", + "Month": "月", + "Week": "周", + "Day": "日" + }, + "COUNTDOWN_CONFIRMATION": { + "CONFIRM": "確認", + "WAS": "秒", + "ENABLED": "啟用", + "DISABLED": "停用", + "WAIT_UNTIL_RELOAD": "等待直至重新加載" + }, + "CONFIRM": { + "DELETE": "確定刪除", + "INPUT_UNIQUE_VALUE": "輸入唯一值", + "NAME": "名稱" + }, + "SINGLE_SELECTION_TABLE": { + "SEARCH": "搜索", + "SELECT": "選擇" + }, + "MEMBER_CONTROL": { + "LABEL_ID": "名稱 / 鍵" + }, + "EDITOR": { + "EDIT": "編輯" + }, + "AdvancedFilter": { + "Title": "組合切片器", + "AND": "且", + "OR": "或", + "GROUP": "組合", + "Operator": "操作符", + "Value": "值", + "Condition": "條件", + "AddGroup": "\"且\"組合", + "OrGroup": "\"或\"組合", + "EndGroup": "結束組合", + "DeleteGroup": "刪除組合", + "Tips": "使用 且/或 創建條件組合" + }, + "Table": { + "firstPageLabel": "第一", + "itemsPerPageLabel": "每頁", + "lastPageLabel": "最後", + "nextPageLabel": "下一頁", + "previousPageLabel": "上一頁", + "rangeLabel0": "頁 1 共 1", + "pageLabel": "頁", + "ofLabel": "共" + } + }, + "FORMLY": { + "COMMON": { + "ADD": "添加", + "Apply": "應用", + "Cancel": "取消", + "Search": "搜索", + "Options": "配置", + "Clear": "清空" + }, + "PROPERTY_SELECT": { + "REFERENCE_LINE": "參考線", + "None": "默認", + "Category": "類別", + "Category2": "類別2", + "Group": "分組", + "Stacked": "堆積", + "Color": "顏色", + "Trellis": "格子", + "Axis1": "軸1", + "Axis2": "軸2", + "Axis3": "軸3", + "Size": "大小", + "Lightness": "明度", + "SizeLightness": "大小和明度", + "Tooltip": "提示信息", + "Bar": "柱形", + "Line": "線形", + "Scatter": "散點", + "Pattern": "圖案", + "Palette": "調色板", + "Invert": "反轉", + "Role": "角色", + "Shape": "形狀", + "Style": "樣式", + "ChartOptions": "圖形屬性", + "ChartAttributes": "圖形屬性", + "BarChart": "條形圖", + "Colors": "顏色" + }, + "TABLE": { + "Action": "操作", + "Open": "打開", + "AddRow": "新增", + "Options": "配置" + }, + "CHART": { + "ChartType": "圖形類型", + "CustomCode": "自定義代碼", + "AutomaticallyGenerateCode": "根據注釋自動生成代碼", + "None": "無", + "Horizontal": "橫向", + "Vertical": "縱向", + "Doughnut": "環形圖", + "Doughnut2": "細環形圖", + "Nightingale": "南丁格爾", + "Nightingale2": "南丁格爾2", + "Polar": "極坐標", + "Comparison": "比較", + "Pie": "餅圖", + "Bar": "柱圖", + "Waterfall": "瀑布圖", + "Map": "地理", + "Histogram": "直方圖", + "Trend": "趨勢", + "Line": "線圖", + "Line2": "縱向線圖", + "Area": "面積圖", + "AreaStacked": "堆積面積圖", + "Theme River": "河流圖", + "ThemeRiver": "河流圖", + "Correlation": "相關", + "Scatterplot": "散點圖", + "Scatter": "散點圖", + "Bubble": "氣泡圖", + "Cluster Bubble": "集群氣泡圖", + "Packed Bubble": "包氣泡圖", + "Radial Scatter": "雷達散點圖", + "Distribution": "分布", + "Heat Map": "熱點圖", + "Heatmap": "熱點圖", + "Box plot": "盒須圖", + "Boxplot": "盒須圖", + "Tree": "樹圖", + "Tree Map": "矩陣樹圖", + "Treemap": "矩陣樹圖", + "Sunburst": "旭日圖", + "Sankey": "桑基圖", + "Radar": "雷達圖", + "Reverse": "反向", + "Funnel": "漏斗圖", + "Calendar": "日曆", + "Radial": "雷達", + "3D": "三維", + "Geo": "地理", + "Custom": "自定義", + "GeoMap": "地理圖", + "MapName": "地圖名稱", + "MapUrl": "地理文件鏈接", + "MapProjection": "地圖投影", + "IsTopoJSON": "是 TopoJSON 格式", + "FeatureObjectNames": "Feature 對象名稱", + "Bar 3D": "三維柱形", + "Bar3D": "三維柱形", + "Line 3D": "三維線圖", + "Line3D": "三維線圖", + "Scatter 3D": "三維散點", + "Scatter3D": "三維散點", + "Column": "柱條形圖", + "ColumnStacked": "堆積柱條形圖", + "BarStacked": "堆積條形圖", + "BarPolar": "極坐標條形圖", + "BatPolarBackground": "極坐標有背景條形圖", + "Combination": "組合圖", + "BarTrellis": "柱形圖矩陣", + "Ask": "提問", + "ChartName": "圖形名稱" + }, + "Select": { + "UnableLoadOptionList": "無法加載可選項" + }, + "SemanticModel": { + "Label": "語義模型" + }, + "Sort": { + "Label": "排序字段" + } + }, + "PANGOLIN": { + "CORE": { + "WIDGET": { + "Rank": "排名", + "Top": "前" + } + } + }, + "FORM": { + "LABELS": { + "EMAILS": "郵箱", + "ROLE": "角色", + "INVITATION_EXPIRATION": "邀請過期" + }, + "PLACEHOLDERS": { + "ROLE": "選擇角色" + } + }, + + "EMAIL_TEMPLATES_PAGE": { + "TEMPLATE_NAMES": { + "password": "密碼重置", + "welcome-user": "歡迎用戶", + "invite-user": "邀請用戶", + "TEMPLATE_NAMES": "模板名稱" + } + }, + "TOASTR": { + "TITLE": { + "SUCCESS": "成功" + }, + "MESSAGE": { + "ERRORS": "錯誤", + "INVITES_DELETE": "刪除邀請 {{email}}", + "INVITES_RESULT": "成功邀請 {{total}} 人, 忽略 {{ignored}} 人", + "EMAIL_TEMPLATE_SAVED": "郵件模板保存", + "CUSTOM_SMTP_UPDATED": "自定義 SMTP 更新" + } + }, + "The name is required": "名稱必輸", + "Must be unique from the table name": "不能與表名重複", + "Initializing": "初始化中", + "offline": "離線", + "online": "在線", + "loading": "加載中", + "error": "錯誤" +} diff --git a/apps/cloud/src/styles.scss b/apps/cloud/src/styles.scss index f56c84deb..500cdc592 100644 --- a/apps/cloud/src/styles.scss +++ b/apps/cloud/src/styles.scss @@ -34,6 +34,8 @@ @include indicator-market.color(thin-theme.$dark-theme); } +@import './app/_app.component'; + html, body { height: 100%; @@ -349,3 +351,35 @@ html.cdk-global-scrollblock { @apply text-xs; } } + + +.pac-page-header { + @apply flex flex-col justify-start items-start gap-2 px-4 pt-4 bg-white; +} +.pac-page-title { + @apply text-2xl font-bold; +} +.pac-page-subtitle { + @apply text-base font-light; +} +.pac-page-body { + @apply bg-slate-50 rounded-lg overflow-auto relative; +} +.pac-page-body-toolbar { + @apply flex justify-between items-center; +} +.pac-tab-nav-bar.mat-mdc-tab-header { + --mdc-secondary-navigation-tab-container-height: 32px; + + .pac-tab-close { + @apply opacity-0 invisible absolute -right-6; + } + .mdc-tab.mdc-tab--active { + .pac-tab-close { + @apply opacity-100 visible; + } + } +} +.mat-mdc-card.mdc-card { + @apply rounded-lg shadow-sm; +} \ No newline at end of file diff --git a/apps/nest/.eslintrc.json b/apps/nest/.eslintrc.json deleted file mode 100644 index 9d9c0db55..000000000 --- a/apps/nest/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": ["../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/apps/nest/jest.config.js b/apps/nest/jest.config.js deleted file mode 100644 index 365b60938..000000000 --- a/apps/nest/jest.config.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - displayName: 'nest', - preset: '../../jest.preset.js', - globals: { - 'ts-jest': { - tsconfig: '/tsconfig.spec.json', - }, - }, - testEnvironment: 'node', - transform: { - '^.+\\.[tj]s$': 'ts-jest', - }, - moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '../../coverage/apps/nest', -}; diff --git a/apps/nest/project.json b/apps/nest/project.json deleted file mode 100644 index c2350a6cb..000000000 --- a/apps/nest/project.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "root": "apps/nest", - "sourceRoot": "apps/nest/src", - "projectType": "application", - "targets": { - "build": { - "executor": "@nrwl/node:webpack", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/nest", - "main": "apps/nest/src/main.ts", - "tsConfig": "apps/nest/tsconfig.app.json", - "assets": ["apps/nest/src/assets"], - "format": ["cjs", "esm", "umd"] - }, - "configurations": { - "production": { - "optimization": true, - "extractLicenses": true, - "inspect": false, - "fileReplacements": [ - { - "replace": "apps/nest/src/environments/environment.ts", - "with": "apps/nest/src/environments/environment.prod.ts" - } - ] - } - } - }, - "serve": { - "executor": "@nrwl/node:node", - "options": { - "buildTarget": "nest:build" - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["apps/nest/**/*.ts"] - } - }, - "test": { - "executor": "@nrwl/jest:jest", - "outputs": ["coverage/apps/nest"], - "options": { - "jestConfig": "apps/nest/jest.config.js", - "passWithNoTests": true - } - } - }, - "tags": [] -} diff --git a/apps/nest/src/app/app.controller.spec.ts b/apps/nest/src/app/app.controller.spec.ts deleted file mode 100644 index 833a43063..000000000 --- a/apps/nest/src/app/app.controller.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; - -import { AppController } from './app.controller'; -import { AppService } from './app.service'; - -describe('AppController', () => { - let app: TestingModule; - - beforeAll(async () => { - app = await Test.createTestingModule({ - controllers: [AppController], - providers: [AppService], - }).compile(); - }); - - describe('getData', () => { - it('should return "Welcome to nest!"', () => { - const appController = app.get(AppController); - expect(appController.getData()).toEqual({ message: 'Welcome to nest!' }); - }); - }); -}); diff --git a/apps/nest/src/app/app.controller.ts b/apps/nest/src/app/app.controller.ts deleted file mode 100644 index dff210a84..000000000 --- a/apps/nest/src/app/app.controller.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Controller, Get } from '@nestjs/common'; - -import { AppService } from './app.service'; - -@Controller() -export class AppController { - constructor(private readonly appService: AppService) {} - - @Get() - getData() { - return this.appService.getData(); - } -} diff --git a/apps/nest/src/app/app.module.ts b/apps/nest/src/app/app.module.ts deleted file mode 100644 index 6a9bc166d..000000000 --- a/apps/nest/src/app/app.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { AppController } from './app.controller'; -import { AppService } from './app.service'; - -@Module({ - imports: [], - controllers: [AppController], - providers: [AppService], -}) -export class AppModule {} diff --git a/apps/nest/src/app/app.service.spec.ts b/apps/nest/src/app/app.service.spec.ts deleted file mode 100644 index c210002de..000000000 --- a/apps/nest/src/app/app.service.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Test } from '@nestjs/testing'; - -import { AppService } from './app.service'; - -describe('AppService', () => { - let service: AppService; - - beforeAll(async () => { - const app = await Test.createTestingModule({ - providers: [AppService], - }).compile(); - - service = app.get(AppService); - }); - - describe('getData', () => { - it('should return "Welcome to nest!"', () => { - expect(service.getData()).toEqual({ message: 'Welcome to nest!' }); - }); - }); -}); diff --git a/apps/nest/src/app/app.service.ts b/apps/nest/src/app/app.service.ts deleted file mode 100644 index 0c2670f24..000000000 --- a/apps/nest/src/app/app.service.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Injectable } from '@nestjs/common'; -// import { core } from '../../../../packages/core/src/index' -import * as core from '@metad/ocap-core' - -@Injectable() -export class AppService { - getData(): { message: string } { - return { message: `Welcome to ${core.core()}!` }; - } -} diff --git a/apps/nest/src/assets/.gitkeep b/apps/nest/src/assets/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/nest/src/environments/environment.prod.ts b/apps/nest/src/environments/environment.prod.ts deleted file mode 100644 index c9669790b..000000000 --- a/apps/nest/src/environments/environment.prod.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const environment = { - production: true, -}; diff --git a/apps/nest/src/environments/environment.ts b/apps/nest/src/environments/environment.ts deleted file mode 100644 index a20cfe557..000000000 --- a/apps/nest/src/environments/environment.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const environment = { - production: false, -}; diff --git a/apps/nest/src/main.ts b/apps/nest/src/main.ts deleted file mode 100644 index 2268b6e1a..000000000 --- a/apps/nest/src/main.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * This is not a production server yet! - * This is only a minimal backend to get started. - */ - -import { Logger } from '@nestjs/common'; -import { NestFactory } from '@nestjs/core'; - -import { AppModule } from './app/app.module'; - -async function bootstrap() { - const app = await NestFactory.create(AppModule); - const globalPrefix = 'api'; - app.setGlobalPrefix(globalPrefix); - const port = process.env.PORT || 3333; - await app.listen(port); - Logger.log( - `🚀 Application is running on: http://localhost:${port}/${globalPrefix}` - ); -} - -bootstrap(); diff --git a/apps/nest/tsconfig.app.json b/apps/nest/tsconfig.app.json deleted file mode 100644 index 149f70bbf..000000000 --- a/apps/nest/tsconfig.app.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "types": ["node"], - "emitDecoratorMetadata": true - }, - "exclude": ["**/*.spec.ts", "**/*.test.ts"], - "include": ["**/*.ts"] -} diff --git a/apps/nest/tsconfig.json b/apps/nest/tsconfig.json deleted file mode 100644 index 63dbe35fb..000000000 --- a/apps/nest/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - } - ] -} diff --git a/apps/nest/tsconfig.spec.json b/apps/nest/tsconfig.spec.json deleted file mode 100644 index a18afb604..000000000 --- a/apps/nest/tsconfig.spec.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] -} diff --git a/apps/rc-e2e/.eslintrc.json b/apps/rc-e2e/.eslintrc.json deleted file mode 100644 index 696cb8b12..000000000 --- a/apps/rc-e2e/.eslintrc.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/apps/rc-e2e/cypress.json b/apps/rc-e2e/cypress.json deleted file mode 100644 index a64fb9e9b..000000000 --- a/apps/rc-e2e/cypress.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "fileServerFolder": ".", - "fixturesFolder": "./src/fixtures", - "integrationFolder": "./src/integration", - "modifyObstructiveCode": false, - "supportFile": "./src/support/index.ts", - "pluginsFile": false, - "video": true, - "videosFolder": "../../dist/cypress/apps/rc-e2e/videos", - "screenshotsFolder": "../../dist/cypress/apps/rc-e2e/screenshots", - "chromeWebSecurity": false -} diff --git a/apps/rc-e2e/project.json b/apps/rc-e2e/project.json deleted file mode 100644 index 2e0e18baa..000000000 --- a/apps/rc-e2e/project.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "root": "apps/rc-e2e", - "sourceRoot": "apps/rc-e2e/src", - "projectType": "application", - "targets": { - "e2e": { - "executor": "@nrwl/cypress:cypress", - "options": { - "cypressConfig": "apps/rc-e2e/cypress.json", - "devServerTarget": "rc:serve" - }, - "configurations": { - "production": { - "devServerTarget": "rc:serve:production" - } - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["apps/rc-e2e/**/*.{js,ts}"] - } - } - }, - "tags": [], - "implicitDependencies": ["rc"] -} diff --git a/apps/rc-e2e/src/fixtures/example.json b/apps/rc-e2e/src/fixtures/example.json deleted file mode 100644 index 294cbed6c..000000000 --- a/apps/rc-e2e/src/fixtures/example.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io" -} diff --git a/apps/rc-e2e/src/integration/app.spec.ts b/apps/rc-e2e/src/integration/app.spec.ts deleted file mode 100644 index 6399353a6..000000000 --- a/apps/rc-e2e/src/integration/app.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { getGreeting } from '../support/app.po'; - -describe('rc', () => { - beforeEach(() => cy.visit('/')); - - it('should display welcome message', () => { - // Custom command example, see `../support/commands.ts` file - cy.login('my-email@something.com', 'myPassword'); - - // Function helper example, see `../support/app.po.ts` file - getGreeting().contains('Welcome rc'); - }); -}); diff --git a/apps/rc-e2e/src/support/app.po.ts b/apps/rc-e2e/src/support/app.po.ts deleted file mode 100644 index 329342469..000000000 --- a/apps/rc-e2e/src/support/app.po.ts +++ /dev/null @@ -1 +0,0 @@ -export const getGreeting = () => cy.get('h1'); diff --git a/apps/rc-e2e/src/support/commands.ts b/apps/rc-e2e/src/support/commands.ts deleted file mode 100644 index 310f1fa0e..000000000 --- a/apps/rc-e2e/src/support/commands.ts +++ /dev/null @@ -1,33 +0,0 @@ -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** - -// eslint-disable-next-line @typescript-eslint/no-namespace -declare namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Chainable { - login(email: string, password: string): void; - } -} -// -// -- This is a parent command -- -Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password); -}); -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/apps/rc-e2e/src/support/index.ts b/apps/rc-e2e/src/support/index.ts deleted file mode 100644 index 3d469a6b6..000000000 --- a/apps/rc-e2e/src/support/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands'; diff --git a/apps/rc-e2e/tsconfig.json b/apps/rc-e2e/tsconfig.json deleted file mode 100644 index c4f818ecd..000000000 --- a/apps/rc-e2e/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "sourceMap": false, - "outDir": "../../dist/out-tsc", - "allowJs": true, - "types": ["cypress", "node"] - }, - "include": ["src/**/*.ts", "src/**/*.js"] -} diff --git a/apps/rc/.babelrc b/apps/rc/.babelrc deleted file mode 100644 index 61641ec8a..000000000 --- a/apps/rc/.babelrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "presets": [ - [ - "@nrwl/react/babel", - { - "runtime": "automatic" - } - ] - ], - "plugins": [] -} diff --git a/apps/rc/.browserslistrc b/apps/rc/.browserslistrc deleted file mode 100644 index f1d12df4f..000000000 --- a/apps/rc/.browserslistrc +++ /dev/null @@ -1,16 +0,0 @@ -# This file is used by: -# 1. autoprefixer to adjust CSS to support the below specified browsers -# 2. babel preset-env to adjust included polyfills -# -# For additional information regarding the format and rule options, please see: -# https://github.com/browserslist/browserslist#queries -# -# If you need to support different browsers in production, you may tweak the list below. - -last 1 Chrome version -last 1 Firefox version -last 2 Edge major versions -last 2 Safari major version -last 2 iOS major versions -Firefox ESR -not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/apps/rc/.eslintrc.json b/apps/rc/.eslintrc.json deleted file mode 100644 index 734ddacee..000000000 --- a/apps/rc/.eslintrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/apps/rc/jest.config.js b/apps/rc/jest.config.js deleted file mode 100644 index c7a4edd89..000000000 --- a/apps/rc/jest.config.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - displayName: 'rc', - preset: '../../jest.preset.js', - transform: { - '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', - '^.+\\.[tj]sx?$': 'babel-jest', - }, - moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], - coverageDirectory: '../../coverage/apps/rc', -}; diff --git a/apps/rc/postcss.config.js b/apps/rc/postcss.config.js deleted file mode 100644 index 26b8d41bd..000000000 --- a/apps/rc/postcss.config.js +++ /dev/null @@ -1,10 +0,0 @@ -const { join } = require('path'); - -module.exports = { - plugins: { - tailwindcss: { - config: join(__dirname, 'tailwind.config.js'), - }, - autoprefixer: {}, - }, -}; \ No newline at end of file diff --git a/apps/rc/project.json b/apps/rc/project.json deleted file mode 100644 index 648f2c4f2..000000000 --- a/apps/rc/project.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "root": "apps/rc", - "sourceRoot": "apps/rc/src", - "projectType": "application", - "targets": { - "build": { - "executor": "@nrwl/web:webpack", - "outputs": ["{options.outputPath}"], - "defaultConfiguration": "production", - "options": { - "compiler": "babel", - "outputPath": "dist/apps/rc", - "index": "apps/rc/src/index.html", - "baseHref": "/", - "main": "apps/rc/src/main.tsx", - "polyfills": "apps/rc/src/polyfills.ts", - "tsConfig": "apps/rc/tsconfig.app.json", - "assets": [ - "apps/rc/src/favicon.ico", - "apps/rc/src/assets", - { - "glob": "*.wasm", - "input": "node_modules/@duckdb/duckdb-wasm/dist/", - "output": "./assets/" - }, - { - "glob": "*.worker.js", - "input": "node_modules/@duckdb/duckdb-wasm/dist/", - "output": "./assets/" - } - ], - "styles": ["apps/rc/src/styles.scss"], - "scripts": [], - "webpackConfig": "@nrwl/react/plugins/webpack" - }, - "configurations": { - "production": { - "fileReplacements": [ - { - "replace": "apps/rc/src/environments/environment.ts", - "with": "apps/rc/src/environments/environment.prod.ts" - } - ], - "optimization": true, - "outputHashing": "all", - "sourceMap": false, - "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false - } - } - }, - "serve": { - "executor": "@nrwl/web:dev-server", - "options": { - "buildTarget": "rc:build", - "hmr": true, - "proxyConfig": "apps/rc/proxy.conf.json" - }, - "configurations": { - "production": { - "buildTarget": "rc:build:production", - "hmr": false - } - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["apps/rc/**/*.{ts,tsx,js,jsx}"] - } - }, - "test": { - "executor": "@nrwl/jest:jest", - "outputs": ["coverage/apps/rc"], - "options": { - "jestConfig": "apps/rc/jest.config.js", - "passWithNoTests": true - } - } - }, - "tags": [] -} diff --git a/apps/rc/proxy.conf.json b/apps/rc/proxy.conf.json deleted file mode 100644 index 62a1e7b76..000000000 --- a/apps/rc/proxy.conf.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "/api": { - "target": "http://localhost:3333", - "secure": false - } -} diff --git a/apps/rc/src/app/app.scss b/apps/rc/src/app/app.scss deleted file mode 100644 index e80c7559e..000000000 --- a/apps/rc/src/app/app.scss +++ /dev/null @@ -1,13 +0,0 @@ -/* Your styles goes here. */ -.appContainer { - margin-top: 1rem; -} - -.MuiGrid-root { - .AnalyticalCard { - border-radius: 6px; - box-shadow: rgba(0, 0, 0, 0.15) 0px 5px 15px 0px; - height: 350px; - overflow: visible; - } -} diff --git a/apps/rc/src/app/app.spec.tsx b/apps/rc/src/app/app.spec.tsx deleted file mode 100644 index ecead7e58..000000000 --- a/apps/rc/src/app/app.spec.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from '@testing-library/react'; - -import App from './app'; - -describe('App', () => { - // it('should render successfully', () => { - // const { baseElement } = render(); - - // expect(baseElement).toBeTruthy(); - // }); - - // it('should have a greeting as the title', () => { - // const { getByText } = render(); - - // expect(getByText(/Welcome rc/gi)).toBeTruthy(); - // }); -}); diff --git a/apps/rc/src/app/app.tsx b/apps/rc/src/app/app.tsx deleted file mode 100644 index a28ccaf9c..000000000 --- a/apps/rc/src/app/app.tsx +++ /dev/null @@ -1,145 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import './app.scss' -import { - AgentType, - DataSource, - Type, -} from '@metad/ocap-core' -import { AnalyticalCard, OCAPCoreProvider } from '@metad/ocap-react' -import MenuIcon from '@mui/icons-material/Menu' -import AppBar from '@mui/material/AppBar' -import Box from '@mui/material/Box' -import Container from '@mui/material/Container' -import Grid from '@mui/material/Grid' -import IconButton from '@mui/material/IconButton' -import Select, { SelectChangeEvent } from '@mui/material/Select' -import Toolbar from '@mui/material/Toolbar' -import Typography from '@mui/material/Typography' -import React, { useEffect, useMemo, useState } from 'react' -import { registerTheme } from 'echarts/core' -import { DEFAULT_THEME } from '@metad/ocap-echarts' -import { DuckdbWasmAgent } from '@metad/ocap-duckdb' -import { DUCKDB_WASM_MODEL, CARTESIAN_CARDS, ANALYTICAL_CARDS } from '@metad/ocap-duckdb/src/lib/examples' -import { MockAgent } from './mock' - -registerTheme(DEFAULT_THEME.name, DEFAULT_THEME.echartsTheme) - -async function importSQL(): Promise> { - const { SQLDataSource } = await import('@metad/ocap-sql') - return SQLDataSource -} - -export function App() { - - const [cards, setCards] = useState([ - CARTESIAN_CARDS[0] - // ...CARTESIAN_CARDS, - // ...ANALYTICAL_CARDS - ]) - - const handleChange = (event: SelectChangeEvent) => { - // - } - - const wasmDBAgent = useMemo(() => { - return new DuckdbWasmAgent([]) - }, []) - - useEffect(() => { - const timer = setTimeout(() => { - console.log(`~~~~~~~~~~~~~~~~~~~~~~~~~ duckdb register model ~~~~~~~~~~~~~~~~~~~~~~~~~~`) - wasmDBAgent.registerModel(DUCKDB_WASM_MODEL) - }, 5000); - return () => clearTimeout(timer) - }, []) - - return ( - - - - - - - - - Analytical Cards - - - - - - - {cards.map(({ title, dataSettings, chartSettings, chartOptions }) => ( - - - - ))} - - - - - ) -} - -export default App diff --git a/apps/rc/src/app/mock.ts b/apps/rc/src/app/mock.ts deleted file mode 100644 index 7908b8a9a..000000000 --- a/apps/rc/src/app/mock.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Agent, AgentStatus, AgentType, AggregationRole, DataSourceOptions } from '@metad/ocap-core' -import { randFloat, randProductAdjective, randProductCategory } from '@ngneat/falso' -import { Observable, of } from 'rxjs' - - -export class MockAgent implements Agent { - type = AgentType.Browser - selectStatus(): Observable { - return of(AgentStatus.ONLINE) - } - selectError(): Observable { - throw new Error('Method not implemented.') - } - error(err: any): void { - throw new Error('Method not implemented.') - } - - request(dataSource: DataSourceOptions, options: any): Promise { - console.log(`~~~~~~~~~~~~~~~~~~~~`, dataSource, options) - - return new Promise((resolve, reject) => { - if (options.method === 'get') { - if (options.url === 'schema') { - if (options.table === 'SalesOrder') { - return resolve([{ - name: 'SalesOrder', - label: '销售订单', - columns: [ - { - name: 'product', - label: '产品', - type: 'string', - aggregationRole: AggregationRole.dimension - }, - { - name: 'productCategory', - label: '产品类别', - type: 'string', - aggregationRole: AggregationRole.dimension - }, - { - name: 'sales', - label: '销售额', - type: 'number', - aggregationRole: AggregationRole.measure - }, - { - name: 'quantity', - label: '销售量', - type: 'number', - aggregationRole: AggregationRole.measure - } - ] - }]) - } - } - } else if (options.method === 'post') { - if (options.url === 'query') { - const results = [] - randProductCategory({ length: 3 }).forEach((productCategory) => { - randProductAdjective({ length: 5 }).forEach((product) => { - results.push({ - product, - productCategory, - sales: randFloat(), - quantity: randFloat() - }) - }) - }) - return resolve({ - data: results, - columns: [] - }) - } - } - - resolve({}) - }) - } -} diff --git a/apps/rc/src/app/types.ts b/apps/rc/src/app/types.ts deleted file mode 100644 index 16df026fc..000000000 --- a/apps/rc/src/app/types.ts +++ /dev/null @@ -1,603 +0,0 @@ -import { - ChartDataZoomType, - ChartDimensionRoleType, - ChartMeasureRoleType, - ChartOptions, - OrderDirection, - ReferenceLineAggregation, - ReferenceLineType, - ReferenceLineValueType -} from '@metad/ocap-core' - -export const MAP_CARDS = [ - { - title: 'Country GDP', - dataSettings: { - dataSource: 'WASM', - entitySet: 'CountryGDP', - chartAnnotation: { - chartType: { - type: 'Map', - map: 'World', - mapUrl: `https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json`, - projection: 'NaturalEarth1' - }, - dimensions: [ - { - dimension: 'Country' - }, - ], - measures: [ - { - dimension: 'Measures', - measure: 'GDP Per Capita', - formatting: { - shortNumber: true - } - } - ] - }, - }, - chartSettings: {}, - chartOptions: {} - }, - { - title: 'Csse Covid-19 Daily', - dataSettings: { - dataSource: 'WASM', - entitySet: 'CsseCovid19Daily', - chartAnnotation: { - chartType: { - type: 'Map', - map: 'World', - mapUrl: `https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json`, - projection: 'NaturalEarth1' - }, - dimensions: [ - { - dimension: 'Country_Region' - }, - { - dimension: 'Lat', - role: ChartDimensionRoleType.Lat - }, - { - dimension: 'Long_', - role: ChartDimensionRoleType.Long - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'Confirmed', - shapeType: 'scatter', - formatting: { - shortNumber: true - } - } - ] - }, - selectionVariant: { - selectOptions: [ - { - dimension: { - dimension: 'Country_Region' - }, - exclude: true, - members: [ - { - value: 'US' - } - ] - } - ] - } - }, - chartSettings: {}, - chartOptions: {} - }, - { - title: 'Csse Covid-19 Daily', - dataSettings: { - dataSource: 'WASM', - entitySet: 'CsseCovid19Daily', - chartAnnotation: { - chartType: { - type: 'Map', - map: 'World', - mapUrl: `https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json`, - projection: 'NaturalEarth1' - }, - dimensions: [ - { - dimension: 'Country_Region' - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'Incident_Rate', - formatting: { - shortNumber: true - } - } - ] - }, - selectionVariant: { - selectOptions: [ - { - dimension: { - dimension: 'Country_Region' - }, - exclude: true, - members: [ - { - value: 'US' - } - ] - } - ] - } - } - }, - { - title: 'Csse Covid-19 Daily', - dataSettings: { - dataSource: 'WASM', - entitySet: 'CsseCovid19Daily', - chartAnnotation: { - chartType: { - type: 'Map', - map: 'USA', - mapUrl: `https://raw.githubusercontent.com/PublicaMundi/MappingAPI/master/data/geojson/us-states.json`, - projection: 'AlbersUsa' - }, - dimensions: [ - { - dimension: 'Province_State' - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'Incident_Rate', - formatting: { - shortNumber: true - } - } - ] - }, - selectionVariant: { - selectOptions: [ - { - dimension: { - dimension: 'Country_Region' - }, - members: [ - { - value: 'US' - } - ] - } - ] - } - } - }, - { - title: 'Csse Covid-19 Daily', - dataSettings: { - dataSource: 'WASM', - entitySet: 'CsseCovid19Daily', - chartAnnotation: { - chartType: { - type: 'Map', - map: 'USA', - mapUrl: `https://raw.githubusercontent.com/PublicaMundi/MappingAPI/master/data/geojson/us-states.json` - }, - dimensions: [ - { - dimension: 'Province_State' - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'Confirmed', - formatting: { - shortNumber: true - } - } - // { - // dimension: 'Measures', - // measure: 'Deaths' - // }, - // { - // dimension: 'Measures', - // measure: 'Case_Fatality_Ratio', - // role: ChartMeasureRoleType.Axis2, - // formatting: { - // unit: '%' - // } - // } - ] - }, - selectionVariant: { - selectOptions: [ - { - dimension: { - dimension: 'Country_Region' - }, - members: [ - { - value: 'US' - } - ] - } - ] - }, - presentationVariant: { - sortOrder: [ - { - by: 'Confirmed', - order: OrderDirection.DESC - } - ] - } - }, - chartSettings: { - universalTransition: true - }, - chartOptions: { - dataZoom: { - type: ChartDataZoomType.INSIDE - } - } as ChartOptions - } -] - -export const CARTESIAN_CARDS = [ - { - title: 'Csse Covid-19 Daily', - dataSettings: { - dataSource: 'WASM', - entitySet: 'CsseCovid19Daily', - chartAnnotation: { - chartType: { - type: 'Bar' - }, - dimensions: [ - { - dimension: 'Country_Region' - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'Confirmed', - formatting: { - shortNumber: true - } - }, - { - dimension: 'Measures', - measure: 'Deaths' - }, - { - dimension: 'Measures', - measure: 'Case_Fatality_Ratio', - role: ChartMeasureRoleType.Axis2, - formatting: { - unit: '%' - } - } - ] - }, - presentationVariant: { - sortOrder: [ - { - by: 'Confirmed', - order: OrderDirection.DESC - } - ] - } - }, - chartSettings: { - universalTransition: true - }, - chartOptions: { - dataZoom: { - type: ChartDataZoomType.INSIDE - } - } as ChartOptions - }, - { - title: 'Sales Order Bar', - dataSettings: { - dataSource: 'Sales', - entitySet: 'SalesOrder', - chartAnnotation: { - chartType: { - type: 'Scatter3D' - }, - dimensions: [ - { - dimension: 'product', - role: ChartDimensionRoleType.Stacked - }, - { - dimension: 'productCategory' - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'sales' - }, - { - dimension: 'Measures', - measure: 'quantity', - role: ChartMeasureRoleType.Size - } - ] - } - } - }, - { - title: 'Sales Order Bar', - dataSettings: { - dataSource: 'Sales', - entitySet: 'SalesOrder', - chartAnnotation: { - chartType: { - type: 'Bar' - }, - dimensions: [ - { - dimension: 'product', - role: ChartDimensionRoleType.Stacked - }, - { - dimension: 'productCategory' - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'sales' - } - ] - } - } - }, - { - title: 'Purchase Order Bar', - dataSettings: { - dataSource: 'Sales', - entitySet: 'SalesOrder', - chartAnnotation: { - chartType: { - type: 'Bar' - }, - dimensions: [ - { - dimension: 'product' - }, - { - dimension: 'productCategory' - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'sales', - palette: { - name: 'PuOr', - pattern: 1 - }, - referenceLines: [ - { - label: 'Sales Average', - type: ReferenceLineType.markLine, - valueType: ReferenceLineValueType.dynamic, - aggregation: ReferenceLineAggregation.average - } - ] - } - ] - } - } - }, - { - title: 'Sales Order Line', - dataSettings: { - dataSource: 'Sales', - entitySet: 'SalesOrder', - chartAnnotation: { - chartType: { - type: 'Line' - }, - dimensions: [ - { - dimension: 'product' - }, - { - dimension: 'productCategory', - role: ChartDimensionRoleType.Trellis - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'sales' - } - ] - } - }, - chartSettings: { - universalTransition: true - } - }, - { - title: 'Sales Order Two Measures', - dataSettings: { - dataSource: 'Sales', - entitySet: 'SalesOrder', - chartAnnotation: { - chartType: { - type: 'Bar' - }, - dimensions: [ - { - dimension: 'product' - }, - { - dimension: 'productCategory', - role: ChartDimensionRoleType.Stacked - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'sales' - }, - { - dimension: 'Measures', - measure: 'quantity' - } - ] - } - }, - chartSettings: { - universalTransition: true - } - }, - { - title: 'Sales Order Treemap', - dataSettings: { - dataSource: 'Sales', - entitySet: 'SalesOrder', - chartAnnotation: { - chartType: { - type: 'Treemap' - }, - dimensions: [ - { - dimension: 'productCategory' - }, - { - dimension: 'product' - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'sales' - } - ] - } - }, - chartSettings: { - universalTransition: true - } - }, - { - title: 'Sales Order Heatmap', - dataSettings: { - dataSource: 'Sales', - entitySet: 'SalesOrder', - chartAnnotation: { - chartType: { - type: 'Heatmap' - }, - dimensions: [ - { - dimension: 'productCategory' - }, - { - dimension: 'product', - role: ChartDimensionRoleType.Category2 - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'sales', - palette: { - name: 'PuOr' - } - } - ] - } - }, - chartSettings: { - universalTransition: true - } - }, - { - title: 'Sales Order Scatter', - dataSettings: { - dataSource: 'Sales', - entitySet: 'SalesOrder', - chartAnnotation: { - chartType: { - type: 'Scatter' - }, - dimensions: [ - { - dimension: 'productCategory', - role: ChartDimensionRoleType.Trellis - }, - { - dimension: 'product' - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'sales', - palette: { - name: 'PuOr' - } - }, - { - dimension: 'Measures', - measure: 'quantity', - role: ChartMeasureRoleType.Size - } - ] - } - }, - chartSettings: { - universalTransition: true - } - }, - { - title: 'Sales Order Sankey', - dataSettings: { - dataSource: 'Sales', - entitySet: 'SalesOrder', - chartAnnotation: { - chartType: { - type: 'Sankey' - }, - dimensions: [ - { - dimension: 'productCategory' - }, - { - dimension: 'product' - } - ], - measures: [ - { - dimension: 'Measures', - measure: 'sales' - } - ] - } - }, - chartSettings: { - universalTransition: true - } - } -] diff --git a/apps/rc/src/assets/.gitkeep b/apps/rc/src/assets/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/rc/src/environments/environment.prod.ts b/apps/rc/src/environments/environment.prod.ts deleted file mode 100644 index c9669790b..000000000 --- a/apps/rc/src/environments/environment.prod.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const environment = { - production: true, -}; diff --git a/apps/rc/src/environments/environment.ts b/apps/rc/src/environments/environment.ts deleted file mode 100644 index 7ed83767f..000000000 --- a/apps/rc/src/environments/environment.ts +++ /dev/null @@ -1,6 +0,0 @@ -// This file can be replaced during build by using the `fileReplacements` array. -// When building for production, this file is replaced with `environment.prod.ts`. - -export const environment = { - production: false, -}; diff --git a/apps/rc/src/favicon.ico b/apps/rc/src/favicon.ico deleted file mode 100644 index 317ebcb23..000000000 Binary files a/apps/rc/src/favicon.ico and /dev/null differ diff --git a/apps/rc/src/index.html b/apps/rc/src/index.html deleted file mode 100644 index 2b031c9f8..000000000 --- a/apps/rc/src/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - Rc - - - - - - -
- - diff --git a/apps/rc/src/main.tsx b/apps/rc/src/main.tsx deleted file mode 100644 index ecea9d9aa..000000000 --- a/apps/rc/src/main.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { StrictMode } from 'react'; -import * as ReactDOMClient from 'react-dom/client'; - -import App from './app/app'; - -const root = ReactDOMClient.createRoot( - document.getElementById('root') as HTMLElement -); -root.render( - - - -); diff --git a/apps/rc/src/polyfills.ts b/apps/rc/src/polyfills.ts deleted file mode 100644 index 2adf3d05b..000000000 --- a/apps/rc/src/polyfills.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. - * - * See: https://github.com/zloirock/core-js#babel - */ -import 'core-js/stable'; -import 'regenerator-runtime/runtime'; diff --git a/apps/rc/src/styles.scss b/apps/rc/src/styles.scss deleted file mode 100644 index 3b081a130..000000000 --- a/apps/rc/src/styles.scss +++ /dev/null @@ -1,4 +0,0 @@ -/* You can add global styles to this file, and also import other style files */ -@tailwind components; -@tailwind base; -@tailwind utilities; diff --git a/apps/rc/tailwind.config.js b/apps/rc/tailwind.config.js deleted file mode 100644 index 28974e0f7..000000000 --- a/apps/rc/tailwind.config.js +++ /dev/null @@ -1,13 +0,0 @@ -const { createGlobPatternsForDependencies } = require('@nrwl/react/tailwind'); -const { join } = require('path'); - -module.exports = { - content: [ - join(__dirname, 'src/**/!(*.stories|*.spec).{ts,tsx,html}'), - ...createGlobPatternsForDependencies(__dirname), - ], - theme: { - extend: {}, - }, - plugins: [], -} diff --git a/apps/rc/tsconfig.app.json b/apps/rc/tsconfig.app.json deleted file mode 100644 index 252904bb7..000000000 --- a/apps/rc/tsconfig.app.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "types": ["node"] - }, - "files": [ - "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", - "../../node_modules/@nrwl/react/typings/image.d.ts" - ], - "exclude": [ - "**/*.spec.ts", - "**/*.test.ts", - "**/*.spec.tsx", - "**/*.test.tsx", - "**/*.spec.js", - "**/*.test.js", - "**/*.spec.jsx", - "**/*.test.jsx" - ], - "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] -} diff --git a/apps/rc/tsconfig.json b/apps/rc/tsconfig.json deleted file mode 100644 index ff68af63a..000000000 --- a/apps/rc/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "jsx": "react-jsx", - "allowJs": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - } - ] -} diff --git a/apps/rc/tsconfig.spec.json b/apps/rc/tsconfig.spec.json deleted file mode 100644 index 95ef66a08..000000000 --- a/apps/rc/tsconfig.spec.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "include": [ - "**/*.test.ts", - "**/*.spec.ts", - "**/*.test.tsx", - "**/*.spec.tsx", - "**/*.test.js", - "**/*.spec.js", - "**/*.test.jsx", - "**/*.spec.jsx", - "**/*.d.ts" - ], - "files": [ - "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", - "../../node_modules/@nrwl/react/typings/image.d.ts" - ] -} diff --git a/apps/vue-app-e2e/.eslintrc.json b/apps/vue-app-e2e/.eslintrc.json deleted file mode 100644 index 696cb8b12..000000000 --- a/apps/vue-app-e2e/.eslintrc.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - } - ] -} diff --git a/apps/vue-app-e2e/cypress.json b/apps/vue-app-e2e/cypress.json deleted file mode 100644 index 73c1101a2..000000000 --- a/apps/vue-app-e2e/cypress.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "fileServerFolder": ".", - "fixturesFolder": "./src/fixtures", - "integrationFolder": "./src/integration", - "modifyObstructiveCode": false, - "supportFile": "./src/support/index.ts", - "pluginsFile": false, - "video": true, - "videosFolder": "../../dist/cypress/apps/vue-app-e2e/videos", - "screenshotsFolder": "../../dist/cypress/apps/vue-app-e2e/screenshots", - "chromeWebSecurity": false -} diff --git a/apps/vue-app-e2e/project.json b/apps/vue-app-e2e/project.json deleted file mode 100644 index 3bc68175d..000000000 --- a/apps/vue-app-e2e/project.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "root": "apps/vue-app-e2e", - "sourceRoot": "apps/vue-app-e2e/src", - "projectType": "application", - "targets": { - "e2e": { - "executor": "@nrwl/cypress:cypress", - "options": { - "cypressConfig": "apps/vue-app-e2e/cypress.json", - "devServerTarget": "vue-app:serve" - }, - "configurations": { - "production": { - "devServerTarget": "vue-app:serve:production" - } - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["apps/vue-app-e2e/**/*.{js,ts}"] - } - } - }, - "tags": [], - "implicitDependencies": ["vue-app"] -} diff --git a/apps/vue-app-e2e/src/fixtures/example.json b/apps/vue-app-e2e/src/fixtures/example.json deleted file mode 100644 index 294cbed6c..000000000 --- a/apps/vue-app-e2e/src/fixtures/example.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io" -} diff --git a/apps/vue-app-e2e/src/integration/app.spec.ts b/apps/vue-app-e2e/src/integration/app.spec.ts deleted file mode 100644 index 637886301..000000000 --- a/apps/vue-app-e2e/src/integration/app.spec.ts +++ /dev/null @@ -1,6 +0,0 @@ -describe('vue-app', () => { - it('should display welcome message', () => { - cy.visit('/') - cy.contains('h1', 'Welcome to Your Vue.js + TypeScript App') - }) -}) diff --git a/apps/vue-app-e2e/src/support/app.po.ts b/apps/vue-app-e2e/src/support/app.po.ts deleted file mode 100644 index 00f556e10..000000000 --- a/apps/vue-app-e2e/src/support/app.po.ts +++ /dev/null @@ -1 +0,0 @@ -export const getGreeting = () => cy.get('h1') diff --git a/apps/vue-app-e2e/src/support/commands.ts b/apps/vue-app-e2e/src/support/commands.ts deleted file mode 100644 index 270f023ff..000000000 --- a/apps/vue-app-e2e/src/support/commands.ts +++ /dev/null @@ -1,33 +0,0 @@ -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** - -// eslint-disable-next-line @typescript-eslint/no-namespace -declare namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Chainable { - login(email: string, password: string): void - } -} -// -// -- This is a parent command -- -Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password) -}) -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/apps/vue-app-e2e/src/support/index.ts b/apps/vue-app-e2e/src/support/index.ts deleted file mode 100644 index 185d654ec..000000000 --- a/apps/vue-app-e2e/src/support/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands' diff --git a/apps/vue-app-e2e/tsconfig.json b/apps/vue-app-e2e/tsconfig.json deleted file mode 100644 index c4f818ecd..000000000 --- a/apps/vue-app-e2e/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "sourceMap": false, - "outDir": "../../dist/out-tsc", - "allowJs": true, - "types": ["cypress", "node"] - }, - "include": ["src/**/*.ts", "src/**/*.js"] -} diff --git a/apps/vue-app/.browserslistrc b/apps/vue-app/.browserslistrc deleted file mode 100644 index 214388fe4..000000000 --- a/apps/vue-app/.browserslistrc +++ /dev/null @@ -1,3 +0,0 @@ -> 1% -last 2 versions -not dead diff --git a/apps/vue-app/.eslintrc.json b/apps/vue-app/.eslintrc.json deleted file mode 100644 index 912421ddf..000000000 --- a/apps/vue-app/.eslintrc.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": ["../../.eslintrc.json", "plugin:vue/vue3-essential", "@vue/typescript/recommended", "prettier"], - "rules": {}, - "ignorePatterns": ["!**/*"], - "env": { - "node": true - }, - "overrides": [ - { - "files": ["**/*.spec.{j,t}s?(x)"], - "env": { - "jest": true - } - } - ] -} diff --git a/apps/vue-app/babel.config.js b/apps/vue-app/babel.config.js deleted file mode 100644 index 716b0237c..000000000 --- a/apps/vue-app/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: ['@vue/cli-plugin-babel/preset'] -} diff --git a/apps/vue-app/configure-webpack.js b/apps/vue-app/configure-webpack.js deleted file mode 100644 index 666aee0b5..000000000 --- a/apps/vue-app/configure-webpack.js +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Modify the webpack config by exporting an Object or Function. - * - * If the value is an Object, it will be merged into the final - * config using `webpack-merge`. - * - * If the value is a function, it will receive the resolved config - * as the argument. The function can either mutate the config and - * return nothing, OR return a cloned or merged version of the config. - * - * https://cli.vuejs.org/config/#configurewebpack - */ -module.exports = (config) => {} diff --git a/apps/vue-app/jest.config.js b/apps/vue-app/jest.config.js deleted file mode 100644 index 2e9280721..000000000 --- a/apps/vue-app/jest.config.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - displayName: 'vue-app', - preset: '../../jest.preset.js', - transform: { - '^.+.vue$': 'vue3-jest', - '.+.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', - '^.+.tsx?$': 'ts-jest' - }, - moduleFileExtensions: ['ts', 'tsx', 'vue', 'js', 'json'], - coverageDirectory: '../../coverage/apps/vue-app', - snapshotSerializers: ['jest-serializer-vue'], - globals: { - 'ts-jest': { - tsconfig: 'apps/vue-app/tsconfig.spec.json', - babelConfig: 'apps/vue-app/babel.config.js' - }, - 'vue-jest': { - tsConfig: 'apps/vue-app/tsconfig.spec.json', - babelConfig: 'apps/vue-app/babel.config.js' - } - } -} diff --git a/apps/vue-app/project.json b/apps/vue-app/project.json deleted file mode 100644 index f508baac5..000000000 --- a/apps/vue-app/project.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "root": "apps/vue-app", - "projectType": "application", - "sourceRoot": "apps/vue-app/src", - "targets": { - "build": { - "executor": "@nx-plus/vue:browser", - "options": { - "dest": "dist/apps/vue-app", - "index": "apps/vue-app/public/index.html", - "main": "apps/vue-app/src/main.ts", - "tsConfig": "apps/vue-app/tsconfig.app.json", - "public": [ - { - "glob": "*.wasm", - "input": "node_modules/@duckdb/duckdb-wasm/dist/", - "output": "./assets/" - }, - { - "glob": "*.worker.js", - "input": "node_modules/@duckdb/duckdb-wasm/dist/", - "output": "./assets/" - } - ] - }, - "configurations": { - "production": { - "mode": "production", - "filenameHashing": true, - "productionSourceMap": true, - "css": { - "extract": true, - "sourceMap": false - } - } - } - }, - "serve": { - "executor": "@nx-plus/vue:dev-server", - "options": { - "browserTarget": "vue-app:build" - }, - "configurations": { - "production": { - "browserTarget": "vue-app:build:production" - } - } - }, - "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["apps/vue-app/**/*.{ts,tsx,vue}"] - } - }, - "test": { - "executor": "@nrwl/jest:jest", - "outputs": ["coverage/apps/vue-app"], - "options": { - "jestConfig": "apps/vue-app/jest.config.js", - "passWithNoTests": true - } - } - }, - "tags": [] -} diff --git a/apps/vue-app/public/favicon.ico b/apps/vue-app/public/favicon.ico deleted file mode 100644 index 586794445..000000000 Binary files a/apps/vue-app/public/favicon.ico and /dev/null differ diff --git a/apps/vue-app/public/index.html b/apps/vue-app/public/index.html deleted file mode 100644 index 26d7f803a..000000000 --- a/apps/vue-app/public/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - <%= htmlWebpackPlugin.options.title %> - - - -
- - - diff --git a/apps/vue-app/src/App.vue b/apps/vue-app/src/App.vue deleted file mode 100644 index ec099f47c..000000000 --- a/apps/vue-app/src/App.vue +++ /dev/null @@ -1,152 +0,0 @@ - - - - - diff --git a/apps/vue-app/src/assets/logo.png b/apps/vue-app/src/assets/logo.png deleted file mode 100644 index f3d2503fc..000000000 Binary files a/apps/vue-app/src/assets/logo.png and /dev/null differ diff --git a/apps/vue-app/src/components/HelloWorld.vue b/apps/vue-app/src/components/HelloWorld.vue deleted file mode 100644 index 8546b2682..000000000 --- a/apps/vue-app/src/components/HelloWorld.vue +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - diff --git a/apps/vue-app/src/main.ts b/apps/vue-app/src/main.ts deleted file mode 100644 index e347f1ca5..000000000 --- a/apps/vue-app/src/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import * as SQL from '@metad/ocap-sql' -import { createApp } from 'vue' -import App from './App.vue' - -if (SQL) { - console.log(`加载 SQL`) -} - -createApp(App).mount('#app') diff --git a/apps/vue-app/src/shims-vue.d.ts b/apps/vue-app/src/shims-vue.d.ts deleted file mode 100644 index 6fd871156..000000000 --- a/apps/vue-app/src/shims-vue.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module '*.vue' { - import type { DefineComponent } from 'vue' - // eslint-disable-next-line - const component: DefineComponent<{}, {}, any> - export default component -} diff --git a/apps/vue-app/tests/unit/example.spec.ts b/apps/vue-app/tests/unit/example.spec.ts deleted file mode 100644 index 7038ce84c..000000000 --- a/apps/vue-app/tests/unit/example.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { shallowMount } from '@vue/test-utils' -import HelloWorld from '../../src/components/HelloWorld.vue' - -describe('HelloWorld.vue', () => { - it('renders props.msg when passed', () => { - const msg = 'new message' - const wrapper = shallowMount(HelloWorld, { - props: { msg } - }) - expect(wrapper.text()).toMatch(msg) - }) -}) diff --git a/apps/vue-app/tsconfig.app.json b/apps/vue-app/tsconfig.app.json deleted file mode 100644 index 6da687b63..000000000 --- a/apps/vue-app/tsconfig.app.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "types": ["webpack-env", "node"] - }, - "exclude": ["**/*.spec.ts", "**/*.spec.tsx"], - "include": ["**/*.ts", "**/*.tsx", "**/*.vue"] -} diff --git a/apps/vue-app/tsconfig.json b/apps/vue-app/tsconfig.json deleted file mode 100644 index 617c2384a..000000000 --- a/apps/vue-app/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "jsx": "preserve", - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "types": ["webpack-env", "node"], - "strict": true - }, - "include": [], - "files": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - } - ] -} diff --git a/apps/vue-app/tsconfig.spec.json b/apps/vue-app/tsconfig.spec.json deleted file mode 100644 index 3e5abc133..000000000 --- a/apps/vue-app/tsconfig.spec.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"], - "jsx": "preserve", - "esModuleInterop": true, - "allowSyntheticDefaultImports": true - }, - "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.test.tsx", "**/*.spec.tsx", "**/*.d.ts"] -} diff --git a/libs/apps/auth/src/lib/i18n/index.ts b/libs/apps/auth/src/lib/i18n/index.ts index 0eec1c963..161e3b519 100644 --- a/libs/apps/auth/src/lib/i18n/index.ts +++ b/libs/apps/auth/src/lib/i18n/index.ts @@ -1,2 +1,3 @@ export * from './zh' export * from './zhHans' +export * from './zhHant' diff --git a/libs/apps/auth/src/lib/i18n/zhHant.ts b/libs/apps/auth/src/lib/i18n/zhHant.ts new file mode 100644 index 000000000..6c3f2e9d0 --- /dev/null +++ b/libs/apps/auth/src/lib/i18n/zhHant.ts @@ -0,0 +1,42 @@ +export const ZhHant = { + Auth: { + AppName: '元數分析雲', + Copyright: '版權', + Login: '登錄', + Signin: '登錄', + Signup: '註冊', + ForgetPassword: '忘記密碼', + RequestPassword: '找回密碼', + RequestSend: '發送', + ChangePassword: '更改密碼', + Change: '更改', + NewPassword: '新密碼', + ConfirmPassword: '確認密碼', + RequestPasswordSuccess: '請求發送成功', + RequestPasswordFail: '請求發送失敗', + ResetPasswordSuccess: '更改密碼成功', + ResetPasswordFail: '更改密碼失敗', + SignupSuccess: '🎉 註冊成功, 請檢測你的郵箱並點擊鏈接激活賬號', + Varify: '驗證', + VarifyEmailSuccess: '郵箱驗證成功, 請前往登錄', + ACCEPT_INVITE: { + HEADING: '接受 {{ organizationName }} 的邀請', + SUB_HEADING: '完善註冊信息 {{ email }}', + ACCEPT_INVITE_FORM: { + FULL_NAME: '全名稱', + ENTER_YOUR_FULL_NAME: '輸入你的全名稱', + PASSWORD: '密碼', + REPEAT_PASSWORD: '確認密碼', + AGREE_TO: '同意', + TERMS_AND_CONDITIONS: '服務條款', + COMPLETE_REGISTRATION: '完成註冊' + }, + PROFILE_UPDATED: '用戶配置更新' + }, + 'Invitation no longer valid': '邀請已失效', + "The passwords don't match.": '密碼不匹配', + 'email exists': '郵箱已存在', + 'Password should be at least 4 characters long.': '密碼長度不少於 4 個字符', + 'Login/Email combination is not correct, please try again.': '賬號密碼不正確, 請重新登錄' + } +} diff --git a/libs/apps/indicator-market/i18n/index.ts b/libs/apps/indicator-market/i18n/index.ts index 1358c9cc7..05235b020 100644 --- a/libs/apps/indicator-market/i18n/index.ts +++ b/libs/apps/indicator-market/i18n/index.ts @@ -1 +1,2 @@ -export * from './zhHans' \ No newline at end of file +export * from './zhHans' +export * from './zhHant' \ No newline at end of file diff --git a/libs/apps/indicator-market/i18n/zhHans.ts b/libs/apps/indicator-market/i18n/zhHans.ts index dbedc75ea..c487d9655 100644 --- a/libs/apps/indicator-market/i18n/zhHans.ts +++ b/libs/apps/indicator-market/i18n/zhHans.ts @@ -25,5 +25,8 @@ export const ZhHans = { AskOrComment: '询问或评论', Pie: '饼图', Bar: '柱图', + TimeGranularity: '时间粒度', + LookbackLimit: '回溯限制', + Refresh: '刷新' } } diff --git a/libs/apps/indicator-market/i18n/zhHant.ts b/libs/apps/indicator-market/i18n/zhHant.ts new file mode 100644 index 000000000..3276fb743 --- /dev/null +++ b/libs/apps/indicator-market/i18n/zhHant.ts @@ -0,0 +1,32 @@ +export const ZhHant = { + IndicatorApp: { + Current: '當期', + MOM: '環比', + YTD: '年累計', + YOY: '同比', + BusinessCaliber: '業務口徑', + IndicatorMarket: '指標市場', + Empty: '空', + Goto: '請前往', + ApplyIndicatorPermission: '申請指標權限', + FreeDimensions: '自由維度', + IndicatorNameOrCode: '指標名稱或代碼', + TagEnum: { + [0]: '單位', + [1]: '環比', + [2]: '同比' + }, + DrillDown: '下鑽', + Done: '完成', + Comments: '評論', + AskCopilot: '詢問 AI 副駕駛', + SaveAsComment: '保存為評論', + IsPeriodRelated: '期間相關', + AskOrComment: '詢問或評論', + Pie: '餅圖', + Bar: '柱圖', + TimeGranularity: '時間粒度', + LookbackLimit: '回溯限制', + Refresh: '刷新' + } +} diff --git a/libs/apps/indicator-market/src/lib/_indicator-market-theme.scss b/libs/apps/indicator-market/src/lib/_indicator-market-theme.scss index 1655c2c8c..cacd6ff11 100644 --- a/libs/apps/indicator-market/src/lib/_indicator-market-theme.scss +++ b/libs/apps/indicator-market/src/lib/_indicator-market-theme.scss @@ -141,15 +141,6 @@ $trend-down: rgb(254, 60, 46); } } - .pac-indicator-market__settings-menu { - .settings-lookback { - overflow: visible; - .mat-slider { - width: 100%; - } - } - } - .pac-indicator-market__infinite-container.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper { max-width: 100%; diff --git a/apps/nest/src/app/.gitkeep b/libs/apps/indicator-market/src/lib/_indicator-market.component.scss similarity index 100% rename from apps/nest/src/app/.gitkeep rename to libs/apps/indicator-market/src/lib/_indicator-market.component.scss diff --git a/libs/apps/indicator-market/src/lib/indicator-item/indicator-item.component.ts b/libs/apps/indicator-market/src/lib/indicator-item/indicator-item.component.ts index 39fa21789..dc1d08194 100644 --- a/libs/apps/indicator-market/src/lib/indicator-item/indicator-item.component.ts +++ b/libs/apps/indicator-market/src/lib/indicator-item/indicator-item.component.ts @@ -1,15 +1,15 @@ import { Component, Input, inject } from '@angular/core' -import { UntilDestroy } from '@ngneat/until-destroy' import { BehaviorSubject, distinctUntilChanged, EMPTY, filter, switchMap, tap } from 'rxjs' import { IndicatorsStore } from '../services/store' import { IndicatorState, StatisticalType, TagEnum, Trend } from '../types' import { IndicatorItemDataService } from './indicator-item.service' +import { takeUntilDestroyed } from '@angular/core/rxjs-interop' + /** * 由于 cdk-virtual-scroll 原理 (待严格确定) 此组件不会随 indicator 变化而重新创建, 所以此组件的 indicator 输入会变化, 导致指标数据显示混乱 * */ -@UntilDestroy({ checkProperties: true }) @Component({ selector: 'pac-indicator-item', templateUrl: 'indicator-item.component.html', @@ -63,13 +63,17 @@ export class IndicatorItemComponent { }), ) }), + takeUntilDestroyed() ) .subscribe(() => { // }) private _indicatorResultSub = this.dataService.selectResult() - .pipe(filter((result: any) => result.indicator?.id && result.indicator?.id === this.indicator?.id)) + .pipe( + filter((result: any) => result.indicator?.id && result.indicator?.id === this.indicator?.id), + takeUntilDestroyed() + ) .subscribe((result: any) => { if (result?.error) { this.store.updateIndicator({ @@ -95,6 +99,11 @@ export class IndicatorItemComponent { } }) + // Response to global refresh event + private refreshSub = this.store.onRefresh().pipe(takeUntilDestroyed()).subscribe((force) => { + this.dataService.refresh(force) + }) + open() { console.log('open') } diff --git a/libs/apps/indicator-market/src/lib/indicator-item/indicator-item.service.ts b/libs/apps/indicator-market/src/lib/indicator-item/indicator-item.service.ts index 172bba54e..9eb11b5b5 100644 --- a/libs/apps/indicator-market/src/lib/indicator-item/indicator-item.service.ts +++ b/libs/apps/indicator-market/src/lib/indicator-item/indicator-item.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core' import { NgmDSCoreService } from '@metad/ocap-angular/core' -import { isNumber, PeriodFunctions, SmartIndicatorDataService } from '@metad/ocap-core' +import { isNumber, PeriodFunctions, QueryOptions, SmartIndicatorDataService } from '@metad/ocap-core' import { UntilDestroy } from '@ngneat/until-destroy' import { combineLatest, map } from 'rxjs' import { Trend } from '../types' @@ -13,12 +13,12 @@ export class IndicatorItemDataService extends SmartIndicatorDataService super(dsCoreService) } - override selectQuery() { + override selectQuery(options?: QueryOptions) { const lookBack = this.get((state) => state.lookBack) return combineLatest([ - super.selectQuery(null, null, [PeriodFunctions.CURRENT, PeriodFunctions.MOM, PeriodFunctions.YOY, PeriodFunctions.YTD], 0), - super.selectQuery(null, null, [PeriodFunctions.CURRENT], lookBack ?? 1) + super.selectQuery(options, null, [PeriodFunctions.CURRENT, PeriodFunctions.MOM, PeriodFunctions.YOY, PeriodFunctions.YTD], 0), + super.selectQuery(options, null, [PeriodFunctions.CURRENT], lookBack ?? 1) ]).pipe( map(([current, trends]) => { if (current.error || trends.error) { diff --git a/libs/apps/indicator-market/src/lib/indicator-market.component.html b/libs/apps/indicator-market/src/lib/indicator-market.component.html index b5e15b30b..54debcb04 100644 --- a/libs/apps/indicator-market/src/lib/indicator-market.component.html +++ b/libs/apps/indicator-market/src/lib/indicator-market.component.html @@ -16,9 +16,14 @@
{{tagText$ | async}}
- @@ -71,9 +76,11 @@ - - - - - + + + +
+ diff --git a/libs/apps/indicator-market/src/lib/indicator-market.component.scss b/libs/apps/indicator-market/src/lib/indicator-market.component.scss index 96aabe4e3..3a6286825 100644 --- a/libs/apps/indicator-market/src/lib/indicator-market.component.scss +++ b/libs/apps/indicator-market/src/lib/indicator-market.component.scss @@ -98,3 +98,7 @@ $searching-transition: all 300ms; background-color: $background-color; border: unset; } + +.pac-indicator-app__options { + background-color: var(--ngm-card-bg-color); +} diff --git a/libs/apps/indicator-market/src/lib/indicator-market.component.ts b/libs/apps/indicator-market/src/lib/indicator-market.component.ts index 17aef49a2..ed0c81c61 100644 --- a/libs/apps/indicator-market/src/lib/indicator-market.component.ts +++ b/libs/apps/indicator-market/src/lib/indicator-market.component.ts @@ -1,23 +1,34 @@ import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout' -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostBinding, Inject, LOCALE_ID, ViewChild, ViewContainerRef } from '@angular/core' +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + HostBinding, + Inject, + LOCALE_ID, + ViewChild, + ViewContainerRef +} from '@angular/core' +import { takeUntilDestroyed } from '@angular/core/rxjs-interop' import { FormControl } from '@angular/forms' import { MatBottomSheet, MatBottomSheetRef } from '@angular/material/bottom-sheet' +import { MatDatepicker } from '@angular/material/datepicker' +import { Store } from '@metad/cloud/state' import { NgmDSCoreService } from '@metad/ocap-angular/core' import { TimeGranularity } from '@metad/ocap-core' import { ComponentStore } from '@metad/store' -import { UntilDestroy } from '@ngneat/until-destroy' import { TranslateService } from '@ngx-translate/core' -import { Store } from '@metad/cloud/state' import { includes, some } from 'lodash-es' +import { NgxPopperjsPlacements, NgxPopperjsTriggers } from 'ngx-popperjs' import { combineLatest, firstValueFrom, Observable } from 'rxjs' import { distinctUntilChanged, map, shareReplay, switchMap, tap } from 'rxjs/operators' import { IndicatorDetailComponent } from './indicator-detail/indicator-detail.component' import { MyDataSource } from './services/data-source' import { IndicatorsStore } from './services/store' import { TagEnum } from './types' -import { MatDatepicker } from '@angular/material/datepicker' -@UntilDestroy({ checkProperties: true }) + @Component({ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'pac-indicator-market', @@ -25,10 +36,12 @@ import { MatDatepicker } from '@angular/material/datepicker' styleUrls: [`indicator-market.component.scss`], providers: [IndicatorsStore] }) -export class IndicatoryMarketComponent extends ComponentStore<{id?: string}> { +export class IndicatoryMarketComponent extends ComponentStore<{ id?: string }> { TIME_GRANULARITY = TimeGranularity + NgxPopperjsTriggers = NgxPopperjsTriggers + NgxPopperjsPlacements = NgxPopperjsPlacements - @HostBinding('class.nx-theme-dark') isDarkTheme = true + @HostBinding('class.nx-theme-dark.dark') isDarkTheme = true @HostBinding('class.indicator-market-app') isIndicatoryMarketComponent = true @HostBinding('class.searching') searching = false @@ -38,17 +51,19 @@ export class IndicatoryMarketComponent extends ComponentStore<{id?: string}> { public readonly tag$ = this.indicatorsStore.tag$ public readonly tagText$ = this.tag$.pipe( switchMap(async (tag) => { - const tagEnum = await firstValueFrom(this.translateService.get('IndicatorApp.TagEnum', { - Default: { - [TagEnum.UNIT]: 'Unit', - [TagEnum.MOM]: 'MOM', - [TagEnum.YOY]: 'YOY', - } - })) + const tagEnum = await firstValueFrom( + this.translateService.get('IndicatorApp.TagEnum', { + Default: { + [TagEnum.UNIT]: 'Unit', + [TagEnum.MOM]: 'MOM', + [TagEnum.YOY]: 'YOY' + } + }) + ) return tagEnum[tag] }) ) - + indicatorDataSource: MyDataSource // = new MyDataSource(this.indicatorsStore) readonly mediaMatcher$ = combineLatest( Object.keys(Breakpoints).map((name) => { @@ -76,11 +91,14 @@ export class IndicatoryMarketComponent extends ComponentStore<{id?: string}> { /** * Subscriptions */ - private _orgSub = this.store.selectOrganizationId().subscribe((id) => { - this.indicatorsStore.init() - this.onLookback(this.lookback) - this.indicatorDataSource = new MyDataSource(this.indicatorsStore) - }) + private _orgSub = this.store + .selectOrganizationId() + .pipe(takeUntilDestroyed()) + .subscribe((id) => { + this.indicatorsStore.init() + this.onLookback(this.lookback) + this.indicatorDataSource = new MyDataSource(this.indicatorsStore) + }) constructor( private store: Store, @@ -169,9 +187,9 @@ export class IndicatoryMarketComponent extends ComponentStore<{id?: string}> { } get lookbackLimit() { - switch(this.timeGranularity) { + switch (this.timeGranularity) { case TimeGranularity.Day: - return 365*2 + return 365 * 2 case TimeGranularity.Month: return 24 case TimeGranularity.Quarter: @@ -184,7 +202,7 @@ export class IndicatoryMarketComponent extends ComponentStore<{id?: string}> { } onLookback(event) { - this.indicatorsStore.patchState({lookBack: event}) + this.indicatorsStore.patchState({ lookBack: event }) } toggleTag(event) { @@ -193,6 +211,7 @@ export class IndicatoryMarketComponent extends ComponentStore<{id?: string}> { refresh() { // 强制刷新指标数据 + this.indicatorsStore.refresh(true) } onSearchFocus(event) { @@ -208,5 +227,4 @@ export class IndicatoryMarketComponent extends ComponentStore<{id?: string}> { public get reverse() { return this.locale === 'zh-Hans' } - } diff --git a/libs/apps/indicator-market/src/lib/indicator-market.module.ts b/libs/apps/indicator-market/src/lib/indicator-market.module.ts index 987a88713..1b8a7da05 100644 --- a/libs/apps/indicator-market/src/lib/indicator-market.module.ts +++ b/libs/apps/indicator-market/src/lib/indicator-market.module.ts @@ -16,13 +16,13 @@ import { MatInputModule } from '@angular/material/input' import { MatListModule } from '@angular/material/list' import { MatMenuModule } from '@angular/material/menu' import { MatSliderModule } from '@angular/material/slider' +import { FavoritesService, IndicatorsService } from '@metad/cloud/state' +import { ReversePipe } from '@metad/core' import { AnalyticalCardModule } from '@metad/ocap-angular/analytical-card' import { ControlsModule } from '@metad/ocap-angular/controls' import { AppearanceDirective, OcapCoreModule } from '@metad/ocap-angular/core' import { LetDirective } from '@ngrx/component' import { TranslateModule } from '@ngx-translate/core' -import { FavoritesService, IndicatorsService } from '@metad/cloud/state' -import { ReversePipe } from '@metad/core' import { NgxEchartsModule } from 'ngx-echarts' import { MarkdownModule } from 'ngx-markdown' import { NgxPopperjsModule } from 'ngx-popperjs' diff --git a/libs/apps/indicator-market/src/lib/services/store.ts b/libs/apps/indicator-market/src/lib/services/store.ts index cb9d36474..aa97b9d1d 100644 --- a/libs/apps/indicator-market/src/lib/services/store.ts +++ b/libs/apps/indicator-market/src/lib/services/store.ts @@ -14,7 +14,7 @@ import { } from '@metad/cloud/state' import { convertStoryModel2DataSource, StoryModel } from '@metad/story/core' import { assign, includes, isEmpty, isEqual, sortBy, uniq } from 'lodash-es' -import { combineLatest, firstValueFrom, Observable } from 'rxjs' +import { combineLatest, firstValueFrom, Observable, Subject } from 'rxjs' import { concatMap, debounceTime, distinctUntilChanged, map, shareReplay, switchMap, tap } from 'rxjs/operators' import { IndicatorState, TagEnum } from '../types' @@ -74,6 +74,8 @@ export class IndicatorsStore extends ComponentStore { this.patchState({locale: value}) } + private refresh$ = new Subject() + // TODO distinctUntilChanged 需要找到原因 public readonly all$: Observable = this.select(selectAll).pipe(distinctUntilChanged(isEqual)) @@ -103,6 +105,7 @@ export class IndicatorsStore extends ComponentStore { public readonly tag$ = this.select((state) => state.tag) public readonly lookBack$ = this.select((state) => state.lookBack) + constructor( private modelsService: ModelsService, private indicatorService: IndicatorsService, @@ -309,4 +312,12 @@ export class IndicatorsStore extends ComponentStore { } }) } + + onRefresh() { + return this.refresh$.asObservable() + } + + refresh(force = false) { + this.refresh$.next(force) + } } diff --git a/libs/apps/state/src/lib/stories.service.ts b/libs/apps/state/src/lib/stories.service.ts index 89f22727e..c79aa3488 100644 --- a/libs/apps/state/src/lib/stories.service.ts +++ b/libs/apps/state/src/lib/stories.service.ts @@ -8,6 +8,8 @@ import { OrganizationBaseService } from './organization-base.service' import { Store } from './store.service' import { convertStory, convertStoryResult } from './types' +const C_API_STORY_PUBLIC = C_API_STORY + '/public/' + @Injectable({ providedIn: 'root' }) @@ -56,7 +58,7 @@ export class StoriesService extends OrganizationBaseService { } getPublicOne(id: string): Observable { - return this.httpClient.get(C_API_STORY + '/public/' + id, { + return this.httpClient.get(C_API_STORY_PUBLIC + id, { params: new HttpParams().append( '$query', JSON.stringify({ @@ -121,7 +123,7 @@ export class StoriesService extends OrganizationBaseService { } getTrends(params: { skip: number; take: number; orderType: 'visits' | 'update' }, searchText?: string) { - return this.httpClient.get>(C_API_STORY + `/trends`, { + return this.httpClient.get>(C_API_STORY_PUBLIC + 'trends', { params: { ...params, relations: ['createdBy', 'updatedBy', 'preview'], diff --git a/libs/component-angular/core/date-fns/date-fns-date-adapter.ts b/libs/component-angular/core/date-fns/date-fns-date-adapter.ts index a6fac4a30..0b5b9ea4f 100644 --- a/libs/component-angular/core/date-fns/date-fns-date-adapter.ts +++ b/libs/component-angular/core/date-fns/date-fns-date-adapter.ts @@ -52,125 +52,125 @@ function range(start: number, end: number): number[] { return arr } -@Injectable() -export class NxDateFnsDateAdapter extends DateAdapter { - addCalendarDays(date: Date, days: number): Date { - return addDays(date, days) - } - - addCalendarMonths(date: Date, months: number): Date { - return addMonths(date, months) - } - - addCalendarYears(date: Date, years: number): Date { - return addYears(date, years) - } - - clone(date: Date): Date { - return toDate(date) - } - - createDate(year: number, month: number, date: number): Date { - return new Date(year, month, date) - } - - format(date: Date, displayFormat: any): string { - return format(date, displayFormat, { - locale, - }) - } - - getDate(date: Date): number { - return getDate(date) - } - - getDateNames(): string[] { - return range(1, 31).map((day) => String(day)) - } - - getDayOfWeek(date: Date): number { - return parseInt(format(date, 'i'), 10) - } - - getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[] { - const map = { - long: 'EEEE', - short: 'E..EEE', - narrow: 'EEEEE', - } - - let formatStr = map[style] - let date = new Date() - - return range(0, 6).map((month) => - format(setDay(date, month), formatStr, { - locale, - }) - ) - } - - getFirstDayOfWeek(): number { - return WEEK_STARTS_ON - } - - getMonth(date: Date): number { - return getMonth(date) - } - - getMonthNames(style: 'long' | 'short' | 'narrow'): string[] { - const map = { - long: 'LLLL', - short: 'LLL', - narrow: 'LLLLL', - } - - let formatStr = map[style] - let date = new Date() - - return range(0, 11).map((month) => - format(setMonth(date, month), formatStr, { - locale, - }) - ) - } - - getNumDaysInMonth(date: Date): number { - return getDaysInMonth(date) - } - - getYear(date: Date): number { - return getYear(date) - } - - getYearName(date: Date): string { - return format(date, 'yyyy', { - locale, - }) - } - - invalid(): Date { - return new Date(NaN) - } - - isDateInstance(obj: any): boolean { - return obj instanceof Date - } - - isValid(date: Date): boolean { - return date instanceof Date && !isNaN(date.getTime()) - } - - parse(value: any, parseFormat: any): Date | null { - return parse(value, parseFormat, new Date(), { - locale, - }) - } - - toIso8601(date: Date): string { - return date.toISOString() - } - - today(): Date { - return new Date() - } -} +// @Injectable() +// export class NxDateFnsDateAdapter extends DateAdapter { +// addCalendarDays(date: Date, days: number): Date { +// return addDays(date, days) +// } + +// addCalendarMonths(date: Date, months: number): Date { +// return addMonths(date, months) +// } + +// addCalendarYears(date: Date, years: number): Date { +// return addYears(date, years) +// } + +// clone(date: Date): Date { +// return toDate(date) +// } + +// createDate(year: number, month: number, date: number): Date { +// return new Date(year, month, date) +// } + +// format(date: Date, displayFormat: any): string { +// return format(date, displayFormat, { +// locale, +// }) +// } + +// getDate(date: Date): number { +// return getDate(date) +// } + +// getDateNames(): string[] { +// return range(1, 31).map((day) => String(day)) +// } + +// getDayOfWeek(date: Date): number { +// return parseInt(format(date, 'i'), 10) +// } + +// getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[] { +// const map = { +// long: 'EEEE', +// short: 'E..EEE', +// narrow: 'EEEEE', +// } + +// let formatStr = map[style] +// let date = new Date() + +// return range(0, 6).map((month) => +// format(setDay(date, month), formatStr, { +// locale, +// }) +// ) +// } + +// getFirstDayOfWeek(): number { +// return WEEK_STARTS_ON +// } + +// getMonth(date: Date): number { +// return getMonth(date) +// } + +// getMonthNames(style: 'long' | 'short' | 'narrow'): string[] { +// const map = { +// long: 'LLLL', +// short: 'LLL', +// narrow: 'LLLLL', +// } + +// let formatStr = map[style] +// let date = new Date() + +// return range(0, 11).map((month) => +// format(setMonth(date, month), formatStr, { +// locale, +// }) +// ) +// } + +// getNumDaysInMonth(date: Date): number { +// return getDaysInMonth(date) +// } + +// getYear(date: Date): number { +// return getYear(date) +// } + +// getYearName(date: Date): string { +// return format(date, 'yyyy', { +// locale, +// }) +// } + +// invalid(): Date { +// return new Date(NaN) +// } + +// isDateInstance(obj: any): boolean { +// return obj instanceof Date +// } + +// isValid(date: Date): boolean { +// return date instanceof Date && !isNaN(date.getTime()) +// } + +// parse(value: any, parseFormat: any): Date | null { +// return parse(value, parseFormat, new Date(), { +// locale, +// }) +// } + +// toIso8601(date: Date): string { +// return date.toISOString() +// } + +// today(): Date { +// return new Date() +// } +// } diff --git a/libs/component-angular/datepicker/datepicker.component.ts b/libs/component-angular/datepicker/datepicker.component.ts index 465009ee3..507254eca 100644 --- a/libs/component-angular/datepicker/datepicker.component.ts +++ b/libs/component-angular/datepicker/datepicker.component.ts @@ -1,6 +1,5 @@ import { Component, EventEmitter, forwardRef, inject, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core' import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms' -import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core' import { MatDatepicker } from '@angular/material/datepicker' import { MatFormFieldAppearance } from '@angular/material/form-field' import { NgmSmartFilterService } from '@metad/ocap-angular/controls' @@ -18,7 +17,6 @@ import { calcRange, mapTimeGranularitySemantic, } from '@metad/ocap-core' -import { NxDateFnsDateAdapter } from '@metad/components/core' import { NxCoreService, TIME_GRANULARITY_SEQUENCES @@ -300,6 +298,7 @@ export class NgmMemberDatepickerComponent implements OnInit, OnChanges, ControlV if (!event) { this.dateChanged(null) } else { + // } } } @@ -322,24 +321,6 @@ export class NgmMemberDatepickerComponent implements OnInit, OnChanges, ControlV
`, providers: [ - { - provide: DateAdapter, - useClass: NxDateFnsDateAdapter - }, - { - provide: MAT_DATE_FORMATS, - useValue: { - parse: { - dateInput: `yyyy'Q'Q` - }, - display: { - dateInput: `yyyy'Q'Q`, - monthYearLabel: 'LLL y', - dateA11yLabel: 'MMMM d, y', - monthYearA11yLabel: 'MMMM y' - } - } - }, { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxQuarterFilterComponent), // replace name as appropriate @@ -347,7 +328,7 @@ export class NgmMemberDatepickerComponent implements OnInit, OnChanges, ControlV } ] }) -export class NxQuarterFilterComponent implements OnInit, ControlValueAccessor { +export class NxQuarterFilterComponent implements ControlValueAccessor { @Input() appearance: MatFormFieldAppearance @Input() label: string @Input() placeholder: string @@ -363,10 +344,6 @@ export class NxQuarterFilterComponent implements OnInit, ControlValueAccessor { */ onTouched: () => void = () => {} - constructor() {} - - ngOnInit(): void {} - chosenYearHandler(event) { const ctrlValue = this.date.value this.date.setValue(setYear(ctrlValue, getYear(event))) @@ -413,24 +390,6 @@ export class NxQuarterFilterComponent implements OnInit, ControlValueAccessor {
`, providers: [ - { - provide: DateAdapter, - useClass: NxDateFnsDateAdapter - }, - { - provide: MAT_DATE_FORMATS, - useValue: { - parse: { - dateInput: `yyyyMM` - }, - display: { - dateInput: `yyyyMM`, - monthYearLabel: 'LLL y', - dateA11yLabel: 'MMMM d, y', - monthYearA11yLabel: 'MMMM y' - } - } - }, { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxMonthFilterComponent), // replace name as appropriate @@ -438,7 +397,7 @@ export class NxQuarterFilterComponent implements OnInit, ControlValueAccessor { } ] }) -export class NxMonthFilterComponent implements OnInit, ControlValueAccessor { +export class NxMonthFilterComponent implements ControlValueAccessor { @Input() appearance: MatFormFieldAppearance @Input() label: string @Input() placeholder: string @@ -454,10 +413,6 @@ export class NxMonthFilterComponent implements OnInit, ControlValueAccessor { */ onTouched: () => void = () => {} - constructor() {} - - ngOnInit(): void {} - chosenYearHandler(event) { const ctrlValue = this.date.value this.date.setValue(setYear(ctrlValue, getYear(event))) @@ -499,24 +454,6 @@ export class NxMonthFilterComponent implements OnInit, ControlValueAccessor {
`, providers: [ - { - provide: DateAdapter, - useClass: NxDateFnsDateAdapter - }, - { - provide: MAT_DATE_FORMATS, - useValue: { - parse: { - dateInput: `yyyy` - }, - display: { - dateInput: `yyyy`, - monthYearLabel: 'LLL y', - dateA11yLabel: 'MMMM d, y', - monthYearA11yLabel: 'MMMM y' - } - } - }, { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NxYearFilterComponent), // replace name as appropriate @@ -524,7 +461,7 @@ export class NxMonthFilterComponent implements OnInit, ControlValueAccessor { } ] }) -export class NxYearFilterComponent implements OnInit, ControlValueAccessor { +export class NxYearFilterComponent implements ControlValueAccessor { @Input() appearance: MatFormFieldAppearance @Input() label: string @Input() placeholder: string @@ -540,10 +477,6 @@ export class NxYearFilterComponent implements OnInit, ControlValueAccessor { */ onTouched: () => void = () => {} - constructor() {} - - ngOnInit(): void {} - chosenYearHandler(event, datepicker: MatDatepicker) { // const ctrlValue = this.date.value this.date.setValue(event) // setYear(ctrlValue, getYear(event))) diff --git a/libs/component-angular/datepicker/monthpicker/monthpicker.component.ts b/libs/component-angular/datepicker/monthpicker/monthpicker.component.ts index ebc580e57..b5d7595ed 100644 --- a/libs/component-angular/datepicker/monthpicker/monthpicker.component.ts +++ b/libs/component-angular/datepicker/monthpicker/monthpicker.component.ts @@ -1,13 +1,12 @@ import { CommonModule } from '@angular/common' import { Component, forwardRef } from '@angular/core' import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms' -import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core' +import { MAT_DATE_FORMATS } from '@angular/material/core' import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker' import { MatInputModule } from '@angular/material/input' -import { getMonth, getYear, setMonth, setYear } from 'date-fns' -import { NxDateFnsDateAdapter } from '@metad/components/core' -import { NgmCommonModule, NgmInputComponent } from '@metad/ocap-angular/common' +import { NgmInputComponent } from '@metad/ocap-angular/common' import { OcapCoreModule } from '@metad/ocap-angular/core' +import { getMonth, getYear, setMonth, setYear } from 'date-fns' @Component({ standalone: true, @@ -16,10 +15,6 @@ import { OcapCoreModule } from '@metad/ocap-angular/core' templateUrl: './monthpicker.component.html', styleUrls: ['./monthpicker.component.scss'], providers: [ - { - provide: DateAdapter, - useClass: NxDateFnsDateAdapter - }, { provide: MAT_DATE_FORMATS, useValue: { diff --git a/libs/component-angular/datepicker/quarterpicker/quarterpicker.component.ts b/libs/component-angular/datepicker/quarterpicker/quarterpicker.component.ts index 86207a909..1114d5366 100644 --- a/libs/component-angular/datepicker/quarterpicker/quarterpicker.component.ts +++ b/libs/component-angular/datepicker/quarterpicker/quarterpicker.component.ts @@ -1,14 +1,12 @@ import { CommonModule } from '@angular/common' import { Component, forwardRef } from '@angular/core' import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms' -import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core' +import { MAT_DATE_FORMATS } from '@angular/material/core' import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker' import { MatInputModule } from '@angular/material/input' import { OcapCoreModule } from '@metad/ocap-angular/core' -import { NxDateFnsDateAdapter } from '@metad/components/core' import { getMonth, getYear, setMonth, setYear } from 'date-fns' - @Component({ standalone: true, imports: [CommonModule, ReactiveFormsModule, MatDatepickerModule, MatInputModule, OcapCoreModule], @@ -16,10 +14,6 @@ import { getMonth, getYear, setMonth, setYear } from 'date-fns' templateUrl: './quarterpicker.component.html', styleUrls: ['./quarterpicker.component.scss'], providers: [ - { - provide: DateAdapter, - useClass: NxDateFnsDateAdapter - }, { provide: MAT_DATE_FORMATS, useValue: { diff --git a/libs/component-angular/datepicker/yearpicker/yearpicker.component.ts b/libs/component-angular/datepicker/yearpicker/yearpicker.component.ts index e8dc4747e..fc87dae90 100644 --- a/libs/component-angular/datepicker/yearpicker/yearpicker.component.ts +++ b/libs/component-angular/datepicker/yearpicker/yearpicker.component.ts @@ -1,11 +1,10 @@ import { CommonModule } from '@angular/common' import { Component, forwardRef } from '@angular/core' import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms' -import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core' +import { MAT_DATE_FORMATS } from '@angular/material/core' import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker' import { MatInputModule } from '@angular/material/input' import { OcapCoreModule } from '@metad/ocap-angular/core' -import { NxDateFnsDateAdapter } from '@metad/components/core' import { getYear, setYear } from 'date-fns' @Component({ @@ -15,10 +14,6 @@ import { getYear, setYear } from 'date-fns' templateUrl: './yearpicker.component.html', styleUrls: ['./yearpicker.component.scss'], providers: [ - { - provide: DateAdapter, - useClass: NxDateFnsDateAdapter - }, { provide: MAT_DATE_FORMATS, useValue: { diff --git a/libs/component-angular/table/table/table.component.html b/libs/component-angular/table/table/table.component.html index 94c749f48..4053f2b9a 100644 --- a/libs/component-angular/table/table/table.component.html +++ b/libs/component-angular/table/table/table.component.html @@ -1,5 +1,8 @@
- +
diff --git a/libs/component-angular/table/table/table.component.ts b/libs/component-angular/table/table/table.component.ts index 4ba376422..6e3d4952b 100644 --- a/libs/component-angular/table/table/table.component.ts +++ b/libs/component-angular/table/table/table.component.ts @@ -21,6 +21,7 @@ import { TranslateService } from '@ngx-translate/core' import get from 'lodash-es/get' import { Subject } from 'rxjs' import { TableColumn } from '../types' +import { DisplayDensity } from '@metad/ocap-angular/core' @UntilDestroy() @Injectable() @@ -127,10 +128,12 @@ export class NxTableComponent implements OnChanges, AfterViewInit { } private _selectable = false + @Input() displayDensity: DisplayDensity | string = DisplayDensity.compact + /** * A cell or row was selected. */ - @Output() select: EventEmitter = new EventEmitter() + // @Output() select: EventEmitter = new EventEmitter() @Output() rowSelectionChanging = new EventEmitter() @ViewChild(MatPaginator) paginator: MatPaginator diff --git a/libs/component-angular/time-filter/today-filter/today-filter.component.ts b/libs/component-angular/time-filter/today-filter/today-filter.component.ts index c1ca0d9bc..ed9151753 100644 --- a/libs/component-angular/time-filter/today-filter/today-filter.component.ts +++ b/libs/component-angular/time-filter/today-filter/today-filter.component.ts @@ -1,11 +1,10 @@ import { Component, forwardRef, HostBinding, inject, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core' import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl } from '@angular/forms' -import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core' +import { MAT_DATE_FORMATS } from '@angular/material/core' import { MatDatepicker } from '@angular/material/datepicker' import { DisplayDensity, NgmAppearance, NgmDSCoreService } from '@metad/ocap-angular/core' import { TimeGranularity } from '@metad/ocap-core' import { UntilDestroy } from '@ngneat/until-destroy' -import { NxDateFnsDateAdapter } from '@metad/components/core' import { NxCoreService, TIME_GRANULARITY_SEQUENCES } from '@metad/core' import { getMonth, getYear, isDate, setMonth, setYear } from 'date-fns' import { filter } from 'rxjs/operators' @@ -107,10 +106,6 @@ export class NxTodayFilterComponent implements OnInit, OnChanges, ControlValueAc `, styleUrls: ['./today-filter.component.scss'], providers: [ - { - provide: DateAdapter, - useClass: NxDateFnsDateAdapter - }, { provide: MAT_DATE_FORMATS, useValue: { @@ -189,10 +184,6 @@ export class NxQuarterFilterComponent implements ControlValueAccessor { `, styleUrls: ['./today-filter.component.scss'], providers: [ - { - provide: DateAdapter, - useClass: NxDateFnsDateAdapter - }, { provide: MAT_DATE_FORMATS, useValue: { @@ -272,10 +263,6 @@ export class NxMonthFilterComponent implements ControlValueAccessor { `, styleUrls: ['./today-filter.component.scss'], providers: [ - { - provide: DateAdapter, - useClass: NxDateFnsDateAdapter - }, { provide: MAT_DATE_FORMATS, useValue: { diff --git a/libs/core-angular/src/lib/i18n/locale_zh-Hant.ts b/libs/core-angular/src/lib/i18n/locale_zh-Hant.ts new file mode 100644 index 000000000..eaaeee037 --- /dev/null +++ b/libs/core-angular/src/lib/i18n/locale_zh-Hant.ts @@ -0,0 +1,30 @@ +import { DateVariableEnum } from '../models' + +export const DateVariable = { + [DateVariableEnum.SYSTEMTIME]: '系统时间', + [DateVariableEnum.TODAY]: '今天', + [DateVariableEnum.YESTERDAY]: '昨天', + [DateVariableEnum.DBY]: '前天', + [DateVariableEnum.DAYS_7_AGO]: '七天前', + [DateVariableEnum.DAYS_8_AGO]: '八天前', + [DateVariableEnum.DAYS_14_AGO]: '十四天前', + [DateVariableEnum.DAYS_15_AGO]: '十五天前', + [DateVariableEnum.DAYS_30_AGO]: '三十天前', + [DateVariableEnum.DAYS_31_AGO]: '三十一天前', + [DateVariableEnum.RECENT_7_DAYS]: '最近七天', + [DateVariableEnum.RECENT_14_DAYS]: '最近十四天', + [DateVariableEnum.RECENT_30_DAYS]: '最近三十天', + [DateVariableEnum.RECENT_90_DAYS]: '最近九十天', + [DateVariableEnum.RECENT_180_DAYS]: '最近一百八十天', + [DateVariableEnum.THIS_WEEK]: '本周', + [DateVariableEnum.THIS_MONTH]: '本月', + [DateVariableEnum.PREVIOUS_MONTH]: '上月', + [DateVariableEnum.THIS_QUARTER]: '本季度', + [DateVariableEnum.YEAR_TO_TODAY]: '当前年至当天', + [DateVariableEnum.YEAR_TO_YESTERDAY]: '当前年至昨天', + [DateVariableEnum.THIS_WHOLE_WEEK]: '本周(包含整周)', + [DateVariableEnum.THIS_WHOLE_MONTH]: '本月(包含整月)', + [DateVariableEnum.THIS_WHOLE_QUARTER]: '本季度(包含整季度)', + [DateVariableEnum.THIS_WHOLE_YEAR]: '今年(包含整年)', + [DateVariableEnum.PREVIOUS_YEAR]: '去年', +} diff --git a/libs/core-angular/src/lib/locales/index.ts b/libs/core-angular/src/lib/locales/index.ts index a3a160c1e..b85b44acf 100644 --- a/libs/core-angular/src/lib/locales/index.ts +++ b/libs/core-angular/src/lib/locales/index.ts @@ -1,2 +1,4 @@ export { default as enUS } from './en-US' export { default as zhHans } from './zh-Hans' +export { default as zhHant } from './zh-Hant' +export * from './utils' \ No newline at end of file diff --git a/libs/core-angular/src/lib/locales/utils.ts b/libs/core-angular/src/lib/locales/utils.ts new file mode 100644 index 000000000..0db1d022b --- /dev/null +++ b/libs/core-angular/src/lib/locales/utils.ts @@ -0,0 +1,11 @@ +export function mapLangToLocale(lang) { + switch (lang) { + case 'en': + return 'en-US'; + case 'zh': + case 'zh-CN': + return 'zh-Hans'; + default: + return lang; + } +} \ No newline at end of file diff --git a/libs/core-angular/src/lib/locales/zh-Hant.ts b/libs/core-angular/src/lib/locales/zh-Hant.ts new file mode 100644 index 000000000..82e4f3766 --- /dev/null +++ b/libs/core-angular/src/lib/locales/zh-Hant.ts @@ -0,0 +1,46 @@ +import { DateVariableEnum } from '../models' + +/** + * 中文 shortNumber 基礎配置 + */ +export default { + lang: 'zh-Hant', + shortNumberFactor: 4, + shortNumberUnits: '萬,億,萬億', + + DateVariable: { + [DateVariableEnum.SYSTEMTIME]: '系統時間', + [DateVariableEnum.TODAY]: '當前日期', + [DateVariableEnum.YESTERDAY]: '昨天', + [DateVariableEnum.DBY]: '前天', + [DateVariableEnum.DAYS_7_AGO]: '七天前', + [DateVariableEnum.DAYS_8_AGO]: '八天前', + [DateVariableEnum.DAYS_14_AGO]: '十四天前', + [DateVariableEnum.DAYS_15_AGO]: '十五天前', + [DateVariableEnum.DAYS_30_AGO]: '三十天前', + [DateVariableEnum.DAYS_31_AGO]: '三十一天前', + [DateVariableEnum.RECENT_7_DAYS]: '最近七天', + [DateVariableEnum.RECENT_14_DAYS]: '最近十四天', + [DateVariableEnum.RECENT_30_DAYS]: '最近三十天', + [DateVariableEnum.RECENT_90_DAYS]: '最近九十天', + [DateVariableEnum.RECENT_180_DAYS]: '最近一百八十天', + [DateVariableEnum.THIS_WEEK]: '本周', + [DateVariableEnum.THIS_MONTH]: '本月', + [DateVariableEnum.PREVIOUS_MONTH]: '上月', + [DateVariableEnum.THIS_QUARTER]: '本季度', + [DateVariableEnum.YEAR_TO_TODAY]: '當前年至當天', + [DateVariableEnum.YEAR_TO_YESTERDAY]: '當前年至昨天', + [DateVariableEnum.THIS_WHOLE_WEEK]: '本周(包含整周)', + [DateVariableEnum.THIS_WHOLE_MONTH]: '本月(包含整月)', + [DateVariableEnum.THIS_WHOLE_QUARTER]: '本季度(包含整季度)', + [DateVariableEnum.THIS_WHOLE_YEAR]: '今年(包含整年)', + [DateVariableEnum.PREVIOUS_YEAR]: '去年' + }, + + NgCore: { + Widget: { + Rank: '排名', + Top: '前', + } + } +} diff --git a/libs/core-angular/src/lib/pipes/short-number.pipe.ts b/libs/core-angular/src/lib/pipes/short-number.pipe.ts index 22dfb15a6..933025836 100644 --- a/libs/core-angular/src/lib/pipes/short-number.pipe.ts +++ b/libs/core-angular/src/lib/pipes/short-number.pipe.ts @@ -113,7 +113,7 @@ export class ShortNumberPipe implements PipeTransform { * * @returns null 或者 short结果数组 (例如: ['4.53', 'K'] ['5.62', '万']) */ -export function formatShortNumber(value: number|string, locale, factor?, shortUnits?): [number, string] { +export function formatShortNumber(value: number|string, locale: string, factor?: number , shortUnits?: string): [number, string] { try { const num = strToNumber(value); diff --git a/libs/story-angular/i18n/index.ts b/libs/story-angular/i18n/index.ts index 1358c9cc7..05235b020 100644 --- a/libs/story-angular/i18n/index.ts +++ b/libs/story-angular/i18n/index.ts @@ -1 +1,2 @@ -export * from './zhHans' \ No newline at end of file +export * from './zhHans' +export * from './zhHant' \ No newline at end of file diff --git a/libs/story-angular/i18n/zhHans.ts b/libs/story-angular/i18n/zhHans.ts index 44f145d5b..7f09672f8 100644 --- a/libs/story-angular/i18n/zhHans.ts +++ b/libs/story-angular/i18n/zhHans.ts @@ -126,6 +126,7 @@ export const ZhHans = { ThumbnailUrl: '缩略图链接', Models: '模型', AddSemanticModels: '添加语义模型', + PreviewExceedsMaximum: '文件大小超过限制', }, Preferences: { Title: '首选项', @@ -679,7 +680,8 @@ export const ZhHans = { Template: '模板', Theme: '主题', ConfirmApply: '应用模板将覆盖故事中的所有页面。你想继续吗?', - Tags: '标签' + Tags: '标签', + PreviewExceedsMaximum: '文件大小超过限制', }, STYLING: { CSS: { diff --git a/libs/story-angular/i18n/zhHant.ts b/libs/story-angular/i18n/zhHant.ts new file mode 100644 index 000000000..a9abac6d8 --- /dev/null +++ b/libs/story-angular/i18n/zhHant.ts @@ -0,0 +1,1276 @@ +export const ZhHant = { + Story: { + Common: { + Apply: '應用', + Cancel: '取消', + Close: '關閉', + Search: '搜索', + Select: '選擇', + Search_Placeholder: '請輸入關鍵詞', + DisplayBehaviour_Description: '描述', + DisplayBehaviour_DescriptionID: '描述 ID', + DisplayBehaviour_IDDescription: 'ID 描述', + DisplayBehaviour_ID: 'ID', + DisplayBehaviour_Auto: '自動', + SelectionType_Single: '單選', + SelectionType_Multiple: '多選', + Presentation_Flat: '平鋪', + Presentation_Hierarchy: '層級', + HierarchySelectionMode_Individual: '單個', + HierarchySelectionMode_SelfDescendants: '自己和後代', + HierarchySelectionMode_DescendantsOnly: '只後代', + HierarchySelectionMode_SelfChildren: '自己和子代', + HierarchySelectionMode_ChildrenOnly: '只子代', + Measures: '度量', + Builder: '構建', + Styling: '樣式', + Label: '標籤', + Placeholder: '占位符', + Story: '故事', + Name: '名稱', + Description: '描述', + Theme: { + Title: '主題', + System: '跟隨系統', + Light: '淺色模式', + Dark: '深色模式', + Thin: '輕色模式' + }, + Untitled: '未命名', + Styles: '樣式', + Parameters: '參數', + Calculations: '計算成員', + StoryTemplates: '故事模板', + ThemeBuilder: '主題構建器', + Suggested: '推薦', + My: '我的', + Save: '保存', + Upload: '上傳', + Reset: '重置', + Public: '公開', + ReUpload: '重新上傳', + Widget: '部件', + ConfirmDeleteInfo: '在實際保存之前不會從服務器上刪除' + }, + Shares: { + VisibilityChanged: '可見性已更改', + Share: '分享', + Embed: '嵌入', + ApplicationURL: '應用鏈接', + StoryVisibility: '故事可見度', + Visibility: '可見度', + Visibility_public: '公開', + Visibility_secret: '密鑰', + Visibility_private: '內部', + EmbedURL: '嵌入鏈接', + Preview: '預覽', + CopyURL: '複製鏈接', + CopyURLSuccess: '複製鏈接成功', + Expires: '過期時間 (分鐘)', + ExpiresDescription: '過期時間後,鏈接將不再可用', + Generate: '生成', + GenerateLinkToPreview: '生成鏈接以預覽', + InitialPage: '初始頁面', + Default: '默認', + SemanticModelPublicFirst: '請先將語義模型可見性更改為公開!', + }, + Designer: { + LookingEmpty: '這個故事看起來有些空洞', + LookingEmptyAddStoryPoint: '添加一個故事點來開始吧' + }, + Story: { + Share: '分享', + Save: '保存', + GlobalFilters: '全局過濾器', + Delete: '刪除', + Copy: '複製', + CopyTo: '複製到', + Duplicate: '複印', + Paste: '粘貼', + Rename: '重命名', + Hidden: '隱藏', + Visiable: '可見', + MOVE_LEFT: '向左移動', + MOVE_RIGHT: '向右移動', + MOVE_FIRST: '移動首位', + MOVE_LAST: '移動末位', + COMMENT: '評論', + NewResponsivePage: '新響應頁面', + NewCanvasPage: '新畫布頁面', + SaveSuccess: '保存成功', + SaveFailed: '保存失敗', + Upload: '上傳' + }, + StoryPoint: { + SaveFailed: '故事頁面保存失敗', + SaveSuccess: '故事頁面保存成功', + LookingEmpty: '這個故事點看起來很空洞', + LookingEmptyAddWidget: '添加一個故事部件開始吧' + }, + StoryDetails: { + StoryName: '故事名稱', + ModelAlias: '模型別名', + TITLE: '故事詳情', + LOCALE: '國家語言代碼', + LOCALE_enUS: '英文(美國)', + LOCALE_en: '英文', + LOCALE_zhHans: '中文簡體', + THEME: '主題', + HIDE_STORY_FILTER_BAR: '隱藏全局過濾器', + DISPLAY_AS_FULLSCREEN: '顯示為全屏', + SHOW_FULLSCREEN_BUTTON: '顯示全屏按鈕', + Description: '描述', + DescriptionPlaceholder: '可選,故事的描述', + General: '通用', + Thumbnail: '縮略圖', + ThumbnailUrl: '縮略圖鏈接', + Models: '模型', + AddSemanticModels: '添加語義模型', + PreviewExceedsMaximum: '文件大小超過限制', + }, + Preferences: { + Title: '首選項', + PageStyles: '頁面樣式', + WidgetStyles: '組件樣式', + CardStyles: '卡片樣式', + TextStyles: '文本樣式', + TableStyles: '表格樣式', + ControlStyles: '控制器樣式', + TabBar: '選項卡欄', + TabBar_Fixed: '固定', + TabBar_Point: '浮點', + TabBar_Hidden: '隱藏', + PageHeaderPosition: '頁面選項卡欄位置', + PageHeaderPosition_Above: '上方', + PageHeaderPosition_Below: '下方', + PageHeaderStretchTabs: '頁面選項卡欄拉伸', + PageHeaderShowLabel: '頁面導航顯示標籤', + PageHeaderLabel: '頁面導航標籤', + PageHeaderAlignTabs: '頁面選項卡欄對齊', + PageHeaderAlignTabs_Start: '開始', + PageHeaderAlignTabs_Center: '居中', + PageHeaderAlignTabs_End: '末端', + PageHeaderShowLabel_Auto: '自動', + PageHeaderShowLabel_Always: '總是', + PageHeaderShowLabel_Never: '從不', + WatermarkOptions: '水印配置', + Text: '文字', + Alpha: '透明度', + Degree: '角度', + StoryStyles: '故事樣式', + WatermarkText: '水印文字', + Width: '寬度', + Height: '高度' + }, + Parameters: { + Title: '參數' + }, + Query: { + Title: '查詢' + }, + Toolbar: { + SaveAs: '另存為', + SaveAsTemplate: '另存為模版', + FILE: '文件', + MENU: '菜單', + MORE: '更多', + MODELING: '模型', + New_Responsive_Page: '新響應頁面', + New_Canvas_Page: '新畫布頁面', + Devices: '設備', + MobileDevices: '移動設備', + EmulatedDevices: '設備型號', + Fullscreen: '全屏', + ExitFullscreen: '退出全屏', + DeviceFold: '摺疊設備', + Orientation: '方向', + Fit: '適配', + OpenModel: '打開模型', + Editable: '編輯', + Preview: '預覽', + Scale: '縮放', + Scale_Unset: '重置', + Widgets: '部件', + Charts: '圖形', + NewPage: '新頁面', + GlobalStyles: '全局樣式', + AttributesPanel: '屬性面板', + PanMode: '平移模式(Alt)', + ZoomIn: '放大(Alt +)', + ZoomOut: '縮小(Alt -)', + 'Default Canvas': '默認畫布', + 'Fit Screen (Dense)': '適配屏幕 (緊湊)', + 'Fit Screen (Cosy)': '適配屏幕 (舒適)', + 'Fit Screen (Comfort)': '適配屏幕 (寬鬆)', + 'Fixed Dense (MacBook Pro 14)': '固定緊湊 (MacBook Pro 14)', + 'Fixed Cosy (MacBook Pro 14)': '固定舒適 (MacBook Pro 14)', + 'Fixed Comfort (MacBook Pro 14)': '固定寬鬆 (MacBook Pro 14)', + 'Vertical Fixed (Phone)': '垂直固定 (手機)', + AddTemplate: '添加模版', + More: '更多', + Less: '收起', + Data: '數據', + Pages: '頁面', + AutoPaging: '自動翻頁', + CopiedtoClipboard: '已複製到剪貼板', + Width: '寬度', + Height: '高度', + EmulatedDevice_Unset: '重置', + EmulatedDevice_Custom: '自定義', + PREFERENCES: { + TITLE: '首選項', + PREFERENCES: '首選項', + DETAILS: '詳情', + ADVANCED_STYLE: '高級樣式', + QUERY_SETTINGS: '查詢設置', + SMART_INSIGHTS: '智慧洞察', + SUBSCRIPTION: '訂閱', + Parameters: '參數', + Calculations: '計算成員', + Templates: '模版', + ThemeBuilder: '主題構建器' + }, + Edit: { + Title: '編輯' + }, + SAVE: { + SAVE: '保存', + SAVE_AS: '另存為', + SAVE_AS_TEMPLATE: '另存為模板', + EXPORT: '導出' + }, + COPY: { + COPY: '複製', + COPY_TO: '複製到', + DUPLICATE: '複印', + PASTE: '粘貼' + }, + SHARE: { + SHARE: '分享', + SHARE_TO: '分享到' + }, + INSERT: { + INSERT: '插入', + IMAGE: '圖片', + FILTER_BAR: '過濾器欄', + ChartCard: '圖形卡片', + InputControl: '輸入控制器', + Table: '表格', + KPI: '關鍵指標', + Document: '文檔', + PivotTable: '透視表', + Geo_Map: '地圖', + Text: '文本', + Image: '圖片', + Today: '今天', + 'Tab Group': '選項卡', + 'Financial Table': '財務表格', + 'Indicator Card': '指標卡片', + Swiper: '滑動組件', + Column: '柱條形圖', + ColumnStacked: '堆積柱條形圖', + Video: '視頻' + } + }, + Widget: { + UpdateFailed: '部件更新失敗', + SaveSuccess: '部件保存成功', + PinSuccess: '部件固定成功', + PinFailed: '部件固定失敗', + MoveTo: '移動到', + Explain: '解釋', + AnalyticalCard: '圖形', + AnalyticalGrid: '表格', + InputControl: '輸入控制器', + KpiCard: '關鍵指標', + BringForward: '上移一層', + BringtoFront: '置於頂層', + SendBackward: '下移一層', + SendtoBack: '置於底層', + EditAttributes: '編輯屬性', + Refresh: '刷新', + Fullscreen: '全屏', + ExitFullscreen: '退出全屏', + Focus: '聚焦', + LinkedAnalysis: '關聯分析', + Navigate: '導航', + PinHome: '固定到首頁', + Share: '分享', + Download: '下載' + }, + LinkedAnalysis: { + Title: '聯動分析', + InteractionApplyTo: '應用至', + OnlyThisWidget: '僅此組件', + AllWidgetsInTheStory: '故事中所有組件', + AllWidgetsOnPage: '頁面中所有組件', + OnlySelectedWidgets: '僅選中組件', + SelectWidgets: '選擇組件', + ConnectNewly: '自動關聯新建部件' + }, + GridOptions: { + TITLE: '網格布局', + None: '無', + GRID_TYPE: '布局類型', + SetGridSize: '固定網格大小', + FixedColumnWidth: '固定列寬', + FixedRowHeight: '固定行高', + MinColsDefault: '默認 10', + MinRowsDefault: '默認 10', + DisplayGrid: '顯示網格', + DisplayGrid_None: '默認', + DisplayGrid_Always: '總是', + DisplayGrid_OnDrag: '拖動時', + CompactType: '緊湊類型', + MinCols: '最小列數', + MinRows: '最小行數', + Margin: '邊緣空白', + OuterMargin: '外邊距', + SwapWhileDragging: '拖動時互換', + AllowMultiLayer: '多層', + DefaultLayerIndex: '默認層級', + MaxLayerIndex: '最大層級', + BaseLayerIndex: '基礎層級', + ScrollToNewItems: '滾動到新元素', + Scale: '縮放', + DisablePushOnDrag: '禁用拖時推', + Type_FittoScreen: '適應屏幕', + Type_VerticalFixed: '垂直固定', + Type_HorizontalFixed: '水平固定', + Type_Fixed: '固定大小' + }, + Widgets: { + Common: { + Title: '標題', + Options: '設置', + initialHierarchyLevel: '初始展示層級', + ShowAllMember: '顯示『All』成員', + None: '無', + Display_Density: '顯示密度', + DensityComfortable: '舒適', + DensityCosy: '適中', + DensityCompact: '緊湊', + TITLE: '標題', + CALCULATED_MEMBER: '計算成員', + DATA: '數據', + DATA_SETTINGS: '數據配置', + SemanticModel: '語義模型', + Entity: '模型實體', + DATA_SOURCE: '數據源', + ENTITY_SET: '模型', + COMPONENT_TYPE: '組件類型', + MODELING: '建模', + NAME: '名稱', + LABEL: '標籤', + SELECTION_VARIANT: '選擇條件', + SELECT_OPTIONS: '過濾器', + PRESENTATION_VARIANT: '展示變式', + TOP: '前', + SORT_BY: '排序', + BY_FIELD: '字段', + DRILL_DOWN: '下鑽維度', + SELECTION_FIELDS_ANNOTATION: { + DIMENSIONS: '維度' + }, + SelectionType: '值類型', + SingleValue: '單值', + MultiValue: '多值', + SingleInterval: '單間隔', + SingleRange: '單區間', + Appearance: '外觀', + FormFieldAppearance: '表單字段外觀', + FormFieldAppearance_Standard: '標準', + FormFieldAppearance_Fill: '填充', + FormFieldAppearance_Outline: '輪廓', + FormFieldFloatLabel: '表單字段浮動標籤', + FormFieldFloatLabel_Always: '總是', + FormFieldFloatLabel_Auto: '自動', + FormFieldFloatLabel_Never: '從不', + Float_Label: '浮動標籤', + Label: '標籤', + Placeholder: '占位符', + Widget: '組件', + OPTIONS: '設置', + Text: '文本', + InsertText: '插入文本...', + Image: '圖片', + ComponentStyling: '組件樣式', + TitleStyling: '標題樣式', + ValueStyling: '值樣式', + SlideStyling: '幻燈片樣式', + ComponentType: '組件類型', + AnalyticalCard: '圖形', + AnalyticalGrid: '表格', + InputControl: '輸入控制器', + IndicatorCard: '指標卡', + AccountingStatement: '會計報表', + IntentNavigation: '導航', + NavigationType: '導航類型', + StoryPoint: '故事點', + Page: '頁面', + StoryStyling: '故事樣式', + Colors: '顏色', + BackgroundColor: '背景顏色', + Color_Auto: '自動', + Color_Primary: '主色', + Color_Accent: '強調色', + Color_Warn: '警告色', + Preview: '預覽', + }, + FilterBar: { + Title: '過濾器欄', + ControlType: { + Title: '控制器類型', + Auto: '自動', + TreeSelect: '樹型選擇', + Select: '成員選擇', + Datepicker: '日曆', + DropDownList: '下拉選擇' + }, + ControlOptions: '控制選項', + TITLE: '過濾器欄', + OPTIONS: '設置', + LIVE_MODE: '實時查詢', + CascadingEffect: '級聯聯動', + CascadingType: '級聯類型', + CascadingType_Default: '默認', + CascadingType_InTurn: '從前到後', + CascadingType_All: '所有', + EnableToday: '啟用當前時間輸入', + CombinationSlicer: '組合切片器', + Query: '查詢', + SaveAsDefaultMembers: '保存為默認成員' + }, + Filter: { + Autocomplete: '自動補全', + InitialLevel: '初始層級', + VirtualScroll: '虛擬滾動', + Multiple: '多選', + Searchable: '可搜索', + MaxTagCount: '最大標籤數量', + AutoActiveFirst: '自動激活第一選項', + USER_DEFINED_DATA: '用戶自定義數據', + Value: '值', + Label: '標籤', + PanelWidth: '下拉麵板寬度', + SelectionType: '值類型', + SingleRange: '單區間', + Single: '單值', + Granularity: '時間粒度', + GranularitySequence: '粒度序列', + TimeFormatter: '時間格式', + DefaultTimeFunction: '默認時間函數', + DefaultTimeFunction_None: '無', + DefaultTime: '默認時間', + Year: '年', + Quarter: '季', + Month: '月', + Day: '日', + ShowAllMember: '顯示『所有』成員' + }, + AnalyticalCard: { + Title: '分析圖形', + Sort: '排序' + }, + AnalyticalGrid: { + Title: '分析表格', + OPTIONS: '設置', + GridOptions: '表格選項', + showToolbar: '顯示工具欄', + exportExcel: '導出 Excel', + columnPinning: '列固定', + Strip: '條斑', + Rows: '行', + Columns: '列', + Paging: '分頁', + PageSize: '每頁行數', + HideDataDownload: '隱藏數據下載', + TableHeaderSticky: '表抬頭固定', + Grid: '網格', + InitialRowLevel: '行初始層級', + InitialColumnLevel: '列初始層級', + Sortable: '可排序', + ColumnSelectable: '列可選擇', + DigitsInfo: '數字格式', + Unit: '度量單位', + CurrencyCode: '貨幣碼', + Bar: '欄', + IsBar: '條型狀', + }, + InputControl: { + Title: '輸入控制器', + InputControlTitle: '輸入控制器標題', + Options: '選項', + SELECT_MODEL: '選擇模型', + ENTITY: '模型實體', + DIMENSIONS: '維度', + MEASURES: '度量', + EditInputControl: '編輯控制器', + UseSlider: '使用滑杆', + SliderMax: '滑杆最大值', + SliderMin: '滑杆最小值', + SliderStep: '滑杆單步大小', + SliderTickInterval: '滑杆間隔長度', + SliderInvert: '滑杆倒置', + SliderVertical: '滑杆垂直', + Color: '顏色', + Color_Auto: '自動', + Color_Primary: 'Primary', + Color_Accent: 'Accent', + Color_Warn: 'Warn', + MemberSource: '成員來源', + MemberSource_AUTO: '自動', + MemberSource_CUBE: '立方體', + MemberSource_DIMENSION: '維度成員', + RadioButton: '單選按鈕', + HideSingleSelectionIndicator: '隱藏單選指示器', + Autocomplete: '自動補全', + ControlType: '控制器類型', + ControlOptions: '控制器選項', + MaxTagCount: '最大標籤數量', + AutoActiveFirst: '自動激活第一選項', + Searchable: '可搜索', + CascadingEffect: '級聯過濾', + TreeSelect: '樹狀選擇', + FlatSelect: '平鋪選擇', + DropDownList: '下拉選擇', + Auto: '自動', + SaveAsDefaultMembers: '另存為默認值', + ClearDefaultMembers: '清除默認值', + HideSelectionIndicator: '隱藏選擇指示器', + HighlightedOptions: '高亮選項', + showThumbLabel: '顯示標籤', + ShowTickMarks: '顯示刻度', + SamePropertyAlreadyExists: '相同字段的組件已存在' + }, + TabGroup: { + Title: '選項卡', + AnimationDuration: '動畫時間', + Options: '選項卡配置', + Components: '組件', + DisableRipple: '禁用漣漪', + PreserveContent: '保存內容', + Color: '顏色', + AlignTabs: '對齊', + HeaderPosition: '抬頭位置', + None: '無', + Above: '上面', + Below: '下面', + DisablePagination: '禁用分頁', + Disabled: '禁用', + Details: '詳情', + StretchTabs: '拉伸', + }, + WIDGET: { + ANALYTICAL_CARD: '分析卡片', + AnalyticalGrid: '分析表格', + ACCOUNTING_STATEMENT: '財務報表', + INDICATOR_CARD: '指標卡片', + TABSET: '選項卡' + }, + IFrame: { + SRC: '源鏈接' + }, + KPI: { + Title: '關鍵指標', + TitleStyle: '標題樣式', + Value: '值', + TargetValue: '目標值', + Options: '屬性', + ShortNumber: '縮寫數字', + DigitsInfo: '數字格式', + Unit: '單位', + UnitSemantics: '單位語義', + CurrencyCode: '貨幣碼', + UnitOfMeasure: '度量單位', + ShowDeviation: '顯示偏差', + DeviationText: '偏差文本', + AdditionalDataPoints: '其他數據指標', + MainKPI: '主關鍵指標' + }, + IndicatorCard: { + Title: '指標卡片', + YearOnYear: '同比' + }, + Swiper: { + Title: '滑動組件', + Slides: '幻燈片', + Details: '詳情', + Options: '屬性', + SlidesPerView: '每屏卡片數', + SpaceBetween: '卡片間隔', + CenteredSlides: '居中', + Direction: '方向', + Horizontal: '橫向', + Vertical: '縱向', + GrabCursor: '抓手', + Autoplay: '自動播放', + Virtual: '虛擬滾動', + Breakpoints: '自適應斷點', + BreakpointSize: '大小', + TouchRatio: '觸摸率', + Pagination: '分頁', + Type: '類型', + Bullets: '子彈', + Fraction: '分數', + Progressbar: '進度條', + Clickable: '點擊', + Delay: '延遲', + DisableOnInteraction: '交互時暫停', + PauseOnMouseEnter: '鼠標懸停暫停', + ReverseDirection: '反向', + StopOnLastSlide: '最後一張停止', + WaitForTransition: '等待過渡', + Effect: '效果', + Slide: '滑動', + Fade: '淡入淡出', + Cube: '立方體', + Coverflow: '覆蓋流', + Flip: '翻轉', + Creative: '創意', + Cards: '卡片', + CreativeEffect: '創意效果', + HideOnClick: '點擊隱藏', + DynamicBullets: '動態子彈', + Enabled: '啟用', + Loop: '循環', + Mousewheel: '鼠標滾輪', + KeyboardControl: '鍵盤控制', + OnlyInViewport: '僅在視窗中', + PageUpDown: '上下翻頁' + }, + AccountingStatement: { + Title: '會計報表' + }, + Document: { + Title: '文檔', + GetStarted: '開始編輯' + }, + Image: { + Title: '圖片', + ImageSizeMode: '大小模式', + ImageSizeModeFitComponent: '適應組件', + ImageSizeModeFitWidth: '適應寬度', + ImageSizeModeFitHeight: '適應高度', + ImageSizeModeOriginalSize: '原始大小', + ImageUrl: '圖片鏈接' + }, + Video: { + VideoUrl: '視頻鏈接' + } + }, + Explain: { + Title: '執行解釋', + ExecuteStatements: '執行語句', + Statement: '語句', + Error: '錯誤', + ErrorInfo: '錯誤信息', + ChartOptions: '圖形配置', + Options: '配置', + Data: '數據', + Slicers: '切片器' + }, + Template: { + TemplateDelete: '刪除模板', + SaveAsStoryTemplate: '另存為故事模版', + CreateOrUpdateTemplate: '創建或更新模板', + Preview: '預覽圖', + Use: '使用', + Type: '類型', + Template: '模板', + Theme: '主題', + ConfirmApply: '應用模板將覆蓋故事中的所有頁面。你想繼續嗎?', + Tags: '標籤', + PreviewExceedsMaximum: '文件大小超過限制', + }, + STYLING: { + CSS: { + BACKGROUND: { + TITLE: '背景', + BackgroundColor: '背景顏色', + Background: '背景', + BackgroundImage: '背景圖片', + BackgroundPosition: '背景位置', + BackgroundSize: '背景大小', + BackgroundRepeat: '背景重複', + BackdropFilter: '背景濾鏡', + Opacity: '不透明度', + BackgroundAttachment: '背景附着' + }, + BOX: { + TITLE: '盒子', + BoxShadow: '盒子陰影', + BorderWidth: '邊框大小', + BorderColor: '邊框顏色', + BorderRadius: '邊框半徑', + BorderStyle: '邊框樣式', + BorderStyle_Null: '空', + BorderStyle_Solid: '實線', + BorderStyle_None: '無', + BorderStyle_Hidden: '隱藏', + BorderStyle_Dashed: '虛線', + BorderStyle_Dotted: '點線', + BorderStyle_Double: '雙線', + BorderStyle_Groove: '槽線', + BorderStyle_Ridge: '脊線', + BorderStyle_Inset: '內凹', + BorderStyle_Outset: '外凸' + }, + LAYOUT: { + TITLE: '布局', + Padding: '填充空白', + Margin: '邊緣空白', + Overflow: '溢出' + }, + SIZE: { + TITLE: '大小', + Width: '寬度', + Height: '高度', + MinWidth: '最小寬度', + MinHeight: '最小高度', + MaxWidth: '最大寬度', + MaxHeight: '最大高度' + }, + FONT: { + TITLE: '字體', + None: '無', + FontSize: '字體大小', + FontColor: '字體顏色', + FontFamily: '字體', + FontStyle: '字體樣式', + FontWeight: '字重', + TextDecoration: '文本裝飾', + TextAlign: '文本對齊', + TextDecoration_Overline: '上劃線', + TextDecoration_Underline: '下劃線', + TextDecoration_LineThrough: '刪除線', + TextAlign_Left: '左對齊', + TextAlign_Center: '居中', + TextAlign_Right: '右對齊', + TextAlign_Top: '頂端對齊', + TextAlign_Middle: '垂直居中', + TextAlign_Bottom: '底對齊', + FontWeight_Bold: '加粗', + FontWeight_Lighter: '細化', + FontWeight_Normal: '正常', + FontStyle_Italic: '斜體 Italic', + FontStyle_Oblique: '斜體 Oblique', + FontStyle_Normal: '正常', + FontFamily_Song: '宋體' + } + }, + + CANVAS: { + TITLE: '畫布' + }, + + STORY_PAGE: { + PAGE_SIZE: '頁面大小', + DefaultBackground: '預設背景', + Dynamic: '動態', + Fixed: '固定', + ContinuousHeight: '連續的高度' + }, + + ECHARTS: { + Common: { + Align: '對齊', + Show: '顯示', + LEFT: '左側距離', + TOP: '上側距離', + RIGHT: '右側距離', + BOTTOM: '下側距離', + Opacity: '不透明度', + Color: '顏色', + ColorJSONPlaceholder: 'JSON 格式的顏色', + BorderWidth: '邊框寬度', + BorderColor: '邊框顏色', + BorderRadius: '邊框半徑', + BorderStyle: '邊框樣式', + BorderType: '邊框類型', + BorderJoin: '邊框連接', + BorderCap: '邊框帽', + BorderMiterLimit: '邊框斜接限制', + UniversalTransition: '全局過渡動畫', + Label: '標籤', + Position: '位置', + Left: '左側', + Right: '右側', + Silent: '靜默', + Cursor: '光標', + Cursor_Auto: '自動', + Cursor_Pointer: '指針', + Cursor_Move: '移動', + ColorBy: '按着色', + ColorBy_Auto: '自動', + ColorBy_SameSeries: '相同系列', + ColorBy_DataItems: '數據項', + SeriesLayoutBy: '數據布局', + Auto: '自動', + Column: '列', + Row: '行', + SelectedMode: '選擇模式', + SelectedMode_None: '無', + SelectedMode_Single: '單選', + SelectedMode_Multiple: '多選', + SelectedMode_Series: '系列', + Formatter: '格式化', + Rotate: '旋轉', + Enabled: '啟用', + Width: '寬度', + Height: '高度', + Disabled: '禁用', + Orient: '方向', + Horizontal: '橫向', + Vertical: '縱向', + None: '無', + Padding: '填充空白', + Radius: '半徑', + Symbol: '符號', + SymbolSize: '符號大小', + SymbolRotate: '符號旋轉', + SymbolOffset: '符號位移', + Stack: '堆積', + TextAlign: { + Title: '文本對齊', + Auto: '自動', + Left: '靠左', + Right: '靠右', + Center: '居中' + } + }, + Global: { + Title: '全局', + DarkMode: '暗黑模式', + BackgroundColor: '背景顏色', + Animation: '動畫', + AnimationThreshold: '動畫閾值', + AnimationDuration: '動畫時間', + AnimationEasing: '動畫函數', + AnimationDelay: '動畫延遲', + AnimationDurationUpdate: '更新動畫時間', + AnimationEasingUpdate: '更新動畫函數', + AnimationDelayUpdate: '更新動畫延遲' + }, + SHADOW: { + SHADOW_BLUR: '陰影模糊', + SHADOW_COLOR: '陰影顏色', + SHADOW_OFFSETX: '水平偏移', + SHADOW_OFFSETY: '垂直偏移' + }, + CATEGORY_AXIS: { + TITLE: '分類軸', + SHOW: '是否顯示', + Position: '位置', + Offset: '偏移', + ShowName: '顯示名稱', + Name: '名稱', + NameLocation: '名稱位置', + NameGap: '名稱間隔', + NameRotate: '名稱旋轉', + Inverse: '倒轉', + BoundaryGap: '邊界差', + Min: '最小值', + Max: '最大值', + Silent: '靜默' + }, + VALUE_AXIS: { + TITLE: '值軸', + SHOW: '是否顯示', + SplitNumber: '分割數', + ValueScale: '自動範圍', + Min: '最小值', + Max: '最大值' + }, + Axis: { + Title: '軸' + }, + SingleAxis: { + Title: '單軸' + }, + XAXIS_STYLE: { + XAXIS: 'x 軸', + SHOW: '顯示', + NAME_LOCATION: '坐標軸名稱顯示位置', + NAME_TEXT_STYLE: '坐標軸名稱的文字樣式', + COLOR: '坐標軸名稱的顏色', + AXIS_LINE: '坐標軸軸線相關設置', + AXIS_LINE_COLOR: '坐標軸線線的顏色', + AXIS_LABEL: '坐標軸刻度標籤的相關設置', + AXISLABEL_ALIGN: '文字水平對齊方式', + AXISLABEL_VERTICALALIGN: '文字垂直對齊方式', + AXIS_TYPE: '坐標軸類型', + AXIS_GRID_AREA_SEPARATOR: '坐標軸grid區域分隔線', + SHOW_SEPARATOR_LINES: '是否顯示分割線', + SEPARATOR_LINE_STYLE: '分隔線樣式', + SEPARATOR_COLOR: '分割線顏色' + }, + YAXIS_STYLE: { + YAXIS: 'y 軸', + SHOW: '顯示', + NAME_LOCATION: '坐標軸名稱顯示位置', + NAME_TEXT_STYLE: '坐標軸名稱的文字樣式', + COLOR: '坐標軸名稱的顏色', + AXIS_LINE: '坐標軸軸線相關設置', + AXIS_LINE_COLOR: '坐標軸線線的顏色', + AXIS_LABEL: '坐標軸刻度標籤的相關設置', + AXISLABEL_ALIGN: '文字水平對齊方式', + AXISLABEL_VERTICALALIGN: '文字垂直對齊方式', + AXIS_GRID_AREA_SEPARATOR: '坐標軸grid區域分隔線', + SHOW_SEPARATOR_LINES: '是否顯示分割線', + SEPARATOR_LINE_STYLE: '分隔線樣式', + SEPARATOR_COLOR: '分割線顏色' + }, + AxisLine: { + Title: '軸線', + OnZero: '在零' + }, + AxisLabel: { + Title: '軸標籤', + Interval: '間隔', + Inside: '內部', + Rotate: '旋轉', + ShowMinLabel: '顯示最小標籤', + ShowMaxLabel: '顯示最大標籤', + HideOverlap: '隱藏重疊', + Overflow: '溢出', + Overflow_Null: '無', + Overflow_Truncate: '截斷', + Overflow_Break: '間斷', + Overflow_BreakAll: '間斷所有' + }, + GRID: { + GRID: '網格', + SHOW: '是否顯示', + CONTAIN_LABEL: '是否包含刻度標籤', + BACKGROUND_COLOR: '背景顏色', + BORDER_COLOR: '邊框顏色', + BORDER_WIDTH: '邊框粗細' + }, + LEGEND: { + TITLE: '圖例', + LEGEND_TYPE: '類型', + WIDTH: '寬度', + HEIGHT: '高度', + LEGEND_LEFT: '左側的距離', + LEGEND_TOP: '上側的距離', + LEGEND_RIGHT: '右側的距離', + LEGEND_BOTTOM: '下側的距離', + LEGEND_ORIENT: '布局朝向', + LEGEND_ALIGN: '對齊', + ItemGap: '元素間距', + ItemWidth: '元素寬度', + ItemHeight: '元素高度' + }, + TOOLTIP: { + TITLE: '提示框', + TOOLTIP_SHOW: '是否顯示', + TOOLTIP_TRIGGER: '觸發類型', + AXIS_POINTER: '坐標軸指示器配置項', + AXIS_POINTER_TYPE: '指示器類型', + ShowContent: '顯示內容', + Trigger: '觸發', + AppendToBody: '追加到 HTML Body', + AxisPointer: '軸指針', + Type: '類型', + Axis: '軸', + Snap: '快照' + }, + TEXT: { + TEXTSTYLE: '全局的字體樣式', + TEXTSTYLE_COLOR: '文字的顏色', + TEXTSTYLE_FONTSTYLE: '文字字體的風格', + TEXTSTYLE_FONTWEIGHT: '文字字體的粗細', + TEXTSTYLE_FONTSIZE: '文字的字體大小' + }, + DATAZOOM_STYLE: { + DATAZOOM: '數據縮放', + ORIENT: '布局方式', + ORIENT_HORIZONTAL: '水平', + ORIENT_VERTICAL: '豎直', + DATAZOOM_TYPE: '類型', + FILTER_MODE: '過濾模式', + START: '起始', + END: '結束', + START_VALUE: '起始數值', + END_VALUE: '結束數值', + YAXIS_INDEX: '控制的 Y 軸', + MIN_SPAN: '窗口最小值', + MAX_SPAN: '窗口最大值', + ZOOM_LOCK: '鎖定窗口大小' + }, + SERIE_STYLE: { + TITLE: '系列統一屬性', + SERIES: 'Echarts系列', + SERIES_TYPE: 'Echarts系列類型', + ITEMS_TYLE: '圖形樣式', + GRADIENT_STYLE: '漸變類型', + LINESTYLE: '線條樣式', + LINEAR_X0: '線性漸變X0參數', + LINEAR_Y0: '線性漸變Y0參數', + RADIAL_R: '徑向漸變半徑參數', + LINEAR_X2: '線性漸變X2參數', + LINEAR_Y2: '線性漸變Y2參數', + LINEWIDTH: '線寬', + LINE_TYPE: '線的類型', + LINESHADOW_BLUR: '圖形陰影的模糊大小', + LINESHADOW_COLOR: '陰影顏色', + LINESHADOW_OFFSETX: '陰影水平方向上的偏移距離', + LINESHAODW_OFFSETY: '陰影垂直方向上的偏移距離', + SMOOTH: '是否平滑曲線顯示', + COLOR_STOPS: '漸變顏色參數', + OFFSET: '0-100%的顏色', + COLOR: '顏色', + ITEMSTYLEBORDER_COLOR: '圖形的描邊顏色', + ITEMSTYLEBORDER_WIDTH: '描邊線寬', + ITEMSTYLEBORDER_TYPE: '描邊類型', + ITEMSTYLESHADOW_BLUR: '圖形陰影的模糊大小', + ITEMSTYLESHADOW_COLOR: '陰影顏色', + ITEMSTYLE_OPCITY: '圖形透明度', + BORDER_RADIUS: '柱狀圖圓角半徑', + BAR_WIDTH: '柱條的寬度', + EMPHASIS_STYLE: 'Emphasis 樣式', + TEXT_LABEL: '文本標籤', + IS_LABEL: '是否顯示標籤', + GRAPHIC_STYLE: '圖形樣式', + GRAPHIC_COLOR: '圖形顏色', + STROKE_COLOR: '描邊顏色', + STROKE_WIDTH: '描邊寬度', + GRAPHIC_SHADOW: '圖形陰影', + SHADOW_COLOR: '陰影顏色', + SHADOW_OFFSET_X: '陰影水平偏移量', + SHADOW_OFFSET_Y: '陰影垂直偏移量', + OPACITY: '不透明度', + ROSETYPE: '是否展示成南丁格爾圖', + PIE_RADIUS: '餅圖半徑', + AREA_STYLE: '區域填充樣式', + SHADOW_BLUR: '陰影模糊大小', + ITEM_STYLE: { + TITLE: '單個體樣式', + OPACITY: '不透明度' + }, + + LABEL: { + TITLE: '標籤' + }, + LabelLine: { + Title: '標籤線' + } + }, + EMPHASIS: { + TITLE: '高亮樣式', + DISABLED: '禁用', + FOCUS: '聚焦', + BlurScope: '模糊範圍', + BlurScope_None: '無', + BlurScope_CoordinateSystem: '坐標系統', + BlurScope_Series: '系列', + BlurScope_Global: '全局', + Focus_None: '無', + Focus_Self: '自己', + Focus_Series: '系列', + Scale: '縮放' + }, + ITEM_STYLE: { + TITLE: '單個體樣式', + OPACITY: '不透明度' + }, + GLOBAL_COLORS: { + TITLE: '全局顏色', + ColorList: '顏色序列', + Color: '顏色' + }, + ARIA: { + TITLE: '輔助增強', + ShowDecal: '顯示貼花', + Decals: '貼花圖案' + }, + SeriesStyle: { + Title: '系列屬性', + HasAll: '有 All 成員', + FunnelAlign: '漏斗對齊' + }, + DDD: { + GridTitle: '3D網格', + BoxWidth: '柱形寬度', + BoxHeight: '柱形高度', + BoxDepth: '柱形深度', + Light: '光線', + BarSeriesTitle: '系列屬性', + Shading: '明暗法' + }, + Select: { + Title: '選中樣式' + }, + MarkLine: { + Title: '標記線', + LineStyle: '線樣式' + }, + VisualMap: { + Title: '可視映射', + RemoveLabel: '刪除', + Type: '類型', + Piecewise: '分段', + Continuous: '連續', + Show: '顯示', + Realtime: '實時', + Calculable: '可計算', + Controller: '控制器', + InRange: '範圍內的', + OutofRange: '範圍外的', + Text: '描述', + SymbolSize: '符號大小', + Inverse: '倒轉', + Min: '最小值', + Max: '最大值', + Range: '預選中範圍', + SplitNumber: '分割數量', + Precision: '數字精度' + }, + Calendar: { + Title: '日曆', + ItemStyle: '元素樣式', + CellSize: '單元格大小' + }, + SplitLine: { + Title: '分割線', + Show: '顯示', + LineStyle: '線樣式' + }, + LineStyle: { + Title: '線樣式', + Color: '顏色', + Width: '寬度', + Type: '類型', + None: '無', + Solid: '實線', + Dashed: '虛線', + Dotted: '點虛線' + }, + ItemStyle: { + Title: '元素樣式' + }, + Text: { + TextBorderColor: '文本邊框顏色', + TextBorderWidth: '文本邊框寬度', + TextBorderType: '文本邊框類型', + TextBorderDashOffset: '文本邊框橫線偏移量', + TextShadowColor: '文本陰影顏色', + TextShadowBlur: '文本陰影模糊', + TextShadowOffsetX: '文本陰影偏移X', + TextShadowOffsetY: '文本陰影偏移Y', + Overflow: '溢出', + Ellipsis: '省略' + }, + Geo: { + Title: '地理組件' + }, + Title: { + Title: '標題', + Text: '主文本', + Link: '主鏈接', + SubText: '附文本', + SubLink: '附鏈接', + Left: '左側', + Top: '上側', + Right: '右側', + Bottom: '下側' + }, + Bar: { + BarWidth: '寬度', + BarMaxWidth: '最大寬度', + BarMinWidth: '最小寬度', + BarMinHeight: '最小高度', + BarMinAngle: '最小角度', + BarGap: '間距', + BarCategoryGap: '類別間距', + ShowBackground: '顯示背景', + Background: '背景', + RoundCap: '圓帽' + }, + Line: { + ShowSymbol: '顯示符號', + ShowAllSymbol: '顯示所有符號', + Smooth: '平滑', + Stack: '堆積', + Step: '分步', + AreaStyle: '面積樣式', + Origin: '源' + }, + Tree: { + SeriesStyle: { + Title: '系列樣式', + Layout: '布局方式', + Orthogonal: '直角', + Radial: '雷達', + Orient: '方位', + EdgeShape: '邊緣形狀', + EdgeForkPosition: '邊緣分叉位置', + InitialTreeDepth: '初始顯示深度', + Leaves: '葉子' + } + }, + Pie: { + RoseType: '玫瑰類型', + Center: '中心', + Radius: '半徑', + MinShowLabelAngle: '最小顯示標籤角度', + Clockwise: '順時針方向', + StartAngle: '開始角度', + MinAngle: '最小顯示角度', + SelectedOffset: '選中偏移', + AlignTo: '對齊方式', + AlignTo_none: '默認', + AlignTo_labelLine: '線末端對齊', + AlignTo_edge: '文字對齊', + EdgeDistance: '文字邊距', + BleedMargin: '出血線大小', + DistanceToLabelLine: '文字與線間距' + }, + Sankey: { + HasAll: '有 All 成員', + NodeWidth: '節點寬度', + NodeGap: '節點間隙', + NodeAlign: '節點對齊', + LayoutIterations: '布局迭代', + Draggable: '可拖拽', + LineStyle: '線樣式', + Curveness: '平滑', + Label: '標籤', + LevelsOptions: '層級屬性' + }, + Treemap: { + HasAll: '有 All 成員', + LeafDepth: '葉子深度', + DrillDownIcon: '下鑽符號', + ColorAlpha: '顏色α', + ColorSaturation: '色彩飽和度', + ColorMappingBy: '顏色映射', + VisibleMin: '最小顯示', + ChildrenVisibleMin: '子級最小顯示', + UpperLabel: '上級標籤', + VisualMin: '最小可視', + VisualMax: '最大可視', + LevelsOptions: '層級屬性', + GapWidth: '間隙寬度' + }, + Sunburst: { + Label: '標籤', + Rotate: '旋轉', + MinAngle: '最小顯示角度', + NodeClick: '節點點擊', + LevelsOptions: '層級屬性' + }, + Polar: { + Title: '極坐標' + }, + Heatmap: { + DateFormatter: '日期格式' + }, + Waterfall: { + Accumulate: '累計' + } + } + } + } +} diff --git a/libs/story-angular/story/embed-widget/widget.component.ts b/libs/story-angular/story/embed-widget/widget.component.ts index c2a4d35b9..76cd8b0cf 100644 --- a/libs/story-angular/story/embed-widget/widget.component.ts +++ b/libs/story-angular/story/embed-widget/widget.component.ts @@ -1,8 +1,8 @@ import { CommonModule } from '@angular/common' -import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core' +import { Component, Input, OnChanges, OnInit, SimpleChanges, inject } from '@angular/core' +import { NxCoreService } from '@metad/core' import { NgmDSCoreService, NgmSmartFilterBarService } from '@metad/ocap-angular/core' import { TimeGranularity } from '@metad/ocap-core' -import { NxCoreService } from '@metad/core' import { NxStoryService, Story, StoryWidget } from '@metad/story/core' import { NxStoryPointService } from '../story-point.service' import { NxStoryModule } from '../story.module' @@ -16,16 +16,14 @@ import { NxStoryModule } from '../story.module' providers: [NxStoryService, NxStoryPointService, NgmSmartFilterBarService, NxCoreService] }) export class EmbedWidgetComponent implements OnInit, OnChanges { + public storyService = inject(NxStoryService) + private pointService = inject(NxStoryPointService) + public smartFilterBarService = inject(NgmSmartFilterBarService) + private dsCoreService = inject(NgmDSCoreService) + @Input() story: Story @Input() widget: StoryWidget - constructor( - public storyService: NxStoryService, - private pointService: NxStoryPointService, - public smartFilterBarService: NgmSmartFilterBarService, - private dsCoreService: NgmDSCoreService - ) {} - ngOnInit(): void { this.dsCoreService.setTimeGranularity(TimeGranularity.Month) } diff --git a/libs/story-angular/widgets/indicator-card/indicator.component.html b/libs/story-angular/widgets/indicator-card/indicator.component.html index 7d1d5e1e5..1529c402e 100644 --- a/libs/story-angular/widgets/indicator-card/indicator.component.html +++ b/libs/story-angular/widgets/indicator-card/indicator.component.html @@ -1,7 +1,7 @@
- {{ title }} + {{ titleSignal() }} - +
{{ headData.currentValue }}  {{headData.shortUnit}}{{ headData.unit }} @@ -27,7 +27,7 @@
-
+
{{indicator.title }}
@@ -50,9 +50,9 @@
- - -
+ + +
diff --git a/libs/story-angular/widgets/indicator-card/indicator.component.ts b/libs/story-angular/widgets/indicator-card/indicator.component.ts index e0d36a0f9..626ad0c0d 100644 --- a/libs/story-angular/widgets/indicator-card/indicator.component.ts +++ b/libs/story-angular/widgets/indicator-card/indicator.component.ts @@ -1,11 +1,11 @@ import { formatNumber } from '@angular/common' -import { Component, InjectFlags, LOCALE_ID, inject } from '@angular/core' -import { Indicator, PeriodFunctions, cloneDeep, isNil } from '@metad/ocap-core' -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy' -import { AbstractStoryWidget, formatShortNumber } from '@metad/core' +import { Component, LOCALE_ID, computed, inject, signal } from '@angular/core' +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop' +import { AbstractStoryWidget, formatShortNumber, mapLangToLocale } from '@metad/core' +import { Indicator, PeriodFunctions, cloneDeep, isNil, nonNullable } from '@metad/ocap-core' +import { LangChangeEvent } from '@ngx-translate/core' import { graphic } from 'echarts/core' -import { Observable } from 'rxjs' -import { distinctUntilChanged, filter, map, shareReplay } from 'rxjs/operators' +import { distinctUntilChanged, filter, map, startWith } from 'rxjs/operators' import { IndicatorDataService } from './indicator-data.service' import { ArrowDirection, IndicatorOption, IndicatorOptions } from './types' @@ -23,7 +23,6 @@ interface MiddleIndicator extends HeadIndicator { title: string } -@UntilDestroy({ checkProperties: true }) @Component({ selector: 'pac-indicator-card', templateUrl: 'indicator.component.html', @@ -37,7 +36,8 @@ export class IndicatorCardComponent extends AbstractStoryWidget { - return !error ? data[0] : null - }), - filter((result) => !!result) + map(({ data, error }) => (!error ? data[0] : null)), + filter(nonNullable) + ) + private readonly queryResult = toSignal( + this.indicatorDataService.selectResult().pipe(map(({ data, error }) => (!error ? data[0] : null))) ) public readonly main$ = this.indicatorDataService.selectResult().pipe( @@ -127,73 +128,70 @@ export class IndicatorCardComponent extends AbstractStoryWidget !!main?.data) ) - public readonly title$ = this.indicatorDataService.indicator$.pipe( - map((indicator) => this.options.title || indicator?.name || indicator?.code) - ) - public headIndicatorData$: Observable = this.result$.pipe( - map(({ main }) => main), - map(({ data, indicator }) => { - const locale = this.locale || this._locale - return mapIndicatorResult(this.options, indicator, data[0], locale) - }), - untilDestroyed(this), - shareReplay(1) + public readonly titleSignal = toSignal( + this.indicatorDataService.indicator$.pipe( + map((indicator) => this.options.title || indicator?.name || indicator?.code) + ) ) - /** - * 子指标数据计算结果 - */ - public subIndicators$: Observable> = this.result$.pipe( - map(({ subIndicators }) => subIndicators), - filter((value) => !!value), - map((subIndicators) => { - const locale = this.locale || this._locale - return subIndicators.map(({ data, indicator }, index) => { - const option = this.options.indicators[index] - return mapIndicatorResult(option, indicator, data[0], locale) - }) + public readonly headIndicatorData = computed(() => { + if (!this.queryResult()) { + return null + } + const { main } = this.queryResult() + const { data, indicator } = main + return mapIndicatorResult(this.options, indicator, data[0], this._locale()) + }) + public readonly subIndicators = computed(() => { + if (!this.queryResult()) { + return null + } + const { subIndicators } = this.queryResult() + return subIndicators?.map(({ data, indicator }, index) => { + const option = this.options.indicators[index] + return mapIndicatorResult(option, indicator, data[0], this._locale()) }) - ) - - public chartOption$ = this.result$.pipe( - map(({ trend }) => trend), - map((trend) => { - if (isNil(trend)) { - return { - show: false, - option: {} - } - } - - const currentName = PeriodFunctions.CURRENT - const timeHierarchyText = this.indicatorDataService.calendar.name - const option: any = cloneDeep(this.option) - const seriesData = trend.data - option.xAxis.data = seriesData.map((x) => x[timeHierarchyText]) - option.series[0].data = seriesData.map((x) => x[currentName]) + }) + public readonly chartOptions = computed(() => { + if (!this.queryResult()) { + return null + } + const { trend } = this.queryResult() + if (isNil(trend)) { return { - show: true, - option: option + show: false, + option: {} } - }) - ) + } + + const currentName = PeriodFunctions.CURRENT + const timeHierarchyText = this.indicatorDataService.calendar.name + const option: any = cloneDeep(this.option) + const seriesData = trend.data + option.xAxis.data = seriesData.map((x) => x[timeHierarchyText]) + option.series[0].data = seriesData.map((x) => x[currentName]) + return { + show: true, + option: option + } + }) public readonly isLoading$ = this.indicatorDataService.loading$ public readonly error$ = this.indicatorDataService.selectResult().pipe(map((result) => result.error)) // Subscriptions (effect) // slicers - private slicersSub = this.selectionVariant$.subscribe((selectionVariant) => { + private slicersSub = this.selectionVariant$.pipe(takeUntilDestroyed()).subscribe((selectionVariant) => { this.indicatorDataService.selectionVariant = selectionVariant this.refresh() }) // dataSettings - private dataSettingsSub = this.dataSettings$.pipe(distinctUntilChanged()).subscribe((value) => { + private dataSettingsSub = this.dataSettings$.pipe(distinctUntilChanged(), takeUntilDestroyed()).subscribe((value) => { this.indicatorDataService.dataSettings = value }) // options - private optionsSub = this.options$.pipe(distinctUntilChanged()).subscribe({ + private optionsSub = this.options$.pipe(distinctUntilChanged(), takeUntilDestroyed()).subscribe({ next: (value) => { this.indicatorDataService.patchState({ indicatorId: value.code, @@ -204,13 +202,28 @@ export class IndicatorCardComponent extends AbstractStoryWidget { - this.refresh() - }) + private serviceSub = this.indicatorDataService + .onAfterServiceInit() + .pipe(takeUntilDestroyed()) + .subscribe(() => { + this.refresh() + }) - private explainSub = this.indicatorDataService.selectResult().subscribe((queryReturn) => { - this.setExplains([queryReturn]) - }) + private explainSub = this.indicatorDataService + .selectResult() + .pipe(takeUntilDestroyed()) + .subscribe((queryReturn) => { + this.setExplains([queryReturn]) + }) + private langSub = this.translateService.onLangChange + .pipe( + map((event: LangChangeEvent) => event.lang), + startWith(this.translateService.currentLang), + takeUntilDestroyed() + ) + .subscribe((lang) => { + this._locale.set(mapLangToLocale(lang)) + }) refresh(force = false): void { this.indicatorDataService.refresh(force) diff --git a/nodemon.json b/nodemon.json index 5685e43b6..1ce4b814d 100644 --- a/nodemon.json +++ b/nodemon.json @@ -1,7 +1,7 @@ { "restartable": "rs", "ignore": [".git", "node_modules/", "dist/", "coverage/", "**/*.spec.ts"], - "watch": ["apps/api/src", "packages/server/src", "packages/auth/src", "packages/analytics/src"], + "watch": ["apps/api/src", "packages/contacts/src", "packages/common/src", "packages/config/src", "packages/adapter/src", "packages/server/src", "packages/auth/src", "packages/analytics/src"], "exec": "yarn ts-node -r tsconfig-paths/register --project apps/api/tsconfig.app.json apps/api/src/main.ts", "env": { "NODE_ENV": "development", diff --git a/package.json b/package.json index 064983c6c..533d178b4 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@angular/elements": "16.1.7", "@angular/forms": "16.1.7", "@angular/material": "16.1.6", + "@angular/material-date-fns-adapter": "^16.1.6", "@angular/platform-browser": "16.1.7", "@angular/platform-browser-dynamic": "16.1.7", "@angular/router": "16.1.7", diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 4d1de79d1..df391b45a 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -23,6 +23,7 @@ "axios": "^0.24.0", "cron": "1.8.2", "date-fns": "2.28.0", + "decompress": "4.2.1", "immer": "^9.0.6", "nestjs-i18n": "^8.1.6", "redis": "^4.0.4", @@ -30,7 +31,6 @@ "sharp": "^0.30.5", "socket.io-redis": "6.1.1", "typeorm": "^0.2.37", - "unzipper": "^0.10.14", "xml2js": "^0.4.23" }, "devDependencies": { @@ -39,6 +39,7 @@ "@types/ws": "7.4.7", "@nestjs/testing": "^8.0.0", "@types/cron": "1.7.3", + "@types/decompress": "4.2.4", "@types/express": "^4.17.11", "@types/redis": "^2.8.32", "nodemon": "^2.0.19" diff --git a/packages/analytics/src/core/events/handlers/organization.demo.handler.ts b/packages/analytics/src/core/events/handlers/organization.demo.handler.ts index f738bd6ac..5bf98a3cb 100644 --- a/packages/analytics/src/core/events/handlers/organization.demo.handler.ts +++ b/packages/analytics/src/core/events/handlers/organization.demo.handler.ts @@ -23,7 +23,7 @@ import { CommandBus, CommandHandler, ICommandHandler } from '@nestjs/cqrs' import { InjectRepository } from '@nestjs/typeorm' import * as fs from 'fs' import * as path from 'path' -import * as unzipper from 'unzipper' +import * as decompress from 'decompress' import * as _axios from 'axios' import { assign, isString } from 'lodash' import { RedisClientType } from 'redis' @@ -44,6 +44,7 @@ import { import { readYamlFile } from '../../helper' import { REDIS_CLIENT } from '../../redis.module' + const axios = _axios.default @CommandHandler(OrganizationDemoCommand) @@ -100,27 +101,33 @@ export class OrganizationDemoHandler implements ICommandHandler - >(path.join(demosFolder, file)) + let sheets + try { + sheets = await readYamlFile< + Array<{ + name: string + installationMode: string + dataSource: IDataSource + dataset: CreationTable & { fileUrl: string } + businessArea: BusinessArea + semanticModel: ISemanticModel + project: IProject + story: IStory[] + indicator: IIndicator[] + }> + >(path.join(demosFolder, file)) + } catch (err) { + this.logger.error(err.message) + continue; + } for await (const { name, installationMode, @@ -250,12 +257,12 @@ export class OrganizationDemoHandler implements ICommandHandler { @@ -556,7 +567,7 @@ export class OrganizationDemoHandler implements ICommandHandler { constructor( private readonly commandBus: CommandBus, @InjectRepository(Story) - private repository: Repository + private repository: Repository, + private tenantService: TenantService ) {} async execute(query: StoryTrendsQuery) { const { searchText, options, orderType } = query const { skip, take } = options ?? {} - const tenantId = RequestContext.currentTenantId() + const tenantId = + RequestContext.currentTenantId() ?? (await this.tenantService.findOne({ name: DEFAULT_TENANT }))?.id let where: FindOneOptions['where'] = { tenantId, visibility: 'public', status: StoryStatusEnum.RELEASED } + if (searchText) { where = [ { @@ -40,19 +43,6 @@ export class StoryTrendsHandler implements IQueryHandler { ] } - // const qb = this.repository.createQueryBuilder('story') - // .leftJoinAndSelect('story.visits', 'visit') - // .leftJoinAndSelect('story.updatedBy', 'updatedBy') - // .select('story') - // .addSelect('updatedBy') - // .addSelect('SUM(visit.visits) AS pv') - // .where(where) - // .groupBy('story.id') - // .addGroupBy('updatedBy.id') - // .orderBy('pv', 'DESC') - // .take(take) - // .skip(skip) - const qb = this.repository.manager .createQueryBuilder() .select('*') diff --git a/packages/analytics/src/story/story.controller.ts b/packages/analytics/src/story/story.controller.ts index 5668abce2..e0f2e9c58 100644 --- a/packages/analytics/src/story/story.controller.ts +++ b/packages/analytics/src/story/story.controller.ts @@ -118,6 +118,23 @@ export class StoryController extends CrudController { async getCount(): Promise { return await this.storyService.countMy() } + + @Public() + @UseInterceptors(ClassSerializerInterceptor) + @Get('public/trends') + async trends( + @Query('take') take: number, + @Query('skip') skip: number, + @Query('orderType') orderType: 'visits' | 'update', + @Query('relations') relations: string[], + @Query('searchText') searchText?: string + ) { + const {items, total} = await this.queryBus.execute(new StoryTrendsQuery(searchText, {take, skip, relations}, orderType)) + return { + total, + items: items.map((item) => new StoryPublicDTO(item)) + } + } @Public() @UseInterceptors(ClassSerializerInterceptor) @@ -144,18 +161,6 @@ export class StoryController extends CrudController { return story } - @UseInterceptors(ClassSerializerInterceptor) - @Get('trends') - async trends(@Query('take') take: number, @Query('skip') skip: number, @Query('orderType') orderType: 'visits' | 'update', - @Query('relations') relations: string[], - @Query('searchText') searchText?: string) { - const {items, total} = await this.queryBus.execute(new StoryTrendsQuery(searchText, {take, skip, relations}, orderType)) // - return { - total, - items: items.map((item) => new StoryPublicDTO(item)) - } - } - /** * 使用 ClassSerializerInterceptor 和 DataSource options 上 @Exclude() 排除了 options 的返回. * 需要返回 options 的 api 地方不使用 ClassSerializerInterceptor; diff --git a/packages/angular/common/input/input.component.ts b/packages/angular/common/input/input.component.ts index 472c7b185..4648b6762 100644 --- a/packages/angular/common/input/input.component.ts +++ b/packages/angular/common/input/input.component.ts @@ -8,7 +8,8 @@ import { OnInit, Output, TemplateRef, - forwardRef + forwardRef, + signal } from '@angular/core' import { ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms' import { MatAutocompleteModule } from '@angular/material/autocomplete' @@ -52,7 +53,14 @@ export class NgmInputComponent implements ControlValueAccessor, OnInit { // We need an initializer here to avoid a TS error. The value will be set in `ngAfterViewInit`. _explicitContent: TemplateRef = undefined! - value: string + get value() { + return this._value() + } + set value(value) { + this._value.set(value) + } + private readonly _value = signal(null) + searchControl = new FormControl() private _onChange: (value) => void private _onTouched: (value) => void diff --git a/packages/angular/common/select/mat/select.component.ts b/packages/angular/common/select/mat/select.component.ts index 22cf6aa2c..861ae0075 100644 --- a/packages/angular/common/select/mat/select.component.ts +++ b/packages/angular/common/select/mat/select.component.ts @@ -228,7 +228,7 @@ export class NgmMatSelectComponent } else { let option: any = this.formControl.value // if (isObject(option)) { - const value = option.value + const value = option?.value if (value && !option.label) { option = { value, diff --git a/packages/angular/common/tag/tag.component.html b/packages/angular/common/tag/tag.component.html index 7599ae1ff..808cf9f12 100644 --- a/packages/angular/common/tag/tag.component.html +++ b/packages/angular/common/tag/tag.component.html @@ -1,5 +1,6 @@ -
diff --git a/packages/angular/common/tag/tag.component.ts b/packages/angular/common/tag/tag.component.ts index 6f1edc909..270191e04 100644 --- a/packages/angular/common/tag/tag.component.ts +++ b/packages/angular/common/tag/tag.component.ts @@ -39,6 +39,15 @@ export class NgmTagsComponent implements ControlValueAccessor { } private _selectable = false + @HostBinding('class.disabled') + @Input() get disabled() { + return this._disabled + } + set disabled(value: string | boolean) { + this._disabled = coerceBooleanProperty(value) + } + private _disabled = false + selection = new SelectionModel(true, []) @Output() selectedChange = this.selection.changed.pipe(map((change) => change.source.selected)) @@ -70,5 +79,7 @@ export class NgmTagsComponent implements ControlValueAccessor { registerOnTouched(fn: any): void { this._onTouched = fn } - setDisabledState?(isDisabled: boolean): void {} + setDisabledState?(isDisabled: boolean): void { + this.disabled = isDisabled + } } diff --git a/packages/angular/i18n/index.ts b/packages/angular/i18n/index.ts index 6517b72a3..a4c8d22fb 100644 --- a/packages/angular/i18n/index.ts +++ b/packages/angular/i18n/index.ts @@ -1 +1,2 @@ export * from './zhHans' +export * from './zhHant' diff --git a/packages/angular/i18n/zhHant.ts b/packages/angular/i18n/zhHant.ts new file mode 100644 index 000000000..91a4460d1 --- /dev/null +++ b/packages/angular/i18n/zhHant.ts @@ -0,0 +1,79 @@ +export const ZhHant = { + Ngm: { + Common: { + Cancel: '取消', + Apply: '應用', + Search: '搜索', + Select: '選擇', + Search_Placeholder: '請輸入關鍵詞', + DisplayBehaviour_Description: '描述', + DisplayBehaviour_DescriptionID: '描述 ID', + DisplayBehaviour_IDDescription: 'ID 描述', + DisplayBehaviour_ID: 'ID', + DisplayBehaviour_Auto: '自動', + SelectionType_Single: '單選', + SelectionType_Multiple: '多選', + Presentation_Flat: '平鋪', + Presentation_Hierarchy: '層級', + HierarchySelectionMode_Individual: '單個', + HierarchySelectionMode_SelfDescendants: '自己和後代', + HierarchySelectionMode_DescendantsOnly: '只後代', + HierarchySelectionMode_SelfChildren: '自己和子代', + HierarchySelectionMode_ChildrenOnly: '只子代', + Measures: '度量', + None: '無', + Default: '默認' + }, + Controls: { + ValueHelp: { + Title: '為{{value}}設置過濾器', + AvailableMembers: '可選成員', + DisplayBehaviour: '展現形式', + SelectedMembers: '選中成員', + ClearSelection: '清空選擇', + ShowUnbookedMembers: '顯示未分配成員', + ShowAllMember: '顯示『所有』成員', + ShowOnlyLeaves: '只顯示葉子節點', + ExcludeSelectedMembers: '排除選中成員', + SelectionType: '選擇類型', + Presentation: '展現形式', + HierarchySelectionMode: '層級選擇模式', + Hierarchy: '層次結構' + } + }, + AnalyticalCard: { + Screenshot: '截圖', + DataDownload: '下載數據', + Refresh: '刷新', + DrillDown: '下鑽', + DrillLevel: '層級下鑽', + DrillDimension: '維度下鑽', + LinkAnalysis: '聯動篩選', + DataEmpty: '數據為空' + }, + AnalyticalGrid: { + DataDownload: '下載數據', + SORT: '排序', + MOVE: '移動', + ASCENDING: '正序', + DESCENDGING: '倒序', + MOVELEFT: '向左', + MOVERIGHT: '向右', + Search: '搜索', + SelectAll: '選擇所有', + Pin: '固定' + }, + EntitySchema: { + Parameters: '參數', + Measures: '度量', + Properties: '屬性' + }, + Formula: { + Editor: { + EditFormula: '編輯公式', + Format: '格式化', + Help: '幫助' + } + } + } +} diff --git a/packages/common/src/utils/xlsx.ts b/packages/common/src/utils/xlsx.ts index bbaea011a..fadef9074 100644 --- a/packages/common/src/utils/xlsx.ts +++ b/packages/common/src/utils/xlsx.ts @@ -58,7 +58,8 @@ export async function readExcelJson(wSheet, fileName = ''): Promise item.reduce((obj, val, i) => { if (!excelTransformNum[i]) { - throw new Error(`没有找到 ${row + 2} 行 ${i + 1} 列单元格对应的列名称`) + throw new Error(`The column name corresponding to cell in row ${row + 2} and column ${i + 1} was not found. The file is ${fileName}. +The current row data is ${item}, and the header row data is ${excelTransformNum}.`) } obj[excelTransformNum[i].trim()] = val return obj @@ -79,7 +80,6 @@ export async function readExcelJson(wSheet, fileName = ''): Promise 1 ? sheetName : name, columns: columns.filter((col) => !!col), data: excelDataEncodeToJson, - // preview: excelDataEncodeToJson.slice(0, 50) } }) } diff --git a/packages/contracts/src/organization.model.ts b/packages/contracts/src/organization.model.ts index d60439e55..4b2019279 100644 --- a/packages/contracts/src/organization.model.ts +++ b/packages/contracts/src/organization.model.ts @@ -253,4 +253,9 @@ export const DEFAULT_TIME_FORMATS: number[] = [12, 24]; export interface IKeyValuePair { key: string; value: boolean | string; +} + +export enum OrganizationDemoNetworkEnum { + github = 'github', + aliyun = 'aliyun' } \ No newline at end of file diff --git a/packages/contracts/src/user.model.ts b/packages/contracts/src/user.model.ts index bd11dda12..376679c5a 100644 --- a/packages/contracts/src/user.model.ts +++ b/packages/contracts/src/user.model.ts @@ -108,15 +108,16 @@ export interface IUserPasswordInput { } export enum LanguagesEnum { - Chinese = "zh", + Chinese = "zh-CN", + SimplifiedChinese = "zh-Hans", TraditionalChinese = 'zh-Hant', English = 'en', } export const LanguagesMap = { - 'zh-CN': LanguagesEnum.Chinese, - 'zh-Hans': LanguagesEnum.Chinese, - 'zh': LanguagesEnum.Chinese, + 'zh-CN': LanguagesEnum.SimplifiedChinese, + 'zh-Hans': LanguagesEnum.SimplifiedChinese, + 'zh': LanguagesEnum.SimplifiedChinese, } export enum ComponentLayoutStyleEnum { diff --git a/packages/core/src/lib/services/indicator-data.service.ts b/packages/core/src/lib/services/indicator-data.service.ts index 6d2e66de9..06695f687 100644 --- a/packages/core/src/lib/services/indicator-data.service.ts +++ b/packages/core/src/lib/services/indicator-data.service.ts @@ -110,7 +110,7 @@ export class SmartIndicatorDataService< indicator: Indicator | string, measures: Array, lookBack?: number, - force?: boolean + force?: boolean | void ): Observable> { indicator = isString(indicator) ? this.getIndicator(indicator as string) : (indicator as Indicator) @@ -221,7 +221,8 @@ export class SmartIndicatorDataService< return this.queryIndicator( indicator ?? this.indicator, measures ?? this.get((state) => state.measures), - lookBack ?? this.lookBack + lookBack ?? this.lookBack, + options?.force ) }