5htp-core 0.2.6-1 → 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 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.2.6-1",
4
+ "version": "0.2.6-2",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp-core.git",
7
7
  "license": "MIT",
@@ -13,6 +13,7 @@
13
13
  "framework"
14
14
  ],
15
15
  "dependencies": {
16
+ "@wojtekmaj/react-daterange-picker": "^4.2.0",
16
17
  "accepts": "^1.3.7",
17
18
  "activity-detector": "^3.0.0",
18
19
  "ansi-to-html": "^0.7.1",
@@ -93,7 +94,7 @@
93
94
  "@types/yargs-parser": "^21.0.0",
94
95
  "babel-plugin-glob-import": "^0.0.6-2"
95
96
  },
96
- "peerDependencies": {
97
- "5htp": "0.2.3"
98
- }
97
+ "peerDependencies": {
98
+ "5htp": "0.2.3"
99
+ }
99
100
  }
@@ -86,7 +86,7 @@ export default function useForm<TFormData extends {}>(
86
86
 
87
87
  // Autosave
88
88
  if (options.autoSave !== undefined)
89
- saveLocally(data, options.autoSave);
89
+ saveLocally(data, options.autoSave.id);
90
90
 
91
91
  }, [data]);
92
92
 
@@ -134,7 +134,7 @@ export default function useForm<TFormData extends {}>(
134
134
 
135
135
  // Reset autosaved data
136
136
  if (options.autoSave)
137
- localStorage.removeItem(options.autoSave.id);
137
+ localStorage.removeItem('form.' + options.autoSave.id);
138
138
 
139
139
  return submitResult;
140
140
  }
@@ -28,6 +28,7 @@ export { default as CircularProgressbar } from './data/progressbar/circular';
28
28
  export { default as Select } from './Select';
29
29
  export { default as Input } from './inputv3';
30
30
  export { default as File } from './inputv3/file';
31
+ export { default as DateRangeInput } from './inputv3/date';
31
32
 
32
33
  // TOD: fix popover component
33
34
  //export { default as Date } from './input/Date';
