5htp-core 0.4.5 → 0.4.6
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 +1 -1
- package/src/client/assets/css/components/button.less +4 -3
- package/src/client/assets/css/components/lists.less +12 -18
- package/src/client/assets/css/text/icons.less +5 -5
- package/src/client/assets/css/text/text.less +3 -15
- package/src/client/assets/css/text/titres.less +1 -1
- package/src/client/assets/css/theme.less +2 -2
- package/src/client/components/Dialog/Manager.tsx +3 -1
- package/src/client/components/Form.ts +23 -24
- package/src/client/components/chart/base.tsx +1 -1
- package/src/client/components/containers/Scrollbar/index.less +1 -1
- package/src/client/components/data/progressbar/index.less +1 -1
- package/src/client/components/data/progressbar/index.tsx +3 -3
- package/src/client/components/input/Slider/index.less +1 -1
- package/src/client/components/inputv3/index.tsx +6 -1
- package/src/client/services/router/components/Page.tsx +12 -14
- package/src/client/services/router/index.tsx +15 -2
- package/src/client/services/router/request/api.ts +3 -2
- package/src/common/data/markdown.ts +9 -0
- package/src/server/services/database/index.ts +18 -13
- package/src/server/services/disks/driver.ts +5 -0
- package/src/server/services/disks/drivers/local/index.ts +7 -0
- package/src/server/services/disks/drivers/s3/index.ts +10 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "5htp-core",
|
|
3
3
|
"description": "Convenient TypeScript framework designed for Performance and Productivity.",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.6",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp-core.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
//transition: all .1s linear;
|
|
42
42
|
|
|
43
43
|
> i {
|
|
44
|
-
color: var(--
|
|
44
|
+
color: var(--cTxtAccent)
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -352,7 +352,8 @@ ul.col {
|
|
|
352
352
|
top: @sizeComponent;
|
|
353
353
|
margin-top: @spacing / 2;
|
|
354
354
|
|
|
355
|
-
|
|
355
|
+
// C'est quoi ?
|
|
356
|
+
/*&::before {
|
|
356
357
|
content: ' ';
|
|
357
358
|
display: block;
|
|
358
359
|
position: absolute;
|
|
@@ -362,7 +363,7 @@ ul.col {
|
|
|
362
363
|
right: calc(0em - @spacing);
|
|
363
364
|
|
|
364
365
|
height: 100%;
|
|
365
|
-
}
|
|
366
|
+
}*/
|
|
366
367
|
|
|
367
368
|
}
|
|
368
369
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
- CONFIG
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
|
-
@sizeStep:
|
|
5
|
+
@sizeStep: 1.8em;
|
|
6
6
|
@itemLineHeight: 1.5em;
|
|
7
7
|
|
|
8
8
|
/*----------------------------------
|
|
@@ -22,8 +22,10 @@ ul, ol {
|
|
|
22
22
|
|
|
23
23
|
ul.liste,
|
|
24
24
|
ol.steps {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
gap: 0.5em;
|
|
27
29
|
text-align: left;
|
|
28
30
|
|
|
29
31
|
> li {
|
|
@@ -48,7 +50,7 @@ ul.liste {
|
|
|
48
50
|
&:before {
|
|
49
51
|
content: '➜';
|
|
50
52
|
font-size: 1.4em;
|
|
51
|
-
color: var(--
|
|
53
|
+
color: var(--cTxtAccent);
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
|
|
@@ -87,17 +89,12 @@ ol.steps {
|
|
|
87
89
|
|
|
88
90
|
&:before {
|
|
89
91
|
content: counter(step-counter);
|
|
90
|
-
font-size: 0.8em;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
&.active::before {
|
|
94
|
-
background-color: var(--cAccent);
|
|
95
92
|
}
|
|
96
93
|
|
|
97
94
|
// Stepnumber = at the left
|
|
98
95
|
&:not(.col) {
|
|
99
96
|
|
|
100
|
-
padding-left:
|
|
97
|
+
padding-left: /*@sizeStep + */(@spacing);
|
|
101
98
|
padding-top: (@sizeStep - @itemLineHeight) / 2;
|
|
102
99
|
line-height: @itemLineHeight;
|
|
103
100
|
margin: 5px 0;
|
|
@@ -122,15 +119,12 @@ ol.steps {
|
|
|
122
119
|
|
|
123
120
|
ol.steps > li:before,
|
|
124
121
|
strong.step {
|
|
125
|
-
|
|
126
|
-
background: @c1 + #666;
|
|
127
|
-
color: @c1;
|
|
128
|
-
|
|
122
|
+
color: var(--cTxtAccent);
|
|
129
123
|
text-align: center;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
124
|
+
font-weight: bold;
|
|
125
|
+
|
|
126
|
+
font-size: 1em;
|
|
127
|
+
line-height: 1.8em;
|
|
134
128
|
}
|
|
135
129
|
|
|
136
130
|
/*----------------------------------
|
|
@@ -32,7 +32,7 @@ i {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
&.solid {
|
|
35
|
-
color: var(--
|
|
35
|
+
color: var(--cTxtAccent2);
|
|
36
36
|
background: var(--cBg);
|
|
37
37
|
border-radius: @radius;
|
|
38
38
|
|
|
@@ -74,10 +74,10 @@ i.logo {
|
|
|
74
74
|
line-height: 3.2em;
|
|
75
75
|
flex: 0 0 3.2em;*/
|
|
76
76
|
|
|
77
|
-
width:
|
|
78
|
-
height:
|
|
79
|
-
line-height:
|
|
80
|
-
flex: 0 0
|
|
77
|
+
width: @sizeComponent * 0.9;
|
|
78
|
+
height: @sizeComponent * 0.9;
|
|
79
|
+
line-height: @sizeComponent * 0.9;
|
|
80
|
+
flex: 0 0 @sizeComponent * 0.9;
|
|
81
81
|
|
|
82
82
|
border-radius: @radius;
|
|
83
83
|
border: none; // For img``
|
|
@@ -122,7 +122,7 @@ em {
|
|
|
122
122
|
display: block;
|
|
123
123
|
height: 0.5em;
|
|
124
124
|
border-radius: 0.25em;
|
|
125
|
-
background: var(--
|
|
125
|
+
background: var(--cTxtAccent2);
|
|
126
126
|
|
|
127
127
|
position: absolute;
|
|
128
128
|
z-index: -1;
|
|
@@ -148,22 +148,9 @@ pre {
|
|
|
148
148
|
@readingMargin: 2.4rem;
|
|
149
149
|
.reading {
|
|
150
150
|
|
|
151
|
-
--cTxtBase: #555;
|
|
152
|
-
|
|
153
151
|
display: flex;
|
|
154
152
|
flex-direction: column;
|
|
155
153
|
gap: 1em;
|
|
156
|
-
|
|
157
|
-
p,
|
|
158
|
-
figcaption,
|
|
159
|
-
h2,
|
|
160
|
-
h3,
|
|
161
|
-
> ul {
|
|
162
|
-
max-width: var(--focusWidth);
|
|
163
|
-
margin: 0 auto;
|
|
164
|
-
width: 100%;
|
|
165
|
-
//padding: 0 @readingMargin;
|
|
166
|
-
}
|
|
167
154
|
|
|
168
155
|
&,
|
|
169
156
|
p {
|
|
@@ -175,7 +162,7 @@ pre {
|
|
|
175
162
|
|
|
176
163
|
h2, h3, h4 {
|
|
177
164
|
text-align: left;
|
|
178
|
-
margin:
|
|
165
|
+
margin: 0.5em 0;
|
|
179
166
|
}
|
|
180
167
|
|
|
181
168
|
h2 {
|
|
@@ -215,6 +202,7 @@ pre {
|
|
|
215
202
|
cursor: default;
|
|
216
203
|
display: block;
|
|
217
204
|
margin: 0 auto;
|
|
205
|
+
border-radius: @radius;
|
|
218
206
|
}
|
|
219
207
|
|
|
220
208
|
figcaption {
|
|
@@ -143,7 +143,9 @@ export const createDialog = (app: Application, isToast: boolean): DialogActions
|
|
|
143
143
|
|
|
144
144
|
if (!isToast)
|
|
145
145
|
render = (
|
|
146
|
-
<div class="modal"
|
|
146
|
+
<div class="modal" onClick={e =>
|
|
147
|
+
e.target.classList.contains('modal') && close(false)
|
|
148
|
+
}>
|
|
147
149
|
{render}
|
|
148
150
|
</div>
|
|
149
151
|
)
|
|
@@ -36,7 +36,6 @@ export type Form<TFormData extends {} = {}> = {
|
|
|
36
36
|
fields: FieldsAttrs<TFormData>,
|
|
37
37
|
data: TFormData,
|
|
38
38
|
options: TFormOptions<TFormData>,
|
|
39
|
-
autosavedData?: Partial<TFormData>,
|
|
40
39
|
|
|
41
40
|
// Actions
|
|
42
41
|
validate: (data: Partial<TFormData>) => TValidationResult<{}>,
|
|
@@ -57,7 +56,7 @@ type FormState = {
|
|
|
57
56
|
----------------------------------*/
|
|
58
57
|
export default function useForm<TFormData extends {}>(
|
|
59
58
|
schema: Schema<TFormData>,
|
|
60
|
-
options: TFormOptions<TFormData>
|
|
59
|
+
options: TFormOptions<TFormData> = {}
|
|
61
60
|
): [ Form, FieldsAttrs<TFormData> ] {
|
|
62
61
|
|
|
63
62
|
const context = useContext();
|
|
@@ -66,31 +65,18 @@ export default function useForm<TFormData extends {}>(
|
|
|
66
65
|
- INIT
|
|
67
66
|
----------------------------------*/
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
console.log('[form] Parse autosaved from json:', autosaved);
|
|
76
|
-
autosavedData = JSON.parse(autosaved);
|
|
77
|
-
} catch (error) {
|
|
78
|
-
console.error('[form] Failed to decode autosaved data from json:', autosaved);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
68
|
+
const [state, setState] = React.useState<FormState>({
|
|
69
|
+
hasChanged: options.data !== undefined,
|
|
70
|
+
isLoading: false,
|
|
71
|
+
errorsCount: 0,
|
|
72
|
+
errors: {}
|
|
73
|
+
});
|
|
82
74
|
|
|
83
75
|
const initialData: Partial<TFormData> = options.data || {};
|
|
84
76
|
|
|
85
77
|
// States
|
|
86
78
|
const fields = React.useRef<FieldsAttrs<TFormData> | null>(null);
|
|
87
79
|
const [data, setData] = React.useState< Partial<TFormData> >(initialData);
|
|
88
|
-
const [state, setState] = React.useState<FormState>({
|
|
89
|
-
hasChanged: false,
|
|
90
|
-
isLoading: false,
|
|
91
|
-
errorsCount: 0,
|
|
92
|
-
errors: {}
|
|
93
|
-
});
|
|
94
80
|
|
|
95
81
|
// Validate data when it changes
|
|
96
82
|
React.useEffect(() => {
|
|
@@ -99,8 +85,22 @@ export default function useForm<TFormData extends {}>(
|
|
|
99
85
|
validate(data, false);
|
|
100
86
|
|
|
101
87
|
// Autosave
|
|
102
|
-
if (options.autoSave !== undefined)
|
|
103
|
-
|
|
88
|
+
if (options.autoSave !== undefined) {
|
|
89
|
+
|
|
90
|
+
if (state.hasChanged)
|
|
91
|
+
saveLocally(data, options.autoSave.id);
|
|
92
|
+
else {
|
|
93
|
+
const autosaved = localStorage.getItem('form.' + options.autoSave.id);
|
|
94
|
+
if (autosaved !== null) {
|
|
95
|
+
try {
|
|
96
|
+
console.log('[form] Parse autosaved from json:', autosaved);
|
|
97
|
+
setData( JSON.parse(autosaved) );
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('[form] Failed to decode autosaved data from json:', autosaved);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
104
|
|
|
105
105
|
}, [data]);
|
|
106
106
|
|
|
@@ -235,7 +235,6 @@ export default function useForm<TFormData extends {}>(
|
|
|
235
235
|
validate,
|
|
236
236
|
submit,
|
|
237
237
|
options,
|
|
238
|
-
autosavedData,
|
|
239
238
|
...state
|
|
240
239
|
}
|
|
241
240
|
|
|
@@ -382,7 +382,7 @@ export default function <TDonnee extends DonneesGraph, TTypeChartJs extends Char
|
|
|
382
382
|
|
|
383
383
|
// Default color
|
|
384
384
|
if (!dataset.colonne.color)
|
|
385
|
-
dataset.colonne.color = css.getPropertyValue('--
|
|
385
|
+
dataset.colonne.color = css.getPropertyValue('--cTxtAccent');
|
|
386
386
|
|
|
387
387
|
return {
|
|
388
388
|
label: dataset.colonne.label,
|
|
@@ -39,9 +39,9 @@ const hsl = (h: number, s: number = 80, l: number = 70) => `hsl(${Math.floor(h)}
|
|
|
39
39
|
export const couleurViaPc = (pc: number, couleurs: [number, number], ecart: number) => {
|
|
40
40
|
|
|
41
41
|
return {
|
|
42
|
-
couleur1: 'var(--
|
|
43
|
-
couleur2: 'var(--
|
|
44
|
-
couleurTxt: 'var(--
|
|
42
|
+
couleur1: 'var(--cTxtAccent)',
|
|
43
|
+
couleur2: 'var(--cTxtAccent)',
|
|
44
|
+
couleurTxt: 'var(--cTxtAccent)'
|
|
45
45
|
}
|
|
46
46
|
const [couleurMin, couleurMax] = couleurs;
|
|
47
47
|
const couleur = couleurMin + (pc * (couleurMax - couleurMin));
|
|
@@ -39,6 +39,11 @@ export type Props = {
|
|
|
39
39
|
validator?: ReturnType< SchemaValidators["number"] >,
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
+
type TInputElementProps = Omit<(
|
|
43
|
+
JSX.HTMLAttributes<HTMLInputElement> &
|
|
44
|
+
JSX.HTMLAttributes<HTMLTextAreaElement>
|
|
45
|
+
), 'onChange'>
|
|
46
|
+
|
|
42
47
|
/*----------------------------------
|
|
43
48
|
- COMPOSANT
|
|
44
49
|
----------------------------------*/
|
|
@@ -52,7 +57,7 @@ export default ({
|
|
|
52
57
|
// Actions
|
|
53
58
|
onPressEnter,
|
|
54
59
|
...props
|
|
55
|
-
}: Props & InputBaseProps<string> &
|
|
60
|
+
}: Props & InputBaseProps<string> & TInputElementProps) => {
|
|
56
61
|
|
|
57
62
|
/*----------------------------------
|
|
58
63
|
- INIT
|
|
@@ -21,14 +21,20 @@ export default ({ page }: { page: Page }) => {
|
|
|
21
21
|
----------------------------------*/
|
|
22
22
|
const context = useContext();
|
|
23
23
|
|
|
24
|
-
// Temporary fix: context.page may not be updated at this stage
|
|
25
|
-
// Seems to be the case when we change page, but still same page component with different data
|
|
26
|
-
context.page = page;
|
|
27
|
-
|
|
28
24
|
// Bind data
|
|
29
25
|
const [apiData, setApiData] = React.useState<{[k: string]: any} | null>( page.data || {});
|
|
30
26
|
page.setAllData = setApiData;
|
|
31
|
-
|
|
27
|
+
const fullData = {
|
|
28
|
+
...context.data,
|
|
29
|
+
...apiData
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Temporary fix: context.page may not be updated at this stage
|
|
33
|
+
// Seems to be the case when we change page, but still same page component with different data
|
|
34
|
+
// TODO: ensure these updated are made every tume we change page / context
|
|
35
|
+
context.page = page;
|
|
36
|
+
context.data = fullData;
|
|
37
|
+
context.context = context;
|
|
32
38
|
|
|
33
39
|
// Page component has not changed, but data were updated (ex: url parameters change)
|
|
34
40
|
React.useEffect(() => {
|
|
@@ -43,15 +49,7 @@ export default ({ page }: { page: Page }) => {
|
|
|
43
49
|
// Make request parameters and api data accessible from the page component
|
|
44
50
|
return page.renderer ? (
|
|
45
51
|
|
|
46
|
-
<page.renderer
|
|
47
|
-
// Services
|
|
48
|
-
{...context}
|
|
49
|
-
// API data & URL params
|
|
50
|
-
data={{
|
|
51
|
-
...apiData,
|
|
52
|
-
...context.request.data
|
|
53
|
-
}}
|
|
54
|
-
/>
|
|
52
|
+
<page.renderer {...context} />
|
|
55
53
|
|
|
56
54
|
) : <>Renderer missing</>
|
|
57
55
|
}
|
|
@@ -23,6 +23,7 @@ import { getLayout } from '@common/router/layouts';
|
|
|
23
23
|
import { getRegisterPageArgs, buildRegex } from '@common/router/register';
|
|
24
24
|
import { TFetcherList } from '@common/router/request/api';
|
|
25
25
|
import type { TFrontRenderer } from '@common/router/response/page';
|
|
26
|
+
import Button from '../../components/button';
|
|
26
27
|
|
|
27
28
|
import App from '@client/app/component';
|
|
28
29
|
import type ClientApplication from '@client/app';
|
|
@@ -359,8 +360,20 @@ export default class ClientRouter<
|
|
|
359
360
|
|
|
360
361
|
} catch (e) {
|
|
361
362
|
console.error(`Failed to fetch the route ${route.chunk}`, e);
|
|
362
|
-
|
|
363
|
-
|
|
363
|
+
try {
|
|
364
|
+
this.context.modal.show(() => (
|
|
365
|
+
<div class="card col bg white w-3">
|
|
366
|
+
<h2>New Update Available!</h2>
|
|
367
|
+
<p>
|
|
368
|
+
A new version of the website is available. Please refresh the page to continue.
|
|
369
|
+
</p>
|
|
370
|
+
<Button type="primary" onClick={() => window.location.reload()}>
|
|
371
|
+
Reload
|
|
372
|
+
</Button>
|
|
373
|
+
</div>
|
|
374
|
+
));
|
|
375
|
+
} catch (error) {}
|
|
376
|
+
throw new Error("A new version of the website is available. Please refresh the page.");
|
|
364
377
|
}
|
|
365
378
|
|
|
366
379
|
} else {
|
|
@@ -238,8 +238,9 @@ export default class ApiClient implements ApiClientService {
|
|
|
238
238
|
const error = errorFromJson(errorData);
|
|
239
239
|
throw error;
|
|
240
240
|
}
|
|
241
|
-
|
|
242
|
-
|
|
241
|
+
const json = await response.json() as TData;
|
|
242
|
+
debug && console.log(`[api] Success:`, json);
|
|
243
|
+
return json;
|
|
243
244
|
})
|
|
244
245
|
.catch((error) => {
|
|
245
246
|
if (error instanceof TypeError) {
|
|
@@ -56,6 +56,15 @@ md.block.ruler.after('list', 'test', (state, startLine, endLine, silent) => {
|
|
|
56
56
|
token.attrs[ aIndex ][1] = 'liste'; // replace value of existing attr
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
} else if (token.type === 'ordered_list_open') {
|
|
60
|
+
|
|
61
|
+
const aIndex = token.attrIndex('class');
|
|
62
|
+
if (aIndex < 0) {
|
|
63
|
+
token.attrPush(['class', 'steps']); // add new attribute
|
|
64
|
+
} else {
|
|
65
|
+
token.attrs[ aIndex ][1] = 'steps'; // replace value of existing attr
|
|
66
|
+
}
|
|
67
|
+
|
|
59
68
|
}
|
|
60
69
|
}
|
|
61
70
|
|
|
@@ -442,7 +442,7 @@ export default class SQL extends Service<Config, Hooks, Application, Services> {
|
|
|
442
442
|
// Upsert
|
|
443
443
|
let upsertStatement: string = '';
|
|
444
444
|
if (opts.upsert !== undefined)
|
|
445
|
-
upsertStatement = ' ' + this.buildUpsertStatement<TData>(table, opts as With<TInsertQueryOptions<TData>, 'upsert'>);
|
|
445
|
+
upsertStatement = ' ' + this.buildUpsertStatement<TData>(table, data, opts as With<TInsertQueryOptions<TData>, 'upsert'>);
|
|
446
446
|
|
|
447
447
|
let okPacket: mysql.OkPacket = { ...emptyOkPacket }
|
|
448
448
|
|
|
@@ -501,10 +501,11 @@ export default class SQL extends Service<Config, Hooks, Application, Services> {
|
|
|
501
501
|
|
|
502
502
|
private buildUpsertStatement<TData extends TObjetDonnees>(
|
|
503
503
|
table: TMetasTable,
|
|
504
|
+
data: TData[],
|
|
504
505
|
opts: With<TInsertQueryOptions<TData>, 'upsert'>
|
|
505
506
|
): string {
|
|
506
507
|
|
|
507
|
-
const valuesToUpdate = this.getValuesToUpdate(table, opts.upsert);
|
|
508
|
+
const valuesToUpdate = this.getValuesToUpdate(table, data, opts.upsert);
|
|
508
509
|
|
|
509
510
|
// All columns are ps
|
|
510
511
|
const valuesToUpdatesEntries = Object.entries(valuesToUpdate);
|
|
@@ -519,35 +520,39 @@ export default class SQL extends Service<Config, Hooks, Application, Services> {
|
|
|
519
520
|
// TODO: Fix typings
|
|
520
521
|
private getValuesToUpdate<TData extends TObjetDonnees>(
|
|
521
522
|
table: TMetasTable,
|
|
523
|
+
data: TData[],
|
|
522
524
|
colsToUpdate: TColsToUpsert<TData>
|
|
523
525
|
) {
|
|
524
526
|
|
|
525
527
|
// Column name => SQL
|
|
526
528
|
let valuesToUpdate: Partial<TData> = {};
|
|
527
|
-
|
|
528
529
|
// Define which columns to update when the record already exists
|
|
529
530
|
let valuesNamesToUpdate: (keyof TData)[] = [];
|
|
530
|
-
|
|
531
|
+
let updateAll: boolean | undefined;
|
|
532
|
+
|
|
533
|
+
if (Array.isArray( colsToUpdate )) {
|
|
531
534
|
|
|
532
|
-
valuesNamesToUpdate =
|
|
533
|
-
console.log(LogPrefix, `Automatic upsert into ${table.chemin} using ${table.pk.join(', ')} as pk: ${valuesNamesToUpdate.join(', ')}`);
|
|
534
|
-
// We don't take columnNamesButPk, because if all the columns are pks, we don't have yny value for the ON DUPLICATE KEY
|
|
535
|
-
// Meaning
|
|
535
|
+
valuesNamesToUpdate = colsToUpdate;
|
|
536
536
|
|
|
537
|
-
} else if (
|
|
537
|
+
} else if (colsToUpdate === '*') {
|
|
538
538
|
|
|
539
|
-
|
|
539
|
+
updateAll = true;
|
|
540
540
|
|
|
541
541
|
} else {
|
|
542
542
|
|
|
543
|
-
|
|
543
|
+
let customValuesToUpdate: Partial<TData>;
|
|
544
|
+
({ '*': updateAll, ...customValuesToUpdate } = colsToUpdate);
|
|
544
545
|
|
|
545
546
|
for (const colKey in customValuesToUpdate)
|
|
546
547
|
valuesToUpdate[ colKey ] = this.esc(customValuesToUpdate[ colKey ], true);
|
|
547
548
|
|
|
548
|
-
|
|
549
|
-
valuesNamesToUpdate = Object.keys(table.colonnes);//table.columnNamesButPk;
|
|
549
|
+
}
|
|
550
550
|
|
|
551
|
+
if (updateAll) {
|
|
552
|
+
for (const record of data)
|
|
553
|
+
for (const key in record)
|
|
554
|
+
if (!valuesNamesToUpdate.includes( key ))
|
|
555
|
+
valuesNamesToUpdate.push( key );
|
|
551
556
|
}
|
|
552
557
|
|
|
553
558
|
for (const colToUpdate of valuesNamesToUpdate)
|
|
@@ -59,6 +59,11 @@ export default abstract class FsDriver<
|
|
|
59
59
|
> extends Service<Config, {}, Application, Services> {
|
|
60
60
|
|
|
61
61
|
public abstract mount(): Promise<void>;
|
|
62
|
+
|
|
63
|
+
public abstract getFileUrl(
|
|
64
|
+
bucketName: TBucketName,
|
|
65
|
+
filename: string
|
|
66
|
+
): string;
|
|
62
67
|
|
|
63
68
|
public abstract readDir( bucketName: TBucketName, dirname?: string ): Promise<SourceFile[]>;
|
|
64
69
|
|
|
@@ -72,6 +72,13 @@ export default class LocalFS<
|
|
|
72
72
|
- ACTIONS
|
|
73
73
|
----------------------------------*/
|
|
74
74
|
|
|
75
|
+
public getFileUrl(
|
|
76
|
+
bucketName: TBucketName,
|
|
77
|
+
filename: string
|
|
78
|
+
) {
|
|
79
|
+
throw new Error("Method not available for local files.");
|
|
80
|
+
}
|
|
81
|
+
|
|
75
82
|
public async readDir( bucketName: TBucketName, dirname?: string ) {
|
|
76
83
|
|
|
77
84
|
const bucketDir = this.config.buckets[bucketName];
|
|
@@ -99,6 +99,16 @@ export default class S3Driver<
|
|
|
99
99
|
- ACTIONS
|
|
100
100
|
----------------------------------*/
|
|
101
101
|
|
|
102
|
+
public getFileUrl(
|
|
103
|
+
bucketName: TBucketName,
|
|
104
|
+
filename: string
|
|
105
|
+
) {
|
|
106
|
+
const bucket = this.config.buckets[bucketName];
|
|
107
|
+
if (bucket === undefined)
|
|
108
|
+
throw new Error(`Bucket "${bucketName}" not found in configuration`);
|
|
109
|
+
return `https://${bucket}.s3.${this.config.region}.amazonaws.com/${filename}`
|
|
110
|
+
}
|
|
111
|
+
|
|
102
112
|
public readDir( bucketName: TBucketName, dirname?: string ) {
|
|
103
113
|
const bucket = this.config.buckets[bucketName];
|
|
104
114
|
return new Promise<SourceFile[]>((resolve, reject) => {
|