proteum 1.0.2 → 2.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/AGENTS.md +101 -0
- package/agents/codex/AGENTS.md +95 -0
- package/agents/codex/CODING_STYLE.md +71 -0
- package/agents/codex/agents.md.zip +0 -0
- package/agents/codex/client/AGENTS.md +102 -0
- package/agents/codex/client/pages/AGENTS.md +35 -0
- package/agents/codex/server/routes/AGENTS.md +12 -0
- package/agents/codex/server/services/AGENTS.md +137 -0
- package/agents/codex/tests/AGENTS.md +8 -0
- package/cli/app/config.ts +13 -11
- package/cli/app/index.ts +74 -82
- package/cli/bin.js +1 -1
- package/cli/commands/build.ts +51 -14
- package/cli/commands/check.ts +19 -0
- package/cli/commands/deploy/app.ts +4 -8
- package/cli/commands/deploy/web.ts +16 -20
- package/cli/commands/dev.ts +189 -64
- package/cli/commands/devEvents.ts +106 -0
- package/cli/commands/init.ts +63 -57
- package/cli/commands/lint.ts +21 -0
- package/cli/commands/refresh.ts +18 -0
- package/cli/commands/typecheck.ts +18 -0
- package/cli/compiler/client/identite.ts +80 -53
- package/cli/compiler/client/index.ts +139 -213
- package/cli/compiler/common/bundleAnalysis.ts +94 -0
- package/cli/compiler/common/clientManifest.ts +67 -0
- package/cli/compiler/common/controllers.ts +288 -0
- package/cli/compiler/common/files/autres.ts +7 -18
- package/cli/compiler/common/files/images.ts +40 -37
- package/cli/compiler/common/files/style.ts +11 -22
- package/cli/compiler/common/generatedRouteModules.ts +368 -0
- package/cli/compiler/common/index.ts +31 -65
- package/cli/compiler/common/loaders/forbid-ssr-import.js +13 -0
- package/cli/compiler/common/rspackAliases.ts +13 -0
- package/cli/compiler/common/scripts.ts +37 -0
- package/cli/compiler/index.ts +781 -230
- package/cli/compiler/server/index.ts +59 -75
- package/cli/compiler/writeIfChanged.ts +21 -0
- package/cli/index.ts +71 -72
- package/cli/paths.ts +51 -57
- package/cli/print.ts +17 -11
- package/cli/tsconfig.json +5 -4
- package/cli/utils/agents.ts +100 -0
- package/cli/utils/check.ts +71 -0
- package/cli/utils/index.ts +1 -3
- package/cli/utils/keyboard.ts +8 -25
- package/cli/utils/runProcess.ts +30 -0
- package/client/app/component.tsx +29 -29
- package/client/app/index.ts +36 -57
- package/client/app/service.ts +7 -12
- package/client/app.tsconfig.json +2 -2
- package/client/components/Dialog/Manager.ssr.tsx +40 -0
- package/client/components/Dialog/Manager.tsx +119 -150
- package/client/components/Dialog/status.tsx +3 -3
- package/client/components/index.ts +1 -1
- package/client/components/types.d.ts +1 -3
- package/client/dev/hmr.ts +65 -0
- package/client/global.d.ts +2 -2
- package/client/hooks.ts +6 -9
- package/client/index.ts +2 -1
- package/client/islands/index.ts +7 -0
- package/client/islands/useDeferredModule.ts +199 -0
- package/client/pages/_layout/index.tsx +4 -12
- package/client/pages/useHeader.tsx +14 -21
- package/client/router.ts +27 -0
- package/client/services/router/components/Link.tsx +34 -27
- package/client/services/router/components/Page.tsx +6 -14
- package/client/services/router/components/router.ssr.tsx +36 -0
- package/client/services/router/components/router.tsx +63 -83
- package/client/services/router/index.tsx +185 -220
- package/client/services/router/request/api.ts +97 -119
- package/client/services/router/request/history.ts +2 -2
- package/client/services/router/request/index.ts +13 -12
- package/client/services/router/request/multipart.ts +72 -62
- package/client/services/router/response/index.tsx +68 -61
- package/client/services/router/response/page.ts +28 -32
- package/client/utils/dom.ts +17 -33
- package/common/app/index.ts +3 -3
- package/common/data/chaines/index.ts +22 -23
- package/common/data/dates.ts +35 -70
- package/common/data/markdown.ts +42 -39
- package/common/dev/serverHotReload.ts +26 -0
- package/common/errors/index.tsx +110 -142
- package/common/router/contracts.ts +29 -0
- package/common/router/index.ts +89 -108
- package/common/router/layouts.ts +34 -47
- package/common/router/pageSetup.ts +50 -0
- package/common/router/register.ts +53 -24
- package/common/router/request/api.ts +30 -36
- package/common/router/request/index.ts +2 -8
- package/common/router/response/index.ts +8 -15
- package/common/router/response/page.ts +70 -58
- package/common/utils.ts +1 -1
- package/doc/TODO.md +1 -1
- package/eslint.js +62 -0
- package/package.json +12 -47
- package/prettier.config.cjs +9 -0
- package/scripts/cleanup-generated-controllers.ts +62 -0
- package/scripts/fix-reference-app-typing.ts +490 -0
- package/scripts/refactor-client-app-imports.ts +244 -0
- package/scripts/refactor-client-pages.ts +587 -0
- package/scripts/refactor-server-controllers.ts +470 -0
- package/scripts/refactor-server-runtime-aliases.ts +360 -0
- package/scripts/restore-client-app-import-files.ts +41 -0
- package/scripts/restore-files-from-git-head.ts +20 -0
- package/scripts/update-codex-agents.ts +35 -0
- package/server/app/commands.ts +35 -64
- package/server/app/container/config.ts +48 -59
- package/server/app/container/console/index.ts +202 -248
- package/server/app/container/index.ts +33 -71
- package/server/app/controller/index.ts +61 -0
- package/server/app/index.ts +39 -105
- package/server/app/service/container.ts +41 -42
- package/server/app/service/index.ts +120 -147
- package/server/context.ts +1 -1
- package/server/index.ts +25 -1
- package/server/services/auth/index.ts +75 -115
- package/server/services/auth/router/index.ts +31 -32
- package/server/services/auth/router/request.ts +14 -16
- package/server/services/cron/CronTask.ts +13 -26
- package/server/services/cron/index.ts +14 -36
- package/server/services/disks/driver.ts +40 -58
- package/server/services/disks/drivers/local/index.ts +79 -90
- package/server/services/disks/drivers/s3/index.ts +116 -163
- package/server/services/disks/index.ts +23 -38
- package/server/services/email/index.ts +45 -104
- package/server/services/email/utils.ts +14 -27
- package/server/services/fetch/index.ts +53 -85
- package/server/services/prisma/Facet.ts +39 -91
- package/server/services/prisma/index.ts +74 -110
- package/server/services/router/generatedRuntime.ts +29 -0
- package/server/services/router/http/index.ts +78 -73
- package/server/services/router/http/multipart.ts +19 -42
- package/server/services/router/index.ts +378 -365
- package/server/services/router/request/api.ts +26 -25
- package/server/services/router/request/index.ts +44 -51
- package/server/services/router/request/service.ts +7 -11
- package/server/services/router/request/validation/zod.ts +111 -148
- package/server/services/router/response/index.ts +110 -125
- package/server/services/router/response/mask/Filter.ts +31 -72
- package/server/services/router/response/mask/index.ts +8 -15
- package/server/services/router/response/mask/selecteurs.ts +11 -25
- package/server/services/router/response/page/clientManifest.ts +25 -0
- package/server/services/router/response/page/document.tsx +199 -127
- package/server/services/router/response/page/index.tsx +89 -94
- package/server/services/router/service.ts +13 -15
- package/server/services/schema/index.ts +17 -26
- package/server/services/schema/request.ts +19 -33
- package/server/services/schema/router/index.ts +8 -11
- package/server/services/security/encrypt/aes/index.ts +15 -35
- package/server/utils/slug.ts +29 -35
- package/skills/clean-project-code/SKILL.md +63 -0
- package/skills/clean-project-code/agents/openai.yaml +4 -0
- package/tsconfig.common.json +4 -3
- package/tsconfig.json +4 -1
- package/types/aliases.d.ts +17 -21
- package/types/controller-input.test.ts +48 -0
- package/types/express-extra.d.ts +6 -0
- package/types/global/constants.d.ts +13 -0
- package/types/global/express-extra.d.ts +6 -0
- package/types/global/modules.d.ts +13 -16
- package/types/global/utils.d.ts +17 -49
- package/types/global/vendors.d.ts +62 -0
- package/types/icons.d.ts +65 -1
- package/types/uuid.d.ts +3 -0
- package/types/vendors.d.ts +62 -0
- package/cli/compiler/common/babel/index.ts +0 -170
- package/cli/compiler/common/babel/plugins/index.ts +0 -0
- package/cli/compiler/common/babel/plugins/services.ts +0 -586
- package/cli/compiler/common/babel/routes/imports.ts +0 -127
- package/cli/compiler/common/babel/routes/routes.ts +0 -1130
- package/client/services/captcha/index.ts +0 -67
- package/client/services/socket/index.ts +0 -147
- package/common/data/rte/nodes.ts +0 -83
- package/common/data/stats.ts +0 -90
- package/common/utils/rte.ts +0 -183
- package/server/services/auth/old.ts +0 -277
- package/server/services/cache/commands.ts +0 -41
- package/server/services/cache/index.ts +0 -297
- package/server/services/cache/service.json +0 -6
- package/server/services/socket/index.ts +0 -162
- package/server/services/socket/scope.ts +0 -226
- package/server/services/socket/service.json +0 -6
- package/server/services_old/SocketClient.ts +0 -92
- package/server/services_old/Token.old.ts +0 -97
|
@@ -2,66 +2,84 @@
|
|
|
2
2
|
- DEPENDANCES
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
|
-
// Libs
|
|
6
|
-
import type
|
|
5
|
+
// Libs
|
|
6
|
+
import type { TAnyRouter } from '@server/services/router';
|
|
7
7
|
import type ServerResponse from '@server/services/router/response';
|
|
8
8
|
|
|
9
9
|
import type { TAnyRoute, TErrorRoute } from '@common/router';
|
|
10
10
|
import BaseResponse, { TResponseData } from '@common/router/response';
|
|
11
11
|
|
|
12
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'
|
|
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
17
|
import { history } from '@client/services/router/request/history';
|
|
18
|
+
import createControllers from '@/common/.generated/controllers';
|
|
19
|
+
import type { TControllers } from '@/common/.generated/controllers';
|
|
18
20
|
|
|
19
21
|
/*----------------------------------
|
|
20
22
|
- TYPES
|
|
21
23
|
----------------------------------*/
|
|
22
24
|
|
|
23
|
-
export type TPageResponse<TRouter extends ClientRouter
|
|
24
|
-
ClientResponse<TRouter, ClientPage
|
|
25
|
-
|
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
export type TPageResponse<TRouter extends ClientRouter<any, any>> =
|
|
26
|
+
| ClientResponse<TRouter, ClientPage<TRouter>>
|
|
27
|
+
| ServerResponse<TAnyRouter>;
|
|
28
|
+
|
|
29
|
+
type TRouterContextBase<
|
|
30
|
+
TRouter extends ClientRouter<any, any> = ClientRouter<any, any>,
|
|
31
|
+
TApplication extends ClientApplication = ClientApplication,
|
|
32
|
+
> = {
|
|
33
|
+
app: TApplication;
|
|
34
|
+
request: ClientRequest<TRouter>;
|
|
35
|
+
route: TAnyRoute<TRouterContext<TRouter, TApplication>>;
|
|
36
|
+
api: ClientRequest<TRouter>['api'];
|
|
37
|
+
Router: TRouter;
|
|
38
|
+
page: ClientPage<TRouter>;
|
|
39
|
+
data: TObjetDonnees;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type TContextOwnState<TValue> = {
|
|
43
|
+
[TKey in keyof TValue as TValue[TKey] extends (...args: any[]) => any ? never : TKey]: TValue[TKey];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type TRouterRuntimeContext<
|
|
47
|
+
TRouter extends ClientRouter<any, any> = ClientRouter<any, any>,
|
|
48
|
+
TApplication extends ClientApplication = ClientApplication,
|
|
49
|
+
> = TRouterContextBase<TRouter, TApplication> &
|
|
50
|
+
TContextOwnState<TApplication> &
|
|
51
|
+
TControllers;
|
|
52
|
+
|
|
53
|
+
const createRuntimeContextBase = <
|
|
54
|
+
TRouter extends ClientRouter<any, any> = ClientRouter<any, any>,
|
|
55
|
+
TApplication extends ClientApplication = ClientApplication,
|
|
56
|
+
>(
|
|
57
|
+
app: TApplication,
|
|
58
|
+
controllers: TControllers,
|
|
59
|
+
fields: TRouterContextBase<TRouter, TApplication>,
|
|
60
|
+
): TRouterRuntimeContext<TRouter, TApplication> => Object.assign({}, app, controllers, fields);
|
|
28
61
|
|
|
29
62
|
export type TRouterContext<
|
|
30
|
-
TRouter extends ClientRouter = ClientRouter,
|
|
31
|
-
TApplication extends ClientApplication = ClientApplication
|
|
32
|
-
> =
|
|
33
|
-
|
|
34
|
-
{
|
|
35
|
-
app: TApplication,
|
|
36
|
-
request: ClientRequest<TRouter>,
|
|
37
|
-
route: TAnyRoute<TRouterContext>,
|
|
38
|
-
api: ClientRequest<TRouter>["api"],
|
|
39
|
-
page: ClientPage<TRouter>,
|
|
40
|
-
data: TObjetDonnees
|
|
41
|
-
}
|
|
42
|
-
// Expose client application services (api, socket, ...)
|
|
43
|
-
//TRouter["app"]
|
|
44
|
-
& TApplication
|
|
45
|
-
& ReturnType<TRouter["config"]["context"]>
|
|
46
|
-
)
|
|
63
|
+
TRouter extends ClientRouter<any, any> = ClientRouter<any, any>,
|
|
64
|
+
TApplication extends ClientApplication = ClientApplication,
|
|
65
|
+
> = TRouterRuntimeContext<TRouter, TApplication> &
|
|
66
|
+
ReturnType<TRouter['config']['context']> & { context: TRouterContext<TRouter, TApplication> };
|
|
47
67
|
|
|
48
68
|
/*----------------------------------
|
|
49
69
|
- ROUTER
|
|
50
70
|
----------------------------------*/
|
|
51
71
|
export default class ClientPageResponse<
|
|
52
72
|
TRouter extends ClientRouter,
|
|
53
|
-
TData extends TResponseData = TResponseData
|
|
73
|
+
TData extends TResponseData = TResponseData,
|
|
54
74
|
> extends BaseResponse<TData> {
|
|
55
|
-
|
|
56
|
-
public context: TRouterContext<TRouter, TRouter["app"]>;
|
|
75
|
+
public context: TRouterContext<TRouter, TRouter['app']>;
|
|
57
76
|
|
|
58
77
|
public constructor(
|
|
59
78
|
public request: ClientRequest<TRouter>,
|
|
60
|
-
public route: TAnyRoute
|
|
79
|
+
public route: TAnyRoute<TRouterContext<TRouter, TRouter['app']>>,
|
|
61
80
|
|
|
62
81
|
public app = request.app,
|
|
63
82
|
) {
|
|
64
|
-
|
|
65
83
|
super(request);
|
|
66
84
|
|
|
67
85
|
request.response = this;
|
|
@@ -70,54 +88,43 @@ export default class ClientPageResponse<
|
|
|
70
88
|
this.context = this.createContext();
|
|
71
89
|
}
|
|
72
90
|
|
|
73
|
-
private createContext(): TRouterContext<TRouter, TRouter[
|
|
74
|
-
|
|
75
|
-
const basicContext: TRouterContext<TRouter, TRouter["app"]> = {
|
|
76
|
-
|
|
77
|
-
// App services (TODO: expose only services)
|
|
78
|
-
...this.request.app,
|
|
79
|
-
|
|
91
|
+
private createContext(): TRouterContext<TRouter, TRouter['app']> {
|
|
92
|
+
const basicContext = createRuntimeContextBase(this.request.app, createControllers(this.request.api), {
|
|
80
93
|
// Router context
|
|
81
94
|
app: this.app,
|
|
82
95
|
request: this.request,
|
|
83
96
|
route: this.route,
|
|
84
97
|
api: this.request.api,
|
|
98
|
+
Router: this.request.router,
|
|
85
99
|
// Will be assigned when the controller will be runned
|
|
86
|
-
page: undefined
|
|
100
|
+
page: undefined!,
|
|
87
101
|
data: {},
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const newContext: TRouterContext<TRouter, TRouter["app"]> = {
|
|
91
|
-
...basicContext,
|
|
92
|
-
// Custom context
|
|
93
|
-
...this.request.router.config.context( basicContext, this.request.router )
|
|
94
|
-
}
|
|
102
|
+
});
|
|
103
|
+
const customContext = this.request.router.config.context(basicContext, this.request.router);
|
|
95
104
|
|
|
105
|
+
const newContext: TRouterContext<TRouter, TRouter['app']> = Object.create(Object.prototype);
|
|
106
|
+
Object.assign(newContext, basicContext, customContext);
|
|
96
107
|
newContext.context = newContext;
|
|
97
108
|
|
|
98
109
|
// Update context object if already exists
|
|
99
110
|
// NOTE: we don't create a nex instance of context because we don't want to rereder the full page (inc layout) to update the context given by thr react context provider
|
|
100
111
|
const existingContext = this.request.router.context;
|
|
101
112
|
if (existingContext === undefined) {
|
|
113
|
+
this.request.router.context = newContext;
|
|
114
|
+
} else {
|
|
115
|
+
Object.assign(existingContext, newContext);
|
|
116
|
+
}
|
|
102
117
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
} else for(const key in newContext)
|
|
106
|
-
existingContext[ key ] = newContext[ key ];
|
|
107
|
-
|
|
108
|
-
return newContext
|
|
118
|
+
return newContext;
|
|
109
119
|
}
|
|
110
120
|
|
|
111
|
-
public async runController(
|
|
112
|
-
|
|
121
|
+
public async runController(additionnalData: {} = {}): Promise<ClientPage<TRouter>> {
|
|
113
122
|
// Run contoller
|
|
114
123
|
const result = this.route.controller(this.context);
|
|
115
124
|
|
|
116
125
|
// Default data type for `return <raw data>`
|
|
117
|
-
if (result instanceof ClientPage)
|
|
118
|
-
|
|
119
|
-
else
|
|
120
|
-
throw new Error(`Unsupported response format: ${result.constructor?.name}`);
|
|
126
|
+
if (result instanceof ClientPage) await result.preRender(additionnalData);
|
|
127
|
+
else throw new Error(`Unsupported response format: ${result.constructor?.name}`);
|
|
121
128
|
|
|
122
129
|
return result;
|
|
123
130
|
}
|
|
@@ -125,4 +132,4 @@ export default class ClientPageResponse<
|
|
|
125
132
|
public redirect(url: string) {
|
|
126
133
|
history?.replace(url);
|
|
127
134
|
}
|
|
128
|
-
}
|
|
135
|
+
}
|
|
@@ -6,81 +6,77 @@
|
|
|
6
6
|
import type { ComponentChild } from 'preact';
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
|
-
import type {
|
|
10
|
-
import PageResponse, { TFrontRenderer } from
|
|
9
|
+
import type { Layout, TErrorRoute, TRoute } from '@common/router';
|
|
10
|
+
import PageResponse, { TFrontRenderer } from '@common/router/response/page';
|
|
11
|
+
import { isClientRequest } from '../request';
|
|
11
12
|
|
|
12
13
|
// Specific
|
|
13
14
|
import type ClientRouter from '..';
|
|
15
|
+
import type { TRouterContext } from '../response';
|
|
14
16
|
|
|
15
17
|
/*----------------------------------
|
|
16
18
|
- TYPES
|
|
17
19
|
----------------------------------*/
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
type TClientPageRouteLike<TRouter extends ClientRouter<any, any>> =
|
|
22
|
+
| TRoute<TRouterContext<TRouter, TRouter['app']>>
|
|
23
|
+
| TErrorRoute<TRouterContext<TRouter, TRouter['app']>>;
|
|
20
24
|
|
|
21
25
|
/*----------------------------------
|
|
22
26
|
- CLASS
|
|
23
27
|
----------------------------------*/
|
|
24
28
|
|
|
25
|
-
export default class ClientPage<TRouter
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
export default class ClientPage<TRouter extends ClientRouter<any, any> = ClientRouter<any, any>> extends PageResponse<
|
|
30
|
+
TRouter,
|
|
31
|
+
TClientPageRouteLike<TRouter>,
|
|
32
|
+
TRouterContext<TRouter, TRouter['app']>
|
|
33
|
+
> {
|
|
34
|
+
public scrollToId?: string;
|
|
28
35
|
|
|
29
36
|
public constructor(
|
|
30
|
-
public route:
|
|
37
|
+
public route: TClientPageRouteLike<TRouter>,
|
|
31
38
|
public component: TFrontRenderer,
|
|
32
|
-
public context:
|
|
33
|
-
public layout?: Layout
|
|
39
|
+
public context: TRouterContext<TRouter, TRouter['app']>,
|
|
40
|
+
public layout?: Layout,
|
|
34
41
|
) {
|
|
35
|
-
|
|
36
42
|
super(route, component, context);
|
|
37
43
|
|
|
38
44
|
this.bodyId = context.route.options.bodyId;
|
|
39
|
-
this.scrollToId = context.request.hash;
|
|
40
|
-
|
|
45
|
+
this.scrollToId = isClientRequest(context.request) ? context.request.hash : undefined;
|
|
41
46
|
}
|
|
42
|
-
|
|
43
|
-
public async preRender( data?: TObjetDonnees ) {
|
|
44
47
|
|
|
48
|
+
public async preRender(data?: TObjetDonnees) {
|
|
45
49
|
// Add the page to the context
|
|
46
50
|
this.context.page = this;
|
|
47
51
|
|
|
48
52
|
// Data succesfully loaded
|
|
49
|
-
this.context.data = this.data = data || await this.fetchData();
|
|
53
|
+
this.context.data = this.data = data || (await this.fetchData());
|
|
50
54
|
|
|
51
55
|
return this;
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
/*----------------------------------
|
|
55
59
|
- ACTIONS
|
|
56
60
|
----------------------------------*/
|
|
57
61
|
// Should be called AFTER rendering the page
|
|
58
62
|
public updateClient() {
|
|
59
|
-
|
|
60
|
-
document.body.id = this.bodyId || this.id;
|
|
63
|
+
document.body.id = this.bodyId || this.chunkId || '';
|
|
61
64
|
document.title = this.title || APP_NAME;
|
|
62
65
|
document.body.className = [...this.bodyClass].join(' ');
|
|
63
|
-
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
public setAllData(
|
|
67
|
-
console.warn(`page.setAllData not yet attached to the page Reatc component.`);
|
|
68
|
+
public setAllData(callback: (data: { [k: string]: any }) => void) {
|
|
69
|
+
console.warn(`page.setAllData not yet attached to the page Reatc component.`);
|
|
68
70
|
}
|
|
69
|
-
public setData(
|
|
70
|
-
this.setAllData(old => ({
|
|
71
|
-
...old,
|
|
72
|
-
[key]: typeof value === 'function' ? value(old[key]) : value
|
|
73
|
-
}));
|
|
71
|
+
public setData(key: string, value: ((value: any) => void) | any) {
|
|
72
|
+
this.setAllData((old) => ({ ...old, [key]: typeof value === 'function' ? value(old[key]) : value }));
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
public setLoading(state: boolean) {
|
|
77
|
-
|
|
78
76
|
if (state === true) {
|
|
79
|
-
if (!document.body.classList.contains(
|
|
80
|
-
document.body.classList.add("loading");
|
|
77
|
+
if (!document.body.classList.contains('loading')) document.body.classList.add('loading');
|
|
81
78
|
} else {
|
|
82
|
-
document.body.classList.remove(
|
|
79
|
+
document.body.classList.remove('loading');
|
|
83
80
|
}
|
|
84
|
-
|
|
85
81
|
}
|
|
86
|
-
}
|
|
82
|
+
}
|
package/client/utils/dom.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import type { RefObject } from 'preact';
|
|
2
1
|
import { history } from '@client/services/router/request/history';
|
|
3
2
|
|
|
4
3
|
type ElementOrSelector = HTMLElement | string;
|
|
5
|
-
export const deepContains = (
|
|
6
|
-
parents
|
|
7
|
-
children: HTMLElement
|
|
8
|
-
): boolean => {
|
|
9
|
-
|
|
10
|
-
if (!Array.isArray(parents))
|
|
11
|
-
parents = [parents];
|
|
4
|
+
export const deepContains = (parents: ElementOrSelector | ElementOrSelector[], children: HTMLElement): boolean => {
|
|
5
|
+
if (!Array.isArray(parents)) parents = [parents];
|
|
12
6
|
|
|
13
7
|
let node: HTMLElement | null = children;
|
|
14
8
|
while (node) {
|
|
@@ -16,8 +10,7 @@ export const deepContains = (
|
|
|
16
10
|
//console.log('Checking if', parent, 'matches with', node);
|
|
17
11
|
if (
|
|
18
12
|
// HTML Element
|
|
19
|
-
node === parent
|
|
20
|
-
||
|
|
13
|
+
node === parent ||
|
|
21
14
|
// CSS Selector
|
|
22
15
|
(typeof parent === 'string' && node.matches && node.matches(parent))
|
|
23
16
|
)
|
|
@@ -28,50 +21,41 @@ export const deepContains = (
|
|
|
28
21
|
}
|
|
29
22
|
|
|
30
23
|
return false;
|
|
31
|
-
}
|
|
24
|
+
};
|
|
32
25
|
|
|
33
26
|
// Usage: React.useEffect( blurable([ <element>, <function> ]) );
|
|
34
27
|
export const blurable = (...args: [HTMLElement, Function][]) => {
|
|
35
|
-
|
|
36
|
-
if (!history)
|
|
37
|
-
return;
|
|
28
|
+
if (!history) return;
|
|
38
29
|
|
|
39
30
|
const blur = (e: MouseEvent) => {
|
|
40
|
-
|
|
41
|
-
if (e.target === null)
|
|
42
|
-
return;
|
|
31
|
+
if (!(e.target instanceof HTMLElement)) return;
|
|
43
32
|
|
|
44
33
|
for (const [refElement, masquer] of args) {
|
|
45
|
-
|
|
46
34
|
//console.log("refElement", refElement, e.target?.matches);
|
|
47
35
|
|
|
48
|
-
if (!deepContains([refElement], e.target))
|
|
49
|
-
masquer();
|
|
50
|
-
|
|
36
|
+
if (!deepContains([refElement], e.target)) masquer();
|
|
51
37
|
}
|
|
52
|
-
}
|
|
38
|
+
};
|
|
53
39
|
|
|
54
40
|
window.addEventListener('mousedown', blur);
|
|
55
41
|
|
|
56
42
|
const unlisten = history.listen(() => {
|
|
57
43
|
for (const [, masquer] of args) {
|
|
58
|
-
|
|
59
44
|
masquer();
|
|
60
|
-
|
|
61
45
|
}
|
|
62
|
-
})
|
|
46
|
+
});
|
|
63
47
|
|
|
64
48
|
return () => {
|
|
65
49
|
window.removeEventListener('mousedown', blur);
|
|
66
50
|
unlisten();
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const focusContent = ( container: HTMLElement ) => {
|
|
51
|
+
};
|
|
52
|
+
};
|
|
71
53
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
54
|
+
export const focusContent = (container: HTMLElement) => {
|
|
55
|
+
const toFocus =
|
|
56
|
+
container.querySelector<HTMLInputElement | HTMLTextAreaElement | HTMLButtonElement>(
|
|
57
|
+
'input, textarea, button.btn.primary, footer > button.btn',
|
|
58
|
+
) || container; // Is it useful ? Creating unwanted scroll issue on showing popover
|
|
75
59
|
|
|
76
60
|
toFocus?.focus();
|
|
77
|
-
}
|
|
61
|
+
};
|
package/common/app/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type ClientApplication from '@client/app';
|
|
2
|
-
import type ServerApplication from '@server/app';
|
|
2
|
+
import type ServerApplication from '@server/app/index';
|
|
3
3
|
|
|
4
4
|
export type ClientOrServerApplication = ClientApplication | ServerApplication;
|
|
5
5
|
|
|
6
6
|
export type TAppArrowFunction<
|
|
7
7
|
TRegisteredData = void,
|
|
8
|
-
TApplication extends ClientOrServerApplication = ClientOrServerApplication
|
|
9
|
-
> = (app: TApplication) => TRegisteredData
|
|
8
|
+
TApplication extends ClientOrServerApplication = ClientOrServerApplication,
|
|
9
|
+
> = (app: TApplication) => TRegisteredData;
|
|
@@ -11,44 +11,43 @@ 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
|
-
}
|
|
14
|
+
};
|
|
15
15
|
|
|
16
16
|
export const linkify = (texte: string): string => {
|
|
17
17
|
const regex = /((http|https)\:\/\/([a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?))/gi;
|
|
18
18
|
return texte.replace(regex, '<a href="$1" target="_blank">$3</a>');
|
|
19
|
-
}
|
|
19
|
+
};
|
|
20
20
|
|
|
21
21
|
export const trim = (s: string, c: string) => {
|
|
22
|
-
if (c ===
|
|
23
|
-
if (c ===
|
|
24
|
-
return s.replace(new RegExp(
|
|
25
|
-
|
|
26
|
-
), "");
|
|
27
|
-
}
|
|
22
|
+
if (c === ']') c = '\\]';
|
|
23
|
+
if (c === '\\') c = '\\\\';
|
|
24
|
+
return s.replace(new RegExp('^[' + c + ']+|[' + c + ']+$', 'g'), '');
|
|
25
|
+
};
|
|
28
26
|
|
|
29
|
-
export const trimLeft = (chaine: string, toTrim: string) =>
|
|
30
|
-
? chaine.substring(toTrim.length) : chaine;
|
|
27
|
+
export const trimLeft = (chaine: string, toTrim: string) =>
|
|
28
|
+
chaine.startsWith(toTrim) ? chaine.substring(toTrim.length) : chaine;
|
|
31
29
|
|
|
32
|
-
export const trimRight = (chaine: string, toTrim: string) =>
|
|
33
|
-
? chaine.substring(0, -toTrim.length) : chaine;
|
|
30
|
+
export const trimRight = (chaine: string, toTrim: string) =>
|
|
31
|
+
chaine.endsWith(toTrim) ? chaine.substring(0, -toTrim.length) : chaine;
|
|
34
32
|
|
|
35
|
-
export const escapeRegExp = (string: string) =>
|
|
36
|
-
string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
|
33
|
+
export const escapeRegExp = (string: string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
|
37
34
|
|
|
38
35
|
/*----------------------------------
|
|
39
36
|
- EXTRACT
|
|
40
37
|
----------------------------------*/
|
|
41
|
-
export const getKeywords = (str: string, delimiter: string = ' ') =>
|
|
38
|
+
export const getKeywords = (str: string, delimiter: string = ' ') =>
|
|
39
|
+
str
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
// Minuscule
|
|
42
|
+
.toLowerCase()
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
// condenseWhitespace ( https://github.com/sindresorhus/condense-whitespace/blob/main/index.js )
|
|
45
|
+
.trim()
|
|
46
|
+
.replace(/\s{2,}/g, ' ')
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
// Ne garde que les caractères alĥanumériques, ainsi que .
|
|
49
|
+
// https://stackoverflow.com/questions/20690499/concrete-javascript-regex-for-accented-characters-diacritics
|
|
50
|
+
.replace(/[^\.0-9A-Za-zÀ-ÖØ-öø-ÿ]/gi, ' ');
|
|
52
51
|
|
|
53
52
|
// TODO: remove stopwords: https://github.com/fergiemcdowall/stopword
|
|
54
|
-
export const getSlug = (str: string) => getKeywords(str, '-')
|
|
53
|
+
export const getSlug = (str: string) => getKeywords(str, '-');
|
package/common/data/dates.ts
CHANGED
|
@@ -49,80 +49,59 @@ console.log(formatRelativeTime(date1, date2)); // Output: "in 1 year"
|
|
|
49
49
|
|
|
50
50
|
*/
|
|
51
51
|
|
|
52
|
-
export type TDateInfo = {
|
|
53
|
-
isPast: boolean,
|
|
54
|
-
delta: number,
|
|
55
|
-
text: string
|
|
56
|
-
}
|
|
52
|
+
export type TDateInfo = { isPast: boolean; delta: number; text: string };
|
|
57
53
|
|
|
58
54
|
export const timeSince = (date: Date | number | string): TDateInfo | null => {
|
|
59
|
-
|
|
60
|
-
if (date === undefined)
|
|
61
|
-
return null;
|
|
55
|
+
if (date === undefined) return null;
|
|
62
56
|
|
|
63
57
|
// Timeago ne prend que des dates et des timestamp
|
|
64
58
|
if (typeof date === 'string') {
|
|
65
59
|
date = Date.parse(date);
|
|
66
|
-
if (isNaN(date))
|
|
67
|
-
return null;
|
|
60
|
+
if (isNaN(date)) return null;
|
|
68
61
|
}
|
|
69
62
|
|
|
70
63
|
// Get metas
|
|
71
|
-
const now = Date.now()
|
|
64
|
+
const now = Date.now();
|
|
72
65
|
const timestamp = date instanceof Date ? date.getTime() : date;
|
|
73
|
-
const deltaSeconds = Math.abs(
|
|
66
|
+
const deltaSeconds = Math.abs(Math.round((now - timestamp) / 1000));
|
|
74
67
|
const isPast = now > timestamp;
|
|
75
68
|
|
|
76
69
|
return {
|
|
77
|
-
text: date
|
|
70
|
+
text: String(date), //timeAgo.format(date),
|
|
78
71
|
isPast,
|
|
79
|
-
delta: deltaSeconds
|
|
72
|
+
delta: deltaSeconds,
|
|
80
73
|
};
|
|
81
|
-
}
|
|
74
|
+
};
|
|
82
75
|
|
|
83
76
|
export const tempsRelatif = (time: number, nbChiffresInit?: number) => {
|
|
84
|
-
|
|
85
77
|
const nbChiffres = nbChiffresInit === undefined ? 2 : nbChiffresInit;
|
|
86
78
|
|
|
87
79
|
const jours = Math.floor(time / (60 * 60 * 24));
|
|
88
80
|
|
|
89
81
|
if (jours >= 1) {
|
|
90
|
-
|
|
91
|
-
return jours + (jours === 1 ? ' day' : ' days')
|
|
92
|
-
|
|
82
|
+
return jours + (jours === 1 ? ' day' : ' days');
|
|
93
83
|
} else {
|
|
94
|
-
|
|
95
84
|
const heures = Math.floor((time % (60 * 60 * 24)) / (60 * 60));
|
|
96
|
-
const minutes = Math.floor((time % (60 * 60)) /
|
|
97
|
-
const secondes = Math.floor(time %
|
|
98
|
-
|
|
99
|
-
return [heures, minutes, secondes]
|
|
100
|
-
(nb
|
|
101
|
-
|
|
102
|
-
(
|
|
103
|
-
).join(':');
|
|
85
|
+
const minutes = Math.floor((time % (60 * 60)) / 60);
|
|
86
|
+
const secondes = Math.floor(time % 60);
|
|
87
|
+
|
|
88
|
+
return [heures, minutes, secondes]
|
|
89
|
+
.filter((nb, i) => nb > 0 || 4 - i <= nbChiffres)
|
|
90
|
+
.map((nb) => (nb < 10 ? '0' + nb : nb))
|
|
91
|
+
.join(':');
|
|
104
92
|
}
|
|
105
|
-
}
|
|
93
|
+
};
|
|
106
94
|
|
|
107
95
|
export const chaineDate = (chaine: string): boolean => {
|
|
108
96
|
// 2019-09-09T11:28:21.778Z
|
|
109
97
|
const regexDate = /[0-9]{4}\-[0-9]{2}\-[0-9]{2}T[0-9]{2}\:[0-9]{2}\:[0-9]{2}\.[0-9]{3}Z/;
|
|
110
|
-
return regexDate.test(
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
98
|
+
return regexDate.test(chaine);
|
|
99
|
+
};
|
|
116
100
|
|
|
117
101
|
// Based on https://github.com/sebastiansandqvist/s-ago/blob/master/index.ts
|
|
118
|
-
type TUnit = {
|
|
119
|
-
max: number,
|
|
120
|
-
divisor?: number,
|
|
121
|
-
past: string,
|
|
122
|
-
future: string
|
|
123
|
-
}
|
|
102
|
+
type TUnit = { max: number; divisor?: number; past: string; future: string };
|
|
124
103
|
|
|
125
|
-
const units: {[name: string]: TUnit} = {
|
|
104
|
+
const units: { [name: string]: TUnit } = {
|
|
126
105
|
seconds: { max: 60000, past: 'just now', future: 'now' },
|
|
127
106
|
minute: { max: 2760000, divisor: 60000, past: 'a minute ago', future: 'in a minute' }, // max: 46 minutes
|
|
128
107
|
hour: { max: 72000000, divisor: 3600000, past: 'an hour ago', future: 'in an hour' }, // max: 20 hours
|
|
@@ -132,13 +111,10 @@ const units: {[name: string]: TUnit} = {
|
|
|
132
111
|
year: { max: Infinity, divisor: 31536000000, past: 'last year', future: 'in a year' },
|
|
133
112
|
};
|
|
134
113
|
|
|
135
|
-
export function ago(date: Date | string, { min, max }: { min?: string
|
|
136
|
-
|
|
137
|
-
if (!date)
|
|
138
|
-
return '-';
|
|
114
|
+
export function ago(date: Date | string, { min, max }: { min?: string; max?: string } = {}): string {
|
|
115
|
+
if (!date) return '-';
|
|
139
116
|
|
|
140
|
-
if (typeof date === 'string')
|
|
141
|
-
date = new Date(date);
|
|
117
|
+
if (typeof date === 'string') date = new Date(date);
|
|
142
118
|
|
|
143
119
|
const minUnit = min ? units[min].max : 0;
|
|
144
120
|
const diff = Date.now() - date.getTime();
|
|
@@ -148,32 +124,21 @@ export function ago(date: Date | string, { min, max }: { min?: string, max?: str
|
|
|
148
124
|
let unit!: TUnit;
|
|
149
125
|
for (unitName in units) {
|
|
150
126
|
unit = units[unitName];
|
|
151
|
-
if (unit.max >= minUnit && (delta < unit.max || unitName === max))
|
|
152
|
-
break;
|
|
127
|
+
if (unit.max >= minUnit && (delta < unit.max || unitName === max)) break;
|
|
153
128
|
}
|
|
154
129
|
|
|
155
|
-
if (unit.divisor === undefined)
|
|
156
|
-
return diff < 0 ? unit.future : unit.past;
|
|
130
|
+
if (unit.divisor === undefined) return diff < 0 ? unit.future : unit.past;
|
|
157
131
|
|
|
158
132
|
var val = Math.round(delta / unit.divisor);
|
|
159
|
-
if (diff < 0)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return val <= 1 ? unit.past : val + ' ' + unitName + 's ago';
|
|
163
|
-
|
|
164
|
-
};
|
|
133
|
+
if (diff < 0) return val <= 1 ? unit.future : 'in ' + val + ' ' + unitName + 's';
|
|
134
|
+
else return val <= 1 ? unit.past : val + ' ' + unitName + 's ago';
|
|
135
|
+
}
|
|
165
136
|
|
|
166
137
|
export const daysAgo = (date: string) => {
|
|
138
|
+
const days = dayjs().diff(date, 'days');
|
|
167
139
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (days
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return 'Yesterday';
|
|
174
|
-
else if (days <= 7)
|
|
175
|
-
return days + ' days ago'
|
|
176
|
-
else
|
|
177
|
-
return dayjs(date).format('DD/MM');
|
|
178
|
-
|
|
179
|
-
}
|
|
140
|
+
if (days === 0) return 'Today';
|
|
141
|
+
else if (days === 1) return 'Yesterday';
|
|
142
|
+
else if (days <= 7) return days + ' days ago';
|
|
143
|
+
else return dayjs(date).format('DD/MM');
|
|
144
|
+
};
|