@@ -0,0 +1,49 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import React from 'react';
7
+ import type { StateUpdater } from 'preact/hooks';
8
+ import DateRangePicker from '@wojtekmaj/react-daterange-picker/dist/entry.nostyle';
9
+
10
+ // Core
11
+
12
+ // App
13
+
14
+ /*----------------------------------
15
+ - TYPES
16
+ ----------------------------------*/
17
+
18
+ type TValue = [Date, Date]
19
+ export type Props = {
20
+ value: TValue,
21
+ onChange: StateUpdater<TValue>,
22
+ placeholder?: string,
23
+ min?: string,
24
+ max?: string
25
+ }
26
+
27
+ /*----------------------------------
28
+ - COMPOSANT
29
+ ----------------------------------*/
30
+ import './react-calendar.less';
31
+ import './react-daterange-picker.less';
32
+ export default ({ value, Props, min, max, onChange }) => {
33
+
34
+ const state = React.useState(false);
35
+
36
+ /*----------------------------------
37
+ - CONSTRUCTION CHAMP
38
+ ----------------------------------*/
39
+
40
+
41
+ /*----------------------------------
42
+ - RENDU DU CHAMP
43
+ ----------------------------------*/
44
+ return (
45
+ <div>
46
+ <DateRangePicker onChange={onChange} value={value || [null, null]} />
47
+ </div>
48
+ )
49
+ }
@@ -0,0 +1,143 @@
1
+ .react-calendar {
2
+ width: 350px;
3
+ max-width: 100%;
4
+ background: white;
5
+ border: 1px solid #a0a096;
6
+ font-family: Arial, Helvetica, sans-serif;
7
+ line-height: 1.125em;
8
+ }
9
+
10
+ .react-calendar--doubleView {
11
+ width: 700px;
12
+ }
13
+
14
+ .react-calendar--doubleView .react-calendar__viewContainer {
15
+ display: flex;
16
+ margin: -0.5em;
17
+ }
18
+
19
+ .react-calendar--doubleView .react-calendar__viewContainer > * {
20
+ width: 50%;
21
+ margin: 0.5em;
22
+ }
23
+
24
+ .react-calendar,
25
+ .react-calendar *,
26
+ .react-calendar *:before,
27
+ .react-calendar *:after {
28
+ -moz-box-sizing: border-box;
29
+ -webkit-box-sizing: border-box;
30
+ box-sizing: border-box;
31
+ }
32
+
33
+ .react-calendar button {
34
+ margin: 0;
35
+ border: 0;
36
+ outline: none;
37
+ }
38
+
39
+ .react-calendar button:enabled:hover {
40
+ cursor: pointer;
41
+ }
42
+
43
+ .react-calendar__navigation {
44
+ display: flex;
45
+ height: 44px;
46
+ margin-bottom: 1em;
47
+ }
48
+
49
+ .react-calendar__navigation button {
50
+ min-width: 44px;
51
+ background: none;
52
+ }
53
+
54
+ .react-calendar__navigation button:disabled {
55
+ background-color: #f0f0f0;
56
+ }
57
+
58
+ .react-calendar__navigation button:enabled:hover,
59
+ .react-calendar__navigation button:enabled:focus {
60
+ background-color: #e6e6e6;
61
+ }
62
+
63
+ .react-calendar__month-view__weekdays {
64
+ text-align: center;
65
+ text-transform: uppercase;
66
+ font-weight: bold;
67
+ font-size: 0.75em;
68
+ }
69
+
70
+ .react-calendar__month-view__weekdays__weekday {
71
+ padding: 0.5em;
72
+ }
73
+
74
+ .react-calendar__month-view__weekNumbers .react-calendar__tile {
75
+ display: flex;
76
+ align-items: center;
77
+ justify-content: center;
78
+ font-size: 0.75em;
79
+ font-weight: bold;
80
+ }
81
+
82
+ .react-calendar__month-view__days__day--weekend {
83
+ color: #d10000;
84
+ }
85
+
86
+ .react-calendar__month-view__days__day--neighboringMonth {
87
+ color: #757575;
88
+ }
89
+
90
+ .react-calendar__year-view .react-calendar__tile,
91
+ .react-calendar__decade-view .react-calendar__tile,
92
+ .react-calendar__century-view .react-calendar__tile {
93
+ padding: 2em 0.5em;
94
+ }
95
+
96
+ .react-calendar__tile {
97
+ max-width: 100%;
98
+ padding: 10px 6.6667px;
99
+ background: none;
100
+ text-align: center;
101
+ line-height: 16px;
102
+ }
103
+
104
+ .react-calendar__tile:disabled {
105
+ background-color: #f0f0f0;
106
+ }
107
+
108
+ .react-calendar__tile:enabled:hover,
109
+ .react-calendar__tile:enabled:focus {
110
+ background-color: #e6e6e6;
111
+ }
112
+
113
+ .react-calendar__tile--now {
114
+ background: #ffff76;
115
+ }
116
+
117
+ .react-calendar__tile--now:enabled:hover,
118
+ .react-calendar__tile--now:enabled:focus {
119
+ background: #ffffa9;
120
+ }
121
+
122
+ .react-calendar__tile--hasActive {
123
+ background: #76baff;
124
+ }
125
+
126
+ .react-calendar__tile--hasActive:enabled:hover,
127
+ .react-calendar__tile--hasActive:enabled:focus {
128
+ background: #a9d4ff;
129
+ }
130
+
131
+ .react-calendar__tile--active {
132
+ background: #006edc;
133
+ color: white;
134
+ }
135
+
136
+ .react-calendar__tile--active:enabled:hover,
137
+ .react-calendar__tile--active:enabled:focus {
138
+ background: #1087ff;
139
+ }
140
+
141
+ .react-calendar--selectRange .react-calendar__tile--hover {
142
+ background-color: #e6e6e6;
143
+ }
@@ -0,0 +1,112 @@
1
+ .react-daterange-picker {
2
+ display: inline-flex;
3
+ position: relative;
4
+ }
5
+
6
+ .react-daterange-picker,
7
+ .react-daterange-picker *,
8
+ .react-daterange-picker *:before,
9
+ .react-daterange-picker *:after {
10
+ -moz-box-sizing: border-box;
11
+ -webkit-box-sizing: border-box;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ .react-daterange-picker--disabled {
16
+ background-color: #f0f0f0;
17
+ color: #6d6d6d;
18
+ }
19
+
20
+ .react-daterange-picker__wrapper {
21
+ display: flex;
22
+ flex-grow: 1;
23
+ flex-shrink: 0;
24
+ align-items: center;
25
+ border: thin solid gray;
26
+ }
27
+
28
+ .react-daterange-picker__inputGroup {
29
+ min-width: calc((4px * 3) + 0.54em * 8 + 0.217em * 2);
30
+ height: 100%;
31
+ flex-grow: 1;
32
+ padding: 0 2px;
33
+ box-sizing: content-box;
34
+ }
35
+
36
+ .react-daterange-picker__inputGroup__divider {
37
+ padding: 1px 0;
38
+ white-space: pre;
39
+ }
40
+
41
+ .react-daterange-picker__inputGroup__divider,
42
+ .react-daterange-picker__inputGroup__leadingZero {
43
+ display: inline-block;
44
+ }
45
+
46
+ .react-daterange-picker__inputGroup__input {
47
+ min-width: 0.54em;
48
+ height: 100%;
49
+ position: relative;
50
+ padding: 0 1px;
51
+ border: 0;
52
+ background: none;
53
+ font: inherit;
54
+ box-sizing: content-box;
55
+ -webkit-appearance: textfield;
56
+ -moz-appearance: textfield;
57
+ appearance: textfield;
58
+ }
59
+
60
+ .react-daterange-picker__inputGroup__input::-webkit-outer-spin-button,
61
+ .react-daterange-picker__inputGroup__input::-webkit-inner-spin-button {
62
+ -webkit-appearance: none;
63
+ -moz-appearance: none;
64
+ appearance: none;
65
+ margin: 0;
66
+ }
67
+
68
+ .react-daterange-picker__inputGroup__input:invalid {
69
+ background: rgba(255, 0, 0, 0.1);
70
+ }
71
+
72
+ .react-daterange-picker__inputGroup__input--hasLeadingZero {
73
+ margin-left: -0.54em;
74
+ padding-left: calc(1px + 0.54em);
75
+ }
76
+
77
+ .react-daterange-picker__button {
78
+ border: 0;
79
+ background: transparent;
80
+ padding: 4px 6px;
81
+ }
82
+
83
+ .react-daterange-picker__button:enabled {
84
+ cursor: pointer;
85
+ }
86
+
87
+ .react-daterange-picker__button:enabled:hover .react-daterange-picker__button__icon,
88
+ .react-daterange-picker__button:enabled:focus .react-daterange-picker__button__icon {
89
+ stroke: #0078d7;
90
+ }
91
+
92
+ .react-daterange-picker__button:disabled .react-daterange-picker__button__icon {
93
+ stroke: #6d6d6d;
94
+ }
95
+
96
+ .react-daterange-picker__button svg {
97
+ display: inherit;
98
+ }
99
+
100
+ .react-daterange-picker__calendar {
101
+ width: 350px;
102
+ max-width: 100vw;
103
+ z-index: 1;
104
+ }
105
+
106
+ .react-daterange-picker__calendar--closed {
107
+ display: none;
108
+ }
109
+
110
+ .react-daterange-picker__calendar .react-calendar {
111
+ border-width: thin;
112
+ }
@@ -89,16 +89,11 @@ export default class ApiClient implements ApiClientService {
89
89
  fetcher.data = { ...(fetcher.data || {}), ...params };
90
90
 
91
91
  console.log("[api][reload]", id, fetcher.method, fetcher.path, fetcher.data);
92
- const indicator = this.toast.loading("Loading ...");
93
92
 
94
93
  this.fetchAsync(fetcher.method, fetcher.path, fetcher.data).then((data) => {
95
94
 
96
95
  this.set({ [id]: data });
97
96
 
98
- }).finally(() => {
99
-
100
- indicator.close(true);
101
-
102
97
  })
103
98
  }
104
99
  }
