pocketbase/ui/src/components/settings/ImportPopup.svelte

196 lines
6.1 KiB
Svelte
Raw Normal View History

2022-08-06 04:25:16 +08:00
<script>
2022-08-06 13:03:34 +08:00
import { createEventDispatcher } from "svelte";
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
2022-08-06 04:25:16 +08:00
import OverlayPanel from "@/components/base/OverlayPanel.svelte";
2022-08-06 13:03:34 +08:00
import { addSuccessToast } from "@/stores/toasts";
2022-08-06 04:25:16 +08:00
2022-08-06 13:03:34 +08:00
const dispatch = createEventDispatcher();
2022-08-06 04:25:16 +08:00
let panel;
2022-08-06 13:03:34 +08:00
let oldCollections = [];
let newCollections = [];
let changes = [];
2022-08-06 13:03:34 +08:00
let isImporting = false;
2022-08-06 04:25:16 +08:00
$: if (Array.isArray(oldCollections) && Array.isArray(newCollections)) {
loadChanges();
}
2022-08-06 04:25:16 +08:00
export function show(a, b) {
2022-08-06 13:03:34 +08:00
oldCollections = a;
newCollections = b;
2022-08-06 04:25:16 +08:00
panel?.show();
}
export function hide() {
return panel?.hide();
}
function loadChanges() {
changes = [];
// add deleted and modified collections
for (const oldCollection of oldCollections) {
const newCollection = CommonHelper.findByKey(newCollections, "id", oldCollection.id) || null;
if (!newCollection?.id || JSON.stringify(oldCollection) != JSON.stringify(newCollection)) {
changes.push({
old: oldCollection,
new: newCollection,
});
}
}
// add only new collections
for (const newCollection of newCollections) {
const oldCollection = CommonHelper.findByKey(oldCollections, "id", newCollection.id) || null;
if (!oldCollection?.id) {
changes.push({
old: oldCollection,
new: newCollection,
});
}
}
}
2022-08-06 13:03:34 +08:00
function diffsToHtml(diffs, ops = [window.DIFF_INSERT, window.DIFF_DELETE, window.DIFF_EQUAL]) {
2022-08-06 04:25:16 +08:00
const html = [];
const pattern_amp = /&/g;
const pattern_lt = /</g;
const pattern_gt = />/g;
const pattern_para = /\n/g;
for (let i = 0; i < diffs.length; i++) {
const op = diffs[i][0]; // operation (insert, delete, equal)
if (!ops.includes(op)) {
continue;
}
const text = diffs[i][1]
.replace(pattern_amp, "&amp;")
.replace(pattern_lt, "&lt;")
.replace(pattern_gt, "&gt;")
.replace(pattern_para, "<br>");
switch (op) {
case DIFF_INSERT:
html[i] = '<ins class="block">' + text + "</ins>";
break;
case DIFF_DELETE:
html[i] = '<del class="block">' + text + "</del>";
break;
case DIFF_EQUAL:
html[i] = text;
break;
}
}
return html.join("");
}
function diff(obj1, obj2, ops = [window.DIFF_INSERT, window.DIFF_DELETE, window.DIFF_EQUAL]) {
2022-08-06 04:25:16 +08:00
const dmp = new diff_match_patch();
2022-08-06 13:03:34 +08:00
const lines = dmp.diff_linesToChars_(
obj1 ? JSON.stringify(obj1, null, 4) : "",
obj2 ? JSON.stringify(obj2, null, 4) : ""
2022-08-06 13:03:34 +08:00
);
2022-08-06 04:25:16 +08:00
const diffs = dmp.diff_main(lines.chars1, lines.chars2, false);
dmp.diff_charsToLines_(diffs, lines.lineArray);
return diffsToHtml(diffs, ops);
}
2022-08-06 13:03:34 +08:00
async function submitImport() {
if (isImporting) {
return;
}
isImporting = true;
try {
await ApiClient.collections.import(newCollections);
2022-08-07 16:14:49 +08:00
addSuccessToast("Successfully imported the collections configuration.");
2022-08-06 13:03:34 +08:00
dispatch("submit");
} catch (err) {
ApiClient.errorResponseHandler(err);
}
isImporting = false;
2022-08-06 23:59:28 +08:00
hide();
2022-08-06 13:03:34 +08:00
}
2022-08-06 04:25:16 +08:00
</script>
<OverlayPanel
bind:this={panel}
class="full-width-popup import-popup"
overlayClose={false}
2022-08-06 23:59:28 +08:00
escClose={!isImporting}
beforeHide={() => !isImporting}
popup
on:show
on:hide
>
2022-08-06 04:25:16 +08:00
<svelte:fragment slot="header">
2022-08-06 13:03:34 +08:00
<h4 class="center txt-break">Side-by-side diff</h4>
2022-08-06 04:25:16 +08:00
</svelte:fragment>
<div class="grid grid-sm m-b-sm">
{#each changes as pair (pair.old?.id + pair.new?.id)}
<div class="col-12">
<div class="flex flex-gap-10">
{#if !pair.old?.id}
<span class="label label-success">New</span>
<strong>{pair.new?.name}</strong>
{:else if !pair.new?.id}
<span class="label label-danger">Deleted</span>
<strong>{pair.old?.name}</strong>
{:else}
<span class="label label-warning">Modified</span>
<div class="inline-flex fleg-gap-5">
{#if pair.old.name !== pair.new.name}
<strong class="txt-strikethrough txt-hint">{pair.old.name}</strong>
<i class="ri-arrow-right-line txt-sm" />
{/if}
<strong class="txt">{pair.new.name}</strong>
</div>
{/if}
</div>
</div>
<div class="col-6 p-b-10">
<code class="code-block">
2022-08-07 16:14:49 +08:00
{@html diff(pair.old, pair.new, [window.DIFF_DELETE, window.DIFF_EQUAL]) || "N/A"}
</code>
</div>
<div class="col-6 p-b-10">
<code class="code-block">
2022-08-07 16:14:49 +08:00
{@html diff(pair.old, pair.new, [window.DIFF_INSERT, window.DIFF_EQUAL]) || "N/A"}
</code>
</div>
{/each}
2022-08-06 04:25:16 +08:00
</div>
<svelte:fragment slot="footer">
2022-08-06 23:59:28 +08:00
<button type="button" class="btn btn-secondary" on:click={hide} disabled={isImporting}>Close</button>
2022-08-06 13:03:34 +08:00
<button
type="button"
class="btn btn-expanded"
2022-08-06 13:03:34 +08:00
class:btn-loading={isImporting}
2022-08-06 23:59:28 +08:00
disabled={isImporting}
2022-08-06 13:03:34 +08:00
on:click={() => submitImport()}
>
<span class="txt">Confirm and import</span>
</button>
2022-08-06 04:25:16 +08:00
</svelte:fragment>
</OverlayPanel>
<style>
code {
color: var(--txtHintColor);
min-height: 100%;
}
</style>