iconograph-ui 1.7.19 → 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.
Files changed (93) hide show
  1. package/example/src/routes/{+page.svelte → basic/+page.svelte} +3 -1
  2. package/example/src/routes/{user → basic/user}/+page.svelte +12 -2
  3. package/example/src/routes/parabole/+layout.svelte +111 -0
  4. package/example/src/routes/parabole/+page.svelte +112 -0
  5. package/example/static/css/testapp.css +8 -3
  6. package/example/static/icons/discord-logo-icon.svg +22 -0
  7. package/example/static/icons/icon-add-w.svg +38 -0
  8. package/example/static/icons/icon-archive-black.svg +1 -0
  9. package/example/static/icons/icon-archive-grey.svg +38 -0
  10. package/example/static/icons/icon-beneficiaire-small.svg +50 -0
  11. package/example/static/icons/icon-beneficiaire.svg +48 -0
  12. package/example/static/icons/icon-cardlist-black.svg +56 -0
  13. package/example/static/icons/icon-cardlist-grey.svg +56 -0
  14. package/example/static/icons/icon-client.png +0 -0
  15. package/example/static/icons/icon-dashboard.svg +40 -0
  16. package/example/static/icons/icon-doc.svg +39 -0
  17. package/example/static/icons/icon-done.svg +1 -0
  18. package/example/static/icons/icon-edit-g.svg +61 -0
  19. package/example/static/icons/icon-edit-w.svg +1 -0
  20. package/example/static/icons/icon-info-100.svg +54 -0
  21. package/example/static/icons/icon-info-w.svg +39 -0
  22. package/example/static/icons/icon-kanban-black.svg +65 -0
  23. package/example/static/icons/icon-kanban-grey.svg +65 -0
  24. package/example/static/icons/icon-link.svg +47 -0
  25. package/example/static/icons/icon-list-black.svg +76 -0
  26. package/example/static/icons/icon-list-grey.svg +76 -0
  27. package/example/static/icons/icon-member.png +0 -0
  28. package/example/static/icons/icon-next-w.svg +42 -0
  29. package/example/static/icons/icon-note.svg +44 -0
  30. package/example/static/icons/icon-order.svg +61 -0
  31. package/example/static/icons/icon-out.svg +38 -0
  32. package/example/static/icons/icon-project.svg +39 -0
  33. package/example/static/icons/icon-red-star.svg +53 -0
  34. package/example/static/icons/icon-save-b.png +0 -0
  35. package/example/static/icons/icon-save-w.png +0 -0
  36. package/example/static/icons/icon-task.svg +40 -0
  37. package/example/static/icons/icon-timeline-black.svg +68 -0
  38. package/example/static/icons/icon-timeline-grey.svg +68 -0
  39. package/example/static/icons/icon-user-add.svg +41 -0
  40. package/example/static/icons/icon-user.png +0 -0
  41. package/example/static/icons/icon-user.svg +39 -0
  42. package/example/static/icons/loader-ring-w.svg +1 -0
  43. package/lib/{display → components/display}/Portal.svelte +3 -3
  44. package/lib/{form → components/form}/ActionButton.svelte +53 -18
  45. package/lib/{layout → components/layout}/Card.svelte +2 -1
  46. package/lib/{navigation → components/navigation}/Button.svelte +10 -2
  47. package/lib/{navigation → components/navigation}/MainMenu.svelte +26 -33
  48. package/lib/{navigation → components/navigation}/MenuItem.svelte +8 -7
  49. package/lib/{navigation → components/navigation}/NavBar.svelte +8 -7
  50. package/lib/network/APIErrors.js +51 -0
  51. package/lib/network/action.js +21 -0
  52. package/lib/network/clientFetch.js +50 -0
  53. package/lib/network/index.js +1 -0
  54. package/lib/network/requestApi.js +127 -0
  55. package/lib/network/requestn8n.js +52 -0
  56. package/lib/utils/flattenType.js +8 -0
  57. package/lib/utils/transformers/entityTransformer.js +28 -0
  58. package/lib/utils/transformers/index.js +1 -0
  59. package/lib/utils/transformers/projectTransformer.js +17 -0
  60. package/lib/utils/transformers/userTransformer.js +36 -0
  61. package/package.json +11 -3
  62. /package/example/src/routes/{+layout.svelte → basic/+layout.svelte} +0 -0
  63. /package/example/src/routes/{example → basic/example}/+server.js +0 -0
  64. /package/example/src/routes/{user → basic/user}/+server.js +0 -0
  65. /package/lib/{display → components/display}/DateStr.svelte +0 -0
  66. /package/lib/{display → components/display}/Field.svelte +0 -0
  67. /package/lib/{display → components/display}/Link.svelte +0 -0
  68. /package/lib/{form → components/form}/Checkbox.svelte +0 -0
  69. /package/lib/{form → components/form}/FlexForm.svelte +0 -0
  70. /package/lib/{form → components/form}/Form.svelte +0 -0
  71. /package/lib/{form → components/form}/FormButton.svelte +0 -0
  72. /package/lib/{form → components/form}/Input.svelte +0 -0
  73. /package/lib/{form → components/form}/MultiSelect.svelte +0 -0
  74. /package/lib/{form → components/form}/SegmentedSwitchInput.svelte +0 -0
  75. /package/lib/{form → components/form}/SexeChoiceInput.svelte +0 -0
  76. /package/lib/{inputs → components/form/inputs}/Editor.svelte +0 -0
  77. /package/lib/{inputs → components/form/inputs}/PasswordInput.svelte +0 -0
  78. /package/lib/{inputs → components/form/inputs}/SearchSelect.svelte +0 -0
  79. /package/lib/{layout → components/layout}/BodySection.svelte +0 -0
  80. /package/lib/{layout → components/layout}/HeadSection.svelte +0 -0
  81. /package/lib/{layout → components/layout}/Modal.svelte +0 -0
  82. /package/lib/{layout → components/layout}/SectionContent.svelte +0 -0
  83. /package/lib/{notification → components/notification}/Notification.svelte +0 -0
  84. /package/lib/{notification → components/notification}/NotificationWrapper.svelte +0 -0
  85. /package/lib/{table → components/table}/CellLink.svelte +0 -0
  86. /package/lib/{table → components/table}/Table.svelte +0 -0
  87. /package/lib/{table → components/table}/TableColumnFilter.svelte +0 -0
  88. /package/lib/{table → components/table}/TableFilter.svelte +0 -0
  89. /package/lib/{table → components/table}/TablePagination.svelte +0 -0
  90. /package/lib/{table → components/table}/TableRow.svelte +0 -0
  91. /package/lib/{user → components/user}/SelectUserInput.svelte +0 -0
  92. /package/lib/{user → components/user}/UserPicture.svelte +0 -0
  93. /package/lib/utils/{clickOutside.js → ui/clickOutside.js} +0 -0