@@ -10,18 +10,129 @@ import { FileToUpload } from '@client/components/inputv3/file';
10
10
  - TYPES
11
11
  ----------------------------------*/
12
12
 
13
+ function mergeObjects(object1, object2) {
14
+ return [object1, object2].reduce(function (carry, objectToMerge) {
15
+ Object.keys(objectToMerge).forEach(function (objectKey) {
16
+ carry[objectKey] = objectToMerge[objectKey];
17
+ });
18
+ return carry;
19
+ }, {});
20
+ }
21
+
22
+ function isArray(val) {
23
+
24
+ return ({}).toString.call(val) === '[object Array]';
25
+ }
26
+
27
+ function isJsonObject(val) {
28
+
29
+ return !isArray(val) && typeof val === 'object' && !!val && !(val instanceof Blob) && !(val instanceof Date);
30
+ }
31
+
32
+ function isAppendFunctionPresent(formData) {
33
+
34
+ return typeof formData.append === 'function';
35
+ }
36
+
37
+ function isGlobalFormDataPresent() {
38
+
39
+ return typeof FormData === 'function';
40
+ }
41
+
42
+ function getDefaultFormData() {
43
+
44
+ if (isGlobalFormDataPresent()) {
45
+ return new FormData();
46
+ }
47
+ }
48
+
49
+ function convertRecursively(jsonObject, options, formData, parentKey) {
50
+
51
+ var index = 0;
52
+
53
+ for (var key in jsonObject) {
54
+
55
+ if (jsonObject.hasOwnProperty(key)) {
56
+
57
+ var propName = parentKey || key;
58
+ var value = options.mapping(jsonObject[key]);
59
+
60
+ if (parentKey && isJsonObject(jsonObject)) {
61
+ propName = parentKey + '[' + key + ']';
62
+ }
63
+
64
+ if (parentKey && isArray(jsonObject)) {
65
+
66
+ if (isArray(value) || options.showLeafArrayIndexes ) {
67
+ propName = parentKey + '[' + index + ']';
68
+ } else {
69
+ propName = parentKey + '[]';
70
+ }
71
+ }
72
+
73
+ // Exract the file object from value
74
+ if (typeof value === 'object' && value instanceof FileToUpload)
75
+ value = value.data;
76
+
77
+ if (isArray(value) || isJsonObject(value)) {
78
+
79
+ convertRecursively(value, options, formData, propName);
80
+
81
+ } else if (value instanceof FileList) {
82
+
83
+ for (var j = 0; j < value.length; j++) {
84
+ formData.append(propName + '[' + j + ']', value.item(j));
85
+ }
86
+ } else if (value instanceof Blob) {
87
+
88
+ formData.append(propName, value, value.name);
89
+
90
+ } else if (value instanceof Date) {
91
+
92
+ formData.append(propName, value.toISOString());
93
+
94
+ } else if (((value === null && options.includeNullValues) || value !== null) && value !== undefined) {
95
+
96
+ formData.append(propName, value);
97
+ }
98
+ }
99
+ index++;
100
+ }
101
+ return formData;
102
+ }
103
+
13
104
  /*----------------------------------
14
105
  - UTILS
15
106
  ----------------------------------*/
