@blueprint-ts/core 1.0.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/.editorconfig +508 -0
- package/.eslintrc.cjs +15 -0
- package/.prettierrc.json +8 -0
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/docker-compose.yaml +8 -0
- package/docs/.vitepress/config.ts +68 -0
- package/docs/.vitepress/theme/Layout.vue +14 -0
- package/docs/.vitepress/theme/components/VersionSelector.vue +64 -0
- package/docs/.vitepress/theme/index.js +13 -0
- package/docs/index.md +70 -0
- package/docs/services/laravel/pagination.md +54 -0
- package/docs/services/laravel/requests.md +62 -0
- package/docs/services/requests/index.md +74 -0
- package/docs/vue/forms.md +326 -0
- package/docs/vue/requests/route-model-binding.md +66 -0
- package/docs/vue/state.md +293 -0
- package/env.d.ts +1 -0
- package/eslint.config.js +15 -0
- package/examples/files/7z2404-x64.exe +0 -0
- package/examples/index.html +14 -0
- package/examples/js/app.js +8 -0
- package/examples/js/router.js +22 -0
- package/examples/js/view/App.vue +49 -0
- package/examples/js/view/layout/DemoPage.vue +28 -0
- package/examples/js/view/pagination/Pagination.vue +28 -0
- package/examples/js/view/pagination/components/errorPagination/ErrorPagination.vue +71 -0
- package/examples/js/view/pagination/components/errorPagination/GetProductsRequest.ts +54 -0
- package/examples/js/view/pagination/components/infiniteScrolling/GetProductsRequest.ts +50 -0
- package/examples/js/view/pagination/components/infiniteScrolling/InfiniteScrolling.vue +57 -0
- package/examples/js/view/pagination/components/tablePagination/GetProductsRequest.ts +50 -0
- package/examples/js/view/pagination/components/tablePagination/TablePagination.vue +63 -0
- package/examples/js/view/requests/Requests.vue +34 -0
- package/examples/js/view/requests/components/abortableRequest/AbortableRequest.vue +36 -0
- package/examples/js/view/requests/components/abortableRequest/GetProductsRequest.ts +25 -0
- package/examples/js/view/requests/components/fileDownloadRequest/DownloadFileRequest.ts +15 -0
- package/examples/js/view/requests/components/fileDownloadRequest/FileDownloadRequest.vue +44 -0
- package/examples/js/view/requests/components/getRequestWithDynamicParams/GetProductsRequest.ts +34 -0
- package/examples/js/view/requests/components/getRequestWithDynamicParams/GetRequestWithDynamicParams.vue +59 -0
- package/examples/js/view/requests/components/serverErrorRequest/ServerErrorRequest.ts +21 -0
- package/examples/js/view/requests/components/serverErrorRequest/ServerErrorRequest.vue +53 -0
- package/package.json +81 -0
- package/release-tool.json +7 -0
- package/src/helpers.ts +78 -0
- package/src/service/bulkRequests/BulkRequestEvent.enum.ts +4 -0
- package/src/service/bulkRequests/BulkRequestSender.ts +184 -0
- package/src/service/bulkRequests/BulkRequestWrapper.ts +49 -0
- package/src/service/bulkRequests/index.ts +6 -0
- package/src/service/laravel/pagination/contracts/PaginationParamsContract.ts +4 -0
- package/src/service/laravel/pagination/contracts/PaginationResponseBodyContract.ts +6 -0
- package/src/service/laravel/pagination/dataDrivers/RequestDriver.ts +32 -0
- package/src/service/laravel/pagination/index.ts +7 -0
- package/src/service/laravel/requests/JsonBaseRequest.ts +35 -0
- package/src/service/laravel/requests/PaginationJsonBaseRequest.ts +29 -0
- package/src/service/laravel/requests/index.ts +9 -0
- package/src/service/laravel/requests/responses/JsonResponse.ts +8 -0
- package/src/service/laravel/requests/responses/PaginationResponse.ts +16 -0
- package/src/service/pagination/InfiniteScroller.ts +21 -0
- package/src/service/pagination/Paginator.ts +149 -0
- package/src/service/pagination/contracts/PaginateableRequestContract.ts +13 -0
- package/src/service/pagination/contracts/PaginationDataDriverContract.ts +5 -0
- package/src/service/pagination/contracts/PaginationResponseContract.ts +7 -0
- package/src/service/pagination/contracts/PaginatorLoadDataOptions.ts +4 -0
- package/src/service/pagination/contracts/ViewDriverContract.ts +12 -0
- package/src/service/pagination/contracts/ViewDriverFactoryContract.ts +5 -0
- package/src/service/pagination/dataDrivers/ArrayDriver.ts +28 -0
- package/src/service/pagination/dtos/PaginationDataDto.ts +14 -0
- package/src/service/pagination/factories/VuePaginationDriverFactory.ts +9 -0
- package/src/service/pagination/frontendDrivers/VuePaginationDriver.ts +61 -0
- package/src/service/pagination/index.ts +16 -0
- package/src/service/persistenceDrivers/LocalStorageDriver.ts +22 -0
- package/src/service/persistenceDrivers/NonPersistentDriver.ts +12 -0
- package/src/service/persistenceDrivers/SessionStorageDriver.ts +22 -0
- package/src/service/persistenceDrivers/index.ts +8 -0
- package/src/service/persistenceDrivers/types/PersistenceDriver.ts +5 -0
- package/src/service/requests/BaseRequest.ts +197 -0
- package/src/service/requests/ErrorHandler.ts +64 -0
- package/src/service/requests/RequestEvents.enum.ts +3 -0
- package/src/service/requests/RequestMethod.enum.ts +8 -0
- package/src/service/requests/bodies/FormDataBody.ts +41 -0
- package/src/service/requests/bodies/JsonBody.ts +16 -0
- package/src/service/requests/contracts/AbortableRequestContract.ts +3 -0
- package/src/service/requests/contracts/BaseRequestContract.ts +36 -0
- package/src/service/requests/contracts/BodyContract.ts +7 -0
- package/src/service/requests/contracts/BodyFactoryContract.ts +5 -0
- package/src/service/requests/contracts/DriverConfigContract.ts +7 -0
- package/src/service/requests/contracts/HeadersContract.ts +5 -0
- package/src/service/requests/contracts/RequestDriverContract.ts +15 -0
- package/src/service/requests/contracts/RequestLoaderContract.ts +5 -0
- package/src/service/requests/contracts/RequestLoaderFactoryContract.ts +5 -0
- package/src/service/requests/contracts/ResponseContract.ts +7 -0
- package/src/service/requests/drivers/contracts/ResponseHandlerContract.ts +10 -0
- package/src/service/requests/drivers/fetch/FetchDriver.ts +115 -0
- package/src/service/requests/drivers/fetch/FetchResponse.ts +30 -0
- package/src/service/requests/exceptions/NoResponseReceivedException.ts +3 -0
- package/src/service/requests/exceptions/NotFoundException.ts +3 -0
- package/src/service/requests/exceptions/PageExpiredException.ts +3 -0
- package/src/service/requests/exceptions/ResponseBodyException.ts +15 -0
- package/src/service/requests/exceptions/ResponseException.ts +11 -0
- package/src/service/requests/exceptions/ServerErrorException.ts +3 -0
- package/src/service/requests/exceptions/UnauthorizedException.ts +3 -0
- package/src/service/requests/exceptions/ValidationException.ts +3 -0
- package/src/service/requests/exceptions/index.ts +19 -0
- package/src/service/requests/factories/FormDataFactory.ts +9 -0
- package/src/service/requests/factories/JsonBodyFactory.ts +9 -0
- package/src/service/requests/index.ts +50 -0
- package/src/service/requests/responses/BaseResponse.ts +41 -0
- package/src/service/requests/responses/BlobResponse.ts +19 -0
- package/src/service/requests/responses/JsonResponse.ts +15 -0
- package/src/service/requests/responses/PlainTextResponse.ts +15 -0
- package/src/service/support/DeferredPromise.ts +67 -0
- package/src/service/support/index.ts +3 -0
- package/src/vue/composables/useConfirmDialog.ts +59 -0
- package/src/vue/composables/useGlobalCheckbox.ts +145 -0
- package/src/vue/composables/useIsEmpty.ts +34 -0
- package/src/vue/composables/useIsOpen.ts +37 -0
- package/src/vue/composables/useIsOpenFromVar.ts +61 -0
- package/src/vue/composables/useModelWrapper.ts +24 -0
- package/src/vue/composables/useOnOpen.ts +34 -0
- package/src/vue/contracts/ModelValueOptions.ts +3 -0
- package/src/vue/contracts/ModelValueProps.ts +3 -0
- package/src/vue/forms/BaseForm.ts +1074 -0
- package/src/vue/forms/PropertyAwareArray.ts +78 -0
- package/src/vue/forms/index.ts +11 -0
- package/src/vue/forms/types/PersistedForm.ts +6 -0
- package/src/vue/forms/validation/ValidationMode.enum.ts +14 -0
- package/src/vue/forms/validation/index.ts +12 -0
- package/src/vue/forms/validation/rules/BaseRule.ts +7 -0
- package/src/vue/forms/validation/rules/ConfirmedRule.ts +39 -0
- package/src/vue/forms/validation/rules/MinRule.ts +61 -0
- package/src/vue/forms/validation/rules/RequiredRule.ts +19 -0
- package/src/vue/forms/validation/rules/UrlRule.ts +24 -0
- package/src/vue/forms/validation/types/BidirectionalRule.ts +11 -0
- package/src/vue/index.ts +14 -0
- package/src/vue/requests/factories/VueRequestLoaderFactory.ts +9 -0
- package/src/vue/requests/index.ts +5 -0
- package/src/vue/requests/loaders/VueRequestBatchLoader.ts +30 -0
- package/src/vue/requests/loaders/VueRequestLoader.ts +18 -0
- package/src/vue/router/routeModelBinding/RouteModelRequestResolver.ts +11 -0
- package/src/vue/router/routeModelBinding/defineRoute.ts +31 -0
- package/src/vue/router/routeModelBinding/index.ts +8 -0
- package/src/vue/router/routeModelBinding/installRouteInjection.ts +73 -0
- package/src/vue/router/routeModelBinding/types.ts +46 -0
- package/src/vue/state/State.ts +391 -0
- package/src/vue/state/index.ts +3 -0
- package/tests/service/helpers/mergeDeep.test.ts +53 -0
- package/tests/service/laravel/pagination/dataDrivers/RequestDriver.test.ts +84 -0
- package/tests/service/laravel/requests/JsonBaseRequest.test.ts +43 -0
- package/tests/service/laravel/requests/PaginationJsonBaseRequest.test.ts +58 -0
- package/tests/service/laravel/requests/responses/JsonResponse.test.ts +59 -0
- package/tests/service/laravel/requests/responses/PaginationResponse.test.ts +127 -0
- package/tests/service/pagination/dtos/PaginationDataDto.test.ts +35 -0
- package/tests/service/pagination/factories/VuePaginationDriverFactory.test.ts +32 -0
- package/tests/service/pagination/frontendDrivers/VuePaginationDriver.test.ts +66 -0
- package/tests/service/requests/ErrorHandler.test.ts +141 -0
- package/tsconfig.json +114 -0
- package/vite.config.ts +34 -0
- package/vitest.config.ts +14 -0
package/src/helpers.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export const getCookie = (cname: string) => {
|
|
2
|
+
const name = cname + '='
|
|
3
|
+
const decodedCookie = decodeURIComponent(document.cookie)
|
|
4
|
+
const ca = decodedCookie.split(';')
|
|
5
|
+
for (let i = 0; i < ca.length; i++) {
|
|
6
|
+
let c = ca[i]
|
|
7
|
+
|
|
8
|
+
if (c === undefined) {
|
|
9
|
+
return ''
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
while (c.charAt(0) == ' ') {
|
|
13
|
+
c = c.substring(1)
|
|
14
|
+
}
|
|
15
|
+
if (c.indexOf(name) == 0) {
|
|
16
|
+
return c.substring(name.length, c.length)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return ''
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const isObject = (item: unknown): boolean => {
|
|
23
|
+
if (!item) {
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (Array.isArray(item)) {
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return typeof item === 'object'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const mergeDeep = (target: object, ...sources: object[]): object => {
|
|
35
|
+
if (!sources.length) return target
|
|
36
|
+
const source = sources.shift()
|
|
37
|
+
|
|
38
|
+
if (isObject(target) && isObject(source)) {
|
|
39
|
+
for (const key in source) {
|
|
40
|
+
// @ts-expect-error unknown structure
|
|
41
|
+
if (isObject(source[key])) {
|
|
42
|
+
// @ts-expect-error unknown structure
|
|
43
|
+
if (!target[key]) Object.assign(target, { [key]: {} })
|
|
44
|
+
// @ts-expect-error unknown structure
|
|
45
|
+
mergeDeep(target[key], source[key])
|
|
46
|
+
} else {
|
|
47
|
+
// @ts-expect-error unknown structure
|
|
48
|
+
Object.assign(target, { [key]: source[key] })
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return mergeDeep(target, ...sources)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const getDisplayablePages = (totalPages: number, pageNumber: number, displayPages: number = 4) => {
|
|
57
|
+
if (totalPages < displayPages) {
|
|
58
|
+
displayPages = totalPages
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let offset = 0
|
|
62
|
+
|
|
63
|
+
const middlePage = Math.ceil(displayPages / 2)
|
|
64
|
+
|
|
65
|
+
if (pageNumber <= middlePage) {
|
|
66
|
+
offset = 0
|
|
67
|
+
} else if (pageNumber > totalPages - middlePage) {
|
|
68
|
+
offset = totalPages - displayPages
|
|
69
|
+
} else {
|
|
70
|
+
offset = pageNumber - middlePage
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return [...Array(displayPages).keys()].map((i) => i + 1 + offset)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const isAtBottom = (scrollHeight: number, scrollTop: number, clientHeight: number): boolean => {
|
|
77
|
+
return Math.abs(scrollHeight - scrollTop - clientHeight) <= 3.0
|
|
78
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { BulkRequestWrapper } from './BulkRequestWrapper'
|
|
2
|
+
import { BulkRequestEventEnum } from './BulkRequestEvent.enum'
|
|
3
|
+
import { BaseRequest } from '../requests'
|
|
4
|
+
|
|
5
|
+
export enum BulkRequestExecutionMode {
|
|
6
|
+
PARALLEL = 'parallel',
|
|
7
|
+
SEQUENTIAL = 'sequential'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class BulkRequestSender {
|
|
11
|
+
// @ts-expect-error
|
|
12
|
+
protected events: Map<BulkRequestEventEnum, ((req: BulkRequestWrapper<BaseRequest>) => void)[]> = new Map()
|
|
13
|
+
protected abortController: AbortController | undefined = undefined
|
|
14
|
+
|
|
15
|
+
public constructor(
|
|
16
|
+
// @ts-expect-error
|
|
17
|
+
protected requests: BulkRequestWrapper<BaseRequest>[] = [],
|
|
18
|
+
protected executionMode: BulkRequestExecutionMode = BulkRequestExecutionMode.PARALLEL,
|
|
19
|
+
protected retryCount: number = 0
|
|
20
|
+
) {}
|
|
21
|
+
|
|
22
|
+
// @ts-expect-error
|
|
23
|
+
public setRequests(requests: BulkRequestWrapper<BaseRequest>[] = []) {
|
|
24
|
+
this.requests = requests
|
|
25
|
+
|
|
26
|
+
return this
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public setExecutionMode(mode: BulkRequestExecutionMode): this {
|
|
30
|
+
this.executionMode = mode
|
|
31
|
+
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public setRetryCount(count: number): this {
|
|
36
|
+
this.retryCount = count
|
|
37
|
+
|
|
38
|
+
return this
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public get isLoading(): boolean {
|
|
42
|
+
return this.requests.some((req) => req.isLoading())
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// @ts-expect-error
|
|
46
|
+
public on(event: BulkRequestEventEnum, callback: (req: BulkRequestWrapper<BaseRequest>) => void): this {
|
|
47
|
+
if (!this.events.has(event)) {
|
|
48
|
+
this.events.set(event, [])
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.events.get(event)!.push(callback)
|
|
52
|
+
|
|
53
|
+
return this
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public off(event: BulkRequestEventEnum): this {
|
|
57
|
+
this.events.delete(event)
|
|
58
|
+
|
|
59
|
+
return this
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// @ts-expect-error
|
|
63
|
+
protected emit(event: BulkRequestEventEnum, req: BulkRequestWrapper<BaseRequest>): void {
|
|
64
|
+
const callbacks = this.events.get(event) || []
|
|
65
|
+
|
|
66
|
+
callbacks.forEach((callback) => callback(req))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public get signal(): AbortSignal | undefined {
|
|
70
|
+
return this.abortController?.signal
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public abort(): void {
|
|
74
|
+
this.abortController?.abort()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public async send() {
|
|
78
|
+
this.abortController = new AbortController()
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
if (this.executionMode === BulkRequestExecutionMode.PARALLEL) {
|
|
82
|
+
await this.sendParallel()
|
|
83
|
+
} else {
|
|
84
|
+
await this.sendSequential()
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
// If an abort occurs, the underlying fetch (or request mechanism) should throw an AbortError.
|
|
88
|
+
console.error('Bulk operation aborted or encountered an error:', error)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
getSuccessCount: () => this.requests.filter((r) => !r.getError()).length,
|
|
93
|
+
getErrorCount: () => this.requests.filter((r) => r.getError()).length,
|
|
94
|
+
getSuccessfulResponses: () => this.requests.filter((r) => !r.getError()).map((r) => r.getResponse()),
|
|
95
|
+
getFailedResponses: () => this.requests.filter((r) => r.getError()).map((r) => r.getError())
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
protected async sendParallel() {
|
|
100
|
+
// First attempt for all requests
|
|
101
|
+
await Promise.all(
|
|
102
|
+
this.requests.map((req) =>
|
|
103
|
+
req.send(this.abortController?.signal).then(() => {
|
|
104
|
+
if (!req.hasError()) {
|
|
105
|
+
this.emit(BulkRequestEventEnum.REQUEST_SUCCESSFUL, req)
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
// Retry logic for failed requests
|
|
112
|
+
let retriesLeft = this.retryCount
|
|
113
|
+
while (retriesLeft > 0) {
|
|
114
|
+
const failedRequests = this.requests.filter((req) => req.hasError())
|
|
115
|
+
|
|
116
|
+
if (failedRequests.length === 0) {
|
|
117
|
+
break // No failed requests to retry
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
console.log(`Retrying ${failedRequests.length} failed requests. Attempts left: ${retriesLeft}`)
|
|
121
|
+
|
|
122
|
+
await Promise.all(
|
|
123
|
+
failedRequests.map((req) =>
|
|
124
|
+
req.send(this.abortController?.signal).then(() => {
|
|
125
|
+
if (!req.hasError()) {
|
|
126
|
+
// Success after retry
|
|
127
|
+
this.emit(BulkRequestEventEnum.REQUEST_SUCCESSFUL, req)
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
retriesLeft--
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Emit failed events for any requests that still have errors after all retries
|
|
137
|
+
this.requests
|
|
138
|
+
.filter((req) => req.hasError())
|
|
139
|
+
.forEach((req) => {
|
|
140
|
+
this.emit(BulkRequestEventEnum.REQUEST_FAILED, req)
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
protected async sendSequential() {
|
|
145
|
+
// First attempt for all requests
|
|
146
|
+
for (const req of this.requests) {
|
|
147
|
+
await req.send(this.abortController?.signal)
|
|
148
|
+
|
|
149
|
+
if (!req.hasError()) {
|
|
150
|
+
this.emit(BulkRequestEventEnum.REQUEST_SUCCESSFUL, req)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Retry logic for failed requests
|
|
155
|
+
let retriesLeft = this.retryCount
|
|
156
|
+
while (retriesLeft > 0) {
|
|
157
|
+
const failedRequests = this.requests.filter((req) => req.hasError())
|
|
158
|
+
|
|
159
|
+
if (failedRequests.length === 0) {
|
|
160
|
+
break // No failed requests to retry
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
console.log(`Retrying ${failedRequests.length} failed requests sequentially. Attempts left: ${retriesLeft}`)
|
|
164
|
+
|
|
165
|
+
for (const req of failedRequests) {
|
|
166
|
+
await req.send(this.abortController?.signal)
|
|
167
|
+
|
|
168
|
+
if (!req.hasError()) {
|
|
169
|
+
// Success after retry
|
|
170
|
+
this.emit(BulkRequestEventEnum.REQUEST_SUCCESSFUL, req)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
retriesLeft--
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Emit failed events for any requests that still have errors after all retries
|
|
178
|
+
this.requests
|
|
179
|
+
.filter((req) => req.hasError())
|
|
180
|
+
.forEach((req) => {
|
|
181
|
+
this.emit(BulkRequestEventEnum.REQUEST_FAILED, req)
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type BaseRequestContract } from '../requests'
|
|
2
|
+
|
|
3
|
+
export class BulkRequestWrapper<RequestLoaderLoadingType, RequestBodyInterface, ResponseClass, RequestParamsInterface extends object> {
|
|
4
|
+
protected response: any = null
|
|
5
|
+
protected error: any = null
|
|
6
|
+
protected sent: boolean = false
|
|
7
|
+
|
|
8
|
+
public constructor(protected request: BaseRequestContract<RequestLoaderLoadingType, RequestBodyInterface, ResponseClass, RequestParamsInterface>) {}
|
|
9
|
+
|
|
10
|
+
public async send(signal?: AbortSignal) {
|
|
11
|
+
try {
|
|
12
|
+
if (signal !== undefined) {
|
|
13
|
+
this.request.setAbortSignal(signal)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
this.response = await this.request.send()
|
|
17
|
+
} catch (err) {
|
|
18
|
+
console.error(err)
|
|
19
|
+
|
|
20
|
+
this.error = err
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.sent = true
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public isLoading(): RequestLoaderLoadingType {
|
|
27
|
+
return this.request.isLoading()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public getResponse() {
|
|
31
|
+
return this.response
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public getError() {
|
|
35
|
+
return this.error
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public getRequest(): BaseRequestContract<RequestLoaderLoadingType, RequestBodyInterface, ResponseClass, RequestParamsInterface> {
|
|
39
|
+
return this.request
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public hasError(): boolean {
|
|
43
|
+
return Boolean(this.getError())
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public wasSent(): boolean {
|
|
47
|
+
return this.sent
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BulkRequestWrapper } from './BulkRequestWrapper'
|
|
2
|
+
import { BulkRequestSender } from './BulkRequestSender'
|
|
3
|
+
import { BulkRequestEventEnum } from './BulkRequestEvent.enum'
|
|
4
|
+
import { BulkRequestExecutionMode } from './BulkRequestSender'
|
|
5
|
+
|
|
6
|
+
export { BulkRequestEventEnum, BulkRequestWrapper, BulkRequestSender, BulkRequestExecutionMode }
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { PaginationDataDto } from '../../../pagination/dtos/PaginationDataDto'
|
|
2
|
+
import { PaginationJsonBaseRequest } from '../../requests/PaginationJsonBaseRequest'
|
|
3
|
+
import { PaginationResponse } from '../../requests/responses/PaginationResponse'
|
|
4
|
+
import { type PaginateableRequestContract } from '../../../pagination/contracts/PaginateableRequestContract'
|
|
5
|
+
import { type PaginationDataDriverContract } from '../../../pagination/contracts/PaginationDataDriverContract'
|
|
6
|
+
|
|
7
|
+
type ExtractRequestTypes<T> =
|
|
8
|
+
T extends PaginationJsonBaseRequest<any, undefined, infer Resource, object>
|
|
9
|
+
? {
|
|
10
|
+
Resource: Resource
|
|
11
|
+
}
|
|
12
|
+
: never
|
|
13
|
+
|
|
14
|
+
export class RequestDriver<
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
TReq extends PaginateableRequestContract<any, any, any, any>
|
|
17
|
+
> implements PaginationDataDriverContract<ExtractRequestTypes<TReq>['Resource']> {
|
|
18
|
+
public constructor(protected request: TReq) {}
|
|
19
|
+
|
|
20
|
+
public get(pageNumber: number, pageSize: number): Promise<PaginationDataDto<ExtractRequestTypes<TReq>['Resource']>> {
|
|
21
|
+
return this.request
|
|
22
|
+
.setPaginationParams(pageNumber, pageSize)
|
|
23
|
+
.send()
|
|
24
|
+
.then((response: PaginationResponse<ExtractRequestTypes<TReq>['Resource']>) => {
|
|
25
|
+
return new PaginationDataDto<ExtractRequestTypes<TReq>['Resource']>(response.getData(), response.getTotal())
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public getRequest(): TReq {
|
|
30
|
+
return this.request
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type PaginationParamsContract } from './contracts/PaginationParamsContract'
|
|
2
|
+
import { type PaginationResponseBodyContract } from './contracts/PaginationResponseBodyContract'
|
|
3
|
+
import { RequestDriver } from '../pagination/dataDrivers/RequestDriver'
|
|
4
|
+
|
|
5
|
+
export type { PaginationParamsContract, PaginationResponseBodyContract }
|
|
6
|
+
|
|
7
|
+
export { RequestDriver }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BaseRequest } from '../../requests/BaseRequest'
|
|
2
|
+
import { JsonResponse } from './responses/JsonResponse'
|
|
3
|
+
import { JsonBodyFactory } from '../../requests/factories/JsonBodyFactory'
|
|
4
|
+
import { type BodyFactoryContract } from '../../requests/contracts/BodyFactoryContract'
|
|
5
|
+
|
|
6
|
+
export interface JsonResponseInterface<ResourceInterface> {
|
|
7
|
+
data: ResourceInterface
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* This requests expects a response in the JSON format
|
|
12
|
+
* and automatically sets the required headers.
|
|
13
|
+
*/
|
|
14
|
+
export abstract class JsonBaseRequest<
|
|
15
|
+
RequestLoaderLoadingType,
|
|
16
|
+
ResponseErrorBody,
|
|
17
|
+
ResourceInterface,
|
|
18
|
+
RequestBodyInterface = undefined,
|
|
19
|
+
RequestParamsInterface extends object = object
|
|
20
|
+
> extends BaseRequest<
|
|
21
|
+
RequestLoaderLoadingType,
|
|
22
|
+
ResponseErrorBody,
|
|
23
|
+
JsonResponseInterface<ResourceInterface>,
|
|
24
|
+
JsonResponse<ResourceInterface>,
|
|
25
|
+
RequestBodyInterface,
|
|
26
|
+
RequestParamsInterface
|
|
27
|
+
> {
|
|
28
|
+
public getResponse(): JsonResponse<ResourceInterface> {
|
|
29
|
+
return new JsonResponse<ResourceInterface>()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public override getRequestBodyFactory(): BodyFactoryContract<RequestBodyInterface | undefined> {
|
|
33
|
+
return new JsonBodyFactory<RequestBodyInterface>()
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BaseRequest } from '../../requests/BaseRequest'
|
|
2
|
+
import { type PaginationResponseBodyContract } from '../pagination/contracts/PaginationResponseBodyContract'
|
|
3
|
+
import { type PaginationResponseContract } from '../../pagination/contracts/PaginationResponseContract'
|
|
4
|
+
import { PaginationResponse } from './responses/PaginationResponse'
|
|
5
|
+
|
|
6
|
+
export abstract class PaginationJsonBaseRequest<
|
|
7
|
+
RequestLoaderLoadingType,
|
|
8
|
+
ResponseErrorBodyInterface,
|
|
9
|
+
ResourceInterface,
|
|
10
|
+
RequestParamsInterface extends object
|
|
11
|
+
> extends BaseRequest<
|
|
12
|
+
RequestLoaderLoadingType,
|
|
13
|
+
ResponseErrorBodyInterface,
|
|
14
|
+
PaginationResponseBodyContract<ResourceInterface>,
|
|
15
|
+
PaginationResponseContract<PaginationResponseBodyContract<ResourceInterface>, ResourceInterface>,
|
|
16
|
+
undefined,
|
|
17
|
+
RequestParamsInterface
|
|
18
|
+
> {
|
|
19
|
+
public getResponse(): PaginationResponse<ResourceInterface> {
|
|
20
|
+
return new PaginationResponse()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public setPaginationParams(page: number, size: number): this {
|
|
24
|
+
return this.withParams({
|
|
25
|
+
page_number: page,
|
|
26
|
+
page_size: size
|
|
27
|
+
} as RequestParamsInterface)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { JsonResponse } from './responses/JsonResponse'
|
|
2
|
+
import { PaginationResponse } from './responses/PaginationResponse'
|
|
3
|
+
import { JsonBaseRequest } from './JsonBaseRequest'
|
|
4
|
+
import { PaginationJsonBaseRequest } from './PaginationJsonBaseRequest'
|
|
5
|
+
import { type JsonResponseInterface } from './JsonBaseRequest'
|
|
6
|
+
|
|
7
|
+
export { JsonResponse, PaginationResponse, JsonBaseRequest, PaginationJsonBaseRequest }
|
|
8
|
+
|
|
9
|
+
export type { JsonResponseInterface }
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { JsonResponse as ParentJsonResponse } from '../../../requests/responses/JsonResponse'
|
|
2
|
+
import { type JsonResponseInterface } from '../JsonBaseRequest'
|
|
3
|
+
|
|
4
|
+
export class JsonResponse<ResourceInterface> extends ParentJsonResponse<JsonResponseInterface<ResourceInterface>> {
|
|
5
|
+
public getData(): ResourceInterface {
|
|
6
|
+
return this.getBody().data
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { JsonResponse } from '../../../requests/responses/JsonResponse'
|
|
2
|
+
import { type PaginationResponseBodyContract } from '../../pagination/contracts/PaginationResponseBodyContract'
|
|
3
|
+
import { type PaginationResponseContract } from '../../../pagination/contracts/PaginationResponseContract'
|
|
4
|
+
|
|
5
|
+
export class PaginationResponse<ResourceInterface>
|
|
6
|
+
extends JsonResponse<PaginationResponseBodyContract<ResourceInterface>>
|
|
7
|
+
implements PaginationResponseContract<PaginationResponseBodyContract<ResourceInterface>, ResourceInterface>
|
|
8
|
+
{
|
|
9
|
+
public getTotal(): number {
|
|
10
|
+
return this.getBody().meta.total
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public getData(): ResourceInterface {
|
|
14
|
+
return this.getBody().data
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Paginator } from './Paginator'
|
|
2
|
+
import { PaginationDataDto } from './dtos/PaginationDataDto'
|
|
3
|
+
import { type PaginatorLoadDataOptions } from './contracts/PaginatorLoadDataOptions'
|
|
4
|
+
|
|
5
|
+
export class InfiniteScroller<ResourceInterface> extends Paginator<ResourceInterface> {
|
|
6
|
+
protected override passDataToViewDriver(dto: PaginationDataDto<ResourceInterface[]>, options: PaginatorLoadDataOptions = {}) {
|
|
7
|
+
const { flush = false, replace = false } = options
|
|
8
|
+
|
|
9
|
+
if (flush) {
|
|
10
|
+
this.flush()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (replace) {
|
|
14
|
+
this.viewDriver.setData(dto.getData())
|
|
15
|
+
} else {
|
|
16
|
+
this.viewDriver.setData(this.viewDriver.getData().concat(dto.getData()))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
this.viewDriver.setTotal(dto.getTotal())
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { PaginationDataDto } from './dtos/PaginationDataDto'
|
|
2
|
+
import { type ViewDriverContract } from './contracts/ViewDriverContract'
|
|
3
|
+
import { type ViewDriverFactoryContract } from './contracts/ViewDriverFactoryContract'
|
|
4
|
+
import { type PaginatorLoadDataOptions } from './contracts/PaginatorLoadDataOptions'
|
|
5
|
+
import { type PaginationDataDriverContract } from './contracts/PaginationDataDriverContract'
|
|
6
|
+
|
|
7
|
+
export interface PaginatorOptions {
|
|
8
|
+
viewDriverFactory?: ViewDriverFactoryContract
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class Paginator<ResourceInterface> {
|
|
12
|
+
protected initialized: boolean = false
|
|
13
|
+
|
|
14
|
+
protected static viewDriverFactory: ViewDriverFactoryContract
|
|
15
|
+
|
|
16
|
+
protected viewDriver: ViewDriverContract<ResourceInterface[]>
|
|
17
|
+
|
|
18
|
+
public static setViewDriverFactory(value: ViewDriverFactoryContract): void {
|
|
19
|
+
Paginator.viewDriverFactory = value
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public constructor(
|
|
23
|
+
protected dataDriver: PaginationDataDriverContract<ResourceInterface[]>,
|
|
24
|
+
pageNumber: number = 1,
|
|
25
|
+
pageSize: number = 10,
|
|
26
|
+
options?: PaginatorOptions
|
|
27
|
+
) {
|
|
28
|
+
this.viewDriver = options?.viewDriverFactory
|
|
29
|
+
? options.viewDriverFactory.make<ResourceInterface>(pageNumber, pageSize)
|
|
30
|
+
: Paginator.viewDriverFactory.make<ResourceInterface>(pageNumber, pageSize)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public setDataDriver(dataDriver: PaginationDataDriverContract<ResourceInterface[]>): this {
|
|
34
|
+
this.dataDriver = dataDriver
|
|
35
|
+
|
|
36
|
+
return this
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public getDataDriver(): PaginationDataDriverContract<ResourceInterface[]> {
|
|
40
|
+
return this.dataDriver
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public init(pageNumber: number, pageSize: number): Promise<PaginationDataDto<ResourceInterface[]>> {
|
|
44
|
+
this.initialized = true
|
|
45
|
+
|
|
46
|
+
if (pageNumber && pageSize) {
|
|
47
|
+
return this.loadData(pageNumber, pageSize)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return this.loadData(this.getCurrentPage(), this.getPageSize())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public refresh(pageNumber?: number, options?: PaginatorLoadDataOptions): Promise<PaginationDataDto<ResourceInterface[]>> {
|
|
54
|
+
if (pageNumber !== undefined) {
|
|
55
|
+
return this.setPage(pageNumber, options)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return this.loadData(this.getCurrentPage(), this.getPageSize(), options)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public flush(): void {
|
|
62
|
+
this.viewDriver.setData([])
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public setPage(pageNumber: number, options?: PaginatorLoadDataOptions): Promise<PaginationDataDto<ResourceInterface[]>> {
|
|
66
|
+
this.viewDriver.setPage(pageNumber)
|
|
67
|
+
|
|
68
|
+
return this.loadData(this.viewDriver.getCurrentPage(), this.viewDriver.getPageSize(), options)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public isInitialized(): boolean {
|
|
72
|
+
return this.initialized
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public getLastPage(): number {
|
|
76
|
+
return this.viewDriver.getLastPage()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public toNextPage(): Promise<PaginationDataDto<ResourceInterface[]>> {
|
|
80
|
+
return this.setPage(this.getCurrentPage() + 1)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public toFirstPage(): Promise<PaginationDataDto<ResourceInterface[]>> {
|
|
84
|
+
return this.setPage(1)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public toLastPage(): Promise<PaginationDataDto<ResourceInterface[]>> {
|
|
88
|
+
return this.setPage(this.viewDriver.getLastPage())
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public toPreviousPage(): Promise<PaginationDataDto<ResourceInterface[]>> {
|
|
92
|
+
return this.setPage(this.getCurrentPage() - 1)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public getPageData(): ResourceInterface[] {
|
|
96
|
+
return this.viewDriver.getData()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public getCurrentPage(): number {
|
|
100
|
+
return this.viewDriver.getCurrentPage()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public getFromItemNumber(): number {
|
|
104
|
+
return (this.getCurrentPage() - 1) * this.getPageSize() + 1
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public getToItemNumber(): number {
|
|
108
|
+
return this.getCurrentPage() * this.getPageSize()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public getTotal(): number {
|
|
112
|
+
return this.viewDriver.getTotal()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public getPageSize(): number {
|
|
116
|
+
return this.viewDriver.getPageSize()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public setPageSize(pageSize: number): Promise<PaginationDataDto<ResourceInterface[]>> {
|
|
120
|
+
this.viewDriver.setPageSize(pageSize)
|
|
121
|
+
|
|
122
|
+
if (this.getCurrentPage() * pageSize > this.getTotal()) {
|
|
123
|
+
return this.setPage(1)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return this.loadData(this.viewDriver.getCurrentPage(), this.viewDriver.getPageSize())
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public getPages(): number[] {
|
|
130
|
+
return this.viewDriver.getPages()
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
protected loadData(pageNumber: number, pageSize: number, options?: PaginatorLoadDataOptions): Promise<PaginationDataDto<ResourceInterface[]>> {
|
|
134
|
+
return this.dataDriver.get(pageNumber, pageSize).then((value: PaginationDataDto<ResourceInterface[]>) => {
|
|
135
|
+
this.passDataToViewDriver(value, options)
|
|
136
|
+
|
|
137
|
+
return value
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected passDataToViewDriver(dto: PaginationDataDto<ResourceInterface[]>, options?: PaginatorLoadDataOptions): void {
|
|
142
|
+
if (options?.flush) {
|
|
143
|
+
this.flush()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
this.viewDriver.setData(dto.getData())
|
|
147
|
+
this.viewDriver.setTotal(dto.getTotal())
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type BaseRequestContract } from '../../requests/contracts/BaseRequestContract'
|
|
2
|
+
|
|
3
|
+
export interface PaginateableRequestContract<
|
|
4
|
+
RequestLoaderLoadingType,
|
|
5
|
+
ResponseClass,
|
|
6
|
+
RequestBodyInterface,
|
|
7
|
+
RequestParamsInterface extends object
|
|
8
|
+
> extends BaseRequestContract<RequestLoaderLoadingType, ResponseClass, RequestBodyInterface, RequestParamsInterface> {
|
|
9
|
+
setPaginationParams(
|
|
10
|
+
page: number,
|
|
11
|
+
size: number
|
|
12
|
+
): BaseRequestContract<RequestLoaderLoadingType, ResponseClass, RequestBodyInterface, RequestParamsInterface>
|
|
13
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ResponseContract } from '../../requests/contracts/ResponseContract'
|
|
2
|
+
|
|
3
|
+
export interface PaginationResponseContract<ResponseBodyInterface, ResourceInterface> extends ResponseContract<ResponseBodyInterface> {
|
|
4
|
+
getData(): ResourceInterface
|
|
5
|
+
|
|
6
|
+
getTotal(): number
|
|
7
|
+
}
|