@aiao/rxdb-angular 0.0.2 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/eslint.config.mjs +58 -0
- package/ng-package.json +7 -0
- package/package.json +13 -23
- package/project.json +48 -0
- package/src/InfiniteScrollingList.ts +123 -0
- package/src/devtools/devtools.html +99 -0
- package/src/devtools/devtools.interface.ts +3 -0
- package/src/devtools/devtools.scss +49 -0
- package/src/devtools/devtools.spec.ts +30 -0
- package/src/devtools/devtools.ts +207 -0
- package/src/devtools/entity-table-item.ts +47 -0
- package/src/devtools/entity-table-tools.html +56 -0
- package/src/devtools/entity-table-tools.scss +8 -0
- package/src/devtools/entity-table-tools.ts +153 -0
- package/src/devtools/event-tools.html +15 -0
- package/src/devtools/event-tools.scss +18 -0
- package/src/devtools/event-tools.ts +45 -0
- package/src/devtools/scroll-advanced-calc.service.ts +41 -0
- package/src/devtools/settings.html +46 -0
- package/src/devtools/settings.scss +19 -0
- package/src/devtools/settings.ts +122 -0
- package/src/hooks.ts +307 -0
- package/src/index.ts +7 -0
- package/src/rxdb-change-detector.directive.spec.ts +94 -0
- package/src/rxdb-change-detector.directive.ts +35 -0
- package/src/rxdb.provider.ts +13 -0
- package/src/rxdb.service.spec.ts +31 -0
- package/src/rxdb.service.ts +35 -0
- package/src/test-setup.ts +14 -0
- package/src/use-action.spec.ts +88 -0
- package/src/use-action.ts +20 -0
- package/src/use-state.spec.ts +105 -0
- package/src/use-state.ts +28 -0
- package/tsconfig.json +33 -0
- package/tsconfig.lib.json +42 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +23 -0
- package/vite.config.mts +55 -0
- package/fesm2022/aiao-rxdb-angular.mjs +0 -47
- package/fesm2022/aiao-rxdb-angular.mjs.map +0 -1
- package/index.d.ts +0 -15
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import nx from '@nx/eslint-plugin';
|
|
2
|
+
import jsoncParser from 'jsonc-eslint-parser';
|
|
3
|
+
import baseConfig from '../../eslint.config.mjs';
|
|
4
|
+
|
|
5
|
+
export default [
|
|
6
|
+
...baseConfig,
|
|
7
|
+
{
|
|
8
|
+
files: ['**/*.json'],
|
|
9
|
+
rules: {
|
|
10
|
+
'@nx/dependency-checks': [
|
|
11
|
+
'error',
|
|
12
|
+
{
|
|
13
|
+
ignoredFiles: ['{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}'],
|
|
14
|
+
ignoredDependencies: [
|
|
15
|
+
'@analogjs/vite-plugin-angular',
|
|
16
|
+
'@codecov/vite-plugin',
|
|
17
|
+
'@angular/common',
|
|
18
|
+
'@angular/core',
|
|
19
|
+
'@angular/forms',
|
|
20
|
+
'@nx/vite',
|
|
21
|
+
'vite'
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
languageOptions: {
|
|
27
|
+
parser: jsoncParser
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
...nx.configs['flat/angular'],
|
|
31
|
+
...nx.configs['flat/angular-template'],
|
|
32
|
+
{
|
|
33
|
+
files: ['**/*.ts'],
|
|
34
|
+
rules: {
|
|
35
|
+
'@angular-eslint/directive-selector': [
|
|
36
|
+
'error',
|
|
37
|
+
{
|
|
38
|
+
type: 'attribute',
|
|
39
|
+
prefix: 'rxdb',
|
|
40
|
+
style: 'camelCase'
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
'@angular-eslint/component-selector': [
|
|
44
|
+
'error',
|
|
45
|
+
{
|
|
46
|
+
type: 'element',
|
|
47
|
+
prefix: 'rxdb',
|
|
48
|
+
style: 'kebab-case'
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
files: ['**/*.html'],
|
|
55
|
+
// Override or add rules here
|
|
56
|
+
rules: {}
|
|
57
|
+
}
|
|
58
|
+
];
|
package/ng-package.json
ADDED
package/package.json
CHANGED
|
@@ -1,27 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiao/rxdb-angular",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@aiao/rxdb": "
|
|
6
|
-
"@
|
|
7
|
-
"@angular
|
|
5
|
+
"@aiao/rxdb": "workspace:*",
|
|
6
|
+
"@aiao/utils": "workspace:*",
|
|
7
|
+
"@aiao/code-editor-angular": "workspace:*",
|
|
8
|
+
"@aiao/rxdb-plugin-graph": "workspace:*",
|
|
9
|
+
"@angular/core": "^20.0.0",
|
|
10
|
+
"rxjs": "^7.8.2",
|
|
11
|
+
"lucide-angular": ">=0.555.0",
|
|
12
|
+
"@rdlabo/ngx-cdk-scroll-strategies": "^21.0.2",
|
|
13
|
+
"@angular/cdk": ">=20.0.0",
|
|
14
|
+
"ngxtension": "^7.0.1"
|
|
8
15
|
},
|
|
9
|
-
"sideEffects": false
|
|
10
|
-
|
|
11
|
-
"access": "public"
|
|
12
|
-
},
|
|
13
|
-
"module": "fesm2022/aiao-rxdb-angular.mjs",
|
|
14
|
-
"typings": "index.d.ts",
|
|
15
|
-
"exports": {
|
|
16
|
-
"./package.json": {
|
|
17
|
-
"default": "./package.json"
|
|
18
|
-
},
|
|
19
|
-
".": {
|
|
20
|
-
"types": "./index.d.ts",
|
|
21
|
-
"default": "./fesm2022/aiao-rxdb-angular.mjs"
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
"dependencies": {
|
|
25
|
-
"tslib": "^2.3.0"
|
|
26
|
-
}
|
|
27
|
-
}
|
|
16
|
+
"sideEffects": false
|
|
17
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
3
|
+
"implicitDependencies": ["code-editor-angular"],
|
|
4
|
+
"name": "rxdb-angular",
|
|
5
|
+
"prefix": "rxdb",
|
|
6
|
+
"projectType": "library",
|
|
7
|
+
"release": {
|
|
8
|
+
"version": {
|
|
9
|
+
"manifestRootsToUpdate": ["dist/{projectRoot}"],
|
|
10
|
+
"currentVersionResolver": "git-tag",
|
|
11
|
+
"fallbackCurrentVersionResolver": "disk"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"sourceRoot": "packages/rxdb-angular/src",
|
|
15
|
+
"tags": ["angular-lib"],
|
|
16
|
+
"targets": {
|
|
17
|
+
"build": {
|
|
18
|
+
"executor": "@nx/angular:package",
|
|
19
|
+
"outputs": ["{workspaceRoot}/dist/{projectRoot}"],
|
|
20
|
+
"options": {
|
|
21
|
+
"project": "packages/rxdb-angular/ng-package.json",
|
|
22
|
+
"tsConfig": "packages/rxdb-angular/tsconfig.lib.json"
|
|
23
|
+
},
|
|
24
|
+
"configurations": {
|
|
25
|
+
"production": {
|
|
26
|
+
"tsConfig": "packages/rxdb-angular/tsconfig.lib.prod.json"
|
|
27
|
+
},
|
|
28
|
+
"development": {}
|
|
29
|
+
},
|
|
30
|
+
"defaultConfiguration": "production"
|
|
31
|
+
},
|
|
32
|
+
"nx-release-publish": {
|
|
33
|
+
"options": {
|
|
34
|
+
"packageRoot": "dist/{projectRoot}"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"lint": {
|
|
38
|
+
"executor": "@nx/eslint:lint"
|
|
39
|
+
},
|
|
40
|
+
"test": {
|
|
41
|
+
"executor": "@nx/vitest:test",
|
|
42
|
+
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
43
|
+
"options": {
|
|
44
|
+
"config": "packages/rxdb-angular/vite.config.mts"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { EntityType, FindByCursorOptions, RxDB } from '@aiao/rxdb';
|
|
2
|
+
import { isFunction, nextMicroTask } from '@aiao/utils';
|
|
3
|
+
import { computed, DestroyRef, effect, EffectRef, inject, Signal, signal, untracked } from '@angular/core';
|
|
4
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
|
+
|
|
6
|
+
type OptionsInput<T extends EntityType> = FindByCursorOptions<T> | Signal<FindByCursorOptions<T>>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 无限滚动的列表
|
|
10
|
+
*/
|
|
11
|
+
export class InfiniteScrollingList<T extends EntityType> {
|
|
12
|
+
readonly #values = signal<InstanceType<T>[][]>([]);
|
|
13
|
+
readonly #destroy_ref = inject(DestroyRef);
|
|
14
|
+
readonly #options_eff: EffectRef;
|
|
15
|
+
|
|
16
|
+
#is_initialized = false;
|
|
17
|
+
|
|
18
|
+
readonly error = signal<Error | undefined>(undefined);
|
|
19
|
+
readonly isLoading = signal<boolean>(false);
|
|
20
|
+
readonly hasMore = signal<boolean>(true);
|
|
21
|
+
readonly value = computed<InstanceType<T>[]>(() => this.#values().flat());
|
|
22
|
+
readonly hasValue = computed<boolean>(() => this.value().length > 0);
|
|
23
|
+
readonly isEmpty = computed<boolean>(() => !this.isLoading() && !this.hasValue() && this.#is_initialized);
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
private readonly rxdb: RxDB,
|
|
27
|
+
private readonly EntityType: T,
|
|
28
|
+
private readonly options: OptionsInput<T>
|
|
29
|
+
) {
|
|
30
|
+
this.#options_eff = effect(() => {
|
|
31
|
+
if (isFunction(this.options)) {
|
|
32
|
+
this.options();
|
|
33
|
+
}
|
|
34
|
+
if (!this.#is_initialized) {
|
|
35
|
+
this.#is_initialized = true;
|
|
36
|
+
nextMicroTask(() => this.loadMore());
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
untracked(() => this.#reset());
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
this.#destroy_ref.onDestroy(() => {
|
|
43
|
+
this.#options_eff.destroy();
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
loadMore(): void {
|
|
48
|
+
if (this.isLoading() || !this.hasMore()) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.isLoading.set(true);
|
|
53
|
+
this.error.set(undefined);
|
|
54
|
+
|
|
55
|
+
const last_entity = this.#get_last_entity();
|
|
56
|
+
const opt = isFunction(this.options) ? this.options() : this.options;
|
|
57
|
+
const options = structuredClone(opt);
|
|
58
|
+
|
|
59
|
+
if (last_entity) {
|
|
60
|
+
options.after = last_entity;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const current_index = this.#values().length;
|
|
64
|
+
|
|
65
|
+
this.rxdb.entityManager
|
|
66
|
+
.getRepository(this.EntityType)
|
|
67
|
+
.findByCursor(options)
|
|
68
|
+
.pipe(takeUntilDestroyed(this.#destroy_ref))
|
|
69
|
+
.subscribe({
|
|
70
|
+
next: result => {
|
|
71
|
+
this.isLoading.set(false);
|
|
72
|
+
this.#values.update(values => {
|
|
73
|
+
const updated = [...values];
|
|
74
|
+
updated[current_index] = result;
|
|
75
|
+
return updated;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (result.length < (options.limit || 100)) {
|
|
79
|
+
this.hasMore.set(false);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
error: error => {
|
|
83
|
+
this.isLoading.set(false);
|
|
84
|
+
this.error.set(error);
|
|
85
|
+
},
|
|
86
|
+
complete: () => {
|
|
87
|
+
this.hasMore.set(false);
|
|
88
|
+
this.isLoading.set(false);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 刷新列表数据
|
|
95
|
+
*/
|
|
96
|
+
refresh(): void {
|
|
97
|
+
// 强制重置状态,即使正在加载中
|
|
98
|
+
this.#values.set([]);
|
|
99
|
+
this.error.set(undefined);
|
|
100
|
+
this.isLoading.set(false); // 强制设置为 false,允许新的 loadMore
|
|
101
|
+
this.hasMore.set(true);
|
|
102
|
+
|
|
103
|
+
// 立即开始加载
|
|
104
|
+
this.loadMore();
|
|
105
|
+
}
|
|
106
|
+
#reset(): void {
|
|
107
|
+
this.#values.set([]);
|
|
108
|
+
this.error.set(undefined);
|
|
109
|
+
this.isLoading.set(false);
|
|
110
|
+
this.hasMore.set(true);
|
|
111
|
+
nextMicroTask(() => this.loadMore());
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
#get_last_entity(): InstanceType<T> | undefined {
|
|
115
|
+
const values = this.#values();
|
|
116
|
+
if (values.length === 0) return undefined;
|
|
117
|
+
|
|
118
|
+
const last_page = values[values.length - 1];
|
|
119
|
+
if (last_page.length === 0) return undefined;
|
|
120
|
+
|
|
121
|
+
return last_page[last_page.length - 1];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
@let tabs = $tabs();
|
|
2
|
+
@let current_tab = $current_tab();
|
|
3
|
+
|
|
4
|
+
<div class="touch" (mousedown)="mousedown($event)"></div>
|
|
5
|
+
|
|
6
|
+
<!-- header -->
|
|
7
|
+
<div class="bg-base-300 z-1 flex min-h-0 flex-row p-0 shadow-sm">
|
|
8
|
+
<div class="flex-1">
|
|
9
|
+
<div class="tabs tabs-border tabs-xs" role="tablist">
|
|
10
|
+
@for (tab of tabs; track $index) {
|
|
11
|
+
<a
|
|
12
|
+
class="tab"
|
|
13
|
+
[class.tab-active]="current_tab === tab.id"
|
|
14
|
+
(click)="$current_tab.set(tab.id)"
|
|
15
|
+
aria-hidden="true"
|
|
16
|
+
role="tab"
|
|
17
|
+
>
|
|
18
|
+
{{ tab.name }}
|
|
19
|
+
</a>
|
|
20
|
+
}
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
<div>
|
|
24
|
+
<button class="btn btn-xs btn-ghost" (click)="toggle_settings()" aria-hidden="true">
|
|
25
|
+
<lucide-icon [img]="Settings" size="16"></lucide-icon>
|
|
26
|
+
</button>
|
|
27
|
+
<button class="btn btn-xs btn-ghost" (click)="close_rxdb_devtools()" aria-hidden="true">
|
|
28
|
+
<lucide-icon [img]="X" size="16"></lucide-icon>
|
|
29
|
+
</button>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<!-- Pages -->
|
|
34
|
+
<div class="bg-base-100 flex h-full flex-1 flex-row overflow-hidden">
|
|
35
|
+
@switch (current_tab) {
|
|
36
|
+
@case ('tables') {
|
|
37
|
+
@defer (on viewport) {
|
|
38
|
+
<rxdb-entity-table-tools [theme]="theme()"></rxdb-entity-table-tools>
|
|
39
|
+
} @placeholder {
|
|
40
|
+
<div>entity table loading...</div>
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@case ('events') {
|
|
45
|
+
@defer (on viewport) {
|
|
46
|
+
<rxdb-event-tools></rxdb-event-tools>
|
|
47
|
+
} @placeholder {
|
|
48
|
+
<div>entity table loading...</div>
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@case ('settings') {
|
|
53
|
+
@defer (on viewport) {
|
|
54
|
+
<rxdb-settings (sideChange)="$side.set($event)"></rxdb-settings>
|
|
55
|
+
} @placeholder {
|
|
56
|
+
<div>entity table loading...</div>
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
</div>
|
|
61
|
+
<!-- footer -->
|
|
62
|
+
@let branchName = $branchName();
|
|
63
|
+
@let switch_branching = $switch_branching();
|
|
64
|
+
|
|
65
|
+
<div class="bg-base-300 relative z-1 flex min-h-0 flex-row p-0 shadow-sm">
|
|
66
|
+
<div class="relative flex w-30 items-center justify-center">
|
|
67
|
+
@if (switch_branching) {
|
|
68
|
+
<span class="loading loading-spinner loading-xs absolute"></span>
|
|
69
|
+
}
|
|
70
|
+
<select
|
|
71
|
+
class="select select-ghost select-xs outline-none"
|
|
72
|
+
[disabled]="switch_branching"
|
|
73
|
+
(change)="switch_branch($event)"
|
|
74
|
+
name="branch"
|
|
75
|
+
>
|
|
76
|
+
@for (branch of branches.value(); track $index) {
|
|
77
|
+
<option [selected]="branch.activated" [value]="branch.id">
|
|
78
|
+
{{ branch.id }}
|
|
79
|
+
</option>
|
|
80
|
+
}
|
|
81
|
+
</select>
|
|
82
|
+
</div>
|
|
83
|
+
<input
|
|
84
|
+
class="input input-xs w-24 outline-none"
|
|
85
|
+
[(ngModel)]="$branchName"
|
|
86
|
+
[disabled]="switch_branching"
|
|
87
|
+
(keyup.enter)="create_branch(branchName)"
|
|
88
|
+
placeholder="branch name"
|
|
89
|
+
type="text"
|
|
90
|
+
/>
|
|
91
|
+
<button
|
|
92
|
+
class="btn btn-xs btn-ghost"
|
|
93
|
+
[class.btn-disabled]="!branchName"
|
|
94
|
+
[disabled]="switch_branching"
|
|
95
|
+
(click)="create_branch(branchName)"
|
|
96
|
+
>
|
|
97
|
+
Create Branch
|
|
98
|
+
</button>
|
|
99
|
+
</div>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
position: fixed;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
z-index: 100;
|
|
6
|
+
border: 1px solid #ccc;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.touch {
|
|
10
|
+
position: absolute;
|
|
11
|
+
height: 100%;
|
|
12
|
+
width: 4px;
|
|
13
|
+
z-index: 1000;
|
|
14
|
+
cursor: ew-resize;
|
|
15
|
+
transition: background 0.1s 0.3s;
|
|
16
|
+
&:hover {
|
|
17
|
+
background-color: rgba($color: blue, $alpha: 0.2);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
:host(.right) {
|
|
22
|
+
top: 0;
|
|
23
|
+
right: 0;
|
|
24
|
+
.touch {
|
|
25
|
+
left: 0;
|
|
26
|
+
transform: translateX(-2px);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
:host(.left) {
|
|
31
|
+
top: 0;
|
|
32
|
+
left: 0;
|
|
33
|
+
.touch {
|
|
34
|
+
right: 0;
|
|
35
|
+
transform: translateX(2px);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
:host(.bottom) {
|
|
40
|
+
bottom: 0;
|
|
41
|
+
left: 0;
|
|
42
|
+
.touch {
|
|
43
|
+
top: 0;
|
|
44
|
+
width: 100%;
|
|
45
|
+
height: 4px;
|
|
46
|
+
transform: translateY(-2px);
|
|
47
|
+
cursor: ns-resize;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { provideZonelessChangeDetection } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
+
import { BrowserModule } from '@angular/platform-browser';
|
|
4
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { provideRxDB } from '../rxdb.provider';
|
|
6
|
+
import { RxDBDevtools } from './devtools';
|
|
7
|
+
|
|
8
|
+
const setup_rxdb = () => {
|
|
9
|
+
return null as any;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
describe('RxDBDevtools', () => {
|
|
13
|
+
let component: RxDBDevtools;
|
|
14
|
+
let fixture: ComponentFixture<RxDBDevtools>;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
await TestBed.configureTestingModule({
|
|
18
|
+
imports: [RxDBDevtools, BrowserModule],
|
|
19
|
+
providers: [provideZonelessChangeDetection(), provideRxDB(setup_rxdb)]
|
|
20
|
+
}).compileComponents();
|
|
21
|
+
|
|
22
|
+
fixture = TestBed.createComponent(RxDBDevtools);
|
|
23
|
+
component = fixture.componentInstance;
|
|
24
|
+
fixture.detectChanges();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should create', () => {
|
|
28
|
+
expect(component).toBeTruthy();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { RxDB, RxDBBranch } from '@aiao/rxdb';
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
ComponentRef,
|
|
6
|
+
DOCUMENT,
|
|
7
|
+
effect,
|
|
8
|
+
ElementRef,
|
|
9
|
+
inject,
|
|
10
|
+
input,
|
|
11
|
+
model,
|
|
12
|
+
signal
|
|
13
|
+
} from '@angular/core';
|
|
14
|
+
import { FormsModule } from '@angular/forms';
|
|
15
|
+
import { LucideAngularModule, PanelBottom, PanelLeft, PanelRight, Settings, X } from 'lucide-angular';
|
|
16
|
+
import { useFindAll } from '../hooks';
|
|
17
|
+
import { useState } from '../use-state';
|
|
18
|
+
import { RxDBEntityTableTools } from './entity-table-tools';
|
|
19
|
+
import { RxDBEventTools } from './event-tools';
|
|
20
|
+
import { RxDBSettings } from './settings';
|
|
21
|
+
|
|
22
|
+
interface FeatureTab {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const defaultSize = '480px';
|
|
28
|
+
const state = useState('rxdb-devtools');
|
|
29
|
+
|
|
30
|
+
@Component({
|
|
31
|
+
selector: 'rxdb-devtools',
|
|
32
|
+
imports: [LucideAngularModule, RxDBEntityTableTools, RxDBEventTools, RxDBSettings, FormsModule],
|
|
33
|
+
styleUrls: ['./devtools.scss'],
|
|
34
|
+
templateUrl: './devtools.html',
|
|
35
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
36
|
+
host: {
|
|
37
|
+
'[class.right]': "$side() === 'right'",
|
|
38
|
+
'[class.left]': "$side() === 'left'",
|
|
39
|
+
'[class.bottom]': "$side() === 'bottom'",
|
|
40
|
+
'[style.width]': '$width()',
|
|
41
|
+
'[style.height]': '$height()'
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
export class RxDBDevtools {
|
|
45
|
+
#last_tab_before_setting = '';
|
|
46
|
+
#document = inject(DOCUMENT);
|
|
47
|
+
#elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
|
|
48
|
+
#rxdb = inject(RxDB);
|
|
49
|
+
|
|
50
|
+
protected readonly X = X;
|
|
51
|
+
protected readonly Settings = Settings;
|
|
52
|
+
protected readonly PanelLeft = PanelLeft;
|
|
53
|
+
protected readonly PanelBottom = PanelBottom;
|
|
54
|
+
protected readonly PanelRight = PanelRight;
|
|
55
|
+
|
|
56
|
+
public readonly componentRef = input<ComponentRef<RxDBDevtools>>();
|
|
57
|
+
theme = input<'light' | 'dark'>('light');
|
|
58
|
+
|
|
59
|
+
$side = state('side').signal<'right' | 'left' | 'bottom'>('right');
|
|
60
|
+
$width = state('width').signal<string>(defaultSize);
|
|
61
|
+
$height = state('height').signal<string>('100%');
|
|
62
|
+
$switch_branching = model<boolean>(false);
|
|
63
|
+
|
|
64
|
+
$branchName = model<string>('');
|
|
65
|
+
|
|
66
|
+
$tabs = signal<FeatureTab[]>([
|
|
67
|
+
{
|
|
68
|
+
id: 'tables',
|
|
69
|
+
name: 'Tables'
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'events',
|
|
73
|
+
name: 'Events'
|
|
74
|
+
}
|
|
75
|
+
]);
|
|
76
|
+
$current_tab = signal<string>('tables');
|
|
77
|
+
|
|
78
|
+
branches = useFindAll(RxDBBranch, {
|
|
79
|
+
where: {
|
|
80
|
+
combinator: 'and',
|
|
81
|
+
rules: []
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
constructor() {
|
|
86
|
+
effect(() => {
|
|
87
|
+
const side = this.$side();
|
|
88
|
+
switch (side) {
|
|
89
|
+
case 'left':
|
|
90
|
+
case 'right':
|
|
91
|
+
if (this.$height() !== '100%') {
|
|
92
|
+
this.$width.set(defaultSize);
|
|
93
|
+
this.$height.set('100%');
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
case 'bottom':
|
|
97
|
+
if (this.$width() !== '100%') {
|
|
98
|
+
this.$width.set('100%');
|
|
99
|
+
this.$height.set(defaultSize);
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
effect(() => {
|
|
105
|
+
const side = this.$side();
|
|
106
|
+
const width = this.$width();
|
|
107
|
+
const height = this.$height();
|
|
108
|
+
this.#body_style_default();
|
|
109
|
+
switch (side) {
|
|
110
|
+
case 'left':
|
|
111
|
+
this.#document.body.style.paddingLeft = width;
|
|
112
|
+
break;
|
|
113
|
+
case 'right':
|
|
114
|
+
this.#document.body.style.paddingRight = width;
|
|
115
|
+
break;
|
|
116
|
+
case 'bottom':
|
|
117
|
+
this.#document.body.style.paddingBottom = height;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
close_rxdb_devtools() {
|
|
124
|
+
this.#body_style_default();
|
|
125
|
+
this.componentRef()?.destroy();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
toggle_settings() {
|
|
129
|
+
const current_tab = this.$current_tab();
|
|
130
|
+
if (current_tab !== 'settings') {
|
|
131
|
+
this.#last_tab_before_setting = current_tab;
|
|
132
|
+
this.$current_tab.set('settings');
|
|
133
|
+
} else {
|
|
134
|
+
this.$current_tab.set(this.#last_tab_before_setting || 'tables');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async create_branch(branch_name: string) {
|
|
139
|
+
try {
|
|
140
|
+
await this.#rxdb.versionManager.createBranch(branch_name);
|
|
141
|
+
this.$branchName.set('');
|
|
142
|
+
} catch {
|
|
143
|
+
//
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
mousedown(event: MouseEvent) {
|
|
148
|
+
const side = this.$side();
|
|
149
|
+
this.#document.body.style.cursor = side === 'bottom' ? 'ns-resize' : 'ew-resize';
|
|
150
|
+
|
|
151
|
+
const pageX = event.pageX;
|
|
152
|
+
const pageY = event.pageY;
|
|
153
|
+
const clientWidth = this.#elementRef.nativeElement.clientWidth;
|
|
154
|
+
const clientHeight = this.#elementRef.nativeElement.clientHeight;
|
|
155
|
+
const mousemove = (event: MouseEvent) => {
|
|
156
|
+
switch (side) {
|
|
157
|
+
case 'left':
|
|
158
|
+
{
|
|
159
|
+
let width = clientWidth + event.pageX - pageX;
|
|
160
|
+
width = width < 100 ? 100 : width;
|
|
161
|
+
this.$width.set(`${width}px`);
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
case 'right':
|
|
165
|
+
{
|
|
166
|
+
let width = clientWidth + pageX - event.pageX;
|
|
167
|
+
width = width < 100 ? 100 : width;
|
|
168
|
+
this.$width.set(`${width}px`);
|
|
169
|
+
}
|
|
170
|
+
break;
|
|
171
|
+
case 'bottom':
|
|
172
|
+
{
|
|
173
|
+
let height = clientHeight + pageY - event.pageY;
|
|
174
|
+
height = height < 100 ? 100 : height;
|
|
175
|
+
this.$height.set(`${height}px`);
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
const mouseup = () => {
|
|
181
|
+
this.#document.body.style.cursor = 'auto';
|
|
182
|
+
this.#document.removeEventListener('mousemove', mousemove);
|
|
183
|
+
this.#document.removeEventListener('mouseup', mouseup);
|
|
184
|
+
};
|
|
185
|
+
this.#document.addEventListener('mousemove', mousemove);
|
|
186
|
+
this.#document.addEventListener('mouseup', mouseup);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
protected async switch_branch(event: Event) {
|
|
190
|
+
const branch = (event.target as HTMLSelectElement).value;
|
|
191
|
+
this.$switch_branching.set(true);
|
|
192
|
+
try {
|
|
193
|
+
await this.#rxdb.versionManager.switchBranch(branch);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error(error);
|
|
196
|
+
} finally {
|
|
197
|
+
this.$switch_branching.set(false);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
#body_style_default() {
|
|
202
|
+
this.#document.body.style.paddingBottom = '';
|
|
203
|
+
this.#document.body.style.paddingRight = '';
|
|
204
|
+
this.#document.body.style.paddingLeft = '';
|
|
205
|
+
this.#document.body.style.cursor = '';
|
|
206
|
+
}
|
|
207
|
+
}
|