16
- export const toMultipart = (postData: TPostData) => {
17
-
18
- const formData = new FormData();
19
- for (const key in postData) {
20
- let data = postData[key];
21
- if (typeof data === 'object' && (data instanceof FileToUpload))
22
- data = data.data;
23
- formData.append(key, data);
107
+ /* Based on https://github.com/hyperatom/json-form-data
108
+ Changes:
109
+ - Add support for FileToUpload
110
+ */
111
+ export const toMultipart = (jsonObject: TPostData, options) => {
112
+
113
+ if (options && options.initialFormData) {
114
+
115
+ if (!isAppendFunctionPresent(options.initialFormData)) {
116
+ throw 'initialFormData must have an append function.';
117
+ }
118
+ } else if (!isGlobalFormDataPresent()) {
119
+
120
+ throw 'This environment does not have global form data. options.initialFormData must be specified.';
24
121
  }
25
122
 
26
- return formData;
123
+ var defaultOptions = {
124
+ initialFormData: getDefaultFormData(),
125
+ showLeafArrayIndexes: true,
126
+ includeNullValues: false,
127
+ mapping: function(value) {
128
+ if (typeof value === 'boolean') {
129
+ return +value ? '1': '0';
130
+ }
131
+ return value;
132
+ }
133
+ };
134
+
135
+ var mergedOptions = mergeObjects(defaultOptions, options || {});
136
+
137
+ return convertRecursively(jsonObject, mergedOptions, mergedOptions.initialFormData);
27
138
  }
@@ -196,6 +196,8 @@ export default abstract class Application extends Service<Config, Hooks, /* TODO
196
196
  console.error("Catched error while starting service " + serviceClassName + '. Exiting process if mode production.', e);
197
197
  if (this.env.profile === 'prod')
198
198
  process.exit();
199
+ else
200
+ throw e;
199
201
  })
200
202
  }
201
203
 
@@ -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
- })