lupine.api 1.1.58 → 1.1.59

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 (137) hide show
  1. package/README.md +3 -3
  2. package/admin/admin-about.tsx +12 -16
  3. package/admin/admin-config.tsx +47 -44
  4. package/admin/admin-css.tsx +3 -3
  5. package/admin/admin-db.tsx +75 -75
  6. package/admin/admin-frame-helper.tsx +364 -364
  7. package/admin/admin-frame.tsx +164 -164
  8. package/admin/admin-index.tsx +65 -65
  9. package/admin/admin-login.tsx +111 -111
  10. package/admin/admin-menu-edit.tsx +637 -637
  11. package/admin/admin-menu-list.tsx +87 -87
  12. package/admin/admin-page-edit.tsx +564 -564
  13. package/admin/admin-page-list.tsx +83 -83
  14. package/admin/admin-performance.tsx +28 -28
  15. package/admin/admin-release.tsx +427 -426
  16. package/admin/admin-resources.tsx +382 -382
  17. package/admin/admin-shell.tsx +89 -89
  18. package/admin/admin-table-data.tsx +146 -146
  19. package/admin/admin-table-list.tsx +230 -230
  20. package/admin/admin-test-animations.tsx +395 -395
  21. package/admin/admin-test-component.tsx +823 -808
  22. package/admin/admin-test-edit.tsx +319 -319
  23. package/admin/admin-test-themes.tsx +56 -56
  24. package/admin/admin-tokens.tsx +338 -338
  25. package/admin/design/admin-design.tsx +174 -174
  26. package/admin/design/block-grid.tsx +36 -36
  27. package/admin/design/block-grid1.tsx +21 -21
  28. package/admin/design/block-paragraph.tsx +19 -19
  29. package/admin/design/block-title.tsx +19 -19
  30. package/admin/design/design-block-box.tsx +140 -140
  31. package/admin/design/drag-data.tsx +24 -24
  32. package/admin/index.ts +9 -9
  33. package/admin/package.json +15 -15
  34. package/admin/tsconfig.json +127 -127
  35. package/dev/copy-folder.js +32 -32
  36. package/dev/cp-index-html.js +69 -69
  37. package/dev/file-utils.js +12 -12
  38. package/dev/index.js +18 -19
  39. package/dev/package.json +12 -12
  40. package/dev/plugin-ifelse.js +168 -168
  41. package/dev/plugin-ifelse.test.js +37 -37
  42. package/dev/run-cmd.js +14 -14
  43. package/dev/send-request.js +12 -12
  44. package/package.json +55 -55
  45. package/src/admin-api/admin-api-helper.ts +210 -205
  46. package/src/admin-api/admin-api.ts +65 -65
  47. package/src/admin-api/admin-auth.ts +152 -146
  48. package/src/admin-api/admin-config.ts +94 -84
  49. package/src/admin-api/admin-csv.ts +94 -94
  50. package/src/admin-api/admin-db.ts +269 -269
  51. package/src/admin-api/admin-menu.ts +135 -135
  52. package/src/admin-api/admin-page.ts +135 -135
  53. package/src/admin-api/admin-performance.ts +128 -128
  54. package/src/admin-api/admin-release.ts +703 -700
  55. package/src/admin-api/admin-resources.ts +318 -318
  56. package/src/admin-api/admin-token-helper.ts +82 -79
  57. package/src/admin-api/admin-tokens.ts +90 -90
  58. package/src/admin-api/index.ts +2 -2
  59. package/src/admin-api/web-config-api.ts +19 -19
  60. package/src/api/api-cache.ts +103 -103
  61. package/src/api/api-helper.ts +44 -44
  62. package/src/api/api-module.ts +67 -60
  63. package/src/api/api-router.ts +177 -177
  64. package/src/api/api-shared-storage.ts +64 -64
  65. package/src/api/async-storage.ts +5 -5
  66. package/src/api/debug-service.ts +56 -56
  67. package/src/api/encode-html.ts +27 -27
  68. package/src/api/handle-status.ts +75 -75
  69. package/src/api/index.ts +15 -16
  70. package/src/api/mini-web-socket.ts +270 -270
  71. package/src/api/server-content-type.ts +82 -82
  72. package/src/api/server-render.ts +235 -215
  73. package/src/api/shell-service.ts +74 -74
  74. package/src/api/simple-storage.ts +80 -80
  75. package/src/api/static-server.ts +128 -125
  76. package/src/api/to-client-delivery.ts +26 -26
  77. package/src/app/app-cache.ts +55 -55
  78. package/src/app/app-helper.ts +62 -62
  79. package/src/app/app-message.ts +109 -109
  80. package/src/app/app-shared-storage.ts +363 -363
  81. package/src/app/app-start.ts +136 -136
  82. package/src/app/cleanup-exit.ts +16 -16
  83. package/src/app/host-to-path.ts +38 -38
  84. package/src/app/index.ts +11 -11
  85. package/src/app/process-dev-requests.ts +130 -130
  86. package/src/app/web-listener.ts +294 -294
  87. package/src/app/web-processor.ts +47 -42
  88. package/src/app/web-server.ts +100 -100
  89. package/src/common-js/web-env.js +104 -104
  90. package/src/index.ts +7 -7
  91. package/src/lang/api-lang-en.ts +26 -26
  92. package/src/lang/api-lang-zh-cn.ts +27 -27
  93. package/src/lang/index.ts +2 -2
  94. package/src/lang/lang-helper.ts +76 -76
  95. package/src/lang/lang-props.ts +6 -6
  96. package/src/lib/db/db-helper.ts +23 -23
  97. package/src/lib/db/db-mysql.ts +249 -250
  98. package/src/lib/db/db-sqlite.ts +101 -101
  99. package/src/lib/db/db.spec.ts +28 -28
  100. package/src/lib/db/db.ts +325 -325
  101. package/src/lib/db/index.ts +5 -5
  102. package/src/lib/index.ts +3 -3
  103. package/src/lib/logger.spec.ts +214 -214
  104. package/src/lib/logger.ts +281 -281
  105. package/src/lib/runtime-require.ts +37 -37
  106. package/src/lib/utils/cookie-util.ts +34 -34
  107. package/src/lib/utils/crypto.ts +58 -58
  108. package/src/lib/utils/date-utils.ts +317 -317
  109. package/src/lib/utils/deep-merge.ts +37 -37
  110. package/src/lib/utils/delay.ts +12 -12
  111. package/src/lib/utils/file-setting.ts +55 -55
  112. package/src/lib/utils/format-bytes.ts +11 -11
  113. package/src/lib/utils/fs-utils.ts +158 -158
  114. package/src/lib/utils/get-env.ts +27 -27
  115. package/src/lib/utils/index.ts +12 -12
  116. package/src/lib/utils/is-type.ts +48 -48
  117. package/src/lib/utils/load-env.ts +14 -14
  118. package/src/lib/utils/pad.ts +6 -6
  119. package/src/models/api-base.ts +5 -5
  120. package/src/models/api-module-props.ts +10 -11
  121. package/src/models/api-router-props.ts +26 -26
  122. package/src/models/app-cache-props.ts +33 -33
  123. package/src/models/app-data-props.ts +10 -10
  124. package/src/models/app-helper-props.ts +6 -6
  125. package/src/models/app-shared-storage-props.ts +38 -38
  126. package/src/models/app-start-props.ts +18 -18
  127. package/src/models/async-storage-props.ts +13 -13
  128. package/src/models/db-config.ts +30 -30
  129. package/src/models/host-to-path-props.ts +12 -12
  130. package/src/models/index.ts +16 -16
  131. package/src/models/json-object.ts +8 -8
  132. package/src/models/locals-props.ts +36 -36
  133. package/src/models/logger-props.ts +84 -84
  134. package/src/models/simple-storage-props.ts +13 -14
  135. package/src/models/to-client-delivery-props.ts +6 -6
  136. package/tsconfig.json +115 -115
  137. package/dev/plugin-gen-versions.js +0 -20
