From ca93bbad5d2cc446e26481c0653a4e219f4e9718 Mon Sep 17 00:00:00 2001 From: meta-d Date: Wed, 13 Sep 2023 14:58:00 +0800 Subject: [PATCH 1/8] feat: print debug detail info for demo data error --- .../home/dashboard/dashboard.component.ts | 5 ++- .../tenant-details.component.html | 4 +-- .../tenant-details.component.ts | 5 ++- nodemon.json | 2 +- .../handlers/organization.demo.handler.ts | 32 +++++++++++-------- packages/common/src/utils/xlsx.ts | 4 +-- packages/contracts/src/organization.model.ts | 5 +++ 7 files changed, 37 insertions(+), 20 deletions(-) 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/onboarding/tenant-details/tenant-details.component.html b/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.html index 5109dc7d6..c45da9547 100644 --- a/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.html +++ b/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.html @@ -80,8 +80,8 @@
- GitHub - Aliyun oss + GitHub + Aliyun oss
diff --git a/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.ts b/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.ts index 8c7329285..73a4cb3e9 100644 --- a/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.ts +++ b/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.ts @@ -27,6 +27,7 @@ import { IOrganization, LanguagesEnum, MatchValidator, + OrganizationDemoNetworkEnum, OrganizationsService, ServerAgent, TenantService, @@ -58,6 +59,8 @@ import { ] }) export class TenantDetailsComponent { + OrganizationDemoNetworkEnum = OrganizationDemoNetworkEnum + private readonly tenantService = inject(TenantService) private readonly typesService = inject(DataSourceTypesService) private readonly dataSourceService = inject(DataSourceService) @@ -88,7 +91,7 @@ export class TenantDetailsComponent { } ) demoFormGroup: FormGroup = this._formBuilder.group({ - source: ['github', Validators.required] + source: [OrganizationDemoNetworkEnum.github, Validators.required] }) dataSourceTypeFormGroup: FormGroup = this._formBuilder.group({ 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/packages/analytics/src/core/events/handlers/organization.demo.handler.ts b/packages/analytics/src/core/events/handlers/organization.demo.handler.ts index f738bd6ac..6b715aaca 100644 --- a/packages/analytics/src/core/events/handlers/organization.demo.handler.ts +++ b/packages/analytics/src/core/events/handlers/organization.demo.handler.ts @@ -108,19 +108,25 @@ 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, diff --git a/packages/common/src/utils/xlsx.ts b/packages/common/src/utils/xlsx.ts index bbaea011a..a0b5e5e0c 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 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 From 40de1241ff138a11750c3592474f6d08246d9f22 Mon Sep 17 00:00:00 2001 From: meta-d Date: Thu, 14 Sep 2023 00:28:25 +0800 Subject: [PATCH 2/8] feat: update settings pages ui layout --- .../src/app/@core/guards/invite.guard.ts | 63 +-- .../feature-toggle.component.scss | 3 + .../email-invite-form.component.ts | 10 +- .../invite-mutation.component.ts | 19 +- .../language-selector.component.html | 16 +- .../language-selector.component.ts | 22 +- .../approvals/approvals.component.scss | 2 +- .../indicators/indicators.component.html | 32 +- .../indicators/indicators.component.scss | 2 +- .../indicators/indicators.component.ts | 92 ++-- .../project/indicators/my/my.component.html | 2 +- .../project/indicators/my/my.component.scss | 2 +- .../register-form.component.html | 2 +- .../register/register.component.html | 2 +- .../register/register.component.scss | 2 +- .../indicators/register/register.component.ts | 19 +- .../project/project-routing.module.ts | 5 + .../app/features/setting/_settings-theme.scss | 22 +- .../setting/account/account.component.html | 53 +-- .../setting/account/account.component.scss | 2 +- .../setting/account/account.component.ts | 35 +- .../area-info-form.component.html | 11 + .../area-info-form.component.ts | 73 ++-- .../area-users/area-users.component.html | 2 +- .../area-users/area-users.component.ts | 29 +- .../business-area-routing.module.ts | 34 +- .../business-area.component.html | 66 +++ .../business-area.component.scss | 3 + .../business-area/business-area.component.ts | 96 +++++ .../business-area/business-area.module.ts | 41 +- .../business-area.component.html | 44 +- .../business-area.component.scss | 4 +- .../business-area/business-area.component.ts | 61 ++- .../business-areas/areas.component.html | 43 +- .../business-areas/areas.component.scss | 6 +- .../business-areas/areas.component.ts | 67 +-- .../certification.component.html | 155 ++++--- .../certification/certification.component.ts | 3 +- .../certification/certification.module.ts | 5 +- .../setting/copilot/copilot.component.html | 4 +- .../custom-smtp/custom-smtp.component.html | 53 +-- .../data-sources/data-sources.component.html | 22 +- .../email-templates.component.html | 133 +++--- .../email-templates.component.scss | 9 +- .../email-templates.component.ts | 407 ++++++++---------- .../email-templates/email-templates.module.ts | 9 +- .../setting/features/features.component.html | 17 +- .../edit-organization.component.html | 22 +- .../organization-demo.component.html | 5 +- .../organization-demo.component.ts | 50 +-- .../organizations.component.html | 64 +-- .../organizations.component.scss | 3 +- .../setting/roles/roles.component.html | 61 +-- .../setting/roles/roles.component.scss | 6 - .../features/setting/settings.component.scss | 14 + .../features/setting/settings.component.ts | 22 +- .../tenant/settings/settings.component.ts | 2 +- .../setting/tenant/tenant.component.html | 23 +- .../users/edit-user/edit-user.component.html | 29 +- .../users/edit-user/edit-user.component.scss | 3 +- .../users/edit-user/edit-user.component.ts | 38 +- .../manage-user-invite.component.html | 42 +- .../manage-user-invite.component.scss | 3 + .../manage-user-invite.component.ts | 42 +- .../manage-user/manage-user.component.html | 60 +++ .../manage-user/manage-user.component.scss | 16 + .../manage-user/manage-user.component.ts | 114 +++++ .../organizations.component.html | 80 ++-- .../organizations/organizations.component.ts | 25 +- .../user-basic/user-basic.component.html | 26 +- .../users/user-basic/user-basic.component.ts | 41 +- .../setting/users/user-routing.module.ts | 37 +- .../app/features/setting/users/user.module.ts | 37 +- .../setting/users/users.component.html | 125 ++---- .../setting/users/users.component.scss | 15 +- .../features/setting/users/users.component.ts | 144 +++---- .../tenant-details.component.html | 2 +- .../tenant-details.component.ts | 1 + apps/cloud/src/assets/i18n/zh-CN.json | 54 ++- apps/cloud/src/styles.scss | 30 ++ packages/analytics/package.json | 1 + .../handlers/organization.demo.handler.ts | 14 +- .../angular/common/input/input.component.ts | 12 +- packages/common/src/utils/xlsx.ts | 2 +- 84 files changed, 1731 insertions(+), 1338 deletions(-) create mode 100644 apps/cloud/src/app/features/setting/business-area/area-info-form/area-info-form.component.html create mode 100644 apps/cloud/src/app/features/setting/business-area/business-area.component.html create mode 100644 apps/cloud/src/app/features/setting/business-area/business-area.component.scss create mode 100644 apps/cloud/src/app/features/setting/business-area/business-area.component.ts create mode 100644 apps/cloud/src/app/features/setting/settings.component.scss create mode 100644 apps/cloud/src/app/features/setting/users/manage-user-invite/manage-user-invite.component.scss create mode 100644 apps/cloud/src/app/features/setting/users/manage-user/manage-user.component.html create mode 100644 apps/cloud/src/app/features/setting/users/manage-user/manage-user.component.scss create mode 100644 apps/cloud/src/app/features/setting/users/manage-user/manage-user.component.ts 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/@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/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/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..0d2357385 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"} }}

@@ -20,21 +20,23 @@

{{ 'PAC.MENU.INDICATOR.BATCH_UPLOAD' | translate: {Default: "Batch Upload"} }} -

-

+
+
+ + +
{{user()?.email}}
+
-
    - - -
- - \ 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..ef4c7716d 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.component.html b/apps/cloud/src/app/features/setting/organizations/edit-organization/edit-organization.component.html index 3a5d115e8..080cf7988 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,12 +1,17 @@ -
-

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

+
+
+ {{ 'PAC.KEY_WORDS.ORGANIZATION' | translate: {Default: 'Organization'} }} +
-
+
+ +
{{ selectedOrg?.name }}
-
+ - + + + \ No newline at end of file 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..8bca3577d 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,4 @@ - \ No newline at end of file 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..adafb2e6c 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,10 +1,10 @@ -import { Component } from '@angular/core' +import { Component, inject, signal } from '@angular/core' +import { toSignal } from '@angular/core/rxjs-interop' import { UntilDestroy } from '@ngneat/until-destroy' -import { OrganizationsService, ToastrService } from 'apps/cloud/src/app/@core' +import { OrganizationsService, ToastrService, getErrorMessage } from 'apps/cloud/src/app/@core' import { TranslationBaseComponent } from 'apps/cloud/src/app/@shared' -import { catchError, concatMap, EMPTY, Observable, tap, withLatestFrom } from 'rxjs' +import { firstValueFrom } from 'rxjs' import { EditOrganizationComponent } from '../edit-organization/edit-organization.component' -import { effectAction } from '@metad/ocap-angular/core' @UntilDestroy({ checkProperties: true }) @Component({ @@ -12,28 +12,24 @@ import { effectAction } from '@metad/ocap-angular/core' styleUrls: ['./organization-demo.component.scss'] }) export class OrganizationDemoComponent extends TranslationBaseComponent { - constructor( - public editOrganizationComponent: EditOrganizationComponent, - private orgsService: OrganizationsService, - private readonly _toastrService: ToastrService - ) { - super() - } + public editOrganizationComponent = inject(EditOrganizationComponent) + private orgsService = inject(OrganizationsService) + private readonly _toastrService = inject(ToastrService) + + private readonly organization = toSignal(this.editOrganizationComponent.organization$) + public readonly loading = signal(false) + public readonly generated = signal(false) - 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') - }) - ) - }) + async generate() { + try { + this.loading.set(true) + await firstValueFrom(this.orgsService.demo(this.organization().id)) + 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.component.html b/apps/cloud/src/app/features/setting/organizations/organizations.component.html index 5499a8f13..ba8d07ea6 100644 --- a/apps/cloud/src/app/features/setting/organizations/organizations.component.html +++ b/apps/cloud/src/app/features/setting/organizations/organizations.component.html @@ -1,7 +1,5 @@ -
-
- {{ 'PAC.MENU.MANAGE_ORGANIZATIONS' | translate: {Default: "Manage Organizations"} }} -
+
+
{{ 'PAC.MENU.MANAGE_ORGANIZATIONS' | translate: {Default: "Manage Organizations"} }}
- +
+ +
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/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..ee6f20a67 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..c52cfd1a0 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..cb76d47ef 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/onboarding/tenant-details/tenant-details.component.html b/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.html index c45da9547..2d44517bb 100644 --- a/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.html +++ b/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.html @@ -87,7 +87,7 @@
- {{demoError()}} + {{demoError()}}
diff --git a/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.ts b/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.ts index 73a4cb3e9..8c976a34d 100644 --- a/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.ts +++ b/apps/cloud/src/app/onboarding/tenant-details/tenant-details.component.ts @@ -156,6 +156,7 @@ export class TenantDetailsComponent { defaultOrganization: { name: this.userFormGroup.get('organizationName').value, preferredLanguage: this.preferredLanguageFormGroup.get('preferredLanguage').value[0], + invitesAllowed: true, currency: CurrenciesEnum.USD, profile_link: '', imageUrl: '', diff --git a/apps/cloud/src/assets/i18n/zh-CN.json b/apps/cloud/src/assets/i18n/zh-CN.json index 7322a6692..ccb230ead 100644 --- a/apps/cloud/src/assets/i18n/zh-CN.json +++ b/apps/cloud/src/assets/i18n/zh-CN.json @@ -152,7 +152,8 @@ "CalculatedFormula": "计算公式", "Visits": "访问量", "UpdatedDate": "更新日期", - "SortBy": "排序" + "SortBy": "排序", + "Role&Permissions": "角色 & 权限" }, "MENU": { "Certification": "认证", @@ -198,7 +199,7 @@ "InviteUsers": "邀请用户", "Authentication": "用户认证", "UserSettings": "用户设置", - + "ManageUsersAndInvites": "管理用户和邀请", "ORGANIZATIONS": "组织", "FEATURES": "功能", "USERS": "用户", @@ -907,6 +908,7 @@ } }, "BUSINESS_AREA": { + "All": "所有", "BASIC": "基本属性", "Delete": "删除", "Update": "更新", @@ -952,6 +954,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": "所有组织" @@ -1181,6 +1205,9 @@ "zh-Hans": "中文简体", "zh-Hant": "中文繁体" }, + "Users": { + "NoMoreOrganizations": "没有更多的组织可添加" + }, "title": { "short": "分析云" }, @@ -1335,6 +1362,7 @@ "MAIN": "主属性", "DEMO": "演示数据", "GENERATE_DEMO": "生成演示数据", + "RegenerateDemo": "重新生成演示数据", "TotalEmployees": "总员工数", "BasicInfo": "基础信息", "OtherInfo": "其他信息", @@ -2813,27 +2841,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/styles.scss b/apps/cloud/src/styles.scss index f56c84deb..8dcf0da54 100644 --- a/apps/cloud/src/styles.scss +++ b/apps/cloud/src/styles.scss @@ -349,3 +349,33 @@ 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 { + .pac-tab-close { + @apply opacity-0 invisible; + } + .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/packages/analytics/package.json b/packages/analytics/package.json index 4d1de79d1..e42e42477 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -41,6 +41,7 @@ "@types/cron": "1.7.3", "@types/express": "^4.17.11", "@types/redis": "^2.8.32", + "@types/unzipper": "^0.10.7", "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 6b715aaca..3eedde47c 100644 --- a/packages/analytics/src/core/events/handlers/organization.demo.handler.ts +++ b/packages/analytics/src/core/events/handlers/organization.demo.handler.ts @@ -44,6 +44,7 @@ import { import { readYamlFile } from '../../helper' import { REDIS_CLIENT } from '../../redis.module' + const axios = _axios.default @CommandHandler(OrganizationDemoCommand) @@ -100,7 +101,7 @@ export class OrganizationDemoHandler implements ICommandHandler = 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/common/src/utils/xlsx.ts b/packages/common/src/utils/xlsx.ts index a0b5e5e0c..fadef9074 100644 --- a/packages/common/src/utils/xlsx.ts +++ b/packages/common/src/utils/xlsx.ts @@ -58,7 +58,7 @@ export async function readExcelJson(wSheet, fileName = ''): Promise item.reduce((obj, val, i) => { if (!excelTransformNum[i]) { - throw new Error(`The column name corresponding to cell in row ${row + 2} and column ${i + 1} was not found. + 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 From f7db43b2caccf9003661103ab8d1b1d90854c539 Mon Sep 17 00:00:00 2001 From: meta-d Date: Thu, 14 Sep 2023 23:37:47 +0800 Subject: [PATCH 3/8] feat: settings pages layout & date fns adapter --- .../cloud/src/app/@shared/directives/index.ts | 2 + .../@shared/directives/manage-entity-base.ts | 52 ++ apps/cloud/src/app/@shared/index.ts | 4 +- apps/cloud/src/app/_app.component.scss | 30 + apps/cloud/src/app/app.component.ts | 33 +- .../src/app/features/_features-theme.scss | 17 - .../indicator/market/market.component.html | 6 + .../indicator/market/market.component.ts | 26 +- .../indicator/viewer/viewer.component.html | 356 ++++++----- .../indicator/viewer/viewer.component.scss | 5 +- .../indicator/viewer/viewer.component.ts | 59 +- .../all.component.html} | 1 + .../all.component.scss} | 0 .../my.component.ts => all/all.component.ts} | 8 +- .../indicators/indicators.component.html | 13 +- .../indicators/indicators.component.ts | 49 +- .../register-form.component.html | 2 +- .../register-form/register-form.component.ts | 4 +- .../register/register.component.html | 2 +- .../indicators/register/register.component.ts | 6 +- .../project/members/members.component.html | 2 +- .../project/project-routing.module.ts | 4 +- .../features/project/project.component.html | 6 +- .../model/members/members.component.html | 2 +- .../setting/account/account.component.html | 2 +- .../business-area.component.html | 4 +- .../custom-smtp/custom-smtp.component.html | 2 +- .../setting/features/features.component.html | 2 +- .../edit-organization-main.component.ts | 189 +++--- .../edit-organization.component.html | 65 +- .../edit-organization.component.scss | 4 +- .../edit-organization.component.ts | 95 +-- .../organization-demo.component.html | 18 +- .../organization-demo.component.scss | 2 +- .../organization-demo.component.ts | 28 +- .../organizations-routing.module.ts | 71 ++- .../organizations.component.html | 87 +-- .../organizations/organizations.component.ts | 9 +- .../organizations/organizations.module.ts | 4 - .../organizations.component.html | 50 ++ .../organizations.component.scss | 3 + .../organizations/organizations.component.ts | 96 +++ .../features/setting/settings.component.ts | 2 +- .../setting/tenant/tenant.component.html | 2 +- .../setting/users/users.component.html | 4 +- apps/cloud/src/assets/i18n/zh-CN.json | 9 +- apps/cloud/src/styles.scss | 8 +- apps/nest/.eslintrc.json | 18 - apps/nest/jest.config.js | 15 - apps/nest/project.json | 53 -- apps/nest/src/app/app.controller.spec.ts | 22 - apps/nest/src/app/app.controller.ts | 13 - apps/nest/src/app/app.module.ts | 11 - apps/nest/src/app/app.service.spec.ts | 21 - apps/nest/src/app/app.service.ts | 10 - apps/nest/src/assets/.gitkeep | 0 .../nest/src/environments/environment.prod.ts | 3 - apps/nest/src/environments/environment.ts | 3 - apps/nest/src/main.ts | 22 - apps/nest/tsconfig.app.json | 10 - apps/nest/tsconfig.json | 13 - apps/nest/tsconfig.spec.json | 9 - apps/rc-e2e/.eslintrc.json | 10 - apps/rc-e2e/cypress.json | 12 - apps/rc-e2e/project.json | 28 - apps/rc-e2e/src/fixtures/example.json | 4 - apps/rc-e2e/src/integration/app.spec.ts | 13 - apps/rc-e2e/src/support/app.po.ts | 1 - apps/rc-e2e/src/support/commands.ts | 33 - apps/rc-e2e/src/support/index.ts | 17 - apps/rc-e2e/tsconfig.json | 10 - apps/rc/.babelrc | 11 - apps/rc/.browserslistrc | 16 - apps/rc/.eslintrc.json | 18 - apps/rc/jest.config.js | 10 - apps/rc/postcss.config.js | 10 - apps/rc/project.json | 84 --- apps/rc/proxy.conf.json | 6 - apps/rc/src/app/app.scss | 13 - apps/rc/src/app/app.spec.tsx | 17 - apps/rc/src/app/app.tsx | 145 ----- apps/rc/src/app/mock.ts | 80 --- apps/rc/src/app/types.ts | 603 ------------------ apps/rc/src/assets/.gitkeep | 0 apps/rc/src/environments/environment.prod.ts | 3 - apps/rc/src/environments/environment.ts | 6 - apps/rc/src/favicon.ico | Bin 15086 -> 0 bytes apps/rc/src/index.html | 14 - apps/rc/src/main.tsx | 13 - apps/rc/src/polyfills.ts | 7 - apps/rc/src/styles.scss | 4 - apps/rc/tailwind.config.js | 13 - apps/rc/tsconfig.app.json | 22 - apps/rc/tsconfig.json | 24 - apps/rc/tsconfig.spec.json | 23 - apps/vue-app-e2e/.eslintrc.json | 10 - apps/vue-app-e2e/cypress.json | 12 - apps/vue-app-e2e/project.json | 28 - apps/vue-app-e2e/src/fixtures/example.json | 4 - apps/vue-app-e2e/src/integration/app.spec.ts | 6 - apps/vue-app-e2e/src/support/app.po.ts | 1 - apps/vue-app-e2e/src/support/commands.ts | 33 - apps/vue-app-e2e/src/support/index.ts | 17 - apps/vue-app-e2e/tsconfig.json | 10 - apps/vue-app/.browserslistrc | 3 - apps/vue-app/.eslintrc.json | 16 - apps/vue-app/babel.config.js | 3 - apps/vue-app/configure-webpack.js | 13 - apps/vue-app/jest.config.js | 22 - apps/vue-app/project.json | 66 -- apps/vue-app/public/favicon.ico | Bin 6796 -> 0 bytes apps/vue-app/public/index.html | 20 - apps/vue-app/src/App.vue | 152 ----- apps/vue-app/src/assets/logo.png | Bin 6849 -> 0 bytes apps/vue-app/src/components/HelloWorld.vue | 86 --- apps/vue-app/src/main.ts | 9 - apps/vue-app/src/shims-vue.d.ts | 6 - apps/vue-app/tests/unit/example.spec.ts | 12 - apps/vue-app/tsconfig.app.json | 9 - apps/vue-app/tsconfig.json | 20 - apps/vue-app/tsconfig.spec.json | 12 - libs/apps/indicator-market/i18n/zhHans.ts | 3 + .../src/lib/_indicator-market-theme.scss | 9 - .../src/lib/_indicator-market.component.scss | 0 .../indicator-item.component.ts | 15 +- .../indicator-item/indicator-item.service.ts | 8 +- .../src/lib/indicator-market.component.html | 48 +- .../src/lib/indicator-market.component.scss | 4 + .../src/lib/indicator-market.component.ts | 66 +- .../src/lib/indicator-market.module.ts | 4 +- .../src/lib/services/store.ts | 13 +- .../core/date-fns/date-fns-date-adapter.ts | 244 +++---- .../datepicker/datepicker.component.ts | 75 +-- .../monthpicker/monthpicker.component.ts | 11 +- .../quarterpicker/quarterpicker.component.ts | 8 +- .../yearpicker/yearpicker.component.ts | 7 +- .../table/table/table.component.html | 5 +- .../table/table/table.component.ts | 5 +- .../today-filter/today-filter.component.ts | 15 +- package.json | 1 + packages/analytics/package.json | 4 +- .../handlers/organization.demo.handler.ts | 7 +- .../common/select/mat/select.component.ts | 2 +- .../angular/common/tag/tag.component.html | 3 +- packages/angular/common/tag/tag.component.ts | 13 +- .../lib/services/indicator-data.service.ts | 5 +- 146 files changed, 1135 insertions(+), 2948 deletions(-) create mode 100644 apps/cloud/src/app/@shared/directives/index.ts create mode 100644 apps/cloud/src/app/@shared/directives/manage-entity-base.ts create mode 100644 apps/cloud/src/app/_app.component.scss rename apps/cloud/src/app/features/project/indicators/{my/my.component.html => all/all.component.html} (99%) rename apps/cloud/src/app/features/project/indicators/{my/my.component.scss => all/all.component.scss} (100%) rename apps/cloud/src/app/features/project/indicators/{my/my.component.ts => all/all.component.ts} (93%) create mode 100644 apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.html create mode 100644 apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.scss create mode 100644 apps/cloud/src/app/features/setting/organizations/organizations/organizations.component.ts delete mode 100644 apps/nest/.eslintrc.json delete mode 100644 apps/nest/jest.config.js delete mode 100644 apps/nest/project.json delete mode 100644 apps/nest/src/app/app.controller.spec.ts delete mode 100644 apps/nest/src/app/app.controller.ts delete mode 100644 apps/nest/src/app/app.module.ts delete mode 100644 apps/nest/src/app/app.service.spec.ts delete mode 100644 apps/nest/src/app/app.service.ts delete mode 100644 apps/nest/src/assets/.gitkeep delete mode 100644 apps/nest/src/environments/environment.prod.ts delete mode 100644 apps/nest/src/environments/environment.ts delete mode 100644 apps/nest/src/main.ts delete mode 100644 apps/nest/tsconfig.app.json delete mode 100644 apps/nest/tsconfig.json delete mode 100644 apps/nest/tsconfig.spec.json delete mode 100644 apps/rc-e2e/.eslintrc.json delete mode 100644 apps/rc-e2e/cypress.json delete mode 100644 apps/rc-e2e/project.json delete mode 100644 apps/rc-e2e/src/fixtures/example.json delete mode 100644 apps/rc-e2e/src/integration/app.spec.ts delete mode 100644 apps/rc-e2e/src/support/app.po.ts delete mode 100644 apps/rc-e2e/src/support/commands.ts delete mode 100644 apps/rc-e2e/src/support/index.ts delete mode 100644 apps/rc-e2e/tsconfig.json delete mode 100644 apps/rc/.babelrc delete mode 100644 apps/rc/.browserslistrc delete mode 100644 apps/rc/.eslintrc.json delete mode 100644 apps/rc/jest.config.js delete mode 100644 apps/rc/postcss.config.js delete mode 100644 apps/rc/project.json delete mode 100644 apps/rc/proxy.conf.json delete mode 100644 apps/rc/src/app/app.scss delete mode 100644 apps/rc/src/app/app.spec.tsx delete mode 100644 apps/rc/src/app/app.tsx delete mode 100644 apps/rc/src/app/mock.ts delete mode 100644 apps/rc/src/app/types.ts delete mode 100644 apps/rc/src/assets/.gitkeep delete mode 100644 apps/rc/src/environments/environment.prod.ts delete mode 100644 apps/rc/src/environments/environment.ts delete mode 100644 apps/rc/src/favicon.ico delete mode 100644 apps/rc/src/index.html delete mode 100644 apps/rc/src/main.tsx delete mode 100644 apps/rc/src/polyfills.ts delete mode 100644 apps/rc/src/styles.scss delete mode 100644 apps/rc/tailwind.config.js delete mode 100644 apps/rc/tsconfig.app.json delete mode 100644 apps/rc/tsconfig.json delete mode 100644 apps/rc/tsconfig.spec.json delete mode 100644 apps/vue-app-e2e/.eslintrc.json delete mode 100644 apps/vue-app-e2e/cypress.json delete mode 100644 apps/vue-app-e2e/project.json delete mode 100644 apps/vue-app-e2e/src/fixtures/example.json delete mode 100644 apps/vue-app-e2e/src/integration/app.spec.ts delete mode 100644 apps/vue-app-e2e/src/support/app.po.ts delete mode 100644 apps/vue-app-e2e/src/support/commands.ts delete mode 100644 apps/vue-app-e2e/src/support/index.ts delete mode 100644 apps/vue-app-e2e/tsconfig.json delete mode 100644 apps/vue-app/.browserslistrc delete mode 100644 apps/vue-app/.eslintrc.json delete mode 100644 apps/vue-app/babel.config.js delete mode 100644 apps/vue-app/configure-webpack.js delete mode 100644 apps/vue-app/jest.config.js delete mode 100644 apps/vue-app/project.json delete mode 100644 apps/vue-app/public/favicon.ico delete mode 100644 apps/vue-app/public/index.html delete mode 100644 apps/vue-app/src/App.vue delete mode 100644 apps/vue-app/src/assets/logo.png delete mode 100644 apps/vue-app/src/components/HelloWorld.vue delete mode 100644 apps/vue-app/src/main.ts delete mode 100644 apps/vue-app/src/shims-vue.d.ts delete mode 100644 apps/vue-app/tests/unit/example.spec.ts delete mode 100644 apps/vue-app/tsconfig.app.json delete mode 100644 apps/vue-app/tsconfig.json delete mode 100644 apps/vue-app/tsconfig.spec.json rename apps/nest/src/app/.gitkeep => libs/apps/indicator-market/src/lib/_indicator-market.component.scss (100%) 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/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/_app.component.scss b/apps/cloud/src/app/_app.component.scss new file mode 100644 index 000000000..7a1e7f75d --- /dev/null +++ b/apps/cloud/src/app/_app.component.scss @@ -0,0 +1,30 @@ +.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..d26e6c993 100644 --- a/apps/cloud/src/app/app.component.ts +++ b/apps/cloud/src/app/app.component.ts @@ -7,18 +7,45 @@ import { TranslateService } from '@ngx-translate/core' import { ThemesEnum } from '@metad/cloud/state' import { NGXLogger } from 'ngx-logger' import { combineLatest } from 'rxjs' -import { filter, map, tap } from 'rxjs/operators' +import { filter, map } from 'rxjs/operators' import { ICONS, PACThemeService, Store, UpdateService } from './@core' import { AppService } from './app.service' +import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core' +import { DateFnsAdapter, MAT_DATE_FNS_FORMATS } from '@angular/material-date-fns-adapter' +import { enUS } from 'date-fns/locale'; +import { zhCN } from 'date-fns/locale'; +import { zhHK } from 'date-fns/locale'; + + +function mapDateLocale(locale: string) { + switch (locale) { + case 'zh-CN': + case 'zh-Hans': + case 'zh': + return zhCN + case 'zh-Hant': + return zhHK + default: + return enUS + } +} @Component({ 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( private store: Store, public readonly appService: AppService, @@ -33,6 +60,7 @@ 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 @@ -42,6 +70,7 @@ export class AppComponent implements OnInit { this.store.preferredLanguage$.pipe(filter(value => !!value)).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)) 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/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 99% 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 e9c2782cc..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 @@ (change)="handleUploadChange($event)" (click)="fileUpload.value=null;">
- diff --git a/apps/cloud/src/app/features/project/indicators/indicators.component.ts b/apps/cloud/src/app/features/project/indicators/indicators.component.ts index f026dda3b..ad4c7a923 100644 --- a/apps/cloud/src/app/features/project/indicators/indicators.component.ts +++ b/apps/cloud/src/app/features/project/indicators/indicators.component.ts @@ -1,21 +1,19 @@ import { CommonModule } from '@angular/common' -import { Component, effect, inject, signal } from '@angular/core' +import { Component, inject } from '@angular/core' import { MatDialog } from '@angular/material/dialog' -import { ActivatedRoute, Router, RouterModule } from '@angular/router' +import { RouterModule } from '@angular/router' import { Indicator, convertIndicatorResult } from '@metad/cloud/state' import { saveAsYaml, uploadYamlFile } from '@metad/core' import { ButtonGroupDirective, DensityDirective } from '@metad/ocap-angular/core' -import { UntilDestroy } from '@ngneat/until-destroy' import { TranslateModule } from '@ngx-translate/core' import { firstValueFrom } from 'rxjs' -import { routeAnimations } from '../../../@core' -import { MaterialModule } from '../../../@shared' -import { TranslationBaseComponent } from '../../../@shared/language/translation-base.component' +import { IIndicator, routeAnimations } from '../../../@core' +import { ManageEntityBaseComponent, MaterialModule } from '../../../@shared' import { ProjectComponent } from '../project.component' import { exportIndicator } from '../types' import { IndicatorImportComponent } from './indicator-import/indicator-import.component' -@UntilDestroy() + @Component({ standalone: true, imports: [CommonModule, RouterModule, TranslateModule, MaterialModule, ButtonGroupDirective, DensityDirective], @@ -24,11 +22,9 @@ import { IndicatorImportComponent } from './indicator-import/indicator-import.co styleUrls: ['./indicators.component.scss'], animations: [routeAnimations] }) -export class ProjectIndicatorsComponent extends TranslationBaseComponent { +export class ProjectIndicatorsComponent extends ManageEntityBaseComponent { private projectComponent = inject(ProjectComponent) private _dialog = inject(MatDialog) - private router = inject(Router) - private _route = inject(ActivatedRoute) get indicators() { return this.projectComponent.project?.indicators @@ -36,21 +32,6 @@ export class ProjectIndicatorsComponent extends TranslationBaseComponent { selectedIndicators = [] - openedIndicators = signal([]) - currentIndicator = signal(null) - - constructor() { - super() - - effect(() => { - if (this.currentIndicator()) { - if (!this.openedIndicators().find((item) => item.id === this.currentIndicator().id)) { - this.openedIndicators.set([...this.openedIndicators(), this.currentIndicator()]) - } - } - }, {allowSignalWrites: true}) - } - async export() { const indicators = this.selectedIndicators.length ? this.selectedIndicators : this.indicators const indicatorsFileName = this.getTranslation('PAC.INDICATOR.Indicators', { Default: 'Indicators' }) @@ -82,24 +63,16 @@ export class ProjectIndicatorsComponent extends TranslationBaseComponent { results ) this.projectComponent.refreshIndicators() - } - } - setCurrentIndicator(indicator: Indicator) { - this.currentIndicator.set(indicator) + this.router.navigate(['.'], { relativeTo: this.route }) + } } replaceNewIndicator(indicator: Indicator) { - const index = this.openedIndicators().findIndex((item) => item.id === 'new') + const index = this.openedLinks().findIndex((item) => item.id === 'new') if (index > -1) { - this.openedIndicators().splice(index, 1, indicator) + this.openedLinks().splice(index, 1, indicator) } - this.currentIndicator.set(indicator) - } - - removeOpenedIndicator(indicator: Indicator) { - this.currentIndicator.set(null) - this.openedIndicators.set(this.openedIndicators().filter((item) => item.id !== indicator.id)) - this.router.navigate(['.'], {relativeTo: this._route}) + this.currentLink.set(indicator) } } diff --git a/apps/cloud/src/app/features/project/indicators/register-form/register-form.component.html b/apps/cloud/src/app/features/project/indicators/register-form/register-form.component.html index 584d68213..3cacd1883 100644 --- a/apps/cloud/src/app/features/project/indicators/register-form/register-form.component.html +++ b/apps/cloud/src/app/features/project/indicators/register-form/register-form.component.html @@ -32,7 +32,7 @@ {{ 'PAC.INDICATOR.REGISTER.CREATED_BY' | translate: {Default: 'Created By'} }} - + diff --git a/apps/cloud/src/app/features/project/indicators/register-form/register-form.component.ts b/apps/cloud/src/app/features/project/indicators/register-form/register-form.component.ts index c01dcb3dd..9bf948963 100644 --- a/apps/cloud/src/app/features/project/indicators/register-form/register-form.component.ts +++ b/apps/cloud/src/app/features/project/indicators/register-form/register-form.component.ts @@ -105,7 +105,7 @@ export class IndicatorRegisterFormComponent implements OnChanges, ControlValueAc visible: new FormControl(true), businessAreaId: new FormControl(null), certificationId: new FormControl(null), - createdByName: new FormControl({ value: '本人', disabled: true }), + createdByName: new FormControl('Me'), principal: new FormControl(null), unit: new FormControl(null), validity: new FormControl(null), @@ -264,6 +264,8 @@ export class IndicatorRegisterFormComponent implements OnChanges, ControlValueAc } setDisabledState?(isDisabled: boolean): void { isDisabled ? this.formGroup.disable() : this.formGroup.enable() + // Disable createdby user as readonly whatever + this.formGroup.get('createdByName').disable() } async openFormula() { diff --git a/apps/cloud/src/app/features/project/indicators/register/register.component.html b/apps/cloud/src/app/features/project/indicators/register/register.component.html index 2ee141fac..b7cbc7be7 100644 --- a/apps/cloud/src/app/features/project/indicators/register/register.component.html +++ b/apps/cloud/src/app/features/project/indicators/register/register.component.html @@ -15,7 +15,7 @@ {{ 'PAC.MENU.INDICATOR.BATCH_UPLOAD' | translate: {Default: "Batch Upload"} }} --> diff --git a/apps/cloud/src/app/features/setting/custom-smtp/custom-smtp.component.html b/apps/cloud/src/app/features/setting/custom-smtp/custom-smtp.component.html index fcee3a39e..b258779fa 100644 --- a/apps/cloud/src/app/features/setting/custom-smtp/custom-smtp.component.html +++ b/apps/cloud/src/app/features/setting/custom-smtp/custom-smtp.component.html @@ -1,7 +1,7 @@
{{ 'PAC.MENU.Custom SMTP' | translate: {Default: "Custom SMTP"} }}
-
- \ No newline at end of file + + + 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/settings.component.ts b/apps/cloud/src/app/features/setting/settings.component.ts index ee6f20a67..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: ` -
+
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 c52cfd1a0..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,7 +1,7 @@
{{ 'PAC.MENU.MANAGE_TENANT' | translate: {Default: "Manage Tenant"} }}
- diff --git a/apps/cloud/src/assets/i18n/zh-CN.json b/apps/cloud/src/assets/i18n/zh-CN.json index ccb230ead..1df23ac36 100644 --- a/apps/cloud/src/assets/i18n/zh-CN.json +++ b/apps/cloud/src/assets/i18n/zh-CN.json @@ -302,7 +302,7 @@ "INDICATOR": { "REGISTER_INDICATOR": "注册指标", "BATCH_UPLOAD": "批量上传", - "DOWNLOAD_TEMPLATE": "下载模板", + "DownloadAsTemplate": "下载为模板", "INDICATOR_MARKET": "指标市场", "INDICATOR_MARKET_DESC": "浏览指标,申请指标权限" }, @@ -546,7 +546,8 @@ "Import": "导入", "Indicators": "指标", "Types": "类型", - "IndicatorMarket": "指标市场" + "IndicatorMarket": "指标市场", + "Certifications": "认证" }, "MODEL": { "ModelOverview": "语义模型概览", @@ -1359,6 +1360,7 @@ "ACCESS_DELETE_ALL_DATA": "Access Delete All Data" }, "Organization": { + "AllOrganizations": "所有组织", "MAIN": "主属性", "DEMO": "演示数据", "GENERATE_DEMO": "生成演示数据", @@ -1379,7 +1381,8 @@ "ProfileLink": "主页链接", "OfficialName": "组织全称", "ShortDescription": "组织简介", - "Website": "网站链接" + "Website": "网站链接", + "SelectDataNetwork": "选择数据网络" } } }, diff --git a/apps/cloud/src/styles.scss b/apps/cloud/src/styles.scss index 8dcf0da54..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%; @@ -366,9 +368,11 @@ html.cdk-global-scrollblock { .pac-page-body-toolbar { @apply flex justify-between items-center; } -.pac-tab-nav-bar { +.pac-tab-nav-bar.mat-mdc-tab-header { + --mdc-secondary-navigation-tab-container-height: 32px; + .pac-tab-close { - @apply opacity-0 invisible; + @apply opacity-0 invisible absolute -right-6; } .mdc-tab.mdc-tab--active { .pac-tab-close { 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 317ebcb2336e0833a22dddf0ab287849f26fda57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 zcmeI332;U^%p|z7g|#(P)qFEA@4f!_@qOK2 z_lJl}!lhL!VT_U|uN7%8B2iKH??xhDa;*`g{yjTFWHvXn;2s{4R7kH|pKGdy(7z!K zgftM+Ku7~24TLlh(!g)gz|foI94G^t2^IO$uvX$3(OR0<_5L2sB)lMAMy|+`xodJ{ z_Uh_1m)~h?a;2W{dmhM;u!YGo=)OdmId_B<%^V^{ovI@y`7^g1_V9G}*f# zNzAtvou}I!W1#{M^@ROc(BZ! z+F!!_aR&Px3_reO(EW+TwlW~tv*2zr?iP7(d~a~yA|@*a89IUke+c472NXM0wiX{- zl`UrZC^1XYyf%1u)-Y)jj9;MZ!SLfd2Hl?o|80Su%Z?To_=^g_Jt0oa#CT*tjx>BI z16wec&AOWNK<#i0Qd=1O$fymLRoUR*%;h@*@v7}wApDl^w*h}!sYq%kw+DKDY)@&A z@9$ULEB3qkR#85`lb8#WZw=@})#kQig9oqy^I$dj&k4jU&^2(M3q{n1AKeGUKPFbr z1^<)aH;VsG@J|B&l>UtU#Ejv3GIqERzYgL@UOAWtW<{p#zy`WyJgpCy8$c_e%wYJL zyGHRRx38)HyjU3y{-4z6)pzb>&Q1pR)B&u01F-|&Gx4EZWK$nkUkOI|(D4UHOXg_- zw{OBf!oWQUn)Pe(=f=nt=zkmdjpO^o8ZZ9o_|4tW1ni+Un9iCW47*-ut$KQOww!;u z`0q)$s6IZO!~9$e_P9X!hqLxu`fpcL|2f^I5d4*a@Dq28;@2271v_N+5HqYZ>x;&O z05*7JT)mUe&%S0@UD)@&8SmQrMtsDfZT;fkdA!r(S=}Oz>iP)w=W508=Rc#nNn7ym z1;42c|8($ALY8#a({%1#IXbWn9-Y|0eDY$_L&j{63?{?AH{);EzcqfydD$@-B`Y3<%IIj7S7rK_N}je^=dEk%JQ4c z!tBdTPE3Tse;oYF>cnrapWq*o)m47X1`~6@(!Y29#>-#8zm&LXrXa(3=7Z)ElaQqj z-#0JJy3Fi(C#Rx(`=VXtJ63E2_bZGCz+QRa{W0e2(m3sI?LOcUBx)~^YCqZ{XEPX)C>G>U4tfqeH8L(3|pQR*zbL1 zT9e~4Tb5p9_G}$y4t`i*4t_Mr9QYvL9C&Ah*}t`q*}S+VYh0M6GxTTSXI)hMpMpIq zD1ImYqJLzbj0}~EpE-aH#VCH_udYEW#`P2zYmi&xSPs_{n6tBj=MY|-XrA;SGA_>y zGtU$?HXm$gYj*!N)_nQ59%lQdXtQZS3*#PC-{iB_sm+ytD*7j`D*k(P&IH2GHT}Eh z5697eQECVIGQAUe#eU2I!yI&%0CP#>%6MWV z@zS!p@+Y1i1b^QuuEF*13CuB zu69dve5k7&Wgb+^s|UB08Dr3u`h@yM0NTj4h7MnHo-4@xmyr7(*4$rpPwsCDZ@2be zRz9V^GnV;;?^Lk%ynzq&K(Aix`mWmW`^152Hoy$CTYVehpD-S1-W^#k#{0^L`V6CN+E z!w+xte;2vu4AmVNEFUOBmrBL>6MK@!O2*N|2=d|Y;oN&A&qv=qKn73lDD zI(+oJAdgv>Yr}8(&@ZuAZE%XUXmX(U!N+Z_sjL<1vjy1R+1IeHt`79fnYdOL{$ci7 z%3f0A*;Zt@ED&Gjm|OFTYBDe%bbo*xXAQsFz+Q`fVBH!N2)kaxN8P$c>sp~QXnv>b zwq=W3&Mtmih7xkR$YA)1Yi?avHNR6C99!u6fh=cL|KQ&PwF!n@ud^n(HNIImHD!h87!i*t?G|p0o+eelJ?B@A64_9%SBhNaJ64EvKgD&%LjLCYnNfc; znj?%*p@*?dq#NqcQFmmX($wms@CSAr9#>hUR^=I+=0B)vvGX%T&#h$kmX*s=^M2E!@N9#m?LhMvz}YB+kd zG~mbP|D(;{s_#;hsKK9lbVK&Lo734x7SIFJ9V_}2$@q?zm^7?*XH94w5Qae{7zOMUF z^?%F%)c1Y)Q?Iy?I>knw*8gYW#ok|2gdS=YYZLiD=CW|Nj;n^x!=S#iJ#`~Ld79+xXpVmUK^B(xO_vO!btA9y7w3L3-0j-y4 z?M-V{%z;JI`bk7yFDcP}OcCd*{Q9S5$iGA7*E1@tfkyjAi!;wP^O71cZ^Ep)qrQ)N z#wqw0_HS;T7x3y|`P==i3hEwK%|>fZ)c&@kgKO1~5<5xBSk?iZV?KI6&i72H6S9A* z=U(*e)EqEs?Oc04)V-~K5AUmh|62H4*`UAtItO$O(q5?6jj+K^oD!04r=6#dsxp?~}{`?&sXn#q2 zGuY~7>O2=!u@@Kfu7q=W*4egu@qPMRM>(eyYyaIE<|j%d=iWNdGsx%c!902v#ngNg z@#U-O_4xN$s_9?(`{>{>7~-6FgWpBpqXb`Ydc3OFL#&I}Irse9F_8R@4zSS*Y*o*B zXL?6*Aw!AfkNCgcr#*yj&p3ZDe2y>v$>FUdKIy_2N~}6AbHc7gA3`6$g@1o|dE>vz z4pl(j9;kyMsjaw}lO?(?Xg%4k!5%^t#@5n=WVc&JRa+XT$~#@rldvN3S1rEpU$;XgxVny7mki3 z-Hh|jUCHrUXuLr!)`w>wgO0N%KTB-1di>cj(x3Bav`7v z3G7EIbU$z>`Nad7Rk_&OT-W{;qg)-GXV-aJT#(ozdmnA~Rq3GQ_3mby(>q6Ocb-RgTUhTN)))x>m&eD;$J5Bg zo&DhY36Yg=J=$Z>t}RJ>o|@hAcwWzN#r(WJ52^g$lh^!63@hh+dR$&_dEGu&^CR*< z!oFqSqO@>xZ*nC2oiOd0eS*F^IL~W-rsrO`J`ej{=ou_q^_(<$&-3f^J z&L^MSYWIe{&pYq&9eGaArA~*kA - - - - 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 58679444595bda4f04b7982a5fccad54e1082d13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6796 zcmds6OKTKC5bhX)iX;X^4|+(BIq5;Oan+bz5R6Zv1_ELp8#S7+iU}k>Fys(_lot^^ z1O-nXy@(f2f`7rUy6T&motHDa**&E4An*N4B+Q778{`S@Yjxf9O0 zF$kQl29Xi}!Px)u0aHA6VVr7v$uk4PS@Y8dSbK#nhUJ*6#{40s{1)dkzAKnBu%0&mkIeN< z!>+R#+cn%V%mda>L)3|ndG~eQW7xSy(_P}gysWctTw*+iyM$lULPyRtYwZh{7!R(~ zN)P$47HfCRE5>Qm`rk^OWetLktb9?QR$|?b_!xGsO`r9PB59fT7QHD5tq!)qFU(3j zZE>{v*X8%mOpUTxs(e4pUrj%c$#beRHA*X5 zVRQ;}7L3H}G)q0fm435>X4OC!u7WK()Y2j?Mg7vWe zd?H#M&{-IEFec0Ucs}DE(vy1KuZ8O9+10kct26`iY2mD@Iiutda3gVxq5qWizm~m| zUhG^%Xmrn#ZTwbvE|MIHdNflG7af95T?a)@9-gMd~2wDW|Js>A4{t=%ai_MoD&5deioeVrf@%+8+2TPXPkncTxZRyG}wY#hp_<<=d)9d|L`Rr& 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 f3d2503fc2a44b5053b0837ebea6e87a2d339a43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6849 zcmaKRcUV(fvo}bjDT-7nLI_nlK}sT_69H+`qzVWDA|yaU?}j417wLi^B1KB1SLsC& zL0ag7$U(XW5YR7p&Ux?sP$d4lvMt8C^+TcQu4F zQqv!UF!I+kw)c0jhd6+g6oCr9P?7)?!qX1ui*iL{p}sKCAGuJ{{W)0z1pLF|=>h}& zt(2Lr0Z`2ig8<5i%Zk}cO5Fm=LByqGWaS`oqChZdEFmc`0hSb#gg|Aap^{+WKOYcj zHjINK)KDG%&s?Mt4CL(T=?;~U@bU2x_mLKN!#GJuK_CzbNw5SMEJorG!}_5;?R>@1 zSl)jns3WlU7^J%=(hUtfmuUCU&C3%8B5C^f5>W2Cy8jW3#{Od{lF1}|?c61##3dzA zsPlFG;l_FzBK}8>|H_Ru_H#!_7$UH4UKo3lKOA}g1(R&|e@}GINYVzX?q=_WLZCgh z)L|eJMce`D0EIwgRaNETDsr+?vQknSGAi=7H00r`QnI%oQnFxm`G2umXso9l+8*&Q z7WqF|$p49js$mdzo^BXpH#gURy=UO;=IMrYc5?@+sR4y_?d*~0^YP7d+y0{}0)zBM zIKVM(DBvICK#~7N0a+PY6)7;u=dutmNqK3AlsrUU9U`d;msiucB_|8|2kY=(7XA;G zwDA8AR)VCA#JOkxm#6oHNS^YVuOU;8p$N)2{`;oF|rQ?B~K$%rHDxXs+_G zF5|-uqHZvSzq}L;5Kcy_P+x0${33}Ofb6+TX&=y;;PkEOpz%+_bCw_{<&~ zeLV|!bP%l1qxywfVr9Z9JI+++EO^x>ZuCK);=$VIG1`kxK8F2M8AdC$iOe3cj1fo(ce4l-9 z7*zKy3={MixvUk=enQE;ED~7tv%qh&3lR<0m??@w{ILF|e#QOyPkFYK!&Up7xWNtL zOW%1QMC<3o;G9_S1;NkPB6bqbCOjeztEc6TsBM<(q9((JKiH{01+Ud=uw9B@{;(JJ z-DxI2*{pMq`q1RQc;V8@gYAY44Z!%#W~M9pRxI(R?SJ7sy7em=Z5DbuDlr@*q|25V)($-f}9c#?D%dU^RS<(wz?{P zFFHtCab*!rl(~j@0(Nadvwg8q|4!}L^>d?0al6}Rrv9$0M#^&@zjbfJy_n!%mVHK4 z6pLRIQ^Uq~dnyy$`ay51Us6WaP%&O;@49m&{G3z7xV3dLtt1VTOMYl3UW~Rm{Eq4m zF?Zl_v;?7EFx1_+#WFUXxcK78IV)FO>42@cm@}2I%pVbZqQ}3;p;sDIm&knay03a^ zn$5}Q$G!@fTwD$e(x-~aWP0h+4NRz$KlnO_H2c< z(XX#lPuW_%H#Q+c&(nRyX1-IadKR-%$4FYC0fsCmL9ky3 zKpxyjd^JFR+vg2!=HWf}2Z?@Td`0EG`kU?{8zKrvtsm)|7>pPk9nu@2^z96aU2<#` z2QhvH5w&V;wER?mopu+nqu*n8p~(%QkwSs&*0eJwa zMXR05`OSFpfyRb!Y_+H@O%Y z0=K^y6B8Gcbl?SA)qMP3Z+=C(?8zL@=74R=EVnE?vY!1BQy2@q*RUgRx4yJ$k}MnL zs!?74QciNb-LcG*&o<9=DSL>1n}ZNd)w1z3-0Pd^4ED1{qd=9|!!N?xnXjM!EuylY z5=!H>&hSofh8V?Jofyd!h`xDI1fYAuV(sZwwN~{$a}MX^=+0TH*SFp$vyxmUv7C*W zv^3Gl0+eTFgBi3FVD;$nhcp)ka*4gSskYIqQ&+M}xP9yLAkWzBI^I%zR^l1e?bW_6 zIn{mo{dD=)9@V?s^fa55jh78rP*Ze<3`tRCN4*mpO$@7a^*2B*7N_|A(Ve2VB|)_o z$=#_=aBkhe(ifX}MLT()@5?OV+~7cXC3r!%{QJxriXo9I%*3q4KT4Xxzyd{ z9;_%=W%q!Vw$Z7F3lUnY+1HZ*lO;4;VR2+i4+D(m#01OYq|L_fbnT;KN<^dkkCwtd zF7n+O7KvAw8c`JUh6LmeIrk4`F3o|AagKSMK3))_5Cv~y2Bb2!Ibg9BO7Vkz?pAYX zoI=B}+$R22&IL`NCYUYjrdhwjnMx_v=-Qcx-jmtN>!Zqf|n1^SWrHy zK|MwJ?Z#^>)rfT5YSY{qjZ&`Fjd;^vv&gF-Yj6$9-Dy$<6zeP4s+78gS2|t%Z309b z0^fp~ue_}i`U9j!<|qF92_3oB09NqgAoehQ`)<)dSfKoJl_A6Ec#*Mx9Cpd-p#$Ez z={AM*r-bQs6*z$!*VA4|QE7bf@-4vb?Q+pPKLkY2{yKsw{&udv_2v8{Dbd zm~8VAv!G~s)`O3|Q6vFUV%8%+?ZSVUa(;fhPNg#vab@J*9XE4#D%)$UU-T5`fwjz! z6&gA^`OGu6aUk{l*h9eB?opVdrHK>Q@U>&JQ_2pR%}TyOXGq_6s56_`U(WoOaAb+K zXQr#6H}>a-GYs9^bGP2Y&hSP5gEtW+GVC4=wy0wQk=~%CSXj=GH6q z-T#s!BV`xZVxm{~jr_ezYRpqqIcXC=Oq`b{lu`Rt(IYr4B91hhVC?yg{ol4WUr3v9 zOAk2LG>CIECZ-WIs0$N}F#eoIUEtZudc7DPYIjzGqDLWk_A4#(LgacooD z2K4IWs@N`Bddm-{%oy}!k0^i6Yh)uJ1S*90>|bm3TOZxcV|ywHUb(+CeX-o1|LTZM zwU>dY3R&U)T(}5#Neh?-CWT~@{6Ke@sI)uSuzoah8COy)w)B)aslJmp`WUcjdia-0 zl2Y}&L~XfA`uYQboAJ1;J{XLhYjH){cObH3FDva+^8ioOQy%Z=xyjGLmWMrzfFoH; zEi3AG`_v+%)&lDJE;iJWJDI@-X9K5O)LD~j*PBe(wu+|%ar~C+LK1+-+lK=t# z+Xc+J7qp~5q=B~rD!x78)?1+KUIbYr^5rcl&tB-cTtj+e%{gpZZ4G~6r15+d|J(ky zjg@@UzMW0k9@S#W(1H{u;Nq(7llJbq;;4t$awM;l&(2s+$l!Ay9^Ge|34CVhr7|BG z?dAR83smef^frq9V(OH+a+ki#q&-7TkWfFM=5bsGbU(8mC;>QTCWL5ydz9s6k@?+V zcjiH`VI=59P-(-DWXZ~5DH>B^_H~;4$)KUhnmGo*G!Tq8^LjfUDO)lASN*=#AY_yS zqW9UX(VOCO&p@kHdUUgsBO0KhXxn1sprK5h8}+>IhX(nSXZKwlNsjk^M|RAaqmCZB zHBolOHYBas@&{PT=R+?d8pZu zUHfyucQ`(umXSW7o?HQ3H21M`ZJal+%*)SH1B1j6rxTlG3hx1IGJN^M7{$j(9V;MZ zRKybgVuxKo#XVM+?*yTy{W+XHaU5Jbt-UG33x{u(N-2wmw;zzPH&4DE103HV@ER86 z|FZEmQb|&1s5#`$4!Cm}&`^{(4V}OP$bk`}v6q6rm;P!H)W|2i^e{7lTk2W@jo_9q z*aw|U7#+g59Fv(5qI`#O-qPj#@_P>PC#I(GSp3DLv7x-dmYK=C7lPF8a)bxb=@)B1 zUZ`EqpXV2dR}B&r`uM}N(TS99ZT0UB%IN|0H%DcVO#T%L_chrgn#m6%x4KE*IMfjX zJ%4veCEqbXZ`H`F_+fELMC@wuy_ch%t*+Z+1I}wN#C+dRrf2X{1C8=yZ_%Pt6wL_~ zZ2NN-hXOT4P4n$QFO7yYHS-4wF1Xfr-meG9Pn;uK51?hfel`d38k{W)F*|gJLT2#T z<~>spMu4(mul-8Q3*pf=N4DcI)zzjqAgbE2eOT7~&f1W3VsdD44Ffe;3mJp-V@8UC z)|qnPc12o~$X-+U@L_lWqv-RtvB~%hLF($%Ew5w>^NR82qC_0FB z)=hP1-OEx?lLi#jnLzH}a;Nvr@JDO-zQWd}#k^an$Kwml;MrD&)sC5b`s0ZkVyPkb zt}-jOq^%_9>YZe7Y}PhW{a)c39G`kg(P4@kxjcYfgB4XOOcmezdUI7j-!gs7oAo2o zx(Ph{G+YZ`a%~kzK!HTAA5NXE-7vOFRr5oqY$rH>WI6SFvWmahFav!CfRMM3%8J&c z*p+%|-fNS_@QrFr(at!JY9jCg9F-%5{nb5Bo~z@Y9m&SHYV`49GAJjA5h~h4(G!Se zZmK{Bo7ivCfvl}@A-ptkFGcWXAzj3xfl{evi-OG(TaCn1FAHxRc{}B|x+Ua1D=I6M z!C^ZIvK6aS_c&(=OQDZfm>O`Nxsw{ta&yiYPA~@e#c%N>>#rq)k6Aru-qD4(D^v)y z*>Rs;YUbD1S8^D(ps6Jbj0K3wJw>L4m)0e(6Pee3Y?gy9i0^bZO?$*sv+xKV?WBlh zAp*;v6w!a8;A7sLB*g-^<$Z4L7|5jXxxP1}hQZ<55f9<^KJ>^mKlWSGaLcO0=$jem zWyZkRwe~u{{tU63DlCaS9$Y4CP4f?+wwa(&1ou)b>72ydrFvm`Rj-0`kBJgK@nd(*Eh!(NC{F-@=FnF&Y!q`7){YsLLHf0_B6aHc# z>WIuHTyJwIH{BJ4)2RtEauC7Yq7Cytc|S)4^*t8Va3HR zg=~sN^tp9re@w=GTx$;zOWMjcg-7X3Wk^N$n;&Kf1RgVG2}2L-(0o)54C509C&77i zrjSi{X*WV=%C17((N^6R4Ya*4#6s_L99RtQ>m(%#nQ#wrRC8Y%yxkH;d!MdY+Tw@r zjpSnK`;C-U{ATcgaxoEpP0Gf+tx);buOMlK=01D|J+ROu37qc*rD(w`#O=3*O*w9?biwNoq3WN1`&Wp8TvKj3C z3HR9ssH7a&Vr<6waJrU zdLg!ieYz%U^bmpn%;(V%%ugMk92&?_XX1K@mwnVSE6!&%P%Wdi7_h`CpScvspMx?N zQUR>oadnG17#hNc$pkTp+9lW+MBKHRZ~74XWUryd)4yd zj98$%XmIL4(9OnoeO5Fnyn&fpQ9b0h4e6EHHw*l68j;>(ya`g^S&y2{O8U>1*>4zR zq*WSI_2o$CHQ?x0!wl9bpx|Cm2+kFMR)oMud1%n2=qn5nE&t@Fgr#=Zv2?}wtEz^T z9rrj=?IH*qI5{G@Rn&}^Z{+TW}mQeb9=8b<_a`&Cm#n%n~ zU47MvCBsdXFB1+adOO)03+nczfWa#vwk#r{o{dF)QWya9v2nv43Zp3%Ps}($lA02*_g25t;|T{A5snSY?3A zrRQ~(Ygh_ebltHo1VCbJb*eOAr;4cnlXLvI>*$-#AVsGg6B1r7@;g^L zFlJ_th0vxO7;-opU@WAFe;<}?!2q?RBrFK5U{*ai@NLKZ^};Ul}beukveh?TQn;$%9=R+DX07m82gP$=}Uo_%&ngV`}Hyv8g{u z3SWzTGV|cwQuFIs7ZDOqO_fGf8Q`8MwL}eUp>q?4eqCmOTcwQuXtQckPy|4F1on8l zP*h>d+cH#XQf|+6c|S{7SF(Lg>bR~l(0uY?O{OEVlaxa5@e%T&xju=o1`=OD#qc16 zSvyH*my(dcp6~VqR;o(#@m44Lug@~_qw+HA=mS#Z^4reBy8iV?H~I;{LQWk3aKK8$bLRyt$g?- -
-

{{ msg }}

-

- For a guide and recipes on how to configure / customize this project,
- check out the - vue-cli documentation. -

-

Installed CLI Plugins

- -

Essential Links

- -

Ecosystem

- -
- - - - - - 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/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/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/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/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 e42e42477..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,9 +39,9 @@ "@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", - "@types/unzipper": "^0.10.7", "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 3eedde47c..821a0fb86 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' @@ -283,8 +283,7 @@ export class OrganizationDemoHandler implements ICommandHandler { @@ -568,7 +567,7 @@ export class OrganizationDemoHandler implements ICommandHandler 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/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 ) } From 7afb84c2ce3013c5ee63651de3854e5c4eac53de Mon Sep 17 00:00:00 2001 From: meta-d Date: Fri, 15 Sep 2023 09:30:16 +0800 Subject: [PATCH 4/8] fix: add material date fns adapter package --- .deploy/webapp/package.json | 1 + 1 file changed, 1 insertion(+) 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", From ca9a74075d6c71a95aafcdae88ee4392ce5b43ca Mon Sep 17 00:00:00 2001 From: meta-d Date: Fri, 15 Sep 2023 11:54:17 +0800 Subject: [PATCH 5/8] feat: 1. indicator card lang 2. preview file size limit --- .../home/dashboard/dashboard.component.html | 24 ++- .../save-as-template.component.html | 42 ++--- .../save-as-template.component.ts | 9 +- .../story-details.component.html | 43 +----- .../story-details/story-details.component.ts | 13 +- apps/cloud/src/assets/i18n/en.json | 3 +- apps/cloud/src/assets/i18n/zh-CN.json | 14 +- libs/core-angular/src/lib/locales/index.ts | 1 + libs/core-angular/src/lib/locales/utils.ts | 11 ++ libs/story-angular/i18n/zhHans.ts | 4 +- .../indicator-card/indicator.component.html | 12 +- .../indicator-card/indicator.component.ts | 145 ++++++++++-------- .../handlers/organization.demo.handler.ts | 2 +- 13 files changed, 165 insertions(+), 158 deletions(-) create mode 100644 libs/core-angular/src/lib/locales/utils.ts 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/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}} +
+