5htp-core 0.2.5 → 0.2.6-2
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/package.json +5 -4
- package/src/client/components/Dialog/Manager.tsx +4 -5
- package/src/client/components/Form.ts +88 -36
- package/src/client/components/Form_old/index.tsx +17 -17
- package/src/client/components/Form_old/index.tsx.old +17 -17
- package/src/client/components/Select/ChoiceSelector.tsx +172 -0
- package/src/client/components/Select/index.tsx +27 -138
- package/src/client/components/containers/Popover/getPosition.ts +14 -11
- package/src/client/components/containers/Popover/index.tsx +52 -35
- package/src/client/components/containers/Popover/popover.less +7 -1
- package/src/client/components/dropdown/index.tsx +1 -1
- package/src/client/components/index.ts +2 -1
- package/src/client/components/input/Number/index.tsx +2 -2
- package/src/client/components/inputv3/date/index.tsx +49 -0
- package/src/client/components/inputv3/date/react-calendar.less +143 -0
- package/src/client/components/inputv3/date/react-daterange-picker.less +112 -0
- package/src/client/components/inputv3/{string/index.tsx → index.tsx} +6 -2
- package/src/client/pages/_messages/403.tsx +1 -1
- package/src/client/pages/_messages/500.tsx +1 -1
- package/src/client/pages/bug.tsx +3 -3
- package/src/client/services/router/request/api.ts +0 -5
- package/src/client/services/router/request/multipart.ts +120 -9
- package/src/client/utils/dom.ts +12 -1
- package/src/common/validation/schema.ts +26 -27
- package/src/common/validation/validator.ts +14 -5
- package/src/server/app/index.ts +10 -1
- package/src/server/app/service.ts +1 -0
- package/src/server/services/console/index.ts +33 -32
- package/src/server/services/database/connection.ts +16 -13
- package/src/server/services/router/index.ts +2 -0
- package/src/server/services/schema/request.ts +0 -1
- package/src/client/components/input/Date/index.less +0 -167
- package/src/client/components/input/Date/index.tsx +0 -90
|
@@ -23,6 +23,8 @@ import logToHTML from './html';
|
|
|
23
23
|
type TLogProfile = 'silly' | 'info' | 'warn' | 'error'
|
|
24
24
|
|
|
25
25
|
export type Config = {
|
|
26
|
+
debug?: boolean,
|
|
27
|
+
bufferLimit: number,
|
|
26
28
|
dev: {
|
|
27
29
|
level: TLogProfile,
|
|
28
30
|
},
|
|
@@ -77,17 +79,12 @@ export type TQueryLogs = ChannelInfos & {
|
|
|
77
79
|
time: number,
|
|
78
80
|
}
|
|
79
81
|
|
|
80
|
-
export type TLog =
|
|
81
|
-
|
|
82
|
-
}
|
|
82
|
+
export type TLog = ILogObject & ChannelInfos
|
|
83
83
|
|
|
84
84
|
/*----------------------------------
|
|
85
85
|
- TYPES: BUG REPORT
|
|
86
86
|
----------------------------------*/
|
|
87
87
|
export type ServerBug = {
|
|
88
|
-
|
|
89
|
-
type: 'server',
|
|
90
|
-
|
|
91
88
|
// Context
|
|
92
89
|
hash: string,
|
|
93
90
|
date: Date, // Timestamp
|
|
@@ -125,7 +122,7 @@ const logFields = [
|
|
|
125
122
|
'lineNumber',
|
|
126
123
|
'argumentsArray',
|
|
127
124
|
'stack',
|
|
128
|
-
]
|
|
125
|
+
] as const
|
|
129
126
|
|
|
130
127
|
/*----------------------------------
|
|
131
128
|
- LOGGER
|
|
@@ -186,14 +183,17 @@ export default class Console extends Service<Config, Hooks, Application> {
|
|
|
186
183
|
fatal: this.logEntry.bind(this),
|
|
187
184
|
}, envConfig.level);
|
|
188
185
|
|
|
189
|
-
setInterval(() => this.clean(),
|
|
186
|
+
setInterval(() => this.clean(), 10000);
|
|
190
187
|
|
|
191
188
|
// Send email report
|
|
192
189
|
this.app.on('error', this.createBugReport.bind(this));
|
|
193
190
|
}
|
|
194
191
|
|
|
195
192
|
private clean() {
|
|
196
|
-
|
|
193
|
+
this.config.debug && console.log(LogPrefix, `Clean logs buffer. Current size:`, this.logs.length, '/', this.config.bufferLimit);
|
|
194
|
+
const bufferOverflow = this.logs.length - this.config.bufferLimit;
|
|
195
|
+
if (bufferOverflow > 0)
|
|
196
|
+
this.logs = this.logs.slice(bufferOverflow);
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
/*----------------------------------
|
|
@@ -235,9 +235,6 @@ export default class Console extends Service<Config, Hooks, Application> {
|
|
|
235
235
|
);
|
|
236
236
|
|
|
237
237
|
const bugReport: ServerBug = {
|
|
238
|
-
|
|
239
|
-
type: 'server',
|
|
240
|
-
|
|
241
238
|
// Context
|
|
242
239
|
hash: hash,
|
|
243
240
|
date: now,
|
|
@@ -264,6 +261,7 @@ export default class Console extends Service<Config, Hooks, Application> {
|
|
|
264
261
|
|
|
265
262
|
private logEntry(entry: ILogObject) {
|
|
266
263
|
|
|
264
|
+
// Don't keep logs from the admin sashboard
|
|
267
265
|
const [channelType, channelId] = entry.requestId?.split(':') || ['master'];
|
|
268
266
|
if (entry.requestId === 'admin')
|
|
269
267
|
return;
|
|
@@ -274,22 +272,6 @@ export default class Console extends Service<Config, Hooks, Application> {
|
|
|
274
272
|
for (const k of logFields)
|
|
275
273
|
miniLog[k] = entry[k];
|
|
276
274
|
|
|
277
|
-
// remove webpack path
|
|
278
|
-
if (miniLog.filePath !== undefined) {
|
|
279
|
-
|
|
280
|
-
const appPrefix = '/webpack:/' + this.app.pkg.name + '/src/';
|
|
281
|
-
const appPrefixIndex = miniLog.filePath.indexOf(appPrefix);
|
|
282
|
-
|
|
283
|
-
const corePrefix = '/webpack:/' + this.app.pkg.name + '/node_modules/5htp-core/src/';
|
|
284
|
-
const corePrefixIndex = miniLog.filePath.indexOf(corePrefix);
|
|
285
|
-
|
|
286
|
-
if (appPrefixIndex !== -1)
|
|
287
|
-
miniLog.filePath = '@/' + miniLog.filePath.substring(appPrefixIndex + appPrefix.length);
|
|
288
|
-
else if (corePrefixIndex !== -1)
|
|
289
|
-
miniLog.filePath = '@' + miniLog.filePath.substring(corePrefixIndex + corePrefix.length);
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
|
|
293
275
|
this.logs.push(miniLog as TLog);
|
|
294
276
|
}
|
|
295
277
|
|
|
@@ -367,11 +349,30 @@ export default class Console extends Service<Config, Hooks, Application> {
|
|
|
367
349
|
if (channelId !== undefined)
|
|
368
350
|
filters.channelId = channelId;
|
|
369
351
|
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
352
|
+
const entries: TLog[] = []
|
|
353
|
+
for (const log of this.logs) {
|
|
354
|
+
|
|
355
|
+
// Filters
|
|
356
|
+
if (!(log.channelId === channelId && log.channelType === channelType))
|
|
357
|
+
continue;
|
|
358
|
+
|
|
359
|
+
// Remove path prefixs
|
|
360
|
+
if (log.filePath !== undefined) {
|
|
361
|
+
|
|
362
|
+
const appPrefix = '/webpack:/' + this.app.pkg.name + '/src/';
|
|
363
|
+
const appPrefixIndex = log.filePath.indexOf(appPrefix);
|
|
364
|
+
|
|
365
|
+
const corePrefix = '/webpack:/' + this.app.pkg.name + '/node_modules/5htp-core/src/';
|
|
366
|
+
const corePrefixIndex = log.filePath.indexOf(corePrefix);
|
|
367
|
+
|
|
368
|
+
if (appPrefixIndex !== -1)
|
|
369
|
+
log.filePath = '@/' + log.filePath.substring(appPrefixIndex + appPrefix.length);
|
|
370
|
+
else if (corePrefixIndex !== -1)
|
|
371
|
+
log.filePath = '@' + log.filePath.substring(corePrefixIndex + corePrefix.length);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
373
374
|
|
|
374
|
-
return this.printHtml(
|
|
375
|
+
return this.printHtml( entries.reverse() );
|
|
375
376
|
}
|
|
376
377
|
|
|
377
378
|
public printHtml(logs: TLog[], full: boolean = false): string {
|
|
@@ -95,8 +95,8 @@ export default class DatabaseManager extends Service<DatabaseServiceConfig, THoo
|
|
|
95
95
|
const connectionErrors: string[] = []
|
|
96
96
|
for (const connectionConfig of this.config.connections){
|
|
97
97
|
try {
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
await this.connect(connectionConfig)
|
|
99
|
+
break;
|
|
100
100
|
} catch (error) {
|
|
101
101
|
console.warn(LogPrefix, `Failed to connect to ${connectionConfig.name}: ` + error);
|
|
102
102
|
connectionErrors.push(connectionConfig.name + ': ' + error);
|
|
@@ -110,9 +110,6 @@ export default class DatabaseManager extends Service<DatabaseServiceConfig, THoo
|
|
|
110
110
|
// Disconnect from the database when the app is terminated
|
|
111
111
|
this.app.on('cleanup', () => this.disconnect());
|
|
112
112
|
|
|
113
|
-
// Load tables metas
|
|
114
|
-
this.tables = await this.metas.load( this.connectionConfig.databases );
|
|
115
|
-
|
|
116
113
|
// Ready to make queries
|
|
117
114
|
this.initialized = true;
|
|
118
115
|
}
|
|
@@ -124,16 +121,17 @@ export default class DatabaseManager extends Service<DatabaseServiceConfig, THoo
|
|
|
124
121
|
/*----------------------------------
|
|
125
122
|
- INIT
|
|
126
123
|
----------------------------------*/
|
|
127
|
-
public async connect(
|
|
128
|
-
|
|
129
|
-
|
|
124
|
+
public async connect(config: ConnectionConfig) {
|
|
125
|
+
|
|
126
|
+
console.info(LogPrefix, `Trying to connect to ${config.name} ...`);
|
|
127
|
+
this.connection = mysql.createPool({
|
|
130
128
|
|
|
131
129
|
// Identification
|
|
132
|
-
host: host,
|
|
133
|
-
port: port,
|
|
134
|
-
user: login,
|
|
135
|
-
password: password,
|
|
136
|
-
database: databases[0],
|
|
130
|
+
host: config.host,
|
|
131
|
+
port: config.port,
|
|
132
|
+
user: config.login,
|
|
133
|
+
password: config.password,
|
|
134
|
+
database: config.databases[0],
|
|
137
135
|
|
|
138
136
|
// Pool
|
|
139
137
|
waitForConnections: true,
|
|
@@ -159,6 +157,11 @@ export default class DatabaseManager extends Service<DatabaseServiceConfig, THoo
|
|
|
159
157
|
return query;
|
|
160
158
|
}
|
|
161
159
|
})
|
|
160
|
+
|
|
161
|
+
this.connectionConfig = config;
|
|
162
|
+
|
|
163
|
+
this.tables = await this.metas.load( config.databases );
|
|
164
|
+
console.info(LogPrefix, `Successfully connected to ${config.name}.`);
|
|
162
165
|
}
|
|
163
166
|
|
|
164
167
|
private typeCast( field: mysql.Field, next: Function ) {
|
|
@@ -548,6 +548,8 @@ declare type Routes = {
|
|
|
548
548
|
// Report error
|
|
549
549
|
await this.app.runHook('error', e, request);
|
|
550
550
|
|
|
551
|
+
console.log("ERROR 500 VIA ROUTER", e);
|
|
552
|
+
|
|
551
553
|
// Don't exose technical errors to users
|
|
552
554
|
if (this.app.env.profile === 'prod')
|
|
553
555
|
e.message = "We encountered an internal error, and our team has just been notified. Sorry for the inconvenience.";
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
.champ.periode {
|
|
2
|
-
|
|
3
|
-
display: flex;
|
|
4
|
-
|
|
5
|
-
> .input-date {
|
|
6
|
-
|
|
7
|
-
display: flex;
|
|
8
|
-
justify-content: center;
|
|
9
|
-
align-items: center;
|
|
10
|
-
|
|
11
|
-
> input[type=number] {
|
|
12
|
-
-moz-appearance: textfield;
|
|
13
|
-
padding: 0;
|
|
14
|
-
text-align: center;
|
|
15
|
-
|
|
16
|
-
width: 30px;
|
|
17
|
-
&.annee { width: 45px; }
|
|
18
|
-
|
|
19
|
-
&::-webkit-outer-spin-button,
|
|
20
|
-
&::-webkit-inner-spin-button {
|
|
21
|
-
-webkit-appearance: none;
|
|
22
|
-
margin: 0;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// https://github.com/wojtekmaj/react-calendar/blob/master/src/Calendar.less
|
|
30
|
-
.react-calendar {
|
|
31
|
-
|
|
32
|
-
&--doubleView {
|
|
33
|
-
width: 700px;
|
|
34
|
-
|
|
35
|
-
.react-calendar__viewContainer {
|
|
36
|
-
display: flex;
|
|
37
|
-
margin: -.5em;
|
|
38
|
-
|
|
39
|
-
> * {
|
|
40
|
-
width: 50%;
|
|
41
|
-
margin: .5em;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
&, & *, & *:before, & *:after {
|
|
47
|
-
-moz-box-sizing: border-box;
|
|
48
|
-
-webkit-box-sizing: border-box;
|
|
49
|
-
box-sizing: border-box;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
button {
|
|
53
|
-
margin: 0;
|
|
54
|
-
border: 0;
|
|
55
|
-
outline: none;
|
|
56
|
-
border-radius: @radiusBase;
|
|
57
|
-
|
|
58
|
-
&:enabled {
|
|
59
|
-
&:hover {
|
|
60
|
-
cursor: pointer;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
&__navigation {
|
|
66
|
-
height: 40px;
|
|
67
|
-
|
|
68
|
-
button {
|
|
69
|
-
min-width: 44px;
|
|
70
|
-
background: none;
|
|
71
|
-
|
|
72
|
-
&:enabled {
|
|
73
|
-
&:hover, &:focus {
|
|
74
|
-
background-color: var(--cBgControl)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
&[disabled] {
|
|
79
|
-
color: var(--cTxtDiscret)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
&__month-view {
|
|
85
|
-
&__weekdays {
|
|
86
|
-
text-align: center;
|
|
87
|
-
text-transform: uppercase;
|
|
88
|
-
font-weight: bold;
|
|
89
|
-
font-size: .75em;
|
|
90
|
-
|
|
91
|
-
&__weekday {
|
|
92
|
-
padding: .5em;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
&__weekNumbers {
|
|
97
|
-
font-weight: bold;
|
|
98
|
-
|
|
99
|
-
.react-calendar__tile {
|
|
100
|
-
display: flex;
|
|
101
|
-
align-items: center;
|
|
102
|
-
justify-content: center;
|
|
103
|
-
font-size: .75em;
|
|
104
|
-
padding: calc(.75em / .75) calc(.5em / .75);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
&__days {
|
|
109
|
-
&__day {
|
|
110
|
-
&--weekend {
|
|
111
|
-
//color: rgb(209, 0, 0);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
&--neighboringMonth {
|
|
115
|
-
color: var(--cTxtDesc)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
&__year-view,
|
|
122
|
-
&__decade-view,
|
|
123
|
-
&__century-view {
|
|
124
|
-
.react-calendar__tile {
|
|
125
|
-
padding: 2em .5em;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
&__tile {
|
|
130
|
-
max-width: 100%;
|
|
131
|
-
text-align: center;
|
|
132
|
-
padding: .75em .5em;
|
|
133
|
-
background: none;
|
|
134
|
-
|
|
135
|
-
&:disabled {
|
|
136
|
-
color: var(--cTxtDiscret)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
&:enabled {
|
|
140
|
-
&:hover, &:focus {
|
|
141
|
-
background-color: var(--cBgControl)
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
&--now {
|
|
146
|
-
font-weight: 700;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
&--hasActive {
|
|
150
|
-
background: var(--cPrincipale);
|
|
151
|
-
color: #fff;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
&--active {
|
|
155
|
-
background: var(--cPrincipale);
|
|
156
|
-
color: #fff;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
&--selectRange {
|
|
161
|
-
.react-calendar__tile {
|
|
162
|
-
&--hover {
|
|
163
|
-
background-color: var(--cBgControl)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/*----------------------------------
|
|
2
|
-
- DEPENDANCES
|
|
3
|
-
----------------------------------*/
|
|
4
|
-
import React from 'react';
|
|
5
|
-
import Champ from '../Base';
|
|
6
|
-
import dayjs from 'dayjs';
|
|
7
|
-
import Popover from '@client/components/Conteneurs/Popover';
|
|
8
|
-
import Calendar from 'react-calendar';
|
|
9
|
-
|
|
10
|
-
/*----------------------------------
|
|
11
|
-
- TYPES
|
|
12
|
-
----------------------------------*/
|
|
13
|
-
type TValeur = string | Date;
|
|
14
|
-
type TValeurDefaut = Date;
|
|
15
|
-
type TValeurOut = Date;
|
|
16
|
-
const valeurDefaut = undefined;
|
|
17
|
-
|
|
18
|
-
export type Props = {
|
|
19
|
-
valeur: TValeur,
|
|
20
|
-
placeholder?: string,
|
|
21
|
-
min?: string,
|
|
22
|
-
max?: string
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/*----------------------------------
|
|
26
|
-
- COMPOSANT
|
|
27
|
-
----------------------------------*/
|
|
28
|
-
import './index.less';
|
|
29
|
-
export default Champ<Props, TValeurDefaut, TValeurOut>('date', { valeurDefaut }, ({
|
|
30
|
-
// Spread TOUTES les props dont on a besoin pour éviter les problèmes de référence avec props
|
|
31
|
-
prefixe, className, min, max
|
|
32
|
-
}, { state, valeur, setState }, rendre) => {
|
|
33
|
-
|
|
34
|
-
const maintenant = new Date;
|
|
35
|
-
|
|
36
|
-
/* TODO: onchange saisie input = pas de validation
|
|
37
|
-
onchange click calendrier = validation immédiate
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
const [affCalendrier, setAffCalendrier] = React.useState<boolean>(false);
|
|
41
|
-
|
|
42
|
-
const saisieValide = valeur !== undefined && (
|
|
43
|
-
typeof valeur !== 'string' || !isNaN( Date.parse( valeur ) )
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
/*----------------------------------
|
|
47
|
-
- CONSTRUCTION CHAMP
|
|
48
|
-
----------------------------------*/
|
|
49
|
-
if (prefixe === undefined)
|
|
50
|
-
prefixe = <i src="calendar-alt" />;
|
|
51
|
-
|
|
52
|
-
/*----------------------------------
|
|
53
|
-
- RENDU DU CHAMP
|
|
54
|
-
----------------------------------*/
|
|
55
|
-
return rendre(<>
|
|
56
|
-
|
|
57
|
-
<Popover
|
|
58
|
-
afficher={affCalendrier}
|
|
59
|
-
fermer={() => setAffCalendrier(false)}
|
|
60
|
-
interactions
|
|
61
|
-
//{...props}
|
|
62
|
-
className={"bloc input-date" + (className ? ' ' + className : '')}
|
|
63
|
-
width={300}
|
|
64
|
-
content={(
|
|
65
|
-
<div>
|
|
66
|
-
<Calendar
|
|
67
|
-
minDate={min ? new Date(min) : maintenant}
|
|
68
|
-
maxDate={max ? new Date(max) : undefined}
|
|
69
|
-
value={saisieValide ? new Date(valeur) : maintenant}
|
|
70
|
-
showDoubleView={false}
|
|
71
|
-
onChange={(val: Date) => {
|
|
72
|
-
setAffCalendrier(false)
|
|
73
|
-
setState({ valeur: val });
|
|
74
|
-
}}
|
|
75
|
-
/>
|
|
76
|
-
</div>
|
|
77
|
-
)}
|
|
78
|
-
>
|
|
79
|
-
<input
|
|
80
|
-
className="champ"
|
|
81
|
-
value={saisieValide ? dayjs(valeur).format('DD/MM/YYYY') : valeur}
|
|
82
|
-
onChange={(e) => setState({ valeur: e.target.value })}
|
|
83
|
-
onFocus={() => setAffCalendrier(true)}
|
|
84
|
-
placeholder='DD/MM/YYYY'
|
|
85
|
-
readOnly
|
|
86
|
-
/>
|
|
87
|
-
</Popover>
|
|
88
|
-
|
|
89
|
-
</>, { prefixe }); // Les propétés modifiées sont passées ici
|
|
90
|
-
})
|