5htp-core 0.1.2 → 0.2.1
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/changelog.md +5 -0
- package/doc/TODO.md +71 -0
- package/package.json +5 -4
- package/src/client/{App.tsx → app/component.tsx} +15 -11
- package/src/client/app/index.ts +128 -0
- package/src/client/app/service.ts +34 -0
- package/src/client/app.tsconfig.json +0 -4
- package/src/client/assets/css/components.less +52 -0
- package/src/client/assets/css/core.less +7 -28
- package/src/client/assets/css/theme.less +1 -1
- package/src/client/assets/css/{borders.less → utils/borders.less} +0 -0
- package/src/client/assets/css/{layouts.less → utils/layouts.less} +0 -0
- package/src/client/assets/css/{medias.less → utils/medias.less} +14 -1
- package/src/client/assets/css/{sizing.less → utils/sizing.less} +0 -0
- package/src/client/assets/css/{spacing.less → utils/spacing.less} +0 -0
- package/src/client/components/Card/index.tsx +13 -7
- package/src/client/components/Dialog/Manager.tsx +41 -14
- package/src/client/components/Dialog/index.less +2 -4
- package/src/client/components/Form/index.tsx +1 -1
- package/src/client/components/Row/index.less +0 -2
- package/src/client/components/Table/index.tsx +3 -2
- package/src/client/components/button.tsx +2 -2
- package/src/client/components/containers/Popover/index.tsx +1 -1
- package/src/client/components/containers/champs.less +0 -2
- package/src/client/components/data/spintext/index.tsx +1 -1
- package/src/client/components/dropdown/index.tsx +1 -1
- package/src/client/components/index.ts +23 -0
- package/src/client/components/input/BaseV2/index.less +0 -2
- package/src/client/components/input/BaseV2/index.tsx +1 -1
- package/src/client/components/input/Date/index.less +0 -2
- package/src/client/components/input/Periode/index.less +0 -2
- package/src/client/components/input/Radio/index.less +0 -2
- package/src/client/components/input/UploadImage/index.less +0 -2
- package/src/client/components/input/UploadImage/index.tsx +1 -1
- package/src/client/hooks/index.ts +5 -0
- package/src/client/hooks/useState/index.tsx +2 -2
- package/src/client/hooks.ts +22 -0
- package/src/client/index.ts +5 -0
- package/src/client/pages/_layout/landing/index.tsx +0 -2
- package/src/client/pages/_messages/400.tsx +2 -2
- package/src/client/pages/_messages/401.tsx +2 -2
- package/src/client/pages/_messages/403.tsx +2 -2
- package/src/client/pages/_messages/404.tsx +2 -2
- package/src/client/pages/_messages/500.tsx +2 -2
- package/src/client/pages/bug.tsx +1 -1
- package/src/client/pages/useHeader.tsx +1 -1
- package/src/client/{context/captcha.ts → services/captcha/index.ts} +0 -0
- package/src/client/services/metrics/index.ts +37 -0
- package/src/client/{router → services/router/components}/Link.tsx +1 -1
- package/src/client/services/router/components/Page.tsx +59 -0
- package/src/client/{router/component.tsx → services/router/components/router.tsx} +52 -74
- package/src/client/services/router/index.tsx +453 -0
- package/src/client/services/router/request/api.ts +227 -0
- package/src/client/{router → services/router}/request/history.ts +0 -0
- package/src/client/services/router/request/index.ts +52 -0
- package/src/client/services/router/response/index.tsx +107 -0
- package/src/client/services/router/response/page.ts +90 -0
- package/src/client/{context/socket.ts → services/socket/index.ts} +2 -2
- package/src/client/utils/dom.ts +1 -1
- package/src/common/app/index.ts +9 -0
- package/src/common/data/chaines/index.ts +9 -6
- package/src/common/data/input/validate.ts +3 -166
- package/src/common/data/objets.ts +25 -0
- package/src/common/data/tableaux.ts +8 -0
- package/src/common/errors/index.ts +3 -1
- package/src/common/router/index.ts +67 -88
- package/src/common/router/layouts.ts +50 -0
- package/src/common/router/register.ts +62 -0
- package/src/common/router/request/api.ts +72 -0
- package/src/common/router/request/index.ts +31 -0
- package/src/common/router/{response.ts → response/index.ts} +9 -13
- package/src/common/router/response/page.ts +46 -54
- package/src/common/validation/index.ts +3 -0
- package/src/common/validation/schema.ts +185 -0
- package/src/common/validation/validator.ts +95 -0
- package/src/common/validation/validators.ts +313 -0
- package/src/server/app/config.ts +9 -27
- package/src/server/app/index.ts +81 -124
- package/src/server/app/service.ts +98 -0
- package/src/server/app.tsconfig.json +0 -8
- package/src/server/index.ts +5 -0
- package/src/server/patch.ts +0 -6
- package/src/server/{data/Cache.ts → services/cache/index.ts} +79 -47
- package/src/server/services/console/bugReporter.ts +26 -16
- package/src/server/services/console/index.ts +59 -51
- package/src/server/services/cron/index.ts +12 -26
- package/src/server/services/database/bucket.ts +40 -0
- package/src/server/services/database/connection.ts +213 -80
- package/src/server/services/database/datatypes.ts +63 -40
- package/src/server/services/database/debug.ts +20 -0
- package/src/server/services/database/index.ts +295 -272
- package/src/server/services/database/metas.ts +246 -135
- package/src/server/services/database/stats.ts +151 -126
- package/src/server/services/email/index.ts +30 -62
- package/src/server/services/email/transporter.ts +38 -0
- package/src/server/services/{router/request/services → metrics}/detect.ts +8 -10
- package/src/server/services/{router/request/services/tracking.ts → metrics/index.ts} +68 -45
- package/src/server/services/{http → router/http}/index.ts +28 -70
- package/src/server/services/{http → router/http}/multipart.ts +0 -0
- package/src/server/services/{http → router/http}/session.ts.old +0 -0
- package/src/server/services/router/index.ts +273 -202
- package/src/server/services/router/request/api.ts +76 -0
- package/src/server/services/router/request/index.ts +16 -97
- package/src/server/services/router/request/service.ts +21 -0
- package/src/server/services/router/response/index.ts +131 -65
- package/src/server/services/router/response/{filter → mask}/Filter.ts +0 -0
- package/src/server/services/router/response/{filter → mask}/index.ts +0 -2
- package/src/server/services/router/response/{filter → mask}/selecteurs.ts +0 -0
- package/src/server/services/router/response/page/document.tsx +194 -0
- package/src/server/services/router/response/page/index.tsx +157 -0
- package/src/server/{libs/pages → services/router/response/page}/schemaGenerator.ts +0 -0
- package/src/server/services/router/service.ts +48 -0
- package/src/server/services/schema/index.ts +47 -0
- package/src/server/services/schema/request.ts +55 -0
- package/src/server/services/schema/router.ts +33 -0
- package/src/server/services/socket/index.ts +38 -43
- package/src/server/services/socket/scope.ts +6 -4
- package/src/server/services/users/index.ts +203 -0
- package/src/server/services/{auth/base.ts → users/old.ts} +28 -112
- package/src/server/services/users/router/index.ts +72 -0
- package/src/server/services/users/router/request.ts +49 -0
- package/src/server/{data → services_old}/SocketClient.ts +0 -0
- package/src/server/{data/Token.olg.ts → services_old/Token.old.ts} +0 -0
- package/src/server/{data → services_old}/aes.ts +0 -0
- package/src/types/aliases.d.ts +43 -2
- package/templates/composant.tsx +1 -1
- package/templates/modal.tsx +1 -1
- package/templates/page.tsx +1 -1
- package/tsconfig.common.json +0 -4
- package/src/client/assets/css/components/components.less +0 -31
- package/src/client/context/api.ts +0 -92
- package/src/client/context/index.ts +0 -246
- package/src/client/index.tsx +0 -129
- package/src/client/router/index.ts +0 -286
- package/src/client/router/request/index.ts +0 -106
- package/src/client/router/response/index.ts +0 -38
- package/src/client/router/route.ts +0 -75
- package/src/common/data/input/validators/basic.ts +0 -299
- package/src/common/data/input/validators/build.ts +0 -63
- package/src/common/router/request.ts +0 -83
- package/src/server/data/ApiClient.ts +0 -119
- package/src/server/data/input.ts +0 -41
- package/src/server/libs/pages/document.static.tsx +0 -41
- package/src/server/libs/pages/document.tsx +0 -203
- package/src/server/libs/pages/render.tsx +0 -90
- package/src/server/routes/auth.ts +0 -151
- package/src/server/services/redis/index.ts +0 -71
- package/src/server/services/router/request/services/auth.ts +0 -177
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import axios, { AxiosResponse, AxiosError, AxiosRequestConfig } from 'axios';
|
|
7
|
+
|
|
8
|
+
// Core
|
|
9
|
+
import type { TApiResponseData } from '@server/services/router';
|
|
10
|
+
import ApiClientService, {
|
|
11
|
+
TApiFetchOptions, TFetcherList, TFetcherArgs, TFetcher
|
|
12
|
+
} from '@common/router/request/api';
|
|
13
|
+
import { instancierViaCode, NetworkError } from '@common/errors';
|
|
14
|
+
import type ClientApplication from '@client/app';
|
|
15
|
+
|
|
16
|
+
// Specific
|
|
17
|
+
import type { default as Router, Request } from '..';
|
|
18
|
+
|
|
19
|
+
/*----------------------------------
|
|
20
|
+
- TYPES
|
|
21
|
+
----------------------------------*/
|
|
22
|
+
|
|
23
|
+
const debug = true;
|
|
24
|
+
|
|
25
|
+
export type Config = {
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/*----------------------------------
|
|
30
|
+
- FUNCTION
|
|
31
|
+
----------------------------------*/
|
|
32
|
+
export default class ApiClient implements ApiClientService {
|
|
33
|
+
|
|
34
|
+
// APO Client needs to know the current request so we can monitor which api request is made from which page
|
|
35
|
+
public constructor(
|
|
36
|
+
public app: ClientApplication,
|
|
37
|
+
public request: Request<Router>
|
|
38
|
+
) {
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/*----------------------------------
|
|
43
|
+
- HIGH LEVEL
|
|
44
|
+
----------------------------------*/
|
|
45
|
+
public get = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
|
|
46
|
+
this.createFetcher<TData>('GET', path, data, opts);
|
|
47
|
+
|
|
48
|
+
public post = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
|
|
49
|
+
this.createFetcher<TData>('POST', path, data, opts);
|
|
50
|
+
|
|
51
|
+
public put = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
|
|
52
|
+
this.createFetcher<TData>('PUT', path, data, opts);
|
|
53
|
+
|
|
54
|
+
public delete = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
|
|
55
|
+
this.createFetcher<TData>('DELETE', path, data, opts);
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
public set( newData: TObjetDonnees ) {
|
|
59
|
+
|
|
60
|
+
console.log("[api] Update page data", newData);
|
|
61
|
+
if (this.app.page)
|
|
62
|
+
this.app.page.setAllData(curData => ({ ...curData, ...newData }));
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public reload( ids?: string | string[], params?: TObjetDonnees ) {
|
|
67
|
+
|
|
68
|
+
if (this.app.page === undefined)
|
|
69
|
+
throw new Error("context.page is missing");
|
|
70
|
+
|
|
71
|
+
if (ids === undefined)
|
|
72
|
+
ids = Object.keys(this.app.page.fetchers);
|
|
73
|
+
else if (typeof ids === 'string')
|
|
74
|
+
ids = [ids];
|
|
75
|
+
|
|
76
|
+
console.log("[api] Reload data", ids, params, this.app.page.fetchers);
|
|
77
|
+
|
|
78
|
+
for (const id of ids) {
|
|
79
|
+
|
|
80
|
+
const fetcher = this.app.page.fetchers[id];
|
|
81
|
+
if (fetcher === undefined)
|
|
82
|
+
return console.error(`Unable to reload ${id}: Request not found in fetchers list.`);
|
|
83
|
+
|
|
84
|
+
if (params !== undefined)
|
|
85
|
+
fetcher.data = { ...(fetcher.data || {}), ...params };
|
|
86
|
+
|
|
87
|
+
console.log("[api][reload]", id, fetcher.method, fetcher.path, fetcher.data);
|
|
88
|
+
const indicator = this.toast.loading("Loading ...");
|
|
89
|
+
|
|
90
|
+
this.fetchAsync(fetcher.method, fetcher.path, fetcher.data).then((data) => {
|
|
91
|
+
|
|
92
|
+
this.set({ [id]: data });
|
|
93
|
+
|
|
94
|
+
}).finally(() => {
|
|
95
|
+
|
|
96
|
+
indicator.close(true);
|
|
97
|
+
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/*----------------------------------
|
|
103
|
+
- LOW LEVEL
|
|
104
|
+
----------------------------------*/
|
|
105
|
+
public createFetcher<TData extends unknown = unknown>(...args: TFetcherArgs): TFetcher<TData> {
|
|
106
|
+
const [method, path, data, options] = args;
|
|
107
|
+
return {
|
|
108
|
+
method, path, data, options,
|
|
109
|
+
// For async calls: api.post(...).then((data) => ...)
|
|
110
|
+
then: (callback: (data: any) => void) => this.fetchAsync<TData>(...args).then(callback),
|
|
111
|
+
catch: (callback: (data: any) => void) => this.fetchAsync(...args).catch(callback),
|
|
112
|
+
finally: (callback: () => void) => this.fetchAsync(...args).finally(callback),
|
|
113
|
+
run: () => this.fetchAsync(...args)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public async fetchAsync<TData extends unknown = unknown>(...[
|
|
118
|
+
method, path, data, options
|
|
119
|
+
]: TFetcherArgs): Promise<TData> {
|
|
120
|
+
|
|
121
|
+
/*if (options?.captcha !== undefined)
|
|
122
|
+
await this.gui.captcha.check(options?.captcha);*/
|
|
123
|
+
|
|
124
|
+
return await this.fetch<TData>(method, path, data, options).catch((e) => {
|
|
125
|
+
this.app.handleError(e);
|
|
126
|
+
throw e;
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public async fetchSync(fetchers: TFetcherList, alreadyLoadedData: {}): Promise<TObjetDonnees> {
|
|
131
|
+
|
|
132
|
+
// Pick the fetchers where the data is needed
|
|
133
|
+
const fetchersToRun: TFetcherList = {};
|
|
134
|
+
let fetchersCount: number = 0;
|
|
135
|
+
for (const fetcherId in fetchers)
|
|
136
|
+
if (!( fetcherId in alreadyLoadedData )) {
|
|
137
|
+
fetchersToRun[ fetcherId ] = fetchers[ fetcherId ]
|
|
138
|
+
fetchersCount++;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Fetch all the api data thanks to one http request
|
|
142
|
+
const fetchedData = fetchersCount === 0
|
|
143
|
+
? 0
|
|
144
|
+
: await this.fetch("POST", "/api", {
|
|
145
|
+
fetchers: fetchersToRun
|
|
146
|
+
}).then((res) => {
|
|
147
|
+
|
|
148
|
+
const data: TObjetDonnees = {};
|
|
149
|
+
for (const id in res)
|
|
150
|
+
data[id] = res[id];
|
|
151
|
+
|
|
152
|
+
return data;
|
|
153
|
+
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return { ...alreadyLoadedData, ...fetchedData }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public configure = (...[method, path, data, options]: TFetcherArgs): AxiosRequestConfig => {
|
|
160
|
+
|
|
161
|
+
const { onProgress, captcha } = options || {};
|
|
162
|
+
|
|
163
|
+
debug && console.log(`[api] Sending request`, method, path, data);
|
|
164
|
+
|
|
165
|
+
const config: AxiosRequestConfig = {
|
|
166
|
+
|
|
167
|
+
url: path,
|
|
168
|
+
method: method,
|
|
169
|
+
headers: {
|
|
170
|
+
'Content-Type': "application/json",
|
|
171
|
+
'Accept': "application/json",
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
validateStatus: function (status: number) {
|
|
175
|
+
return status === 200;
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
onUploadProgress: onProgress === undefined ? undefined : (e) => {
|
|
179
|
+
const percentCompleted = Math.round((e.loaded * 100) / e.total);
|
|
180
|
+
onProgress(percentCompleted);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
if (data) {
|
|
186
|
+
if (method === "GET")
|
|
187
|
+
config.params = data;
|
|
188
|
+
else {
|
|
189
|
+
config.data = data;
|
|
190
|
+
if (data instanceof FormData)
|
|
191
|
+
config.headers["Content-Type"] = 'multipart/form-data';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return config;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public fetch<TData = unknown>(...args: TFetcherArgs): Promise<TData> {
|
|
199
|
+
|
|
200
|
+
const config = this.configure(...args);
|
|
201
|
+
|
|
202
|
+
return axios.request(config)
|
|
203
|
+
.then((res: AxiosResponse<TApiResponseData>) => {
|
|
204
|
+
|
|
205
|
+
debug && console.log(`[api] Success:`, res);
|
|
206
|
+
return res.data as TData;
|
|
207
|
+
|
|
208
|
+
})
|
|
209
|
+
.catch((e: AxiosError) => {
|
|
210
|
+
|
|
211
|
+
if (e.response !== undefined) {
|
|
212
|
+
|
|
213
|
+
console.warn(`[api] Failure:`, e);
|
|
214
|
+
throw instancierViaCode(
|
|
215
|
+
e.response.status || 500,
|
|
216
|
+
e.response.data
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// Erreur réseau: l'utilisateur n'ets probablement plus connecté à internet
|
|
220
|
+
} else {
|
|
221
|
+
const error = new NetworkError(e.message);
|
|
222
|
+
this.app.handleError(error);
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import { Location } from 'history';
|
|
7
|
+
import type Bowser from 'bowser';
|
|
8
|
+
|
|
9
|
+
// Core
|
|
10
|
+
import BaseRequest from '@common/router/request';
|
|
11
|
+
|
|
12
|
+
// Specific
|
|
13
|
+
import type ClientRouter from '..';
|
|
14
|
+
import ApiClient from './api';
|
|
15
|
+
import type ClientResponse from '../response';
|
|
16
|
+
|
|
17
|
+
/*----------------------------------
|
|
18
|
+
- TYPES
|
|
19
|
+
----------------------------------*/
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/*----------------------------------
|
|
23
|
+
- ROUTER
|
|
24
|
+
----------------------------------*/
|
|
25
|
+
// Since we do SSR, the server router can also be passed here
|
|
26
|
+
export default class ClientRequest<TRouter extends ClientRouter = ClientRouter> extends BaseRequest {
|
|
27
|
+
|
|
28
|
+
public api: ApiClient;
|
|
29
|
+
public response?: ClientResponse<TRouter>;
|
|
30
|
+
public hash?: string;
|
|
31
|
+
|
|
32
|
+
public constructor(
|
|
33
|
+
location: Location,
|
|
34
|
+
public router: TRouter,
|
|
35
|
+
public app = router.app
|
|
36
|
+
) {
|
|
37
|
+
|
|
38
|
+
super(location.pathname);
|
|
39
|
+
|
|
40
|
+
this.host = window.location.host;
|
|
41
|
+
this.hash = location.hash;
|
|
42
|
+
|
|
43
|
+
this.api = new ApiClient(this.app, this);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// To move to a service
|
|
47
|
+
public device(): Bowser.Parser.ParsedResult | undefined {
|
|
48
|
+
// We load bowser only when required
|
|
49
|
+
const Bowser = require("bowser");
|
|
50
|
+
return Bowser.parse(window.navigator.userAgent);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Libs
|
|
6
|
+
import type ServerRouter from '@server/services/router';
|
|
7
|
+
import type ServerResponse from '@server/services/router/response';
|
|
8
|
+
|
|
9
|
+
import type { TRoute, TErrorRoute } from '@common/router';
|
|
10
|
+
import BaseResponse from '@common/router/response';
|
|
11
|
+
|
|
12
|
+
import type ClientApplication from '@client/app';
|
|
13
|
+
import type { default as ClientRouter } from '@client/services/router'
|
|
14
|
+
import type ClientResponse from '@client/services/router/response'
|
|
15
|
+
import ClientRequest from '@client/services/router/request'
|
|
16
|
+
import ClientPage from '@client/services/router/response/page'
|
|
17
|
+
import { history } from '@client/services/router/request/history';
|
|
18
|
+
import CommonPage from '@common/router/response/page';
|
|
19
|
+
|
|
20
|
+
/*----------------------------------
|
|
21
|
+
- TYPES
|
|
22
|
+
----------------------------------*/
|
|
23
|
+
|
|
24
|
+
export type TPageResponse<TRouter extends ClientRouter> = (
|
|
25
|
+
ClientResponse<TRouter, ClientPage>
|
|
26
|
+
|
|
|
27
|
+
ServerResponse<ServerRouter, ClientPage>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export type TRouterContext<TRouter extends ClientRouter = ClientRouter, TApplication extends ClientApplication = ClientApplication> = (
|
|
31
|
+
// ClientPage context
|
|
32
|
+
{
|
|
33
|
+
app: TApplication,
|
|
34
|
+
context: TRouterContext<TRouter, TApplication>,
|
|
35
|
+
request: ClientRequest<TRouter>,
|
|
36
|
+
route: TRoute<TRouter>,
|
|
37
|
+
api: ClientRequest<TRouter>["api"],
|
|
38
|
+
page: ClientPage<TRouter>,
|
|
39
|
+
user: User
|
|
40
|
+
}
|
|
41
|
+
&
|
|
42
|
+
// Expose client application services (api, socket, ...)
|
|
43
|
+
//TRouter["app"]
|
|
44
|
+
TApplication
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
/*----------------------------------
|
|
48
|
+
- ROUTER
|
|
49
|
+
----------------------------------*/
|
|
50
|
+
export default class ClientPageResponse<
|
|
51
|
+
TRouter extends ClientRouter,
|
|
52
|
+
TData extends TResponseData = TResponseData
|
|
53
|
+
> extends BaseResponse<TData> {
|
|
54
|
+
|
|
55
|
+
public context: TRouterContext<TRouter, TRouter["app"]>;
|
|
56
|
+
|
|
57
|
+
public constructor(
|
|
58
|
+
public request: ClientRequest<TRouter>,
|
|
59
|
+
public route: TRoute | TErrorRoute,
|
|
60
|
+
|
|
61
|
+
public app = request.app,
|
|
62
|
+
) {
|
|
63
|
+
|
|
64
|
+
super(request);
|
|
65
|
+
|
|
66
|
+
request.response = this;
|
|
67
|
+
|
|
68
|
+
// Create response context for controllers
|
|
69
|
+
this.context = this.createContext();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private createContext(): TRouterContext<TRouter, TRouter["app"]> {
|
|
73
|
+
|
|
74
|
+
const context: TRouterContext<TRouter, TRouter["app"]> = {
|
|
75
|
+
// App services (TODO: expose only services)
|
|
76
|
+
...this.request.app,
|
|
77
|
+
// Router context
|
|
78
|
+
app: this.app,
|
|
79
|
+
context: undefined as unknown as TRouterContext<TRouter, TRouter["app"]>,
|
|
80
|
+
request: this.request,
|
|
81
|
+
route: this.route,
|
|
82
|
+
api: this.request.api,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
context.context = context;
|
|
86
|
+
|
|
87
|
+
return context;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public async runController( additionnalData: {} = {} ): Promise<ClientPage> {
|
|
91
|
+
|
|
92
|
+
// Run contoller
|
|
93
|
+
const result = this.route.controller(this.context);
|
|
94
|
+
|
|
95
|
+
// Default data type for `return <raw data>`
|
|
96
|
+
if (result instanceof ClientPage)
|
|
97
|
+
await result.preRender(additionnalData);
|
|
98
|
+
else
|
|
99
|
+
throw new Error(`Unsupported response format: ${result.constructor?.name}`);
|
|
100
|
+
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public redirect(url: string) {
|
|
105
|
+
history?.replace(url);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import type { ComponentChild } from 'preact';
|
|
7
|
+
|
|
8
|
+
// Core
|
|
9
|
+
import type { TClientOrServerContext } from '@common/router';
|
|
10
|
+
import PageResponse, { TDataProvider, TFrontRenderer } from "@common/router/response/page";
|
|
11
|
+
|
|
12
|
+
// Specific
|
|
13
|
+
import type ClientRouter from '..';
|
|
14
|
+
|
|
15
|
+
/*----------------------------------
|
|
16
|
+
- TYPES
|
|
17
|
+
----------------------------------*/
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
/*----------------------------------
|
|
22
|
+
- CLASS
|
|
23
|
+
----------------------------------*/
|
|
24
|
+
|
|
25
|
+
export default class ClientPage<TRouter = ClientRouter> extends PageResponse<TRouter> {
|
|
26
|
+
|
|
27
|
+
public isLoading: boolean = false;
|
|
28
|
+
public loading: false | ComponentChild;
|
|
29
|
+
public scrollToId: string;
|
|
30
|
+
|
|
31
|
+
public constructor(
|
|
32
|
+
public dataProvider: TDataProvider | null,
|
|
33
|
+
public component: TFrontRenderer,
|
|
34
|
+
public context: TClientOrServerContext,
|
|
35
|
+
|
|
36
|
+
public route = context.route
|
|
37
|
+
) {
|
|
38
|
+
|
|
39
|
+
super(dataProvider, component, context);
|
|
40
|
+
|
|
41
|
+
this.bodyId = context.route.options.bodyId;
|
|
42
|
+
this.scrollToId = context.request.hash;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public async preRender( data?: TObjetDonnees ) {
|
|
46
|
+
|
|
47
|
+
// Add the page to the context
|
|
48
|
+
this.context.page = this;
|
|
49
|
+
this.isLoading = true;
|
|
50
|
+
|
|
51
|
+
// Data succesfully loaded
|
|
52
|
+
this.data = data || await this.fetchData();
|
|
53
|
+
this.isLoading = false;
|
|
54
|
+
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/*----------------------------------
|
|
59
|
+
- ACTIONS
|
|
60
|
+
----------------------------------*/
|
|
61
|
+
// Should be called AFTER rendering the page
|
|
62
|
+
public updateClient() {
|
|
63
|
+
|
|
64
|
+
document.body.id = this.bodyId || this.id;
|
|
65
|
+
document.title = this.title || APP_NAME;
|
|
66
|
+
document.body.className = [...this.bodyClass].join(' ');
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public setAllData( callback: (data: {[k: string]: any}) => void) {
|
|
71
|
+
console.warn(`page.setAllData not yet attached to the page Reatc component.`);
|
|
72
|
+
}
|
|
73
|
+
public setData( key: string, value: ((value: any) => void) | any ) {
|
|
74
|
+
this.setAllData(old => ({
|
|
75
|
+
...old,
|
|
76
|
+
[key]: typeof value === 'function' ? value(old[key]) : value
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public setLoading(state: boolean) {
|
|
81
|
+
|
|
82
|
+
if (state === true) {
|
|
83
|
+
if (!document.body.classList.contains("loading"))
|
|
84
|
+
document.body.classList.add("loading");
|
|
85
|
+
} else {
|
|
86
|
+
document.body.classList.remove("loading");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
- DEPENDANCES
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
|
-
import type { ClientContext } from '
|
|
5
|
+
import type { ClientContext } from '../../context';
|
|
6
6
|
|
|
7
7
|
import type { TDialogControls } from '@client/components/Dialog/Manager';
|
|
8
8
|
|
|
@@ -131,7 +131,7 @@ export default class SocketClient {
|
|
|
131
131
|
|
|
132
132
|
public scopes: { [name: string]: SocketScope } = {}
|
|
133
133
|
|
|
134
|
-
public constructor(public context: ClientContext ) {
|
|
134
|
+
public constructor( public context: ClientContext ) {
|
|
135
135
|
|
|
136
136
|
|
|
137
137
|
}
|
package/src/client/utils/dom.ts
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type ClientApplication from '@client/app';
|
|
2
|
+
import type ServerApplication from '@server/app';
|
|
3
|
+
|
|
4
|
+
export type ClientOrServerApplication = ClientApplication | ServerApplication;
|
|
5
|
+
|
|
6
|
+
export type TAppArrowFunction<
|
|
7
|
+
TRegisteredData = void,
|
|
8
|
+
TApplication extends ClientOrServerApplication = ClientOrServerApplication
|
|
9
|
+
> = (app: TApplication) => TRegisteredData
|
|
@@ -11,6 +11,11 @@ export const nameToID = (name: string) => name.toLowerCase().replace(/[^a-z1-9]/
|
|
|
11
11
|
|
|
12
12
|
export const ucfirst = (chaine: string): string => {
|
|
13
13
|
return chaine.charAt(0).toUpperCase() + chaine.slice(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const linkify = (texte: string): string => {
|
|
17
|
+
const regex = /((http|https)\:\/\/([a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?))/gi;
|
|
18
|
+
return texte.replace(regex, '<a href="$1" target="_blank">$3</a>');
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
export const trim = (s: string, c: string) => {
|
|
@@ -19,12 +24,7 @@ export const trim = (s: string, c: string) => {
|
|
|
19
24
|
return s.replace(new RegExp(
|
|
20
25
|
"^[" + c + "]+|[" + c + "]+$", "g"
|
|
21
26
|
), "");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const linkify = (texte: string): string => {
|
|
25
|
-
const regex = /((http|https)\:\/\/([a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?))/gi;
|
|
26
|
-
return texte.replace(regex, '<a href="$1" target="_blank">$3</a>');
|
|
27
|
-
}
|
|
27
|
+
}
|
|
28
28
|
|
|
29
29
|
export const trimLeft = (chaine: string, toTrim: string) => chaine.startsWith(toTrim)
|
|
30
30
|
? chaine.substring(toTrim.length) : chaine;
|
|
@@ -32,6 +32,9 @@ export const trimLeft = (chaine: string, toTrim: string) => chaine.startsWith(to
|
|
|
32
32
|
export const trimRight = (chaine: string, toTrim: string) => chaine.endsWith(toTrim)
|
|
33
33
|
? chaine.substring(0, -toTrim.length) : chaine;
|
|
34
34
|
|
|
35
|
+
export const escapeRegExp = (string: string) =>
|
|
36
|
+
string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
|
37
|
+
|
|
35
38
|
/*----------------------------------
|
|
36
39
|
- EXTRACT
|
|
37
40
|
----------------------------------*/
|