@@ -1,319 +1,319 @@
1
- import {
2
- CssProps,
3
- RefProps,
4
- EditableLabel,
5
- HtmlVar,
6
- ModalWindow,
7
- NotificationColor,
8
- NotificationMessage,
9
- PagingLink,
10
- ToggleBaseHookProps,
11
- ToggleSwitch,
12
- ToggleSwitchSize,
13
- } from 'lupine.components';
14
-
15
- type SampleDataProps = {
16
- id: number;
17
- name: string;
18
- info: string;
19
- checked: boolean;
20
- };
21
- const _DEFAULT_PAGE_LIMIT = 10;
22
- const _DEFAULT_ITEM_COUNT = 101;
23
- const sampleData: SampleDataProps[] = Array.from({ length: _DEFAULT_ITEM_COUNT }, (_, i) => ({
24
- id: i + 1,
25
- name: `Book Name ${i + 1}`,
26
- info: `This is the info field ${i + 1}`,
27
- checked: true,
28
- }));
29
- const getSampleData = (pageIndex = 0, searchTexts: string[] = []) => {
30
- const filterItems = sampleData.filter((item) =>
31
- searchTexts.every(
32
- (text) =>
33
- item.name.toLowerCase().includes(text.toLowerCase()) || item.info.toLowerCase().includes(text.toLowerCase())
34
- )
35
- );
36
- const pageLimit = _DEFAULT_PAGE_LIMIT;
37
- const itemsCount = filterItems.length;
38
- let maxPages = Math.floor(itemsCount / pageLimit);
39
- if (itemsCount % pageLimit !== 0) {
40
- maxPages++;
41
- }
42
- if (pageIndex > maxPages) {
43
- pageIndex = maxPages - 1;
44
- }
45
- const offset = pageIndex * pageLimit;
46
- return {
47
- status: 'ok',
48
- itemsCount,
49
- pageIndex,
50
- result: filterItems.slice(offset, offset + pageLimit),
51
- };
52
- };
53
- const removeSampleData = (itemId: number) => {
54
- const index = sampleData.findIndex((item) => item.id === itemId);
55
- if (index !== -1) {
56
- sampleData.splice(index, 1);
57
- }
58
- };
59
- const updateSampleData = (item: SampleDataProps) => {
60
- const index = sampleData.findIndex((i) => i.id === item.id);
61
- if (index !== -1) {
62
- sampleData[index] = { ...item };
63
- } else {
64
- // it's a new record
65
- let newId = sampleData.length + 1;
66
- while (sampleData.some((item) => item.id === newId)) {
67
- newId++;
68
- }
69
- item.id = newId;
70
- sampleData.push({ ...item });
71
- }
72
- return item;
73
- };
74
-
75
- type SampleDataUpdateProps = {
76
- save?: () => SampleDataProps | null;
77
- cancel?: () => void;
78
- };
79
- // show dialog to edit one item, and call update when save the result
80
- const showBookEditItem = async (item: SampleDataProps, update: (item: SampleDataProps) => void) => {
81
- const handleClicked = async (index: number) => {
82
- if (index === 1) {
83
- updateFn.cancel?.();
84
- modalClose();
85
- }
86
- if (index === 0) {
87
- const newItem = updateFn.save?.();
88
- if (newItem) {
89
- update(newItem);
90
- modalClose();
91
- }
92
- }
93
- };
94
- const updateFn: SampleDataUpdateProps = {};
95
- const modalClose = await ModalWindow.show({
96
- title: 'Edit Sample Data',
97
- buttons: ['Save', 'Cancel'],
98
- // contentMaxHeight: '400px',
99
- handleClicked,
100
- children: <BookEditItem item={item} update={updateFn}></BookEditItem>,
101
- closeWhenClickOutside: false,
102
- });
103
- };
104
-
105
- // edit one item
106
- export const BookEditItem = (props: { item: SampleDataProps; update: SampleDataUpdateProps }) => {
107
- const ref: RefProps = { id: '' };
108
- const css: CssProps = {
109
- padding: '10px',
110
- border: 'solid 1px gray',
111
- margin: '1px',
112
- position: 'relative',
113
- '.lable': {
114
- width: '70px',
115
- },
116
- };
117
- props.update.save = () => {
118
- const name = ref.$('input.name').value;
119
- const info = ref.$('input.info').value;
120
- if (name && info) {
121
- const newItem = updateSampleData({ id: props.item.id, name, info, checked: switchUpdate.getChecked!() });
122
- props.item.name = newItem.name;
123
- props.item.info = newItem.info;
124
- props.item.checked = newItem.checked;
125
- props.item.id = newItem.id;
126
- return newItem;
127
- }
128
- NotificationMessage.sendMessage('Please input name and info', NotificationColor.Error);
129
- return null;
130
- };
131
- const switchUpdate: ToggleBaseHookProps = {};
132
- return (
133
- <div ref={ref} css={css} class='sample-data'>
134
- <div class='row-box'>
135
- <div class='lable'>Name: </div>
136
- <div>
137
- <input type='text' class='input-base name' value={props.item.name} />
138
- </div>
139
- </div>
140
- <div class='row-box mt-m'>
141
- <div class='lable'>Info: </div>
142
- <div>
143
- <input type='text' class='input-base info' value={props.item.info} />
144
- </div>
145
- </div>
146
- <div class='row-box mt-m'>
147
- <div class='lable'>Checked: </div>
148
- <ToggleSwitch size={ToggleSwitchSize.Small} hook={switchUpdate} checked={props.item.checked} />
149
- </div>
150
- </div>
151
- );
152
- };
153
-
154
- // show one item
155
- export const BookShowItem = (props: { item: SampleDataProps }) => {
156
- const ref: RefProps = { id: '' };
157
- const css: CssProps = {
158
- padding: '10px',
159
- border: 'solid 1px gray',
160
- margin: '1px',
161
- position: 'relative',
162
- '.control-box': {
163
- display: 'none',
164
- position: 'absolute',
165
- right: '10px',
166
- top: '10px',
167
- },
168
- '&:hover .control-box': {
169
- display: 'block',
170
- },
171
- '.lable': {
172
- width: '70px',
173
- },
174
- };
175
- const onEdit = (ev: any) => {
176
- const update = (item: SampleDataProps) => {
177
- dom.value = makeDom(item);
178
- };
179
- showBookEditItem(props.item, update);
180
- };
181
- const onRemove = (ev: any) => {
182
- removeSampleData(props.item.id);
183
- ref.current.remove();
184
- };
185
-
186
- const makeDom = (item: SampleDataProps) => {
187
- const saveText = (text: string) => {
188
- item.name = text;
189
- updateSampleData(item);
190
- dom.value = makeDom(item);
191
- };
192
- return (
193
- <>
194
- <div class='control-box'>
195
- <button class='button-base button-ss' onClick={onEdit}>
196
- Edit
197
- </button>
198
- <button class='button-base button-ss' onClick={onRemove}>
199
- Delete
200
- </button>
201
- </div>
202
- <div class='row-box'>
203
- <div class='lable'>Name: </div>
204
- <div>{item.name}</div>
205
- <div class='px-m'>Double Click to edit: </div>
206
- <EditableLabel text={item.name} save={saveText} type='text' />
207
- </div>
208
- <div class='row-box'>
209
- <div class='lable'>Info: </div>
210
- <div>{item.info}</div>
211
- </div>
212
- <div class='row-box'>
213
- <div class='lable'>Checked: </div>
214
- <div>{item.checked ? 'Yes' : 'No'}</div>
215
- </div>
216
- </>
217
- );
218
- };
219
-
220
- const dom = new HtmlVar(makeDom(props.item));
221
- return (
222
- <div ref={ref} css={css} class='sample-data'>
223
- {dom.node}
224
- </div>
225
- );
226
- };
227
-
228
- // show the list
229
- export const BookList = () => {
230
- let currentIndex = 0;
231
- let searchTexts: string[] = [];
232
- let items = getSampleData(currentIndex, searchTexts);
233
- const ref: RefProps = { onLoad: async (self: Element) => {} };
234
- const onAdd = async () => {
235
- const update = (item: SampleDataProps) => {
236
- // new item is added at the list end, so update the last page
237
- currentIndex = Math.floor((items.itemsCount + 1) / _DEFAULT_PAGE_LIMIT);
238
- listDom.value = makeList(currentIndex);
239
- };
240
- showBookEditItem(
241
- {
242
- id: -1,
243
- name: '',
244
- info: '',
245
- checked: false,
246
- },
247
- update
248
- );
249
- };
250
- const onSearch = () => {
251
- searchTexts = ref.$('input.search').value.trim().split(' ');
252
- items = getSampleData(currentIndex, searchTexts);
253
- listDom.value = makeList(currentIndex);
254
- };
255
- const makeList = (pageIndex: number) => {
256
- const onLinkClick = (index: number) => {
257
- currentIndex = index;
258
- listDom.value = makeList(currentIndex);
259
- };
260
- const items = getSampleData(pageIndex, searchTexts);
261
- return (
262
- <div>
263
- <PagingLink
264
- itemsCount={items.itemsCount}
265
- pageIndex={pageIndex}
266
- pageLimit={_DEFAULT_PAGE_LIMIT}
267
- onClick={onLinkClick}
268
- baseLink=''
269
- ></PagingLink>
270
- {items.result.map((item) => (
271
- <BookShowItem item={item}></BookShowItem>
272
- ))}
273
- <PagingLink
274
- itemsCount={items.itemsCount}
275
- pageIndex={pageIndex}
276
- pageLimit={_DEFAULT_PAGE_LIMIT}
277
- onClick={onLinkClick}
278
- baseLink=''
279
- ></PagingLink>
280
- </div>
281
- );
282
- };
283
- const listDom = new HtmlVar(makeList(currentIndex));
284
- const css: CssProps = {
285
- display: 'flex',
286
- flexDirection: 'column',
287
- '.label': {
288
- width: '70px',
289
- },
290
- };
291
- return (
292
- <div ref={ref} css={css}>
293
- <div>
294
- <div class='row-box'>
295
- <div class='label'>Search: </div>
296
- <input type='text' class='input-base search' />
297
- <button class='button-base mr-s' onClick={onSearch}>
298
- Search
299
- </button>
300
- <button class='button-base' onClick={onAdd}>
301
- Add
302
- </button>
303
- </div>
304
- </div>
305
- <div class='list'>{listDom.node}</div>
306
- </div>
307
- );
308
- };
309
-
310
- export const AdminTestEditPage = () => {
311
- return (
312
- <div>
313
- <div>
314
- <div>Test editing.</div>
315
- <BookList />
316
- </div>
317
- </div>
318
- );
319
- };
1
+ import {
2
+ CssProps,
3
+ RefProps,
4
+ EditableLabel,
5
+ HtmlVar,
6
+ ModalWindow,
7
+ NotificationColor,
8
+ NotificationMessage,
9
+ PagingLink,
10
+ ToggleBaseHookProps,
11
+ ToggleSwitch,
12
+ ToggleSwitchSize,
13
+ } from 'lupine.components';
14
+
15
+ type SampleDataProps = {
16
+ id: number;
17
+ name: string;
18
+ info: string;
19
+ checked: boolean;
20
+ };
21
+ const _DEFAULT_PAGE_LIMIT = 10;
22
+ const _DEFAULT_ITEM_COUNT = 101;
23
+ const sampleData: SampleDataProps[] = Array.from({ length: _DEFAULT_ITEM_COUNT }, (_, i) => ({
24
+ id: i + 1,
25
+ name: `Book Name ${i + 1}`,
26
+ info: `This is the info field ${i + 1}`,
27
+ checked: true,
28
+ }));
29
+ const getSampleData = (pageIndex = 0, searchTexts: string[] = []) => {
30
+ const filterItems = sampleData.filter((item) =>
31
+ searchTexts.every(
32
+ (text) =>
33
+ item.name.toLowerCase().includes(text.toLowerCase()) || item.info.toLowerCase().includes(text.toLowerCase())
34
+ )
35
+ );
36
+ const pageLimit = _DEFAULT_PAGE_LIMIT;
37
+ const itemsCount = filterItems.length;
38
+ let maxPages = Math.floor(itemsCount / pageLimit);
39
+ if (itemsCount % pageLimit !== 0) {
40
+ maxPages++;
41
+ }
42
+ if (pageIndex > maxPages) {
43
+ pageIndex = maxPages - 1;
44
+ }
45
+ const offset = pageIndex * pageLimit;
46
+ return {
47
+ status: 'ok',
48
+ itemsCount,
49
+ pageIndex,
50
+ result: filterItems.slice(offset, offset + pageLimit),
51
+ };
52
+ };
53
+ const removeSampleData = (itemId: number) => {
54
+ const index = sampleData.findIndex((item) => item.id === itemId);
55
+ if (index !== -1) {
56
+ sampleData.splice(index, 1);
57
+ }
58
+ };
59
+ const updateSampleData = (item: SampleDataProps) => {
60
+ const index = sampleData.findIndex((i) => i.id === item.id);
61
+ if (index !== -1) {
62
+ sampleData[index] = { ...item };
63
+ } else {
64
+ // it's a new record
65
+ let newId = sampleData.length + 1;
66
+ while (sampleData.some((item) => item.id === newId)) {
67
+ newId++;
68
+ }
69
+ item.id = newId;
70
+ sampleData.push({ ...item });
71
+ }
72
+ return item;
73
+ };
74
+
75
+ type SampleDataUpdateProps = {
76
+ save?: () => SampleDataProps | null;
77
+ cancel?: () => void;
78
+ };
79
+ // show dialog to edit one item, and call update when save the result
80
+ const showBookEditItem = async (item: SampleDataProps, update: (item: SampleDataProps) => void) => {
81
+ const handleClicked = async (index: number) => {
82
+ if (index === 1) {
83
+ updateFn.cancel?.();
84
+ modalClose();
85
+ }
86
+ if (index === 0) {
87
+ const newItem = updateFn.save?.();
88
+ if (newItem) {
89
+ update(newItem);
90
+ modalClose();
91
+ }
92
+ }
93
+ };
94
+ const updateFn: SampleDataUpdateProps = {};
95
+ const modalClose = await ModalWindow.show({
96
+ title: 'Edit Sample Data',
97
+ buttons: ['Save', 'Cancel'],
98
+ // contentMaxHeight: '400px',
99
+ handleClicked,
100
+ children: <BookEditItem item={item} update={updateFn}></BookEditItem>,
101
+ closeWhenClickOutside: false,
102
+ });
103
+ };
104
+
105
+ // edit one item
106
+ export const BookEditItem = (props: { item: SampleDataProps; update: SampleDataUpdateProps }) => {
107
+ const ref: RefProps = { id: '' };
108
+ const css: CssProps = {
109
+ padding: '10px',
110
+ border: 'solid 1px gray',
111
+ margin: '1px',
112
+ position: 'relative',
113
+ '.lable': {
114
+ width: '70px',
115
+ },
116
+ };
117
+ props.update.save = () => {
118
+ const name = ref.$('input.name').value;
119
+ const info = ref.$('input.info').value;
120
+ if (name && info) {
121
+ const newItem = updateSampleData({ id: props.item.id, name, info, checked: switchUpdate.getChecked!() });
122
+ props.item.name = newItem.name;
123
+ props.item.info = newItem.info;
124
+ props.item.checked = newItem.checked;
125
+ props.item.id = newItem.id;
126
+ return newItem;
127
+ }
128
+ NotificationMessage.sendMessage('Please input name and info', NotificationColor.Error);
129
+ return null;
130
+ };
131
+ const switchUpdate: ToggleBaseHookProps = {};
132
+ return (
133
+ <div ref={ref} css={css} class='sample-data'>
134
+ <div class='row-box'>
135
+ <div class='lable'>Name: </div>
136
+ <div>
137
+ <input type='text' class='input-base name' value={props.item.name} />
138
+ </div>
139
+ </div>
140
+ <div class='row-box mt-m'>
141
+ <div class='lable'>Info: </div>
142
+ <div>
143
+ <input type='text' class='input-base info' value={props.item.info} />
144
+ </div>
145
+ </div>
146
+ <div class='row-box mt-m'>
147
+ <div class='lable'>Checked: </div>
148
+ <ToggleSwitch size={ToggleSwitchSize.Small} hook={switchUpdate} checked={props.item.checked} />
149
+ </div>
150
+ </div>
151
+ );
152
+ };
153
+
154
+ // show one item
155
+ export const BookShowItem = (props: { item: SampleDataProps }) => {
156
+ const ref: RefProps = { id: '' };
157
+ const css: CssProps = {
158
+ padding: '10px',
159
+ border: 'solid 1px gray',
160
+ margin: '1px',
161
+ position: 'relative',
162
+ '.control-box': {
163
+ display: 'none',
164
+ position: 'absolute',
165
+ right: '10px',
166
+ top: '10px',
167
+ },
168
+ '&:hover .control-box': {
169
+ display: 'block',
170
+ },
171
+ '.lable': {
172
+ width: '70px',
173
+ },
174
+ };
175
+ const onEdit = (ev: any) => {
176
+ const update = (item: SampleDataProps) => {
177
+ dom.value = makeDom(item);
178
+ };
179
+ showBookEditItem(props.item, update);
180
+ };
181
+ const onRemove = (ev: any) => {
182
+ removeSampleData(props.item.id);
183
+ ref.current.remove();
184
+ };
185
+
186
+ const makeDom = (item: SampleDataProps) => {
187
+ const saveText = (text: string) => {
188
+ item.name = text;
189
+ updateSampleData(item);
190
+ dom.value = makeDom(item);
191
+ };
192
+ return (
193
+ <>
194
+ <div class='control-box'>
195
+ <button class='button-base button-ss' onClick={onEdit}>
196
+ Edit
197
+ </button>
198
+ <button class='button-base button-ss' onClick={onRemove}>
199
+ Delete
200
+ </button>
201
+ </div>
202
+ <div class='row-box'>
203
+ <div class='lable'>Name: </div>
204
+ <div>{item.name}</div>
205
+ <div class='px-m'>Double Click to edit: </div>
206
+ <EditableLabel text={item.name} save={saveText} type='text' />
207
+ </div>
208
+ <div class='row-box'>
209
+ <div class='lable'>Info: </div>
210
+ <div>{item.info}</div>
211
+ </div>
212
+ <div class='row-box'>
213
+ <div class='lable'>Checked: </div>
214
+ <div>{item.checked ? 'Yes' : 'No'}</div>
215
+ </div>
216
+ </>
217
+ );
218
+ };
219
+
220
+ const dom = new HtmlVar(makeDom(props.item));
221
+ return (
222
+ <div ref={ref} css={css} class='sample-data'>
223
+ {dom.node}
224
+ </div>
225
+ );
226
+ };
227
+
228
+ // show the list
229
+ export const BookList = () => {
230
+ let currentIndex = 0;
231
+ let searchTexts: string[] = [];
232
+ let items = getSampleData(currentIndex, searchTexts);
233
+ const ref: RefProps = { onLoad: async (self: Element) => {} };
234
+ const onAdd = async () => {
235
+ const update = (item: SampleDataProps) => {
236
+ // new item is added at the list end, so update the last page
237
+ currentIndex = Math.floor((items.itemsCount + 1) / _DEFAULT_PAGE_LIMIT);
238
+ listDom.value = makeList(currentIndex);
239
+ };
240
+ showBookEditItem(
241
+ {
242
+ id: -1,
243
+ name: '',
244
+ info: '',
245
+ checked: false,
246
+ },
247
+ update
248
+ );
249
+ };
250
+ const onSearch = () => {
251
+ searchTexts = ref.$('input.search').value.trim().split(' ');
252
+ items = getSampleData(currentIndex, searchTexts);
253
+ listDom.value = makeList(currentIndex);
254
+ };
255
+ const makeList = (pageIndex: number) => {
256
+ const onLinkClick = (index: number) => {
257
+ currentIndex = index;
258
+ listDom.value = makeList(currentIndex);
259
+ };
260
+ const items = getSampleData(pageIndex, searchTexts);
261
+ return (
262
+ <div>
263
+ <PagingLink
264
+ itemsCount={items.itemsCount}
265
+ pageIndex={pageIndex}
266
+ pageLimit={_DEFAULT_PAGE_LIMIT}
267
+ onClick={onLinkClick}
268
+ baseLink=''
269
+ ></PagingLink>
270
+ {items.result.map((item) => (
271
+ <BookShowItem item={item}></BookShowItem>
272
+ ))}
273
+ <PagingLink
274
+ itemsCount={items.itemsCount}
275
+ pageIndex={pageIndex}
276
+ pageLimit={_DEFAULT_PAGE_LIMIT}
277
+ onClick={onLinkClick}
278
+ baseLink=''
279
+ ></PagingLink>
280
+ </div>
281
+ );
282
+ };
283
+ const listDom = new HtmlVar(makeList(currentIndex));
284
+ const css: CssProps = {
285
+ display: 'flex',
286
+ flexDirection: 'column',
287
+ '.label': {
288
+ width: '70px',
289
+ },
290
+ };
291
+ return (
292
+ <div ref={ref} css={css}>
293
+ <div>
294
+ <div class='row-box'>
295
+ <div class='label'>Search: </div>
296
+ <input type='text' class='input-base search' />
297
+ <button class='button-base mr-s' onClick={onSearch}>
298
+ Search
299
+ </button>
300
+ <button class='button-base' onClick={onAdd}>
301
+ Add
302
+ </button>
303
+ </div>
304
+ </div>
305
+ <div class='list'>{listDom.node}</div>
306
+ </div>
307
+ );
308
+ };
309
+
310
+ export const AdminTestEditPage = () => {
311
+ return (
312
+ <div>
313
+ <div>
314
+ <div>Test editing.</div>
315
+ <BookList />
316
+ </div>
317
+ </div>
318
+ );
319
+ };