@@ -7,6 +7,7 @@
7
7
 
8
8
  export let options = [];
9
9
  export let style = "classic";
10
+ export let outline = false;
10
11
 
11
12
  let open = false;
12
13
  let dropdownEl;
@@ -26,7 +27,7 @@
26
27
 
27
28
  <!-- svelte-ignore a11y_click_events_have_key_events -->
28
29
  <!-- svelte-ignore a11y_no_static_element_interactions -->
29
- <div class="dropdown {open ? 'open' : ''} {style == "icon" ? 'icon' : ''}"
30
+ <div class="dropdown {open ? 'open' : ''} {style == "icon" ? 'icon' : ''} {outline ? 'outline' : '' }"
30
31
  bind:this={dropdownEl} use:clickOutside on:click_outside={() => {open = false}}
31
32
  on:click|preventDefault|stopPropagation={openDropdown}>
32
33
  {#if style == "icon"}
@@ -38,12 +39,16 @@
38
39
  <!-- Liste déroulante -->
39
40
  {#if open}
40
41
  <Portal target="#main-container" position={"top: 0px; right: 0px"}>
41
- <div class="list" style="position: absolute; top:{coords.top + 4}px; right:{coords.right - 14}px; width: {coords.width}px;" >
42
+ <div class="list" style="position: absolute; top:{coords.top + 6}px; right:{coords.right - 0}px; width: {coords.width}px;" >
42
43
  <!-- Options -->
43
44
  {#each options as opt}
44
- <div class="option" on:click={opt.action}>
45
+ {#if opt.separator }
46
+ <hr />
47
+ {:else}
48
+ <div class="option" on:click={opt.action} style:background-image={`url("${opt.icon}")`} >
45
49
  <span>{opt.label}</span>
46
50
  </div>
51
+ {/if}
47
52
  {/each}
48
53
  </div>
49
54
  </Portal>
@@ -67,27 +72,34 @@
67
72
  }
68
73
  .dropdown > div:first-of-type {
69
74
  background-color: var(--theme-input-bg-highlight);
75
+ box-shadow: var(--button-box-shadow);
70
76
  height: 32px;
71
77
  border: none;
72
- border-radius: 8px;
78
+ border-radius: 7px;
73
79
  cursor: pointer;
74
80
  padding: 0px 8px;
75
81
  font-size: 14px;
76
- line-height: 33px;
77
- font-weight: 600;
82
+ line-height: 32px;
83
+ font-weight: 500;
78
84
  font-family: var(--theme-text-font);
79
- color: #333;
85
+ color: #121212;
80
86
  flex: 1;
81
- min-width: 76px;
82
87
  background-size: 14px auto;
83
88
  background-repeat: no-repeat;
84
- background-position: center right 14px;
85
- padding-left: 20px;
86
-
89
+ background-position: center right 12px;
90
+ padding-left: 18px;
91
+ padding-right: 32px;
87
92
  transition: all ease-in-out 0.17s;
88
93
  }
94
+ .dropdown.outline > div:first-of-type {
95
+ height: 30px;
96
+ line-height: 30px;
97
+ border: 1px solid var(--button-border-color);
98
+ background-color: var(--main-bg-color);
99
+ }
89
100
  .dropdown > div:first-of-type:hover {
90
101
  background-color: var(--theme-input-bg-hover);
102
+ box-shadow: var(--button-hover-box-shadow);
91
103
  }
92
104
  .dropdown > div:first-of-type.icon {
93
105
  min-width: 1px;
@@ -99,30 +111,45 @@
99
111
  padding: 0px;
100
112
  height: 32px;
101
113
  }
114
+ .dropdown.outline > div:first-of-type.icon {
115
+ height: 30px;
116
+ line-height: 30px;
117
+ max-width: 30px;
118
+ border: 1px solid var(--button-border-color);
119
+ background-color: var(--main-bg-color);
120
+ }
121
+ .dropdown.outline > div:first-of-type:hover {
122
+ background-color: var(--theme-input-bg-highlight);
123
+ }
102
124
  .list {
103
125
  position: absolute;
104
126
  top: 100%;
105
127
  right: 0px;
106
128
  background: #ffffff; /*var(--theme-input-bg-highlight, #ebebed);*/
107
- border-radius: 8px;
129
+ border-radius: 7px;
108
130
  padding: 8px 0px;
109
131
  max-height: 220px;
110
132
  overflow-y: auto;
111
133
  z-index: 9999;
112
- min-width: 200px;
113
- border: 1px solid #00000012;
114
- box-shadow: #00000012 0 0px 8px;
134
+ min-width: 260px;
135
+ border: 1px solid var(--button-border-color);
136
+ box-shadow: #77777715 0 3px 10px;
115
137
  }
116
138
  .option {
117
139
  display: flex;
118
140
  align-items: center;
119
- padding: 8px 24px;
141
+ padding: 8px 12px 8px 36px;
142
+ margin: 0px 8px;
120
143
  gap: 8px;
121
144
  cursor: pointer;
145
+ border-radius: 5px;
146
+ background-size: 20px auto;
147
+ background-repeat: no-repeat;
148
+ background-position: center left 8px;
122
149
  }
123
150
  .option > span {
124
151
  font-size: 14px;
125
- line-height: 18px;
152
+ line-height: 20px;
126
153
  font-weight: 400;
127
154
  font-family: var(--theme-text-font);
128
155
  color: var(--theme-input-text-color);
@@ -131,6 +158,14 @@
131
158
  text-overflow: ellipsis;
132
159
  }
133
160
  .option:hover {
134
- background: var(--theme-input-bg-highlight);
161
+ background-color: var(--theme-input-bg-color);
162
+ }
163
+ hr {
164
+ color: var(--button-border-color);
165
+ height: 0;
166
+ line-height: 0;
167
+ margin: 7px 12px;
168
+ border-top: 1px solid var(--button-border-color);
169
+ border-bottom: 0px solid var(--button-border-color);
135
170
  }
136
171
  </style>
@@ -12,8 +12,9 @@
12
12
  width: 100%;
13
13
  background-color: var(--main-bg-color);
14
14
  box-sizing: border-box;
15
- border: 1px solid var(--main-border-color);
15
+ border: var(--main-border, 1px solid var(--main-border-color));
16
16
  border-radius: 8px;
17
17
  overflow: hidden;
18
+ box-shadow: var(--main-shadow);
18
19
  }
19
20
  </style>
@@ -34,9 +34,9 @@ a, button {
34
34
  display: inline-block;
35
35
  background-color: var(--theme-main-color);
36
36
  color: #ffffff !important;
37
- /*box-shadow: #000000a0 0px 1px 3px 0px !important;*/
37
+ box-shadow: var(--button-box-shadow);
38
38
  border: 1px solid var(--theme-main-color);
39
- border-radius: 8px;
39
+ border-radius: 7px;
40
40
  height: 30px;
41
41
  line-height: 30px !important;
42
42
  font-size: 13px;
@@ -86,6 +86,14 @@ a:disabled {
86
86
  background-size: 18px;
87
87
  padding-left: 36px;
88
88
  }
89
+ .min {
90
+ min-width: 30px;
91
+ border: 1px solid var(--theme-main-color);
92
+ padding: 0px 0px;
93
+ background-position: center center;
94
+ background-size: 18px;
95
+ padding-left: 0px;
96
+ }
89
97
  .disabled {
90
98
  background-color: #eee;
91
99
  color: #888 !important;
@@ -13,6 +13,8 @@
13
13
  afterUpdate(() => {
14
14
  current_url = $page.url.pathname.split('/');
15
15
  current_url = '/' + current_url[1];
16
+
17
+ console.log(current_url);
16
18
  });
17
19
 
18
20
  </script>
@@ -26,9 +28,12 @@
26
28
  </div>
27
29
  </header>
28
30
 
29
- <div class="logo" >
30
- <!-- Logo -->
31
- </div>
31
+ {#if menu.logo != null}
32
+ <div class="logo" >
33
+ </div>
34
+ {:else}
35
+ <div><h1>Bienvenue</h1></div>
36
+ {/if}
32
37
 
33
38
  <div class="main">
34
39
  <ul>
@@ -53,19 +58,21 @@
53
58
  padding: 14px;
54
59
  position: absolute;
55
60
  top: 10px;
56
- right: -11px;
61
+ /*right: -11px;*/
62
+ left: 20px;
57
63
  z-index: 300;
64
+ margin-bottom: 12px;
58
65
  }
59
66
  header > div {
60
67
  position: absolute;
61
- top: 10px;
68
+ top: 16px;
62
69
  left: 0px;
63
70
  width: 32px;
64
71
  height: 32px;
65
72
  border-radius: 30px;
66
73
  cursor: pointer;
67
- background-color: #fff;
68
- border: 1px solid var(--main-border-color);
74
+ /*background-color: var(--main-menu-bg-color, #ffffff);
75
+ border: 1px solid var(--main-border-color);*/
69
76
  transition: all ease-in-out 0.3s;
70
77
  align-self: flex-end;
71
78
  }
@@ -77,22 +84,22 @@
77
84
  height: 32px;
78
85
  }
79
86
  header > div.menu-open {
80
- background-color: #fff;
87
+ /*background-color: var(--main-menu-bg-color, #ffffff);*/
81
88
  box-shadow: inset;
82
89
  }
83
90
  header > div > div > div{
84
91
  display: inline-block;
85
92
  position: absolute;
86
93
  vertical-align: top;
87
- background-color: #333;
94
+ background-color: #555;
88
95
  border-radius: 0px;
89
- height: 2px;
90
- width: 16px;
96
+ height: 3px;
97
+ width: 25px;
91
98
  transition: all 0.3s;
92
99
  border-radius: 0px;
93
100
  }
94
101
  header > div > div > div:nth-of-type(1){
95
- top: 15px;
102
+ top: 12px;
96
103
  left: 10px;
97
104
  }
98
105
  header > div > div > div:nth-of-type(2){
@@ -100,7 +107,7 @@
100
107
  left: 10px;
101
108
  }
102
109
  header > div > div > div:nth-of-type(3){
103
- top: 24px;
110
+ top: 28px;
104
111
  left: 10px;
105
112
  }
106
113
  header > div.menu-open > div > div:nth-of-type(1){
@@ -115,7 +122,7 @@
115
122
  transform: rotate(-45deg);
116
123
  }
117
124
  nav {
118
- background-color: var(--main-bg-color);
125
+ background-color: var(--main-menu-bg-color, #ffffff);
119
126
  position: fixed;
120
127
  top: 0px;
121
128
  left: 0px;
@@ -124,7 +131,7 @@
124
131
  max-height: 100vh;
125
132
  box-sizing: border-box;
126
133
  border-right: 1px solid var(--main-border-color);
127
- padding-top: 58px;
134
+ padding-top: 80px;
128
135
  padding-bottom: 10px;
129
136
  transition: all ease-in-out 0.4s;
130
137
  display: flex;
@@ -136,23 +143,6 @@
136
143
  transform: translateX(0px);
137
144
  width: 285px;
138
145
  }
139
- nav > .logo {
140
- width: 48px;
141
- height: 40px;
142
- min-height: 40px;
143
- background-image: var(--logo-large);
144
- background-size: auto 32px;
145
- background-repeat: no-repeat;
146
- background-position: 0px center;
147
- margin-bottom: 32px;
148
- margin-left: 17px;
149
- transition: all ease-in-out 0.4s;
150
- }
151
- nav.menu-open > .logo {
152
- width: 248px;
153
- background-size: auto 32px;
154
- background-position: 0px center;
155
- }
156
146
 
157
147
  nav > .main {
158
148
  flex: 1;
@@ -184,12 +174,15 @@
184
174
  width: 285px;
185
175
  }
186
176
  header {
177
+ position: fixed;
187
178
  top: 10px;
188
179
  right: initial;
189
180
  left: 105px;
181
+ transform: translateX(0px);
182
+ transition: all ease-in-out 0.4s;
190
183
  }
191
184
  nav.menu-open > header {
192
- left: 20px;
185
+ transform: translateX(-85px);
193
186
  }
194
187
  header > div {
195
188
  border: none;
@@ -24,7 +24,7 @@
24
24
  li {
25
25
  list-style: none;
26
26
  width: 100%;
27
- margin-bottom: 14px;
27
+ margin-bottom: 2px;
28
28
  }
29
29
 
30
30
  .menu-item {
@@ -68,8 +68,9 @@
68
68
  line-height: 48px;
69
69
  padding-left: 48px;
70
70
  overflow: hidden;
71
- font-weight: 600;
72
- color: var(--theme-text-darkgrey);
71
+ font-weight: var(--main-menu-font-weight, 600);
72
+ font-size: var(--main-menu-font-size);
73
+ color: var(--main-menu-fg-color, --theme-text-darkgrey);
73
74
  font-family: var(--theme-title-font);
74
75
  }
75
76
  .menu-item > div.menu-open > div:nth-of-type(2) {
@@ -78,13 +79,13 @@
78
79
  display: flex;
79
80
  }
80
81
  .menu-item.selected > div > div:nth-of-type(1) {
81
- background-color: var(--theme-main-color);
82
+ background-color: var(--main-menu-fg-color, --theme-main-color);
82
83
  }
83
84
  .menu-item.selected > div > div:nth-of-type(2) {
84
- color: var(--theme-main-color);
85
+ color: var(--main-menu-fg-color, --theme-main-color);
85
86
  }
86
87
  .menu-item:hover > div > div:nth-of-type(2) {
87
- background-color: var(--theme-bg-color-light);
88
- color: var(--theme-main-color);
88
+ background-color: var(--main-menu-bg-hover-color, --theme-bg-color-light);
89
+ color: var(--main-menu-fg-color, --theme-main-color);
89
90
  }
90
91
  </style>
@@ -4,16 +4,17 @@
4
4
  export let tabs;
5
5
  export let currentTab;
6
6
 
7
- /*$: if (currentTab) {
8
- history.replaceState(null, '', `#${currentTab}`);
9
- }*/
10
-
11
- /*onMount(() => {
7
+ onMount(() => {
12
8
  const hash = window.location.hash.replace('#', '');
13
9
 
14
10
  if (hash && Object.keys(tabs).includes(hash))
15
11
  currentTab = hash;
16
- });*/
12
+ });
13
+
14
+ function onChangeTab(key) {
15
+ currentTab = key;
16
+ history.replaceState({}, "", `#${key}`);
17
+ }
17
18
 
18
19
  </script>
19
20
 
@@ -21,7 +22,7 @@
21
22
  {#each Object.keys(tabs) as key}
22
23
  <!-- svelte-ignore a11y_click_events_have_key_events -->
23
24
  <!-- svelte-ignore a11y_no_static_element_interactions -->
24
- <div on:click={() => {currentTab = key}} class="{currentTab == key ? 'selected' : ''}">
25
+ <div on:click={() => {onChangeTab(key)}} class="{currentTab == key ? 'selected' : ''}">
25
26
  {tabs[key]}
26
27
  </div>
27
28
  {/each}
@@ -0,0 +1,51 @@
1
+ // @ts-nocheck
2
+
3
+ export class APIError extends Error {
4
+ constructor(message, statusCode, endpoint, user = null) {
5
+ super(message);
6
+ this.name = 'APIError';
7
+ this.statusCode = statusCode;
8
+ this.endpoint = endpoint;
9
+ this.user = user ? user : { id: null, email: null };
10
+ this.timestamp = new Date();
11
+ }
12
+
13
+ async logError() {
14
+ this.user = this.user.id ? await JSON.parse(this.user) : {};
15
+ console.error(`[${this.timestamp.toISOString()}] ${this.name}: ${this.message} (${this.statusCode}) at ${this.endpoint} - ${this.user.id}`);
16
+ console.trace(`${this.message} (${this.statusCode}) at ${this.endpoint}`);
17
+
18
+ if (this.statusCode != 401) {
19
+ const webhookUrl = "https://discord.com/api/webhooks/1422717261738676244/qZ5jx0uGTmcL2DEH8Kdb0IoerCh6VG27xIyKKJU55XYqwADhXXqM-qlh3E5WZzVH5nuV";
20
+
21
+ let stackTrace = this.stack || "No stack trace available.";
22
+ if (stackTrace.length > 1020)
23
+ stackTrace = stackTrace.slice(0, 1017) + "...";
24
+
25
+ const embed = {
26
+ title: process.env.NODE_ENV == 'development' ? "[DEV] erreur" : "⚠️ Nouvelle erreur détectée",
27
+ color: process.env.NODE_ENV == 'development' ? 0x0000ff : 0xff0000,
28
+ fields: [
29
+ { name: "Message", value: String(this.statusCode) + ' ' + this.message },
30
+ { name: "Endpoint", value: this.endpoint },
31
+ { name: "User", value: this.user.email },
32
+ { name: "Timestamp", value: this.timestamp.toISOString() },
33
+ { name: "Stack Trace", value: "```" + stackTrace + "```" }
34
+ ],
35
+ };
36
+
37
+ try {
38
+ await fetch(webhookUrl, {
39
+ method: "POST",
40
+ headers: { "Content-Type": "application/json" },
41
+ body: JSON.stringify({
42
+ username: "Error Logger",
43
+ embeds: [embed],
44
+ }),
45
+ });
46
+ } catch (err) {
47
+ console.error("Erreur lors de l'envoi au webhook Discord:", err);
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,21 @@
1
+ // @ts-nocheck
2
+ import { json } from '@sveltejs/kit';
3
+ import { requestApi } from './requestApi.js';
4
+
5
+ export async function addActivity(objectId, objectType, type, content, cookies) {
6
+
7
+ const response = await requestApi('POST', '/graphql', {
8
+ query: `mutation {
9
+ createAction (
10
+ objectId: "${objectId}",
11
+ objectType: "${objectType}",
12
+ type: "${type}",
13
+ content: "${encodeURI(content)}"
14
+ ) {
15
+ id
16
+ }
17
+ }`
18
+ }, cookies);
19
+
20
+ return response.data.createAction;
21
+ }
@@ -0,0 +1,50 @@
1
+ // @ts-nocheck
2
+ import { addNotification } from "iconograph-ui";
3
+ import { APIError } from "./APIErrors";
4
+ import { json } from "@sveltejs/kit";
5
+
6
+ export const Notifications = {
7
+ All: 'ALL',
8
+ ErrorsOnly: 'ERROR_ONLY',
9
+ None: 'NONE'
10
+ }
11
+
12
+ export async function clientFetch(method, uri, body, n = Notifications.All) {
13
+ let response;
14
+
15
+ if (method == 'GET' || !body) {
16
+ response = await fetch(uri, {
17
+ method: method,
18
+ headers: { 'Content-Type': 'application/json' }
19
+ });
20
+ }
21
+ else {
22
+ response = await fetch(uri, {
23
+ method: method,
24
+ body: JSON.stringify(body),
25
+ headers: { 'Content-Type': 'application/json' }
26
+ });
27
+ }
28
+
29
+ if (!response.ok && response.status == 401) {
30
+ if (n != Notifications.None)
31
+ addNotification({ 'status': 'failure', 'message': 'Votre session a expiré, veuillez vous reconnecter' });
32
+ return window.location = '/auth/signout?reason=Expired'
33
+ }
34
+ if (!response.ok && response.status == 404 && n != Notifications.None) {
35
+ (new APIError(JSON.stringify(response, null, 4) , response.status, uri, null)).logError();
36
+ return addNotification({ 'status': 'failure', 'message': 'Erreur ' + response.status });
37
+ }
38
+
39
+ const data = await response.json();
40
+
41
+ if (!response.ok && (n === Notifications.ErrorsOnly || n === Notifications.All)) {
42
+ (new APIError(JSON.stringify(data.message, null, 4) , response.status, uri, null)).logError();
43
+ addNotification({ 'status': 'failure', 'message': response.status + ': ' + data.message });
44
+ data.__errors == true;
45
+ }
46
+ else if (method != 'GET' && n == Notifications.All)
47
+ addNotification({ 'status': 'success', 'message': data.message });
48
+
49
+ return data;
50
+ }
@@ -0,0 +1 @@
1
+ export * as network from "./"
@@ -0,0 +1,127 @@
1
+ // @ts-nocheck
2
+ import { error, redirect } from '@sveltejs/kit';
3
+ import { env } from '$env/dynamic/private';
4
+ import { APIError } from './APIErrors';
5
+
6
+ let API_DATA_HOST = process.env.API_DATA_HOST || 'srvc-data';
7
+ let API_DATA_PORT = process.env.API_DATA_PORT || '3030';
8
+
9
+ let API_OIDC_HOST = env.API_OIDC_HOST || 'localhost';
10
+ let API_OIDC_PORT = env.API_OIDC_PORT || '3030';
11
+
12
+ const dev = (!env.NODE_ENV) || env.NODE_ENV === 'development';
13
+
14
+ async function fetchInterceptor(resource, config, cookies, cookieName) {
15
+ try {
16
+ const raw = await fetch(resource, config);
17
+ const text = await raw.text();
18
+ let json;
19
+
20
+ try {
21
+ json = JSON.parse(text);
22
+ }
23
+ catch {
24
+ throw new APIError("Invalid JSON received from API", 502, resource);
25
+ }
26
+
27
+ /*if (response.errors) {
28
+ if (response.errors[0].message == 'Not authenticated') {
29
+
30
+ /*const refreshToken = cookies.get('refreshToken');
31
+ response = await fetch('http://' + API_OIDC_HOST + ':' + API_OIDC_PORT + '/jwks/sign/' + tokenNames[cookieName], {
32
+ method: 'POST',
33
+ body: JSON.stringify({refreshToken: refreshToken}),
34
+ headers: headers,
35
+ });
36
+
37
+ if (!response.ok)
38
+ return response;
39
+
40
+ const data = await response.json();
41
+ cookies.set(cookieName, data.token, {
42
+ path: '/',
43
+ httpOnly: true,
44
+ sameSite: 'lax',
45
+ secure: !dev,
46
+ maxAge: 60 * 100
47
+ });*/
48
+
49
+ // config.headers['Authorization'] = data.token;
50
+ // response = await fetch(resource, config);
51
+
52
+
53
+ return { raw, json };
54
+ }
55
+ catch (e) {
56
+ if (e.message === 'fetch failed') {
57
+ error(501, { message: "Le serveur de données n'est pas disponible (__SRVC_DATACORE_DOWN__)"});
58
+ }
59
+ throw e;
60
+ }
61
+ }
62
+
63
+ export async function request(method, url, body, cookies, cookieName) {
64
+
65
+ const jwt = cookies.get(cookieName);
66
+ const headers = {
67
+ 'Accept': 'application/json',
68
+ 'Content-Type': 'application/json',
69
+ ...(jwt ? { Authorization: 'Bearer ' + jwt } : {})
70
+ };
71
+
72
+ try {
73
+ const { raw, json } = await fetchInterceptor(url, {
74
+ method: method,
75
+ body: (method == 'GET' || method == 'HEAD') ? undefined : JSON.stringify(body),
76
+ headers: headers,
77
+ }, cookies, cookieName);
78
+
79
+ if (json.errors?.length) {
80
+ const msg = json.errors[0].message;
81
+
82
+ switch (msg) {
83
+ case "Not authenticated":
84
+ throw new APIError(msg, 401, url);
85
+ case "Unauthorized":
86
+ throw new APIError(msg, 403, url);
87
+ case "Invalid credentials":
88
+ throw new APIError("Identifiants non valides", 401, url);
89
+ default:
90
+ throw new APIError(msg, 500, url);
91
+ }
92
+ }
93
+
94
+ return json;
95
+ }
96
+ catch (e) {
97
+ throw e;
98
+ }
99
+ }
100
+
101
+ export async function requestApi(method, uri, body, cookies) {
102
+ try {
103
+ return await request(method, 'http://' + API_DATA_HOST + ':' + API_DATA_PORT + uri, body, cookies, 'BibliapediaAccessToken');
104
+ }
105
+ catch (e) {
106
+ if (e instanceof APIError)
107
+ e.logError();
108
+ else
109
+ console.error(e)
110
+
111
+ error(e.statusCode, { message: e.message })
112
+ }
113
+ }
114
+
115
+ export async function loadApi(method, uri, body, cookies) {
116
+ try {
117
+ return await request(method, 'http://' + API_DATA_HOST + ':' + API_DATA_PORT + uri, body, cookies, 'BibliapediaAccessToken');
118
+ }
119
+ catch (e) {
120
+ e.logError();
121
+
122
+ if (e.statusCode == 401)
123
+ return redirect(307, "/auth/signout?reason=Expired");
124
+ else
125
+ error(e.statusCode, { message: e.message })
126
+ }
127
+ }