+ [title]="'All Db Context'">
add New
Context
-
- delete
- Remove(s)
- @if (store.vm$ |async; as vm) {
-
- @for (item of vm.data; track item.id) {
-
-
- {{ item.displayName }}
-
-
{{ item.databaseProvider }}
+ @if (store.vm$ |async; as vm) { @if (vm.status === 'Loading') {
+
+
+
+ } @else if (!vm.data.length) {
+
+
+
+ } @else {
+
+
Choose provider:
+
+
+ {{ ProviderLabel[item] }}
+
+
+
+
+
+
Available contexts:
+
+
+
+ @for (item of combineFilter(vm.data, filterForm.value); track item.id)
+ {
+
+
+ {{ item.displayName }}
+
+ {{ item.databaseProvider }}
+
+ more_horiz
+
+ }
- }
- }
+ } }
+
+
+
+
+
diff --git a/apps/mix-cms/src/app/pages/portal/database/database-context/database-context.component.scss b/apps/mix-cms/src/app/pages/portal/database/database-context/database-context.component.scss
index 83c9d7a7..618778bc 100644
--- a/apps/mix-cms/src/app/pages/portal/database/database-context/database-context.component.scss
+++ b/apps/mix-cms/src/app/pages/portal/database/database-context/database-context.component.scss
@@ -1,10 +1,11 @@
.context-card {
- padding: 1rem;
+ padding: 1rem 4rem 1rem 1rem;
background: var(--tui-base-02);
height: 8rem;
min-width: 200px;
width: fit-content;
cursor: pointer;
+ position: relative;
&:hover:after {
transform: scale(1.1);
@@ -17,17 +18,27 @@
&.sqlserver:after {
background: url('/assets/icons/microsoft.svg') bottom right no-repeat;
+ background-size: 50px;
}
&.postgres:after {
background: url('/assets/icons/postgres.svg') bottom right no-repeat;
+ background-size: 50px;
}
&.mysql:after {
background: url('/assets/icons/mysql.svg') bottom right no-repeat;
+ background-size: 100px;
}
- &.sqllite:after {
+ &.sqlite:after {
background: url('/assets/icons/sqllite.svg') bottom right no-repeat;
+ background-size: 50px;
+ }
+
+ &__action {
+ position: absolute;
+ top: 2px;
+ right: 2px;
}
}
diff --git a/apps/mix-cms/src/app/pages/portal/database/database-context/database-context.component.ts b/apps/mix-cms/src/app/pages/portal/database/database-context/database-context.component.ts
index 7ebf19fd..cd97b608 100644
--- a/apps/mix-cms/src/app/pages/portal/database/database-context/database-context.component.ts
+++ b/apps/mix-cms/src/app/pages/portal/database/database-context/database-context.component.ts
@@ -1,16 +1,31 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
-import { DatabaseProvider } from '@mixcore/lib/model';
+import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
+import {
+ DatabaseProvider,
+ DatabaseProviderDisplay,
+ MixDbContext,
+} from '@mixcore/lib/model';
+import { MixApiFacadeService } from '@mixcore/share/api';
import {
MixStatusIndicatorComponent,
MixSubToolbarComponent,
} from '@mixcore/share/components';
+import { toastObserverProcessing } from '@mixcore/share/helper';
import { RelativeTimeSpanPipe } from '@mixcore/share/pipe';
import { MixButtonComponent } from '@mixcore/ui/button';
+import { MixEmptyContentComponent } from '@mixcore/ui/empty-content';
import { DynamicFilterComponent } from '@mixcore/ui/filter';
+import { ModalService } from '@mixcore/ui/modal';
+import { SkeletonLoadingComponent } from '@mixcore/ui/skeleton';
import { MixDataTableModule } from '@mixcore/ui/table';
import { DialogService } from '@ngneat/dialog';
+import { TippyDirective } from '@ngneat/helipopper';
+import { HotToastService } from '@ngneat/hot-toast';
+import { tuiPure } from '@taiga-ui/cdk';
+import { TuiLoaderModule } from '@taiga-ui/core';
import { TuiCardModule, TuiSurfaceModule } from '@taiga-ui/experimental';
+import { TuiFilterModule } from '@taiga-ui/kit';
import { DbContextFormComponent } from '../components/db-context-form/db-context-form.component';
import { DatabaseContextStore } from '../store/db-context.store';
@@ -19,6 +34,7 @@ import { DatabaseContextStore } from '../store/db-context.store';
standalone: true,
imports: [
CommonModule,
+ ReactiveFormsModule,
MixSubToolbarComponent,
MixButtonComponent,
MixDataTableModule,
@@ -27,6 +43,11 @@ import { DatabaseContextStore } from '../store/db-context.store';
DynamicFilterComponent,
TuiCardModule,
TuiSurfaceModule,
+ TuiFilterModule,
+ MixEmptyContentComponent,
+ SkeletonLoadingComponent,
+ TippyDirective,
+ TuiLoaderModule,
],
templateUrl: './database-context.component.html',
styleUrl: './database-context.component.scss',
@@ -35,14 +56,31 @@ import { DatabaseContextStore } from '../store/db-context.store';
export class DatabaseContextComponent {
public dialog = inject(DialogService);
public store = inject(DatabaseContextStore);
+ public modal = inject(ModalService);
+ public mixApi = inject(MixApiFacadeService);
+ public toast = inject(HotToastService);
public ProviderIconMap: Record
= {
[DatabaseProvider.SQLSERVER]: 'sqlserver',
[DatabaseProvider.MySQL]: 'mysql',
[DatabaseProvider.PostgreSQL]: 'postgres',
- [DatabaseProvider.SQLLITE]: 'sqllite',
+ [DatabaseProvider.SQLITE]: 'sqlite',
};
+ public filterForm = inject(FormBuilder).control([]);
+ public filterItems = Object.values(DatabaseProvider);
+ public ProviderLabel = DatabaseProviderDisplay as any;
+ public selected?: MixDbContext;
+
+ @tuiPure
+ public combineFilter(
+ value: MixDbContext[],
+ filterValue: DatabaseProvider[] | null
+ ): MixDbContext[] {
+ if (!filterValue?.length) return value;
+ return value.filter((v) => filterValue.includes(v.databaseProvider));
+ }
+
public addContext() {
const dialogRef = this.dialog.open(DbContextFormComponent, {
windowClass: 'top-align-modal',
@@ -52,4 +90,19 @@ export class DatabaseContextComponent {
if (isReload) this.store.reload();
});
}
+
+ public onDelete() {
+ if (!this.selected) return;
+
+ this.modal.asKForAction('Are you sure to delete this item?', () => {
+ this.mixApi.databaseContext
+ .deleteById(this.selected!.id)
+ .pipe(toastObserverProcessing(this.toast))
+ .subscribe({
+ next: () => {
+ this.store.reload();
+ },
+ });
+ });
+ }
}
diff --git a/apps/mix-cms/src/app/pages/portal/database/store/db-context.store.ts b/apps/mix-cms/src/app/pages/portal/database/store/db-context.store.ts
index bdfae874..0ecfa0bc 100644
--- a/apps/mix-cms/src/app/pages/portal/database/store/db-context.store.ts
+++ b/apps/mix-cms/src/app/pages/portal/database/store/db-context.store.ts
@@ -10,7 +10,7 @@ export class DatabaseContextStore extends BaseCRUDStore {
this.mixApi.databaseContext.gets({ ...request, columns: '', pageSize: 50 });
public override vm$ = this.select((s) => s);
- public override requestName = 'database-context';
+ public override requestName = 'databaseContext';
public override searchColumns = ['Name', 'Description'];
public override searchColumnsDict: { [key: string]: string } = {
Name: 'displayName',
diff --git a/apps/mix-cms/src/assets/icons/empty-content.svg b/apps/mix-cms/src/assets/icons/empty-content.svg
new file mode 100644
index 00000000..fe8350ba
--- /dev/null
+++ b/apps/mix-cms/src/assets/icons/empty-content.svg
@@ -0,0 +1,154 @@
+
diff --git a/libs/mix-lib/src/model/core/database.model.ts b/libs/mix-lib/src/model/core/database.model.ts
index 4e44fec4..8d1797ca 100644
--- a/libs/mix-lib/src/model/core/database.model.ts
+++ b/libs/mix-lib/src/model/core/database.model.ts
@@ -402,12 +402,16 @@ export enum DatabaseProvider {
SQLSERVER = 'SQLSERVER',
MySQL = 'MySQL',
PostgreSQL = 'PostgreSQL',
- SQLLITE = 'SQLLITE',
+ SQLITE = 'SQLITE',
}
-export const DatabaseProviderDisplay: Record = {
+export const DatabaseProviderDisplay: Record<
+ DatabaseProvider | string,
+ string
+> = {
+ All: 'All provider',
[DatabaseProvider.SQLSERVER]: 'Microsoft Sql Server',
[DatabaseProvider.MySQL]: 'My SQL',
[DatabaseProvider.PostgreSQL]: 'Postgres Sql',
- [DatabaseProvider.SQLLITE]: 'Sql Lite',
+ [DatabaseProvider.SQLITE]: 'Sql Lite',
};
diff --git a/libs/mix-share/src/bases/base-crud.store.ts b/libs/mix-share/src/bases/base-crud.store.ts
index 17c88b5f..4d919fef 100644
--- a/libs/mix-share/src/bases/base-crud.store.ts
+++ b/libs/mix-share/src/bases/base-crud.store.ts
@@ -109,7 +109,7 @@ export class BaseCRUDStore extends ComponentStore> {
}
public reload() {
- this.patchState({ status: 'Loading' });
+ this.patchState({ status: 'SilentLoading' });
this.loadData(this.request$());
}
diff --git a/libs/mix-ui/src/empty-content/empty-content.component.html b/libs/mix-ui/src/empty-content/empty-content.component.html
new file mode 100644
index 00000000..a06d8d39
--- /dev/null
+++ b/libs/mix-ui/src/empty-content/empty-content.component.html
@@ -0,0 +1,18 @@
+
+
+
+ {{ title }}
+
+
+ {{ description }}
+
+
+
+ Create
+
+
diff --git a/libs/mix-ui/src/empty-content/empty-content.component.scss b/libs/mix-ui/src/empty-content/empty-content.component.scss
new file mode 100644
index 00000000..702fed44
--- /dev/null
+++ b/libs/mix-ui/src/empty-content/empty-content.component.scss
@@ -0,0 +1,6 @@
+.t-block-text {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/libs/mix-ui/src/empty-content/empty-content.component.ts b/libs/mix-ui/src/empty-content/empty-content.component.ts
new file mode 100644
index 00000000..808f9f25
--- /dev/null
+++ b/libs/mix-ui/src/empty-content/empty-content.component.ts
@@ -0,0 +1,26 @@
+import { CommonModule } from '@angular/common';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ EventEmitter,
+ Input,
+ Output,
+ ViewEncapsulation,
+} from '@angular/core';
+import { MixButtonComponent } from '@mixcore/ui/button';
+import { TuiBlockStatusModule } from '@taiga-ui/layout';
+
+@Component({
+ selector: 'mix-empty-content',
+ standalone: true,
+ imports: [CommonModule, TuiBlockStatusModule, MixButtonComponent],
+ templateUrl: './empty-content.component.html',
+ styleUrl: './empty-content.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ encapsulation: ViewEncapsulation.None,
+})
+export class MixEmptyContentComponent {
+ @Input() title: string = 'No data found';
+ @Input() description: string = 'Create your own wonderful data';
+ @Output() actionClick = new EventEmitter();
+}
diff --git a/libs/mix-ui/src/empty-content/index.ts b/libs/mix-ui/src/empty-content/index.ts
new file mode 100644
index 00000000..60650c5d
--- /dev/null
+++ b/libs/mix-ui/src/empty-content/index.ts
@@ -0,0 +1 @@
+export * from './empty-content.component';
diff --git a/libs/mix-ui/src/empty-content/ng-package.json b/libs/mix-ui/src/empty-content/ng-package.json
new file mode 100644
index 00000000..1dc0b0bd
--- /dev/null
+++ b/libs/mix-ui/src/empty-content/ng-package.json
@@ -0,0 +1,5 @@
+{
+ "lib": {
+ "entryFile": "index.ts"
+ }
+}
diff --git a/libs/mix-ui/src/empty-content/project.json b/libs/mix-ui/src/empty-content/project.json
new file mode 100644
index 00000000..e5e0a6c6
--- /dev/null
+++ b/libs/mix-ui/src/empty-content/project.json
@@ -0,0 +1,18 @@
+{
+ "name": "@mixcore/ui/empty-content",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "library",
+ "sourceRoot": "libs/mix-ui/src/error-alert",
+ "targets": {
+ "lint": {
+ "executor": "@nx/eslint:lint",
+ "outputs": ["{options.outputFile}"],
+ "options": {
+ "lintFilePatterns": [
+ "libs/mix-ui/src/empty-content/**/*.ts",
+ "libs/mix-ui/src/empty-content/**/*.html"
+ ]
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
index 6834eb18..1f191dc9 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
"@taiga-ui/experimental": "^3.57.0",
"@taiga-ui/icons": "3.55.0",
"@taiga-ui/kit": "3.55.0",
+ "@taiga-ui/layout": "^3.57.0",
"@tinkoff/ng-dompurify": "^4.0.0",
"@tinkoff/ng-polymorpheus": "4.2.0",
"ag-grid-angular": "^30.0.6",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5dc517b3..8fcb4ddd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -113,6 +113,9 @@ dependencies:
'@taiga-ui/kit':
specifier: 3.55.0
version: 3.55.0(@angular/common@17.0.2)(@angular/core@17.0.2)(@angular/forms@17.0.2)(@angular/router@17.0.2)(@ng-web-apis/common@3.0.6)(@ng-web-apis/mutation-observer@3.0.6)(@ng-web-apis/resize-observer@3.0.6)(@taiga-ui/cdk@3.55.0)(@taiga-ui/core@3.55.0)(@taiga-ui/i18n@3.55.0)(@tinkoff/ng-polymorpheus@4.2.0)(rxjs@7.8.1)
+ '@taiga-ui/layout':
+ specifier: ^3.57.0
+ version: 3.57.0(@angular/common@17.0.2)(@angular/core@17.0.2)(@taiga-ui/cdk@3.55.0)(@taiga-ui/core@3.55.0)(@tinkoff/ng-polymorpheus@4.2.0)(rxjs@7.8.1)
'@tinkoff/ng-dompurify':
specifier: ^4.0.0
version: 4.0.0(@angular/core@17.0.2)(@angular/platform-browser@17.0.2)(@types/dompurify@3.0.5)(dompurify@3.0.6)
@@ -5411,6 +5414,25 @@ packages:
tslib: 2.6.2
dev: false
+ /@taiga-ui/layout@3.57.0(@angular/common@17.0.2)(@angular/core@17.0.2)(@taiga-ui/cdk@3.55.0)(@taiga-ui/core@3.55.0)(@tinkoff/ng-polymorpheus@4.2.0)(rxjs@7.8.1):
+ resolution: {integrity: sha512-BG5mK7cb6e3GOOq67bGiyg/2ppsfn0576jlcSTJWQ6zWxl4KaL5ya0GWeSSR5zuGZEUHH01wq16wJqJy+bEuLw==}
+ peerDependencies:
+ '@angular/common': '>=12.0.0'
+ '@angular/core': '>=12.0.0'
+ '@taiga-ui/cdk': '>=3.57.0'
+ '@taiga-ui/core': '>=3.57.0'
+ '@tinkoff/ng-polymorpheus': 4.3.0
+ rxjs: '>=6.0.0'
+ dependencies:
+ '@angular/common': 17.0.2(@angular/core@17.0.2)(rxjs@7.8.1)
+ '@angular/core': 17.0.2(rxjs@7.8.1)(zone.js@0.14.2)
+ '@taiga-ui/cdk': 3.55.0(@angular-devkit/core@17.0.0)(@angular-devkit/schematics@17.0.0)(@angular/animations@17.0.2)(@angular/common@17.0.2)(@angular/core@17.0.2)(@angular/forms@17.0.2)(@angular/platform-browser@17.0.2)(rxjs@7.8.1)
+ '@taiga-ui/core': 3.55.0(@angular/animations@17.0.2)(@angular/common@17.0.2)(@angular/core@17.0.2)(@angular/forms@17.0.2)(@angular/platform-browser@17.0.2)(@angular/router@17.0.2)(@ng-web-apis/common@3.0.6)(@ng-web-apis/mutation-observer@3.0.6)(@taiga-ui/cdk@3.55.0)(@taiga-ui/i18n@3.55.0)(@tinkoff/ng-event-plugins@3.1.0)(@tinkoff/ng-polymorpheus@4.2.0)(rxjs@7.8.1)
+ '@tinkoff/ng-polymorpheus': 4.2.0(@angular/core@17.0.2)(@angular/platform-browser@17.0.2)
+ rxjs: 7.8.1
+ tslib: 2.6.2
+ dev: false
+
/@tinkoff/ng-dompurify@4.0.0(@angular/core@17.0.2)(@angular/platform-browser@17.0.2)(@types/dompurify@3.0.5)(dompurify@3.0.6):
resolution: {integrity: sha512-BjKUweWLrOx8UOZw+Tl+Dae5keYuSbeMkppcXQdsvwASMrPfmP7d3Q206Q6HDqOV2WnpnFqGUB95IMbLAeRRuw==}
peerDependencies:
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 930192a4..db270124 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -62,7 +62,8 @@
"@mixcore/ui/table": ["libs/mix-ui/src/data-table/index.ts"],
"@mixcore/ui/textarea": ["libs/mix-ui/src/text-area/index.ts"],
"@mixcore/ui/toggle": ["libs/mix-ui/src/toggle/index.ts"],
- "@mixcore/ui/upload": ["libs/mix-ui/src/upload/index.ts"]
+ "@mixcore/ui/upload": ["libs/mix-ui/src/upload/index.ts"],
+ "@mixcore/ui/empty-content": ["libs/mix-ui/src/empty-content/index.ts"]
}
},
"exclude": ["node_modules", "tmp"]