added ImportPopup
This commit is contained in:
		
							parent
							
								
									93ab5fbea2
								
							
						
					
					
						commit
						4e58e7ad6a
					
				|  | @ -169,6 +169,7 @@ func (api *collectionApi) delete(c echo.Context) error { | ||||||
| 	return handlerErr | 	return handlerErr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // @todo add event
 | ||||||
| func (api *collectionApi) bulkImport(c echo.Context) error { | func (api *collectionApi) bulkImport(c echo.Context) error { | ||||||
| 	form := forms.NewCollectionsImport(api.app) | 	form := forms.NewCollectionsImport(api.app) | ||||||
| 
 | 
 | ||||||
|  | @ -182,5 +183,5 @@ func (api *collectionApi) bulkImport(c echo.Context) error { | ||||||
| 		return rest.NewBadRequestError("Failed to import the submitted collections.", submitErr) | 		return rest.NewBadRequestError("Failed to import the submitted collections.", submitErr) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return c.NoContent(http.StatusNoContent) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| package forms | package forms | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log" | 	"log" | ||||||
| 
 | 
 | ||||||
|  | @ -59,24 +60,8 @@ func (form *CollectionsImport) Submit() error { | ||||||
| 			mappedOldCollections[old.GetId()] = old | 			mappedOldCollections[old.GetId()] = old | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// raw insert/replace (aka. without any validations)
 |  | ||||||
| 		// (required to make sure that all linked collections exists before running the validations)
 |  | ||||||
| 		mappedFormCollections := make(map[string]*models.Collection, len(form.Collections)) | 		mappedFormCollections := make(map[string]*models.Collection, len(form.Collections)) | ||||||
| 		for _, collection := range form.Collections { | 		for _, collection := range form.Collections { | ||||||
| 			if mappedOldCollections[collection.GetId()] == nil { |  | ||||||
| 				collection.MarkAsNew() |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if err := txDao.Save(collection); err != nil { |  | ||||||
| 				if form.app.IsDebug() { |  | ||||||
| 					log.Println("[CollectionsImport] Save failure", collection.Name, err) |  | ||||||
| 				} |  | ||||||
| 				return validation.Errors{"collections": validation.NewError( |  | ||||||
| 					"collections_import_save_failure", |  | ||||||
| 					fmt.Sprintf("Failed to save the imported collection %q (id: %s).", collection.Name, collection.Id), |  | ||||||
| 				)} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			mappedFormCollections[collection.GetId()] = collection | 			mappedFormCollections[collection.GetId()] = collection | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -89,15 +74,33 @@ func (form *CollectionsImport) Submit() error { | ||||||
| 						if form.app.IsDebug() { | 						if form.app.IsDebug() { | ||||||
| 							log.Println("[CollectionsImport] DeleteOthers failure", old.Name, err) | 							log.Println("[CollectionsImport] DeleteOthers failure", old.Name, err) | ||||||
| 						} | 						} | ||||||
| 						return validation.Errors{"deleteOthers": validation.NewError( | 						return validation.Errors{"collections": validation.NewError( | ||||||
| 							"collections_import_collection_delete_failure", | 							"collections_import_collection_delete_failure", | ||||||
| 							fmt.Sprintf("Failed to delete collection %q. Make sure that the collection is not system or referenced by other collections.", old.Name), | 							fmt.Sprintf("Failed to delete collection %q (%s). Make sure that the collection is not system or referenced by other collections.", old.Name, old.Id), | ||||||
| 						)} | 						)} | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		// raw insert/replace (aka. without any validations)
 | ||||||
|  | 		// (required to make sure that all linked collections exists before running the validations)
 | ||||||
|  | 		for _, collection := range form.Collections { | ||||||
|  | 			if mappedOldCollections[collection.GetId()] == nil { | ||||||
|  | 				collection.MarkAsNew() | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if err := txDao.Save(collection); err != nil { | ||||||
|  | 				if form.app.IsDebug() { | ||||||
|  | 					log.Println("[CollectionsImport] Save failure", collection.Name, err) | ||||||
|  | 				} | ||||||
|  | 				return validation.Errors{"collections": validation.NewError( | ||||||
|  | 					"collections_import_save_failure", | ||||||
|  | 					fmt.Sprintf("Integrity constraints failed - the collection %q (%s) cannot be imported.", collection.Name, collection.Id), | ||||||
|  | 				)} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		// refresh the actual persisted collections list
 | 		// refresh the actual persisted collections list
 | ||||||
| 		refreshedCollections := []*models.Collection{} | 		refreshedCollections := []*models.Collection{} | ||||||
| 		if err := txDao.CollectionQuery().All(&refreshedCollections); err != nil { | 		if err := txDao.CollectionQuery().All(&refreshedCollections); err != nil { | ||||||
|  | @ -125,9 +128,13 @@ func (form *CollectionsImport) Submit() error { | ||||||
| 				if form.app.IsDebug() { | 				if form.app.IsDebug() { | ||||||
| 					log.Println("[CollectionsImport] Validate failure", collection.Name, err) | 					log.Println("[CollectionsImport] Validate failure", collection.Name, err) | ||||||
| 				} | 				} | ||||||
|  | 
 | ||||||
|  | 				// serialize the validation error(s)
 | ||||||
|  | 				serializedErr, _ := json.Marshal(err) | ||||||
|  | 
 | ||||||
| 				return validation.Errors{"collections": validation.NewError( | 				return validation.Errors{"collections": validation.NewError( | ||||||
| 					"collections_import_validate_failure", | 					"collections_import_validate_failure", | ||||||
| 					fmt.Sprintf("Integrity check failed - collection %q has invalid data.", collection.Name), | 					fmt.Sprintf("Data validations failed for collection %q (%s): %s", collection.Name, collection.Id, serializedErr), | ||||||
| 				)} | 				)} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -9,7 +9,6 @@ | ||||||
|         "@codemirror/autocomplete": "^6.0.0", |         "@codemirror/autocomplete": "^6.0.0", | ||||||
|         "@codemirror/commands": "^6.0.0", |         "@codemirror/commands": "^6.0.0", | ||||||
|         "@codemirror/lang-javascript": "^6.0.2", |         "@codemirror/lang-javascript": "^6.0.2", | ||||||
|         "@codemirror/lang-json": "^6.0.0", |  | ||||||
|         "@codemirror/language": "^6.0.0", |         "@codemirror/language": "^6.0.0", | ||||||
|         "@codemirror/legacy-modes": "^6.0.0", |         "@codemirror/legacy-modes": "^6.0.0", | ||||||
|         "@codemirror/search": "^6.0.0", |         "@codemirror/search": "^6.0.0", | ||||||
|  | @ -29,8 +28,7 @@ | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "../../js-sdk": { |     "../../js-sdk": { | ||||||
|       "name": "pocketbase", |       "version": "0.3.1", | ||||||
|       "version": "0.3.0", |  | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "devDependencies": { |       "devDependencies": { | ||||||
|  | @ -101,16 +99,6 @@ | ||||||
|         "@lezer/javascript": "^1.0.0" |         "@lezer/javascript": "^1.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@codemirror/lang-json": { |  | ||||||
|       "version": "6.0.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.0.tgz", |  | ||||||
|       "integrity": "sha512-DvTcYTKLmg2viADXlTdufrT334M9jowe1qO02W28nvm+nejcvhM5vot5mE8/kPrxYw/HJHhwu1z2PyBpnMLCNQ==", |  | ||||||
|       "dev": true, |  | ||||||
|       "dependencies": { |  | ||||||
|         "@codemirror/language": "^6.0.0", |  | ||||||
|         "@lezer/json": "^1.0.0" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "node_modules/@codemirror/language": { |     "node_modules/@codemirror/language": { | ||||||
|       "version": "6.2.1", |       "version": "6.2.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz", |       "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz", | ||||||
|  | @ -163,9 +151,9 @@ | ||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "node_modules/@codemirror/view": { |     "node_modules/@codemirror/view": { | ||||||
|       "version": "6.1.4", |       "version": "6.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.1.4.tgz", |       "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.2.0.tgz", | ||||||
|       "integrity": "sha512-pekgUX+0hL4ri2JV7/bu7jhhwOgOhU1eRc1/ZyAQYCWcCI4TPB1qLrPE3cD/qW9yjBcYiN9MN0XI1tjK7Yw05Q==", |       "integrity": "sha512-3emW1symh+GoteFMBPsltjmF790U/trouLILATh3JodbF/z98HvcQh2g3+H6dfNIHx16uNonsAF4mNzVr1TJNA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@codemirror/state": "^6.0.0", |         "@codemirror/state": "^6.0.0", | ||||||
|  | @ -214,16 +202,6 @@ | ||||||
|         "@lezer/lr": "^1.0.0" |         "@lezer/lr": "^1.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@lezer/json": { |  | ||||||
|       "version": "1.0.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz", |  | ||||||
|       "integrity": "sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==", |  | ||||||
|       "dev": true, |  | ||||||
|       "dependencies": { |  | ||||||
|         "@lezer/highlight": "^1.0.0", |  | ||||||
|         "@lezer/lr": "^1.0.0" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "node_modules/@lezer/lr": { |     "node_modules/@lezer/lr": { | ||||||
|       "version": "1.2.1", |       "version": "1.2.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.1.tgz", |       "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.1.tgz", | ||||||
|  | @ -1038,9 +1016,9 @@ | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/sass": { |     "node_modules/sass": { | ||||||
|       "version": "1.54.2", |       "version": "1.54.3", | ||||||
|       "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.2.tgz", |       "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.3.tgz", | ||||||
|       "integrity": "sha512-wbVV26sejsCIbBScZZtNkvnrB/bVCQ8hSlZ01D9nzsVh9zLqCkWrlpvTb3YEb6xsuNi9cx75hncqwikHFSz7tw==", |       "integrity": "sha512-fLodey5Qd41Pxp/Tk7Al97sViYwF/TazRc5t6E65O7JOk4XF8pzwIW7CvCxYVOfJFFI/1x5+elDyBIixrp+zrw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "chokidar": ">=3.0.0 <4.0.0", |         "chokidar": ">=3.0.0 <4.0.0", | ||||||
|  | @ -1232,16 +1210,6 @@ | ||||||
|         "@lezer/javascript": "^1.0.0" |         "@lezer/javascript": "^1.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "@codemirror/lang-json": { |  | ||||||
|       "version": "6.0.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.0.tgz", |  | ||||||
|       "integrity": "sha512-DvTcYTKLmg2viADXlTdufrT334M9jowe1qO02W28nvm+nejcvhM5vot5mE8/kPrxYw/HJHhwu1z2PyBpnMLCNQ==", |  | ||||||
|       "dev": true, |  | ||||||
|       "requires": { |  | ||||||
|         "@codemirror/language": "^6.0.0", |  | ||||||
|         "@lezer/json": "^1.0.0" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "@codemirror/language": { |     "@codemirror/language": { | ||||||
|       "version": "6.2.1", |       "version": "6.2.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz", |       "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz", | ||||||
|  | @ -1294,9 +1262,9 @@ | ||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "@codemirror/view": { |     "@codemirror/view": { | ||||||
|       "version": "6.1.4", |       "version": "6.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.1.4.tgz", |       "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.2.0.tgz", | ||||||
|       "integrity": "sha512-pekgUX+0hL4ri2JV7/bu7jhhwOgOhU1eRc1/ZyAQYCWcCI4TPB1qLrPE3cD/qW9yjBcYiN9MN0XI1tjK7Yw05Q==", |       "integrity": "sha512-3emW1symh+GoteFMBPsltjmF790U/trouLILATh3JodbF/z98HvcQh2g3+H6dfNIHx16uNonsAF4mNzVr1TJNA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "@codemirror/state": "^6.0.0", |         "@codemirror/state": "^6.0.0", | ||||||
|  | @ -1336,16 +1304,6 @@ | ||||||
|         "@lezer/lr": "^1.0.0" |         "@lezer/lr": "^1.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "@lezer/json": { |  | ||||||
|       "version": "1.0.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz", |  | ||||||
|       "integrity": "sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==", |  | ||||||
|       "dev": true, |  | ||||||
|       "requires": { |  | ||||||
|         "@lezer/highlight": "^1.0.0", |  | ||||||
|         "@lezer/lr": "^1.0.0" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "@lezer/lr": { |     "@lezer/lr": { | ||||||
|       "version": "1.2.1", |       "version": "1.2.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.1.tgz", |       "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.1.tgz", | ||||||
|  | @ -1855,9 +1813,9 @@ | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "sass": { |     "sass": { | ||||||
|       "version": "1.54.2", |       "version": "1.54.3", | ||||||
|       "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.2.tgz", |       "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.3.tgz", | ||||||
|       "integrity": "sha512-wbVV26sejsCIbBScZZtNkvnrB/bVCQ8hSlZ01D9nzsVh9zLqCkWrlpvTb3YEb6xsuNi9cx75hncqwikHFSz7tw==", |       "integrity": "sha512-fLodey5Qd41Pxp/Tk7Al97sViYwF/TazRc5t6E65O7JOk4XF8pzwIW7CvCxYVOfJFFI/1x5+elDyBIixrp+zrw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "chokidar": ">=3.0.0 <4.0.0", |         "chokidar": ">=3.0.0 <4.0.0", | ||||||
|  |  | ||||||
|  | @ -1,134 +0,0 @@ | ||||||
| <script> |  | ||||||
|     import { onMount, createEventDispatcher } from "svelte"; |  | ||||||
|     // code mirror imports |  | ||||||
|     // --- |  | ||||||
|     import { |  | ||||||
|         keymap, |  | ||||||
|         highlightSpecialChars, |  | ||||||
|         drawSelection, |  | ||||||
|         dropCursor, |  | ||||||
|         rectangularSelection, |  | ||||||
|         EditorView, |  | ||||||
|         placeholder as placeholderExt, |  | ||||||
|     } from "@codemirror/view"; |  | ||||||
|     import { EditorState, Compartment } from "@codemirror/state"; |  | ||||||
|     import { defaultHighlightStyle, syntaxHighlighting, bracketMatching } from "@codemirror/language"; |  | ||||||
|     import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands"; |  | ||||||
|     import { searchKeymap, highlightSelectionMatches } from "@codemirror/search"; |  | ||||||
|     import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete"; |  | ||||||
|     import { javascript } from "@codemirror/lang-javascript"; |  | ||||||
|     // --- |  | ||||||
| 
 |  | ||||||
|     const dispatch = createEventDispatcher(); |  | ||||||
| 
 |  | ||||||
|     export let value = ""; |  | ||||||
|     export let disabled = false; |  | ||||||
|     export let placeholder = ""; |  | ||||||
|     export let singleLine = false; |  | ||||||
| 
 |  | ||||||
|     let editor; |  | ||||||
|     let container; |  | ||||||
|     let editableCompartment = new Compartment(); |  | ||||||
|     let readOnlyCompartment = new Compartment(); |  | ||||||
|     let placeholderCompartment = new Compartment(); |  | ||||||
| 
 |  | ||||||
|     $: if (editor && typeof disabled !== "undefined") { |  | ||||||
|         editor.dispatch({ |  | ||||||
|             effects: [ |  | ||||||
|                 editableCompartment.reconfigure(EditorView.editable.of(!disabled)), |  | ||||||
|                 readOnlyCompartment.reconfigure(EditorState.readOnly.of(disabled)), |  | ||||||
|             ], |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         triggerNativeChange(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $: if (editor && value != editor.state.doc.toString()) { |  | ||||||
|         editor.dispatch({ |  | ||||||
|             changes: { |  | ||||||
|                 from: 0, |  | ||||||
|                 to: editor.state.doc.length, |  | ||||||
|                 insert: value, |  | ||||||
|             }, |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     $: if (editor && typeof placeholder !== "undefined") { |  | ||||||
|         editor.dispatch({ |  | ||||||
|             effects: [placeholderCompartment.reconfigure(placeholderExt(placeholder))], |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Focus the editor (if inited). |  | ||||||
|     export function focus() { |  | ||||||
|         editor?.focus(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Emulate native change event for the editor container element. |  | ||||||
|     function triggerNativeChange() { |  | ||||||
|         container?.dispatchEvent( |  | ||||||
|             new CustomEvent("change", { |  | ||||||
|                 detail: { value }, |  | ||||||
|                 bubbles: true, |  | ||||||
|             }) |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     onMount(() => { |  | ||||||
|         const submitShortcut = { |  | ||||||
|             key: "Enter", |  | ||||||
|             run: (_) => { |  | ||||||
|                 // trigger submit on enter for singleline input |  | ||||||
|                 if (singleLine) { |  | ||||||
|                     dispatch("submit", value); |  | ||||||
|                 } |  | ||||||
|             }, |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         editor = new EditorView({ |  | ||||||
|             parent: container, |  | ||||||
|             state: EditorState.create({ |  | ||||||
|                 doc: value, |  | ||||||
|                 extensions: [ |  | ||||||
|                     highlightSpecialChars(), |  | ||||||
|                     history(), |  | ||||||
|                     drawSelection(), |  | ||||||
|                     dropCursor(), |  | ||||||
|                     EditorState.allowMultipleSelections.of(true), |  | ||||||
|                     syntaxHighlighting(defaultHighlightStyle, { fallback: true }), |  | ||||||
|                     bracketMatching(), |  | ||||||
|                     closeBrackets(), |  | ||||||
|                     rectangularSelection(), |  | ||||||
|                     highlightSelectionMatches(), |  | ||||||
|                     keymap.of([ |  | ||||||
|                         submitShortcut, |  | ||||||
|                         indentWithTab, |  | ||||||
|                         ...closeBracketsKeymap, |  | ||||||
|                         ...defaultKeymap, |  | ||||||
|                         ...searchKeymap, |  | ||||||
|                         ...historyKeymap, |  | ||||||
|                     ]), |  | ||||||
|                     EditorView.lineWrapping, |  | ||||||
|                     javascript(), |  | ||||||
|                     placeholderCompartment.of(placeholderExt(placeholder)), |  | ||||||
|                     editableCompartment.of(EditorView.editable.of(true)), |  | ||||||
|                     readOnlyCompartment.of(EditorState.readOnly.of(false)), |  | ||||||
|                     EditorState.transactionFilter.of((tr) => { |  | ||||||
|                         return singleLine && tr.newDoc.lines > 1 ? [] : tr; |  | ||||||
|                     }), |  | ||||||
|                     EditorView.updateListener.of((v) => { |  | ||||||
|                         if (!v.docChanged || disabled) { |  | ||||||
|                             return; |  | ||||||
|                         } |  | ||||||
|                         value = v.state.doc.toString(); |  | ||||||
|                         triggerNativeChange(); |  | ||||||
|                     }), |  | ||||||
|                 ], |  | ||||||
|             }), |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         return () => editor?.destroy(); |  | ||||||
|     }); |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| <div bind:this={container} class="code-editor" /> |  | ||||||
|  | @ -1,352 +0,0 @@ | ||||||
| <script> |  | ||||||
|     import ApiClient from "@/utils/ApiClient"; |  | ||||||
|     import CommonHelper from "@/utils/CommonHelper"; |  | ||||||
|     import Field from "@/components/base/Field.svelte"; |  | ||||||
|     import CodeBlock from "@/components/base/CodeBlock.svelte"; |  | ||||||
|     import { onMount } from "svelte"; |  | ||||||
| 
 |  | ||||||
|     const uniqueId = "exports_" + CommonHelper.randomString(5); |  | ||||||
| 
 |  | ||||||
|     let collections = []; |  | ||||||
|     let isLoadingCollections = false; |  | ||||||
| 
 |  | ||||||
|     loadCollections(); |  | ||||||
| 
 |  | ||||||
|     async function loadCollections() { |  | ||||||
|         isLoadingCollections = true; |  | ||||||
| 
 |  | ||||||
|         try { |  | ||||||
|             collections = await ApiClient.collections.getFullList(100, { |  | ||||||
|                 $cancelKey: uniqueId, |  | ||||||
|             }); |  | ||||||
|         } catch (err) { |  | ||||||
|             ApiClient.errorResponseHandler(err); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         isLoadingCollections = false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     let oldSchema = ""; |  | ||||||
|     let newSchema = ""; |  | ||||||
| 
 |  | ||||||
|     function diff_prettyHtml(diffs, showInsert) { |  | ||||||
|         const html = []; |  | ||||||
|         const pattern_amp = /&/g; |  | ||||||
|         const pattern_lt = /</g; |  | ||||||
|         const pattern_gt = />/g; |  | ||||||
|         const pattern_para = /\n/g; |  | ||||||
|         for (let x = 0; x < diffs.length; x++) { |  | ||||||
|             let op = diffs[x][0]; // Operation (insert, delete, equal) |  | ||||||
|             let data = diffs[x][1]; // Text of change. |  | ||||||
|             let text = data |  | ||||||
|                 .replace(pattern_amp, "&") |  | ||||||
|                 .replace(pattern_lt, "<") |  | ||||||
|                 .replace(pattern_gt, ">") |  | ||||||
|                 .replace(pattern_para, "<br>"); |  | ||||||
|             // text = CommonHelper.stripTags(text); |  | ||||||
|             switch (op) { |  | ||||||
|                 case DIFF_INSERT: |  | ||||||
|                     if (showInsert) { |  | ||||||
|                         html[x] = '<ins class="block">' + text + "</ins>"; |  | ||||||
|                     } |  | ||||||
|                     break; |  | ||||||
|                 case DIFF_DELETE: |  | ||||||
|                     if (!showInsert) { |  | ||||||
|                         html[x] = '<del class="block">' + text + "</del>"; |  | ||||||
|                     } |  | ||||||
|                     break; |  | ||||||
|                 case DIFF_EQUAL: |  | ||||||
|                     html[x] = "<span>" + text + "</span>"; |  | ||||||
|                     break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return html.join(""); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     onMount(() => { |  | ||||||
|         var dmp = new diff_match_patch(); |  | ||||||
|         const text1 = [ |  | ||||||
|             { |  | ||||||
|                 id: "zwWlxR46txtoAwx", |  | ||||||
|                 created: "2022-08-01 17:32:24.329", |  | ||||||
|                 updated: "2022-08-04 10:19:57.248", |  | ||||||
|                 name: "profia sdles", |  | ||||||
|                 system: true, |  | ||||||
|                 listRule: "userId = @request.user.id", |  | ||||||
|                 viewRule: "userId = @request.user.id", |  | ||||||
|                 createRule: "userId = @request.user.id", |  | ||||||
|                 updateRule: "userId = @request.user.id", |  | ||||||
|                 deleteRule: null, |  | ||||||
|                 schema: [ |  | ||||||
|                     { |  | ||||||
|                         id: "nsght7oy", |  | ||||||
|                         name: "userId", |  | ||||||
|                         type: "user", |  | ||||||
|                         system: true, |  | ||||||
|                         required: true, |  | ||||||
|                         unique: true, |  | ||||||
|                         options: { |  | ||||||
|                             maxSelect: 1, |  | ||||||
|                             cascadeDelete: true, |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                     { |  | ||||||
|                         id: "atpc4yjm", |  | ||||||
|                         name: "name", |  | ||||||
|                         type: "text", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: false, |  | ||||||
|                         options: { |  | ||||||
|                             min: null, |  | ||||||
|                             max: null, |  | ||||||
|                             pattern: "", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                     { |  | ||||||
|                         id: "akb4s9de", |  | ||||||
|                         name: "avatar", |  | ||||||
|                         type: "file", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: false, |  | ||||||
|                         options: { |  | ||||||
|                             maxSelect: 1, |  | ||||||
|                             maxSize: 5242880, |  | ||||||
|                             mimeTypes: ["image/jpg", "image/jpeg", "image/png", "image/svg+xml", "image/gif"], |  | ||||||
|                             thumbs: null, |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                 ], |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 id: "IV8FbE78jmXF56d", |  | ||||||
|                 created: "", |  | ||||||
|                 updated: "2022-08-04 10:21:54.100", |  | ||||||
|                 name: "abc", |  | ||||||
|                 system: false, |  | ||||||
|                 listRule: null, |  | ||||||
|                 viewRule: null, |  | ||||||
|                 createRule: null, |  | ||||||
|                 updateRule: null, |  | ||||||
|                 deleteRule: null, |  | ||||||
|                 schema: [ |  | ||||||
|                     { |  | ||||||
|                         id: "t2pukeas", |  | ||||||
|                         name: "demo", |  | ||||||
|                         type: "text", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: false, |  | ||||||
|                         options: { |  | ||||||
|                             min: null, |  | ||||||
|                             max: null, |  | ||||||
|                             pattern: "", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                     { |  | ||||||
|                         id: "dddddd", |  | ||||||
|                         name: "aaaa", |  | ||||||
|                         type: "text", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: false, |  | ||||||
|                         options: { |  | ||||||
|                             min: null, |  | ||||||
|                             max: null, |  | ||||||
|                             pattern: "", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                     { |  | ||||||
|                         id: "squmamtm", |  | ||||||
|                         name: "test", |  | ||||||
|                         type: "date", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: false, |  | ||||||
|                         options: { |  | ||||||
|                             min: "", |  | ||||||
|                             max: "", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                 ], |  | ||||||
|             }, |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         const text2 = [ |  | ||||||
|             { |  | ||||||
|                 id: "zwWlxR46txtoAwx", |  | ||||||
|                 created: "2022-08-01 17:32:24.329", |  | ||||||
|                 updated: "2022-08-04 10:19:57.248", |  | ||||||
|                 name: "Demo", |  | ||||||
|                 system: true, |  | ||||||
|                 listRule: "userId = @request.user.id", |  | ||||||
|                 viewRule: "userId = @request.user.id", |  | ||||||
|                 createRule: "userId = @request.user.id", |  | ||||||
|                 updateRule: "userId = @request.user.id", |  | ||||||
|                 deleteRule: null, |  | ||||||
|                 schema: [ |  | ||||||
|                     { |  | ||||||
|                         id: "nsght7oy", |  | ||||||
|                         name: "userId", |  | ||||||
|                         type: "user", |  | ||||||
|                         system: true, |  | ||||||
|                         required: true, |  | ||||||
|                         unique: true, |  | ||||||
|                         options: { |  | ||||||
|                             maxSelect: 1, |  | ||||||
|                             cascadeDelete: true, |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                     { |  | ||||||
|                         id: "atpc4yjm", |  | ||||||
|                         name: "name", |  | ||||||
|                         type: "text", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: false, |  | ||||||
|                         options: { |  | ||||||
|                             min: null, |  | ||||||
|                             max: null, |  | ||||||
|                             pattern: "", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                     { |  | ||||||
|                         id: "akb4s9de", |  | ||||||
|                         name: "avatar", |  | ||||||
|                         type: "file", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: true, |  | ||||||
|                         options: { |  | ||||||
|                             maxSelect: 1, |  | ||||||
|                             maxSize: 5242880, |  | ||||||
|                             mimeTypes: ["image/jpg", "image/jpeg", "image/png", "image/svg+xml", "image/gif"], |  | ||||||
|                             thumbs: null, |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                 ], |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 id: "IV8FbE78jmXF56d", |  | ||||||
|                 created: "", |  | ||||||
|                 updated: "2022-08-04 10:21:54.100", |  | ||||||
|                 name: "abc", |  | ||||||
|                 system: false, |  | ||||||
|                 listRule: null, |  | ||||||
|                 viewRule: null, |  | ||||||
|                 createRule: null, |  | ||||||
|                 updateRule: null, |  | ||||||
|                 deleteRule: null, |  | ||||||
|                 schema: [ |  | ||||||
|                     { |  | ||||||
|                         id: "t2pukeas", |  | ||||||
|                         name: "demo", |  | ||||||
|                         type: "text", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: false, |  | ||||||
|                         options: { |  | ||||||
|                             min: null, |  | ||||||
|                             max: null, |  | ||||||
|                             pattern: "", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                     { |  | ||||||
|                         id: "dddddd", |  | ||||||
|                         name: "aaaa", |  | ||||||
|                         type: "text", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: false, |  | ||||||
|                         options: { |  | ||||||
|                             min: null, |  | ||||||
|                             max: null, |  | ||||||
|                             pattern: "", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                     { |  | ||||||
|                         id: "squmamtm", |  | ||||||
|                         name: "test", |  | ||||||
|                         type: "date", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: false, |  | ||||||
|                         options: { |  | ||||||
|                             min: "", |  | ||||||
|                             max: "", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                 ], |  | ||||||
|             }, |  | ||||||
|             { |  | ||||||
|                 id: "GGACt8sa1tcJp7T", |  | ||||||
|                 created: "2022-08-04 10:22:15.871", |  | ||||||
|                 updated: "2022-08-04 10:22:15.871", |  | ||||||
|                 name: "asdasd", |  | ||||||
|                 system: true, |  | ||||||
|                 listRule: null, |  | ||||||
|                 viewRule: null, |  | ||||||
|                 createRule: null, |  | ||||||
|                 updateRule: null, |  | ||||||
|                 deleteRule: null, |  | ||||||
|                 schema: [ |  | ||||||
|                     { |  | ||||||
|                         id: "0eklwfvl", |  | ||||||
|                         name: "field", |  | ||||||
|                         type: "text", |  | ||||||
|                         system: false, |  | ||||||
|                         required: false, |  | ||||||
|                         unique: false, |  | ||||||
|                         options: { |  | ||||||
|                             min: null, |  | ||||||
|                             max: null, |  | ||||||
|                             pattern: "", |  | ||||||
|                         }, |  | ||||||
|                     }, |  | ||||||
|                 ], |  | ||||||
|             }, |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         // var diffs = dmp.diff_main(JSON.stringify(text1, null, 2), JSON.stringify(text2, null, 2)); |  | ||||||
| 
 |  | ||||||
|         var a = dmp.diff_linesToChars_(JSON.stringify(text1, null, 2), JSON.stringify(text2, null, 2)); |  | ||||||
|         var lineText1 = a.chars1; |  | ||||||
|         var lineText2 = a.chars2; |  | ||||||
|         var lineArray = a.lineArray; |  | ||||||
|         var diffs = dmp.diff_main(lineText1, lineText2, false); |  | ||||||
|         dmp.diff_charsToLines_(diffs, lineArray); |  | ||||||
| 
 |  | ||||||
|         oldSchema = diff_prettyHtml(diffs, false); |  | ||||||
|         newSchema = diff_prettyHtml(diffs, true); |  | ||||||
|     }); |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| <br /> |  | ||||||
| <div class="grid"> |  | ||||||
|     <div class="col-6"> |  | ||||||
|         <code> |  | ||||||
|             {@html oldSchema} |  | ||||||
|         </code> |  | ||||||
|     </div> |  | ||||||
|     <div class="col-6"> |  | ||||||
|         <code> |  | ||||||
|             {@html newSchema} |  | ||||||
|         </code> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| 
 |  | ||||||
| <style lang="scss"> |  | ||||||
|     .collections-list { |  | ||||||
|         column-count: 2; |  | ||||||
|         column-gap: var(--baseSpacing); |  | ||||||
|     } |  | ||||||
|     code { |  | ||||||
|         display: block; |  | ||||||
|         width: 100%; |  | ||||||
|         overflow: auto; |  | ||||||
|         padding: var(--xsSpacing); |  | ||||||
|         white-space: pre; |  | ||||||
|         background: var(--baseAlt1Color); |  | ||||||
|     } |  | ||||||
| </style> |  | ||||||
|  | @ -1,29 +0,0 @@ | ||||||
| <script> |  | ||||||
|     import OverlayPanel from "@/components/base/OverlayPanel.svelte"; |  | ||||||
|     import CollectionsExportForm from "@/components/collections/CollectionsExportForm.svelte"; |  | ||||||
| 
 |  | ||||||
|     let overlayPanel; |  | ||||||
| 
 |  | ||||||
|     export function show() { |  | ||||||
|         return overlayPanel?.show(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     export function hide() { |  | ||||||
|         return overlayPanel?.hide(); |  | ||||||
|     } |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| <OverlayPanel |  | ||||||
|     bind:this={overlayPanel} |  | ||||||
|     class="overlay-panel-xl collections-export-panel" |  | ||||||
|     on:hide |  | ||||||
|     on:show |  | ||||||
|     popup |  | ||||||
|     active |  | ||||||
| > |  | ||||||
|     <svelte:fragment slot="header"> |  | ||||||
|         <h4>Export collections schema</h4> |  | ||||||
|     </svelte:fragment> |  | ||||||
| 
 |  | ||||||
|     <CollectionsExportForm /> |  | ||||||
| </OverlayPanel> |  | ||||||
|  | @ -13,7 +13,6 @@ | ||||||
|     import CollectionsSidebar from "@/components/collections/CollectionsSidebar.svelte"; |     import CollectionsSidebar from "@/components/collections/CollectionsSidebar.svelte"; | ||||||
|     import CollectionUpsertPanel from "@/components/collections/CollectionUpsertPanel.svelte"; |     import CollectionUpsertPanel from "@/components/collections/CollectionUpsertPanel.svelte"; | ||||||
|     import CollectionDocsPanel from "@/components/collections/docs/CollectionDocsPanel.svelte"; |     import CollectionDocsPanel from "@/components/collections/docs/CollectionDocsPanel.svelte"; | ||||||
|     import CollectionsExportPanel from "@/components/collections/CollectionsExportPanel.svelte"; |  | ||||||
|     import RecordUpsertPanel from "@/components/records/RecordUpsertPanel.svelte"; |     import RecordUpsertPanel from "@/components/records/RecordUpsertPanel.svelte"; | ||||||
|     import RecordsList from "@/components/records/RecordsList.svelte"; |     import RecordsList from "@/components/records/RecordsList.svelte"; | ||||||
| 
 | 
 | ||||||
|  | @ -21,7 +20,6 @@ | ||||||
| 
 | 
 | ||||||
|     const queryParams = new URLSearchParams($querystring); |     const queryParams = new URLSearchParams($querystring); | ||||||
| 
 | 
 | ||||||
|     let collectionsExportPanel; |  | ||||||
|     let collectionUpsertPanel; |     let collectionUpsertPanel; | ||||||
|     let collectionDocsPanel; |     let collectionDocsPanel; | ||||||
|     let recordPanel; |     let recordPanel; | ||||||
|  | @ -132,8 +130,6 @@ | ||||||
|     </main> |     </main> | ||||||
| {/if} | {/if} | ||||||
| 
 | 
 | ||||||
| <CollectionsExportPanel bind:this={collectionsExportPanel} /> |  | ||||||
| 
 |  | ||||||
| <CollectionUpsertPanel bind:this={collectionUpsertPanel} /> | <CollectionUpsertPanel bind:this={collectionUpsertPanel} /> | ||||||
| 
 | 
 | ||||||
| <CollectionDocsPanel bind:this={collectionDocsPanel} /> | <CollectionDocsPanel bind:this={collectionDocsPanel} /> | ||||||
|  |  | ||||||
|  | @ -1,17 +1,19 @@ | ||||||
| <script> | <script> | ||||||
|  |     import { createEventDispatcher } from "svelte"; | ||||||
|  |     import ApiClient from "@/utils/ApiClient"; | ||||||
|     import OverlayPanel from "@/components/base/OverlayPanel.svelte"; |     import OverlayPanel from "@/components/base/OverlayPanel.svelte"; | ||||||
|  |     import { addSuccessToast } from "@/stores/toasts"; | ||||||
| 
 | 
 | ||||||
|     export let title = "Side-by-side diff"; |     const dispatch = createEventDispatcher(); | ||||||
|     export let contentATitle = "Old state"; |  | ||||||
|     export let contentBTitle = "New state"; |  | ||||||
| 
 | 
 | ||||||
|     let panel; |     let panel; | ||||||
|     let contentA = ""; |     let oldCollections = []; | ||||||
|     let contentB = ""; |     let newCollections = []; | ||||||
|  |     let isImporting = false; | ||||||
| 
 | 
 | ||||||
|     export function show(a, b) { |     export function show(a, b) { | ||||||
|         contentA = a; |         oldCollections = a; | ||||||
|         contentB = b; |         newCollections = b; | ||||||
| 
 | 
 | ||||||
|         panel?.show(); |         panel?.show(); | ||||||
|     } |     } | ||||||
|  | @ -20,7 +22,7 @@ | ||||||
|         return panel?.hide(); |         return panel?.hide(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function diffsToHtml(diffs, ops = [DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL]) { |     function diffsToHtml(diffs, ops = [window.DIFF_INSERT, window.DIFF_DELETE, window.DIFF_EQUAL]) { | ||||||
|         const html = []; |         const html = []; | ||||||
|         const pattern_amp = /&/g; |         const pattern_amp = /&/g; | ||||||
|         const pattern_lt = /</g; |         const pattern_lt = /</g; | ||||||
|  | @ -56,35 +58,66 @@ | ||||||
|         return html.join(""); |         return html.join(""); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function diff(ops = [DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL]) { |     function diff(ops = [window.DIFF_INSERT, window.DIFF_DELETE, window.DIFF_EQUAL]) { | ||||||
|         const dmp = new diff_match_patch(); |         const dmp = new diff_match_patch(); | ||||||
|         const lines = dmp.diff_linesToChars_(contentA, contentB); |         const lines = dmp.diff_linesToChars_( | ||||||
|  |             JSON.stringify(oldCollections, null, 4), | ||||||
|  |             JSON.stringify(newCollections, null, 4) | ||||||
|  |         ); | ||||||
|         const diffs = dmp.diff_main(lines.chars1, lines.chars2, false); |         const diffs = dmp.diff_main(lines.chars1, lines.chars2, false); | ||||||
| 
 | 
 | ||||||
|         dmp.diff_charsToLines_(diffs, lines.lineArray); |         dmp.diff_charsToLines_(diffs, lines.lineArray); | ||||||
| 
 | 
 | ||||||
|         return diffsToHtml(diffs, ops); |         return diffsToHtml(diffs, ops); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     async function submitImport() { | ||||||
|  |         if (isImporting) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         isImporting = true; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             await ApiClient.collections.import(newCollections); | ||||||
|  |             addSuccessToast("Successfully imported the provided schema."); | ||||||
|  |             dispatch("submit"); | ||||||
|  |         } catch (err) { | ||||||
|  |             ApiClient.errorResponseHandler(err); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         hide(); | ||||||
|  | 
 | ||||||
|  |         isImporting = false; | ||||||
|  |     } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <OverlayPanel bind:this={panel} class="full-width-popup diff-popup" popup on:show on:hide> | <OverlayPanel bind:this={panel} class="full-width-popup import-popup" popup on:show on:hide> | ||||||
|     <svelte:fragment slot="header"> |     <svelte:fragment slot="header"> | ||||||
|         <h4 class="center txt-break">{title}</h4> |         <h4 class="center txt-break">Side-by-side diff</h4> | ||||||
|     </svelte:fragment> |     </svelte:fragment> | ||||||
| 
 | 
 | ||||||
|     <div class="grid m-b-base"> |     <div class="grid m-b-base"> | ||||||
|         <div class="col-6"> |         <div class="col-6"> | ||||||
|             <div class="section-title">{contentATitle}</div> |             <div class="section-title">Old schema</div> | ||||||
|             <code class="code-block">{@html diff([DIFF_DELETE, DIFF_EQUAL])}</code> |             <code class="code-block">{@html diff([window.DIFF_DELETE, window.DIFF_EQUAL])}</code> | ||||||
|         </div> |         </div> | ||||||
|         <div class="col-6"> |         <div class="col-6"> | ||||||
|             <div class="section-title">{contentBTitle}</div> |             <div class="section-title">New schema</div> | ||||||
|             <code class="code-block">{@html diff([DIFF_INSERT, DIFF_EQUAL])}</code> |             <code class="code-block">{@html diff([window.DIFF_INSERT, window.DIFF_EQUAL])}</code> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
|     <svelte:fragment slot="footer"> |     <svelte:fragment slot="footer"> | ||||||
|         <button type="button" class="btn btn-secondary" on:click={hide}>Close</button> |         <button type="button" class="btn btn-secondary" on:click={hide}>Close</button> | ||||||
|  |         <button | ||||||
|  |             type="button" | ||||||
|  |             class="btn btn-expanded m-l-auto" | ||||||
|  |             class:btn-loading={isImporting} | ||||||
|  |             on:click={() => submitImport()} | ||||||
|  |         > | ||||||
|  |             <span class="txt">Confirm and import</span> | ||||||
|  |         </button> | ||||||
|     </svelte:fragment> |     </svelte:fragment> | ||||||
| </OverlayPanel> | </OverlayPanel> | ||||||
| 
 | 
 | ||||||
|  | @ -3,18 +3,18 @@ | ||||||
|     import ApiClient from "@/utils/ApiClient"; |     import ApiClient from "@/utils/ApiClient"; | ||||||
|     import CommonHelper from "@/utils/CommonHelper"; |     import CommonHelper from "@/utils/CommonHelper"; | ||||||
|     import { pageTitle } from "@/stores/app"; |     import { pageTitle } from "@/stores/app"; | ||||||
|     import { addInfoToast, addErrorToast } from "@/stores/toasts"; |     import { addErrorToast } from "@/stores/toasts"; | ||||||
|  |     import { setErrors } from "@/stores/errors"; | ||||||
|     import Field from "@/components/base/Field.svelte"; |     import Field from "@/components/base/Field.svelte"; | ||||||
|     import DiffPopup from "@/components/base/DiffPopup.svelte"; |  | ||||||
|     import SettingsSidebar from "@/components/settings/SettingsSidebar.svelte"; |     import SettingsSidebar from "@/components/settings/SettingsSidebar.svelte"; | ||||||
|  |     import ImportPopup from "@/components/settings/ImportPopup.svelte"; | ||||||
| 
 | 
 | ||||||
|     $pageTitle = "Import collections"; |     $pageTitle = "Import collections"; | ||||||
| 
 | 
 | ||||||
|     let fileInput; |     let fileInput; | ||||||
|     let diffPopup; |     let importPopup; | ||||||
| 
 | 
 | ||||||
|     let schema = ""; |     let schema = ""; | ||||||
|     let isImporting = false; |  | ||||||
|     let isLoadingFile = false; |     let isLoadingFile = false; | ||||||
|     let newCollections = []; |     let newCollections = []; | ||||||
|     let oldCollections = []; |     let oldCollections = []; | ||||||
|  | @ -141,22 +141,10 @@ | ||||||
|         reader.readAsText(file); |         reader.readAsText(file); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     function submitImport() { |  | ||||||
|         isImporting = true; |  | ||||||
| 
 |  | ||||||
|         try { |  | ||||||
|             const newCollections = JSON.parse(schema); |  | ||||||
|             ApiClient.collections.import(newCollections); |  | ||||||
|         } catch (err) { |  | ||||||
|             ApiClient.errorResponseHandler(err); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         isImporting = false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     function clear() { |     function clear() { | ||||||
|         schema = ""; |         schema = ""; | ||||||
|         fileInput.value = ""; |         fileInput.value = ""; | ||||||
|  |         setErrors({}); | ||||||
|     } |     } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
|  | @ -224,36 +212,23 @@ | ||||||
|                             <i class="ri-information-line" /> |                             <i class="ri-information-line" /> | ||||||
|                         </div> |                         </div> | ||||||
|                         <div class="content"> |                         <div class="content"> | ||||||
|                             <string>Everything is up-to-date!</string> |                             <string>Your collections schema is already up-to-date!</string> | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                 {/if} |                 {/if} | ||||||
| 
 | 
 | ||||||
|                 {#if isValid && newCollections.length && hasChanges} |                 {#if isValid && newCollections.length && hasChanges} | ||||||
|                     <div class="flex flex-gap-10"> |                     <h5 class="section-title">Detected changes</h5> | ||||||
|                         <div> |  | ||||||
|                             <h5 class="section-title m-0">Detected changes</h5> |  | ||||||
|                         </div> |  | ||||||
|                         <button |  | ||||||
|                             type="button" |  | ||||||
|                             class="btn btn-sm btn-warning" |  | ||||||
|                             on:click={() => { |  | ||||||
|                                 diffPopup?.show( |  | ||||||
|                                     JSON.stringify(oldCollections, null, 2), |  | ||||||
|                                     JSON.stringify(newCollections, null, 2) |  | ||||||
|                                 ); |  | ||||||
|                             }} |  | ||||||
|                         > |  | ||||||
|                             View diff |  | ||||||
|                         </button> |  | ||||||
|                     </div> |  | ||||||
| 
 | 
 | ||||||
|                     <div class="list m-t-sm"> |                     <div class="list"> | ||||||
|                         {#if collectionsToDelete.length} |                         {#if collectionsToDelete.length} | ||||||
|                             {#each collectionsToDelete as collection (collection.id)} |                             {#each collectionsToDelete as collection (collection.id)} | ||||||
|                                 <div class="list-item"> |                                 <div class="list-item"> | ||||||
|                                     <span class="label label-danger list-label">Deleted</span> |                                     <span class="label label-danger list-label">Deleted</span> | ||||||
|                                     <strong>{collection.name}</strong> |                                     <strong>{collection.name}</strong> | ||||||
|  |                                     {#if collection.id} | ||||||
|  |                                         <small class="txt-hint">({collection.id})</small> | ||||||
|  |                                     {/if} | ||||||
|                                 </div> |                                 </div> | ||||||
|                             {/each} |                             {/each} | ||||||
|                         {/if} |                         {/if} | ||||||
|  | @ -268,6 +243,9 @@ | ||||||
|                                         {/if} |                                         {/if} | ||||||
|                                         {entry.new.name} |                                         {entry.new.name} | ||||||
|                                     </strong> |                                     </strong> | ||||||
|  |                                     {#if entry.new.id} | ||||||
|  |                                         <small class="txt-hint">({entry.new.id})</small> | ||||||
|  |                                     {/if} | ||||||
|                                 </div> |                                 </div> | ||||||
|                             {/each} |                             {/each} | ||||||
|                         {/if} |                         {/if} | ||||||
|  | @ -277,6 +255,9 @@ | ||||||
|                                 <div class="list-item"> |                                 <div class="list-item"> | ||||||
|                                     <span class="label label-success list-label">New</span> |                                     <span class="label label-success list-label">New</span> | ||||||
|                                     <strong>{collection.name}</strong> |                                     <strong>{collection.name}</strong> | ||||||
|  |                                     {#if collection.id} | ||||||
|  |                                         <small class="txt-hint">({collection.id})</small> | ||||||
|  |                                     {/if} | ||||||
|                                 </div> |                                 </div> | ||||||
|                             {/each} |                             {/each} | ||||||
|                         {/if} |                         {/if} | ||||||
|  | @ -284,23 +265,19 @@ | ||||||
|                 {/if} |                 {/if} | ||||||
| 
 | 
 | ||||||
|                 <div class="flex m-t-base"> |                 <div class="flex m-t-base"> | ||||||
|                     <button |                     {#if !!schema} | ||||||
|                         type="button" |                         <button type="button" class="btn btn-secondary link-hint" on:click={() => clear()}> | ||||||
|                         class="btn btn-secondary link-hint" |                             <span class="txt">Clear</span> | ||||||
|                         disabled={!schema || isImporting} |                         </button> | ||||||
|                         on:click={() => clear()} |                     {/if} | ||||||
|                     > |  | ||||||
|                         <span class="txt">Clear</span> |  | ||||||
|                     </button> |  | ||||||
|                     <div class="flex-fill" /> |                     <div class="flex-fill" /> | ||||||
|                     <button |                     <button | ||||||
|                         type="button" |                         type="button" | ||||||
|                         class="btn btn-expanded m-l-auto" |                         class="btn btn-expanded btn-warning m-l-auto" | ||||||
|                         class:btn-loading={isImporting} |  | ||||||
|                         disabled={!canImport} |                         disabled={!canImport} | ||||||
|                         on:click={() => submitImport()} |                         on:click={() => importPopup?.show(oldCollections, newCollections)} | ||||||
|                     > |                     > | ||||||
|                         <span class="txt">Import</span> |                         <span class="txt">Review</span> | ||||||
|                     </button> |                     </button> | ||||||
|                 </div> |                 </div> | ||||||
|             {/if} |             {/if} | ||||||
|  | @ -308,7 +285,7 @@ | ||||||
|     </div> |     </div> | ||||||
| </main> | </main> | ||||||
| 
 | 
 | ||||||
| <DiffPopup bind:this={diffPopup} /> | <ImportPopup bind:this={importPopup} on:submit={() => clear()} /> | ||||||
| 
 | 
 | ||||||
| <style> | <style> | ||||||
|     .list-label { |     .list-label { | ||||||
|  |  | ||||||
|  | @ -667,7 +667,7 @@ a, | ||||||
|     border: 1px solid var(--baseAlt1Color); |     border: 1px solid var(--baseAlt1Color); | ||||||
|     border-radius: var(--baseRadius); |     border-radius: var(--baseRadius); | ||||||
|     .list-item { |     .list-item { | ||||||
|         word-break: break-all; |         word-break: break-word; | ||||||
|         position: relative; |         position: relative; | ||||||
|         display: flex; |         display: flex; | ||||||
|         align-items: center; |         align-items: center; | ||||||
|  |  | ||||||
|  | @ -495,6 +495,7 @@ select { | ||||||
|         font-size: var(--smFontSize); |         font-size: var(--smFontSize); | ||||||
|         line-height: var(--smLineHeight); |         line-height: var(--smLineHeight); | ||||||
|         color: var(--txtHintColor); |         color: var(--txtHintColor); | ||||||
|  |         word-break: break-word; | ||||||
|     } |     } | ||||||
|     .help-block-error { |     .help-block-error { | ||||||
|         color: var(--dangerColor); |         color: var(--dangerColor); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue