@ethlete/query 5.15.0 → 5.16.0
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/.eslintrc.json +40 -0
- package/CHANGELOG.md +14 -0
- package/jest.config.ts +23 -0
- package/ng-package.json +8 -0
- package/package.json +6 -23
- package/project.json +37 -0
- package/{index.d.ts → src/index.ts} +2 -0
- package/src/lib/auth/auth-provider.types.ts +160 -0
- package/src/lib/auth/auth-provider.utils.ts +39 -0
- package/src/lib/auth/basic-auth-provider.ts +17 -0
- package/src/lib/auth/bearer-auth-provider.ts +243 -0
- package/src/lib/auth/custom-header-auth-provider.ts +13 -0
- package/{lib/class-validator/class-validator.types.d.ts → src/lib/class-validator/class-validator.types.ts} +4 -3
- package/src/lib/class-validator/class-validator.utils.ts +5 -0
- package/src/lib/devtools/components/query-devtools/query-devtools.component.html +402 -0
- package/src/lib/devtools/components/query-devtools/query-devtools.component.scss +360 -0
- package/src/lib/devtools/components/query-devtools/query-devtools.component.ts +427 -0
- package/src/lib/devtools/pipes/query-short-name.pipe.ts +24 -0
- package/src/lib/devtools/utils/query-client.utils.ts +25 -0
- package/src/lib/directives/infinity-query-trigger.directive.ts +58 -0
- package/src/lib/directives/infinity-query.directive.ts +208 -0
- package/src/lib/directives/query.directive.ts +201 -0
- package/src/lib/entity/entity-store.ts +180 -0
- package/src/lib/entity/entity.types.ts +34 -0
- package/src/lib/entity/entity.utils.ts +51 -0
- package/src/lib/gql/gql.ts +22 -0
- package/src/lib/infinite-query/infinity-query.ts +245 -0
- package/src/lib/infinite-query/infinity-query.types.ts +149 -0
- package/src/lib/infinite-query/infinity-query.utils.ts +14 -0
- package/src/lib/logger/logger.ts +30 -0
- package/src/lib/query/query.ts +631 -0
- package/src/lib/query/query.types.ts +532 -0
- package/src/lib/query/query.utils.spec.ts +92 -0
- package/src/lib/query/query.utils.ts +450 -0
- package/src/lib/query-client/query-client.spec.ts +77 -0
- package/src/lib/query-client/query-client.ts +195 -0
- package/src/lib/query-client/query-client.types.ts +101 -0
- package/src/lib/query-client/query-client.utils.spec.ts +61 -0
- package/src/lib/query-client/query-client.utils.ts +28 -0
- package/src/lib/query-creator/query-creator.ts +103 -0
- package/src/lib/query-creator/query-creator.types.ts +74 -0
- package/src/lib/query-form/query-form.ts +526 -0
- package/src/lib/query-form/query-form.types.ts +169 -0
- package/src/lib/query-form/query-form.utils.ts +116 -0
- package/src/lib/query-store/query-store.ts +192 -0
- package/src/lib/request/request.ts +253 -0
- package/src/lib/request/request.types.ts +164 -0
- package/src/lib/request/request.util.spec.ts +177 -0
- package/src/lib/request/request.util.ts +399 -0
- package/src/lib/stories/angular-example-page.mdx +85 -0
- package/src/lib/stories/authentication-page.mdx +35 -0
- package/src/lib/stories/changelog-page.mdx +9 -0
- package/src/lib/stories/client-page.mdx +100 -0
- package/src/lib/stories/queries-page.mdx +117 -0
- package/src/lib/symfony/symfony.types.ts +21 -0
- package/src/lib/symfony/symfony.utils.ts +43 -0
- package/src/lib/utils/data.utils.ts +280 -0
- package/src/lib/utils/deep-freeze.util.ts +21 -0
- package/{lib/utils/def.util.d.ts → src/lib/utils/def.util.ts} +1 -1
- package/src/test-setup.ts +1 -0
- package/tsconfig.json +29 -0
- package/tsconfig.lib.json +12 -0
- package/tsconfig.lib.prod.json +10 -0
- package/tsconfig.spec.json +11 -0
- package/esm2022/ethlete-query.mjs +0 -5
- package/esm2022/index.mjs +0 -20
- package/esm2022/lib/auth/auth-provider.types.mjs +0 -2
- package/esm2022/lib/auth/auth-provider.utils.mjs +0 -25
- package/esm2022/lib/auth/basic-auth-provider.mjs +0 -15
- package/esm2022/lib/auth/bearer-auth-provider.mjs +0 -168
- package/esm2022/lib/auth/custom-header-auth-provider.mjs +0 -12
- package/esm2022/lib/auth/index.mjs +0 -6
- package/esm2022/lib/class-validator/class-validator.types.mjs +0 -2
- package/esm2022/lib/class-validator/class-validator.utils.mjs +0 -4
- package/esm2022/lib/class-validator/index.mjs +0 -3
- package/esm2022/lib/devtools/components/query-devtools/index.mjs +0 -2
- package/esm2022/lib/devtools/components/query-devtools/query-devtools.component.mjs +0 -297
- package/esm2022/lib/devtools/pipes/index.mjs +0 -2
- package/esm2022/lib/devtools/pipes/query-short-name.pipe.mjs +0 -24
- package/esm2022/lib/devtools/utils/index.mjs +0 -2
- package/esm2022/lib/devtools/utils/query-client.utils.mjs +0 -13
- package/esm2022/lib/directives/index.mjs +0 -4
- package/esm2022/lib/directives/infinity-query-trigger.directive.mjs +0 -56
- package/esm2022/lib/directives/infinity-query.directive.mjs +0 -147
- package/esm2022/lib/directives/query.directive.mjs +0 -123
- package/esm2022/lib/entity/entity-store.mjs +0 -127
- package/esm2022/lib/entity/entity.types.mjs +0 -2
- package/esm2022/lib/entity/entity.utils.mjs +0 -29
- package/esm2022/lib/entity/index.mjs +0 -4
- package/esm2022/lib/gql/gql.mjs +0 -23
- package/esm2022/lib/gql/index.mjs +0 -2
- package/esm2022/lib/infinite-query/index.mjs +0 -4
- package/esm2022/lib/infinite-query/infinity-query.mjs +0 -171
- package/esm2022/lib/infinite-query/infinity-query.types.mjs +0 -2
- package/esm2022/lib/infinite-query/infinity-query.utils.mjs +0 -3
- package/esm2022/lib/logger/index.mjs +0 -2
- package/esm2022/lib/logger/logger.mjs +0 -16
- package/esm2022/lib/query/index.mjs +0 -4
- package/esm2022/lib/query/query.mjs +0 -428
- package/esm2022/lib/query/query.types.mjs +0 -2
- package/esm2022/lib/query/query.utils.mjs +0 -253
- package/esm2022/lib/query-client/index.mjs +0 -4
- package/esm2022/lib/query-client/query-client.mjs +0 -80
- package/esm2022/lib/query-client/query-client.types.mjs +0 -2
- package/esm2022/lib/query-client/query-client.utils.mjs +0 -20
- package/esm2022/lib/query-creator/index.mjs +0 -3
- package/esm2022/lib/query-creator/query-creator.mjs +0 -55
- package/esm2022/lib/query-creator/query-creator.types.mjs +0 -2
- package/esm2022/lib/query-form/index.mjs +0 -4
- package/esm2022/lib/query-form/query-form.mjs +0 -368
- package/esm2022/lib/query-form/query-form.types.mjs +0 -2
- package/esm2022/lib/query-form/query-form.utils.mjs +0 -97
- package/esm2022/lib/query-store/index.mjs +0 -2
- package/esm2022/lib/query-store/query-store.mjs +0 -144
- package/esm2022/lib/request/index.mjs +0 -4
- package/esm2022/lib/request/request.mjs +0 -196
- package/esm2022/lib/request/request.types.mjs +0 -2
- package/esm2022/lib/request/request.util.mjs +0 -252
- package/esm2022/lib/symfony/index.mjs +0 -3
- package/esm2022/lib/symfony/symfony.types.mjs +0 -2
- package/esm2022/lib/symfony/symfony.utils.mjs +0 -31
- package/esm2022/lib/utils/data.utils.mjs +0 -138
- package/esm2022/lib/utils/deep-freeze.util.mjs +0 -17
- package/esm2022/lib/utils/def.util.mjs +0 -8
- package/esm2022/lib/utils/index.mjs +0 -4
- package/fesm2022/ethlete-query.mjs +0 -3276
- package/fesm2022/ethlete-query.mjs.map +0 -1
- package/lib/auth/auth-provider.types.d.ts +0 -133
- package/lib/auth/auth-provider.utils.d.ts +0 -9
- package/lib/auth/basic-auth-provider.d.ts +0 -10
- package/lib/auth/bearer-auth-provider.d.ts +0 -23
- package/lib/auth/custom-header-auth-provider.d.ts +0 -9
- package/lib/class-validator/class-validator.utils.d.ts +0 -2
- package/lib/devtools/components/query-devtools/query-devtools.component.d.ts +0 -151
- package/lib/devtools/pipes/query-short-name.pipe.d.ts +0 -8
- package/lib/devtools/utils/query-client.utils.d.ts +0 -12
- package/lib/directives/infinity-query-trigger.directive.d.ts +0 -15
- package/lib/directives/infinity-query.directive.d.ts +0 -49
- package/lib/directives/query.directive.d.ts +0 -63
- package/lib/entity/entity-store.d.ts +0 -25
- package/lib/entity/entity.types.d.ts +0 -25
- package/lib/entity/entity.utils.d.ts +0 -12
- package/lib/gql/gql.d.ts +0 -6
- package/lib/infinite-query/infinity-query.d.ts +0 -29
- package/lib/infinite-query/infinity-query.types.d.ts +0 -104
- package/lib/infinite-query/infinity-query.utils.d.ts +0 -4
- package/lib/logger/logger.d.ts +0 -12
- package/lib/query/query.d.ts +0 -60
- package/lib/query/query.types.d.ts +0 -388
- package/lib/query/query.utils.d.ts +0 -91
- package/lib/query-client/query-client.d.ts +0 -29
- package/lib/query-client/query-client.types.d.ts +0 -82
- package/lib/query-client/query-client.utils.d.ts +0 -4
- package/lib/query-creator/query-creator.d.ts +0 -20
- package/lib/query-creator/query-creator.types.d.ts +0 -13
- package/lib/query-form/query-form.d.ts +0 -89
- package/lib/query-form/query-form.types.d.ts +0 -138
- package/lib/query-form/query-form.utils.d.ts +0 -13
- package/lib/query-store/query-store.d.ts +0 -31
- package/lib/request/request.d.ts +0 -3
- package/lib/request/request.types.d.ts +0 -126
- package/lib/request/request.util.d.ts +0 -92
- package/lib/symfony/symfony.types.d.ts +0 -19
- package/lib/symfony/symfony.utils.d.ts +0 -6
- package/lib/utils/data.utils.d.ts +0 -59
- package/lib/utils/deep-freeze.util.d.ts +0 -1
- /package/{lib/auth/index.d.ts → src/lib/auth/index.ts} +0 -0
- /package/{lib/class-validator/index.d.ts → src/lib/class-validator/index.ts} +0 -0
- /package/{lib/devtools/components/query-devtools/index.d.ts → src/lib/devtools/components/query-devtools/index.ts} +0 -0
- /package/{lib/devtools/pipes/index.d.ts → src/lib/devtools/pipes/index.ts} +0 -0
- /package/{lib/devtools/utils/index.d.ts → src/lib/devtools/utils/index.ts} +0 -0
- /package/{lib/directives/index.d.ts → src/lib/directives/index.ts} +0 -0
- /package/{lib/entity/index.d.ts → src/lib/entity/index.ts} +0 -0
- /package/{lib/gql/index.d.ts → src/lib/gql/index.ts} +0 -0
- /package/{lib/infinite-query/index.d.ts → src/lib/infinite-query/index.ts} +0 -0
- /package/{lib/logger/index.d.ts → src/lib/logger/index.ts} +0 -0
- /package/{lib/query/index.d.ts → src/lib/query/index.ts} +0 -0
- /package/{lib/query-client/index.d.ts → src/lib/query-client/index.ts} +0 -0
- /package/{lib/query-creator/index.d.ts → src/lib/query-creator/index.ts} +0 -0
- /package/{lib/query-form/index.d.ts → src/lib/query-form/index.ts} +0 -0
- /package/{lib/query-store/index.d.ts → src/lib/query-store/index.ts} +0 -0
- /package/{lib/request/index.d.ts → src/lib/request/index.ts} +0 -0
- /package/{lib/symfony/index.d.ts → src/lib/symfony/index.ts} +0 -0
- /package/{lib/utils/index.d.ts → src/lib/utils/index.ts} +0 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { AsyncPipe, JsonPipe, NgClass } from '@angular/common';
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
ChangeDetectorRef,
|
|
5
|
+
Component,
|
|
6
|
+
TrackByFunction,
|
|
7
|
+
ViewEncapsulation,
|
|
8
|
+
computed,
|
|
9
|
+
effect,
|
|
10
|
+
inject,
|
|
11
|
+
signal,
|
|
12
|
+
untracked,
|
|
13
|
+
} from '@angular/core';
|
|
14
|
+
import { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop';
|
|
15
|
+
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
|
16
|
+
import { createDestroy, nextFrame } from '@ethlete/core';
|
|
17
|
+
import { BehaviorSubject, map, of, startWith, switchMap, takeUntil, tap } from 'rxjs';
|
|
18
|
+
import { BasicAuthProvider, CustomHeaderAuthProvider, isBearerAuthProvider } from '../../../auth';
|
|
19
|
+
import { QueryDirective } from '../../../directives';
|
|
20
|
+
import { EntityStore } from '../../../entity';
|
|
21
|
+
import { AnyQuery, isGqlQueryConfig } from '../../../query';
|
|
22
|
+
import { QueryShortNamePipe } from '../../pipes';
|
|
23
|
+
import { QUERY_CLIENT_DEVTOOLS_TOKEN, QueryClientDevtoolsOptions } from '../../utils';
|
|
24
|
+
|
|
25
|
+
type QueryDevtoolsSnapLayout = 'full' | 'left' | 'right' | 'bottom' | 'top';
|
|
26
|
+
type QueryListMode = 'live' | 'history';
|
|
27
|
+
type QueryViewMode = 'query' | 'authProvider';
|
|
28
|
+
|
|
29
|
+
@Component({
|
|
30
|
+
selector: 'et-query-devtools',
|
|
31
|
+
templateUrl: './query-devtools.component.html',
|
|
32
|
+
styleUrls: ['./query-devtools.component.scss'],
|
|
33
|
+
standalone: true,
|
|
34
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
35
|
+
encapsulation: ViewEncapsulation.ShadowDom,
|
|
36
|
+
// eslint-disable-next-line @angular-eslint/no-host-metadata-property
|
|
37
|
+
host: {
|
|
38
|
+
class: 'et-query-devtools',
|
|
39
|
+
},
|
|
40
|
+
imports: [AsyncPipe, JsonPipe, ReactiveFormsModule, NgClass, QueryShortNamePipe, QueryDirective],
|
|
41
|
+
})
|
|
42
|
+
export class QueryDevtoolsComponent {
|
|
43
|
+
private readonly _cdr = inject(ChangeDetectorRef);
|
|
44
|
+
protected readonly _destroy$ = createDestroy();
|
|
45
|
+
|
|
46
|
+
protected readonly queryClientConfigs = inject(QUERY_CLIENT_DEVTOOLS_TOKEN);
|
|
47
|
+
|
|
48
|
+
protected readonly isOpen = signal(false);
|
|
49
|
+
protected readonly isTranslucent = signal(false);
|
|
50
|
+
protected readonly snapLayout = signal<QueryDevtoolsSnapLayout>('full');
|
|
51
|
+
protected readonly queryListMode = signal<QueryListMode>('live');
|
|
52
|
+
protected readonly viewMode = signal<QueryViewMode>('query');
|
|
53
|
+
|
|
54
|
+
protected showResponse = signal(false);
|
|
55
|
+
protected showRawResponse = signal(false);
|
|
56
|
+
protected showQueryConfig = signal(false);
|
|
57
|
+
protected showEntityStoreValue = signal(false);
|
|
58
|
+
protected showArguments = signal(false);
|
|
59
|
+
|
|
60
|
+
protected selectedClientIdCtrl = new FormControl(0);
|
|
61
|
+
|
|
62
|
+
protected readonly selectedClientId = toSignal(
|
|
63
|
+
this.selectedClientIdCtrl.valueChanges.pipe(startWith(this.selectedClientIdCtrl.value)),
|
|
64
|
+
);
|
|
65
|
+
protected readonly selectedQueryId = signal<number | null>(null);
|
|
66
|
+
|
|
67
|
+
protected readonly selectedClientConfig = computed(() => {
|
|
68
|
+
if (this.queryClientConfigs.length === 1) {
|
|
69
|
+
return this.queryClientConfigs[0]!;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const index = this.selectedClientId() ?? 0;
|
|
73
|
+
|
|
74
|
+
const cfg = this.queryClientConfigs[index];
|
|
75
|
+
|
|
76
|
+
if (!cfg) {
|
|
77
|
+
return this.queryClientConfigs[0]!;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return cfg;
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
protected readonly queryStore = computed(() => {
|
|
84
|
+
const config = this.selectedClientConfig();
|
|
85
|
+
|
|
86
|
+
return config.client._store;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
protected readonly queryStore$ = toObservable(this.queryStore);
|
|
90
|
+
|
|
91
|
+
private readonly _queries$ = new BehaviorSubject<AnyQuery[]>([]);
|
|
92
|
+
protected readonly queries = toSignal(this._queries$);
|
|
93
|
+
|
|
94
|
+
protected readonly selectedQuery = computed(() => {
|
|
95
|
+
const id = this.selectedQueryId();
|
|
96
|
+
const mode = this.queryListMode();
|
|
97
|
+
|
|
98
|
+
if (id === null || !mode) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (mode === 'live') {
|
|
103
|
+
return this.queries()?.find((q) => q._id === id) ?? null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return this.queryHistory$.getValue()?.find((q) => q._id === id) ?? null;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
protected readonly selectedQuery$ = toObservable(this.selectedQuery);
|
|
110
|
+
|
|
111
|
+
protected selectedQueryEntityStore = computed(() => {
|
|
112
|
+
const query = this.selectedQuery();
|
|
113
|
+
|
|
114
|
+
if (!query) return null;
|
|
115
|
+
|
|
116
|
+
return query.store as EntityStore<unknown> | null;
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
protected readonly selectedQueryEntityStore$ = toObservable(this.selectedQueryEntityStore);
|
|
120
|
+
|
|
121
|
+
protected readonly selectedQueryEntityStoreValue$ = this.selectedQueryEntityStore$.pipe(
|
|
122
|
+
switchMap(
|
|
123
|
+
(s) =>
|
|
124
|
+
s?._change$.pipe(
|
|
125
|
+
startWith(''),
|
|
126
|
+
map(() => {
|
|
127
|
+
if (!s._dictionary) return null;
|
|
128
|
+
|
|
129
|
+
return Array.from(s._dictionary).reduce(
|
|
130
|
+
(obj, [key, value]) => {
|
|
131
|
+
obj[key] = value;
|
|
132
|
+
return obj;
|
|
133
|
+
},
|
|
134
|
+
{} as Record<string, unknown>,
|
|
135
|
+
);
|
|
136
|
+
}),
|
|
137
|
+
) ?? of(null),
|
|
138
|
+
),
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
protected readonly queryHistory$ = new BehaviorSubject<AnyQuery[]>([]);
|
|
142
|
+
|
|
143
|
+
protected readonly stringifiedQueryConfig = computed(() => {
|
|
144
|
+
const query = this.selectedQuery();
|
|
145
|
+
|
|
146
|
+
if (!query) return null;
|
|
147
|
+
|
|
148
|
+
const cfg = query._queryConfig;
|
|
149
|
+
const route =
|
|
150
|
+
typeof cfg.route === 'string' ? cfg.route : cfg.route ? cfg.route({}).replace(/undefined/g, ':param') : null;
|
|
151
|
+
|
|
152
|
+
const sharedCfg = {
|
|
153
|
+
method: cfg.method,
|
|
154
|
+
secure: cfg.secure,
|
|
155
|
+
route,
|
|
156
|
+
reportProgress: cfg.reportProgress,
|
|
157
|
+
responseType: cfg.responseType,
|
|
158
|
+
withCredentials: cfg.withCredentials,
|
|
159
|
+
autoRefreshOn: cfg.autoRefreshOn,
|
|
160
|
+
enableSmartPolling: cfg.enableSmartPolling,
|
|
161
|
+
hasEntityStore: !!cfg.entity,
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
if (isGqlQueryConfig(cfg)) {
|
|
165
|
+
return {
|
|
166
|
+
...sharedCfg,
|
|
167
|
+
query: cfg.query,
|
|
168
|
+
transferVia: cfg.transferVia,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
...sharedCfg,
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
protected readonly authProvider = toSignal(
|
|
178
|
+
toObservable(this.selectedClientConfig).pipe(switchMap((c) => c.client.authProvider$)),
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
protected readonly authProviderDetails = computed(() => {
|
|
182
|
+
const provider = this.authProvider();
|
|
183
|
+
|
|
184
|
+
if (!provider) return null;
|
|
185
|
+
|
|
186
|
+
if (provider instanceof CustomHeaderAuthProvider) {
|
|
187
|
+
return {
|
|
188
|
+
type: 'CustomHeaderAuthProvider',
|
|
189
|
+
header: () => provider.header,
|
|
190
|
+
provider: provider,
|
|
191
|
+
config: {
|
|
192
|
+
name: provider._config.name,
|
|
193
|
+
value: provider._config.value,
|
|
194
|
+
},
|
|
195
|
+
} as const;
|
|
196
|
+
} else if (provider instanceof BasicAuthProvider) {
|
|
197
|
+
return {
|
|
198
|
+
type: 'BasicAuthProvider',
|
|
199
|
+
header: () => provider.header,
|
|
200
|
+
provider: provider,
|
|
201
|
+
config: {
|
|
202
|
+
username: provider._config.username,
|
|
203
|
+
password: provider._config.password,
|
|
204
|
+
},
|
|
205
|
+
} as const;
|
|
206
|
+
} else if (isBearerAuthProvider(provider)) {
|
|
207
|
+
const refreshCfg = provider._config.refreshConfig;
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
type: 'BearerAuthProvider',
|
|
211
|
+
header: () => provider.header,
|
|
212
|
+
provider: provider,
|
|
213
|
+
config: {
|
|
214
|
+
token: provider._config.token,
|
|
215
|
+
refreshConfig: {
|
|
216
|
+
refreshOnUnauthorizedResponse: refreshCfg?.refreshOnUnauthorizedResponse ?? 'true (default)',
|
|
217
|
+
token: refreshCfg?.token,
|
|
218
|
+
cookieName: refreshCfg?.cookieName,
|
|
219
|
+
cookieDomain: refreshCfg?.cookieDomain ?? 'current origin (default)',
|
|
220
|
+
cookieExpiresInDays: refreshCfg?.cookieExpiresInDays ?? '30 (default)',
|
|
221
|
+
cookiePath: refreshCfg?.cookiePath ?? '/ (default)',
|
|
222
|
+
cookieEnabled: refreshCfg?.cookieEnabled ?? 'true (default)',
|
|
223
|
+
cookieSameSite: refreshCfg?.cookieSameSite ?? 'lax (default)',
|
|
224
|
+
refreshBuffer: refreshCfg?.refreshBuffer ?? '30000 (default)',
|
|
225
|
+
expiresInPropertyName: refreshCfg?.expiresInPropertyName ?? 'exp (default)',
|
|
226
|
+
strategy: refreshCfg?.strategy ?? 'AuthBearerRefreshStrategy.BeforeExpiration (default)',
|
|
227
|
+
requestArgsAdapter: refreshCfg?.requestArgsAdapter ? 'custom' : 'default',
|
|
228
|
+
responseAdapter: refreshCfg?.responseAdapter ? 'custom' : 'default',
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
} as const;
|
|
232
|
+
} else {
|
|
233
|
+
return {
|
|
234
|
+
type: 'UnknownAuthProvider',
|
|
235
|
+
header: () => provider.header,
|
|
236
|
+
provider: provider,
|
|
237
|
+
config: {},
|
|
238
|
+
} as const;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
constructor() {
|
|
243
|
+
this.selectedClientIdCtrl.valueChanges
|
|
244
|
+
.pipe(
|
|
245
|
+
tap(() => this.clearQueryHistory()),
|
|
246
|
+
takeUntil(this._destroy$),
|
|
247
|
+
)
|
|
248
|
+
.subscribe();
|
|
249
|
+
|
|
250
|
+
this.selectedQuery$
|
|
251
|
+
.pipe(
|
|
252
|
+
switchMap((q) => q?._dependentsChanged$ ?? of(null)),
|
|
253
|
+
tap(() => this._cdr.markForCheck()),
|
|
254
|
+
takeUntilDestroyed(),
|
|
255
|
+
)
|
|
256
|
+
.subscribe();
|
|
257
|
+
|
|
258
|
+
toObservable(this.authProviderDetails)
|
|
259
|
+
.pipe(switchMap((ap) => (ap?.type === 'BearerAuthProvider' ? ap.provider.tokens$ : of(null))))
|
|
260
|
+
.pipe(
|
|
261
|
+
tap(() => this._cdr.markForCheck()),
|
|
262
|
+
takeUntilDestroyed(),
|
|
263
|
+
)
|
|
264
|
+
.subscribe();
|
|
265
|
+
|
|
266
|
+
this.queryStore$
|
|
267
|
+
.pipe(
|
|
268
|
+
switchMap((s) =>
|
|
269
|
+
s.storeChange$.pipe(
|
|
270
|
+
startWith(''),
|
|
271
|
+
map(() => s._store),
|
|
272
|
+
tap((s) => {
|
|
273
|
+
untracked(() => {
|
|
274
|
+
this._queries$.next(Array.from(s.values()));
|
|
275
|
+
});
|
|
276
|
+
}),
|
|
277
|
+
takeUntil(this._destroy$),
|
|
278
|
+
),
|
|
279
|
+
),
|
|
280
|
+
)
|
|
281
|
+
.subscribe();
|
|
282
|
+
|
|
283
|
+
this.queryStore$
|
|
284
|
+
.pipe(
|
|
285
|
+
switchMap((s) =>
|
|
286
|
+
s.queryCreated$.pipe(
|
|
287
|
+
tap((query) => {
|
|
288
|
+
const currentHistory = this.queryHistory$.getValue();
|
|
289
|
+
|
|
290
|
+
if (!currentHistory) return;
|
|
291
|
+
|
|
292
|
+
const currentHistoryClone = [...currentHistory];
|
|
293
|
+
|
|
294
|
+
if (!currentHistory.some((q) => q._id === query._id)) {
|
|
295
|
+
currentHistoryClone.unshift(query);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
currentHistoryClone.splice(50);
|
|
299
|
+
|
|
300
|
+
this.queryHistory$.next(currentHistoryClone);
|
|
301
|
+
}),
|
|
302
|
+
takeUntil(this._destroy$),
|
|
303
|
+
),
|
|
304
|
+
),
|
|
305
|
+
)
|
|
306
|
+
.subscribe();
|
|
307
|
+
|
|
308
|
+
this._queries$
|
|
309
|
+
.pipe(
|
|
310
|
+
tap((queries) => {
|
|
311
|
+
const currentHistory = this.queryHistory$.getValue();
|
|
312
|
+
|
|
313
|
+
if (!queries || !currentHistory) return;
|
|
314
|
+
|
|
315
|
+
const currentHistoryClone = [...currentHistory];
|
|
316
|
+
|
|
317
|
+
for (const query of queries) {
|
|
318
|
+
if (!currentHistoryClone.some((q) => q._id === query._id)) {
|
|
319
|
+
currentHistoryClone.unshift(query);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
currentHistoryClone.splice(50);
|
|
324
|
+
|
|
325
|
+
this.queryHistory$.next(currentHistoryClone);
|
|
326
|
+
}),
|
|
327
|
+
takeUntil(this._destroy$),
|
|
328
|
+
)
|
|
329
|
+
.subscribe();
|
|
330
|
+
|
|
331
|
+
effect(
|
|
332
|
+
() => {
|
|
333
|
+
const devtoolConfig = {
|
|
334
|
+
isOpen: this.isOpen(),
|
|
335
|
+
isTranslucent: this.isTranslucent(),
|
|
336
|
+
snapLayout: this.snapLayout(),
|
|
337
|
+
showResponse: this.showResponse(),
|
|
338
|
+
showRawResponse: this.showRawResponse(),
|
|
339
|
+
showQueryConfig: this.showQueryConfig(),
|
|
340
|
+
showEntityStoreValue: this.showEntityStoreValue(),
|
|
341
|
+
showArguments: this.showArguments(),
|
|
342
|
+
selectedClientId: this.selectedClientId(),
|
|
343
|
+
selectedQueryPath: this.selectedQueryId(),
|
|
344
|
+
queryListMode: this.queryListMode(),
|
|
345
|
+
viewMode: this.viewMode(),
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
window.localStorage.setItem('ethlete:query:devtools', JSON.stringify(devtoolConfig));
|
|
349
|
+
},
|
|
350
|
+
{ allowSignalWrites: true },
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
const initialConfig = window.localStorage.getItem('ethlete:query:devtools');
|
|
354
|
+
|
|
355
|
+
if (initialConfig) {
|
|
356
|
+
const parsed = JSON.parse(initialConfig);
|
|
357
|
+
|
|
358
|
+
this.isOpen.set(parsed.isOpen ?? false);
|
|
359
|
+
this.isTranslucent.set(parsed.isTranslucent ?? false);
|
|
360
|
+
this.snapLayout.set(parsed.snapLayout ?? 'full');
|
|
361
|
+
this.showResponse.set(parsed.showResponse ?? false);
|
|
362
|
+
this.showRawResponse.set(parsed.showRawResponse ?? false);
|
|
363
|
+
this.showQueryConfig.set(parsed.showQueryConfig ?? false);
|
|
364
|
+
this.showEntityStoreValue.set(parsed.showEntityStoreValue ?? false);
|
|
365
|
+
this.showArguments.set(parsed.showArguments ?? false);
|
|
366
|
+
this.selectedClientIdCtrl.setValue(parsed.selectedClientId ?? 0);
|
|
367
|
+
this.selectedQueryId.set(parsed.selectedQueryPath ?? null);
|
|
368
|
+
this.queryListMode.set(parsed.queryListMode ?? 'live');
|
|
369
|
+
this.viewMode.set(parsed.viewMode ?? 'query');
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
protected trackByClient: TrackByFunction<QueryClientDevtoolsOptions> = (_, { client }) => client.config.baseRoute;
|
|
374
|
+
protected trackByQuery: TrackByFunction<AnyQuery> = (_, { _id }) => _id;
|
|
375
|
+
|
|
376
|
+
protected toggleOpen() {
|
|
377
|
+
this.isOpen.set(!this.isOpen());
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
protected toggleTranslucent() {
|
|
381
|
+
this.isTranslucent.set(!this.isTranslucent());
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
protected toggleShowResponse() {
|
|
385
|
+
this.showResponse.set(!this.showResponse());
|
|
386
|
+
|
|
387
|
+
nextFrame(() => {
|
|
388
|
+
this._cdr.markForCheck();
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
protected toggleShowQueryConfig() {
|
|
393
|
+
this.showQueryConfig.set(!this.showQueryConfig());
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
protected toggleShowRawResponse() {
|
|
397
|
+
this.showRawResponse.set(!this.showRawResponse());
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
protected toggleShowEntityStoreValue() {
|
|
401
|
+
this.showEntityStoreValue.set(!this.showEntityStoreValue());
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
protected toggleShowArguments() {
|
|
405
|
+
this.showArguments.set(!this.showArguments());
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
protected selectSnapLayout(layout: QueryDevtoolsSnapLayout) {
|
|
409
|
+
this.snapLayout.set(layout);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
protected selectQueryListMode(mode: QueryListMode) {
|
|
413
|
+
this.queryListMode.set(mode);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
protected selectViewMode(mode: QueryViewMode) {
|
|
417
|
+
this.viewMode.set(mode);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
protected selectQuery(query: AnyQuery) {
|
|
421
|
+
this.selectedQueryId.set(query._id);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
protected clearQueryHistory() {
|
|
425
|
+
this.queryHistory$.next([]);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Pipe, PipeTransform } from '@angular/core';
|
|
2
|
+
import { AnyQuery } from '../../query';
|
|
3
|
+
|
|
4
|
+
@Pipe({ name: 'queryShortName', standalone: true })
|
|
5
|
+
export class QueryShortNamePipe implements PipeTransform {
|
|
6
|
+
transform(value: AnyQuery) {
|
|
7
|
+
const route = value._routeWithParams;
|
|
8
|
+
|
|
9
|
+
if (typeof route === 'string') {
|
|
10
|
+
// given an url that looks like this: https://api.github.com/repos/EladBezalel/etimo-achievements or https://api.github.com/repos/EladBezalel/etimo-achievements?test=1&test2=2
|
|
11
|
+
// we want to extract the last 3 parts of the url, so we get: repos/EladBezalel/etimo-achievements
|
|
12
|
+
|
|
13
|
+
const parts = route.split('/');
|
|
14
|
+
|
|
15
|
+
if (parts.length > 3) {
|
|
16
|
+
return `.../${parts.slice(parts.length - 3).join('/')}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return route;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return route as string;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { InjectionToken, isDevMode } from '@angular/core';
|
|
2
|
+
import { QueryClient } from '../../query-client';
|
|
3
|
+
|
|
4
|
+
export interface QueryClientDevtoolsOptions {
|
|
5
|
+
displayName?: string;
|
|
6
|
+
client: QueryClient;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const QUERY_CLIENT_DEVTOOLS_TOKEN = new InjectionToken<QueryClientDevtoolsOptions[]>(
|
|
10
|
+
'QUERY_CLIENT_DEVTOOLS_TOKEN',
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export const provideQueryClientForDevtools = (queryClient: QueryClientDevtoolsOptions) => {
|
|
14
|
+
if (!isDevMode()) {
|
|
15
|
+
console.warn(
|
|
16
|
+
'You are using the Query Devtools in production mode. This increases the size of your bundle and should only be used for development purposes.',
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
provide: QUERY_CLIENT_DEVTOOLS_TOKEN,
|
|
22
|
+
useValue: queryClient,
|
|
23
|
+
multi: true,
|
|
24
|
+
};
|
|
25
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Directive, ElementRef, inject, Input, OnDestroy, OnInit } from '@angular/core';
|
|
2
|
+
import { fromEvent, Subject, takeUntil } from 'rxjs';
|
|
3
|
+
import { INFINITY_QUERY_TOKEN } from './infinity-query.directive';
|
|
4
|
+
|
|
5
|
+
@Directive({
|
|
6
|
+
// eslint-disable-next-line @angular-eslint/directive-selector
|
|
7
|
+
selector: '[etInfinityQueryTrigger], et-infinity-query-trigger',
|
|
8
|
+
standalone: true,
|
|
9
|
+
})
|
|
10
|
+
export class InfinityQueryTriggerDirective implements OnInit, OnDestroy {
|
|
11
|
+
private _elementRef = inject(ElementRef<HTMLElement>);
|
|
12
|
+
private _infinityQuery = inject(INFINITY_QUERY_TOKEN);
|
|
13
|
+
|
|
14
|
+
private _destroy = new Subject<boolean>();
|
|
15
|
+
private _observer: IntersectionObserver | null = null;
|
|
16
|
+
|
|
17
|
+
click$ = fromEvent(this._elementRef.nativeElement, 'click');
|
|
18
|
+
|
|
19
|
+
@Input()
|
|
20
|
+
scrollContainerSelector: string | null = null;
|
|
21
|
+
|
|
22
|
+
ngOnInit(): void {
|
|
23
|
+
const isInteractive = this._elementRef.nativeElement.tagName === 'BUTTON';
|
|
24
|
+
|
|
25
|
+
if (isInteractive) {
|
|
26
|
+
this.click$.pipe(takeUntil(this._destroy)).subscribe(() => this._infinityQuery.loadNextPage());
|
|
27
|
+
} else {
|
|
28
|
+
this._setupIntersectionObserver();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
ngOnDestroy(): void {
|
|
33
|
+
this._destroy.next(true);
|
|
34
|
+
this._destroy.unsubscribe();
|
|
35
|
+
this._observer?.disconnect();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private _setupIntersectionObserver(): void {
|
|
39
|
+
this._observer = new IntersectionObserver(
|
|
40
|
+
(entries) => {
|
|
41
|
+
const entry = entries[0];
|
|
42
|
+
|
|
43
|
+
if (!entry) return;
|
|
44
|
+
|
|
45
|
+
if (entry.isIntersecting && !this._infinityQuery.context.loading) {
|
|
46
|
+
this._infinityQuery.loadNextPage();
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
root: this.scrollContainerSelector ? document.querySelector(this.scrollContainerSelector) : null,
|
|
51
|
+
rootMargin: '0px',
|
|
52
|
+
threshold: [0.25, 0.5, 0.75, 1],
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
this._observer.observe(this._elementRef.nativeElement);
|
|
57
|
+
}
|
|
58
|
+
}
|