merge newui branch
This commit is contained in:
273
ui/src/collections/indexUpsertModal.js
Normal file
273
ui/src/collections/indexUpsertModal.js
Normal file
@@ -0,0 +1,273 @@
|
||||
window.app = window.app || {};
|
||||
window.app.modals = window.app.modals || {};
|
||||
|
||||
window.app.modals.openIndexUpsert = function(
|
||||
collection,
|
||||
index = "",
|
||||
settings = {
|
||||
onsave: () => {},
|
||||
ondelete: () => {},
|
||||
},
|
||||
) {
|
||||
const modal = indexUpsertModal(collection, index, settings);
|
||||
if (!modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.body.appendChild(modal);
|
||||
app.modals.open(modal);
|
||||
};
|
||||
|
||||
function indexUpsertModal(collection, index = "", settings = {}) {
|
||||
if (!collection) {
|
||||
console.warn("[indexUpsertModal] missing required collection argument");
|
||||
return;
|
||||
}
|
||||
|
||||
let modal;
|
||||
|
||||
const uniqueId = app.utils.randomString();
|
||||
|
||||
const data = store({
|
||||
originalIndex: "",
|
||||
index: "",
|
||||
get isNew() {
|
||||
return data.originalIndex == "";
|
||||
},
|
||||
get indexParts() {
|
||||
return app.utils.parseIndex(data.index);
|
||||
},
|
||||
get lowerCasedIndexColumnNames() {
|
||||
return data.indexParts.columns.map((c) => c.name.toLowerCase());
|
||||
},
|
||||
get canSave() {
|
||||
return data.lowerCasedIndexColumnNames.length > 0;
|
||||
},
|
||||
});
|
||||
|
||||
const presetColumns = collection?.fields?.filter((f) => !f["@toDelete"] && f.name != "id")?.map((f) => f.name)
|
||||
|| [];
|
||||
|
||||
function loadIndex(index) {
|
||||
data.originalIndex = index || "";
|
||||
|
||||
if (!index) {
|
||||
const parsed = app.utils.parseIndex("");
|
||||
parsed.tableName = collection?.name || "";
|
||||
index = app.utils.buildIndex(parsed);
|
||||
}
|
||||
|
||||
data.index = index;
|
||||
}
|
||||
|
||||
function saveIndex() {
|
||||
if (!collection || !data.canSave) {
|
||||
console.warn("[saveIndex] no collection or invalid save state:", collection, data.canSave);
|
||||
return;
|
||||
}
|
||||
|
||||
collection.indexes = collection.indexes || [];
|
||||
|
||||
// search for existing
|
||||
const pos = collection.indexes.findIndex((index) => index == data.originalIndex);
|
||||
if (pos >= 0) {
|
||||
// replace
|
||||
collection.indexes[pos] = data.index;
|
||||
app.utils.deleteByPath(app.store.errors, "indexes." + pos);
|
||||
} else {
|
||||
// push missing
|
||||
collection.indexes.push(data.index);
|
||||
}
|
||||
|
||||
if (typeof settings?.onsave == "function") {
|
||||
settings.onsave({
|
||||
collection: collection,
|
||||
index: data.index,
|
||||
oldIndex: data.originalIndex,
|
||||
});
|
||||
}
|
||||
|
||||
clearIndexError();
|
||||
|
||||
app.modals.close(modal);
|
||||
}
|
||||
|
||||
function deleteIndex() {
|
||||
if (!collection || !data.originalIndex) {
|
||||
console.warn("[deleteIndex] no collection or index:", collection, data.originalIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
const pos = collection.indexes?.findIndex((index) => index == data.originalIndex);
|
||||
if (pos == -1) {
|
||||
console.warn("[deleteIndex] missing index:", data.originalIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
collection.indexes.splice(pos, 1);
|
||||
app.utils.deleteByPath(app.store.errors, "indexes." + pos);
|
||||
|
||||
if (typeof settings?.ondelete == "function") {
|
||||
settings.ondelete({
|
||||
collection: collection,
|
||||
position: pos,
|
||||
index: data.originalIndex,
|
||||
});
|
||||
}
|
||||
|
||||
clearIndexError();
|
||||
|
||||
app.modals.close(modal);
|
||||
}
|
||||
|
||||
function toggleColumn(column) {
|
||||
const clone = JSON.parse(JSON.stringify(data.indexParts));
|
||||
clone.tableName = collection?.name || "";
|
||||
|
||||
const colLowerCased = column.toLowerCase();
|
||||
|
||||
const i = clone.columns.findIndex((c) => c.name.toLowerCase() == colLowerCased);
|
||||
if (i >= 0) {
|
||||
clone.columns.splice(i, 1);
|
||||
} else {
|
||||
app.utils.pushUnique(clone.columns, { name: column });
|
||||
}
|
||||
|
||||
data.index = app.utils.buildIndex(clone);
|
||||
|
||||
clearIndexError();
|
||||
}
|
||||
|
||||
function clearIndexError() {
|
||||
if (app.store.errors?.indexes) {
|
||||
const pos = collection.indexes.findIndex((idx) => idx == data.originalIndex);
|
||||
app.utils.deleteByPath(app.store.errors, "indexes." + pos);
|
||||
}
|
||||
}
|
||||
|
||||
modal = t.div(
|
||||
{
|
||||
className: "modal popup index-upsert-modal",
|
||||
onbeforeopen: () => {
|
||||
loadIndex(index);
|
||||
},
|
||||
onafteropen: () => {
|
||||
// retrigger indexes error (if any)
|
||||
if (app.store.errors?.indexes) {
|
||||
app.store.errors.indexes = JSON.parse(JSON.stringify(app.store.errors.indexes));
|
||||
}
|
||||
},
|
||||
onafterclose: (el) => {
|
||||
el?.remove();
|
||||
},
|
||||
},
|
||||
t.header(
|
||||
{ className: "modal-header" },
|
||||
t.h6(
|
||||
{ className: "modal-title" },
|
||||
t.span({ className: "txt" }, () => (data.isNew ? "Create index" : "Update index")),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "modal-content" },
|
||||
t.form(
|
||||
{
|
||||
id: uniqueId + "form",
|
||||
className: "grid sm index-upsert-form",
|
||||
onsubmit: (e) => {
|
||||
e.preventDefault();
|
||||
saveIndex();
|
||||
},
|
||||
},
|
||||
t.div(
|
||||
{ className: "col-12" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
t.input({
|
||||
type: "checkbox",
|
||||
className: "switch",
|
||||
id: uniqueId + "checkbox_unique",
|
||||
checked: () => data.indexParts.unique,
|
||||
onchange: (e) => {
|
||||
const newIndexParts = JSON.parse(JSON.stringify(data.indexParts));
|
||||
newIndexParts.unique = e.target.checked;
|
||||
newIndexParts.tableName = newIndexParts.tableName || collection?.name || "";
|
||||
data.index = app.utils.buildIndex(newIndexParts);
|
||||
},
|
||||
}),
|
||||
t.label({ htmlFor: uniqueId + "checkbox_unique" }, "Unique"),
|
||||
),
|
||||
),
|
||||
t.div(
|
||||
{ className: "col-12" },
|
||||
t.div(
|
||||
{ className: "field" },
|
||||
app.components.codeEditor({
|
||||
required: true,
|
||||
className: "collection-index-input pre-wrap",
|
||||
name: () => "indexes." + collection.indexes?.findIndex((idx) => idx == data.originalIndex),
|
||||
placeholder: () => `e.g. CREATE INDEX idx_test on ${collection?.name || "X"} (created)`,
|
||||
value: () => data.index,
|
||||
oninput: (val) => (data.index = val),
|
||||
}),
|
||||
),
|
||||
t.div(
|
||||
{ hidden: () => !presetColumns.length, className: "field-help m-t-sm" },
|
||||
t.div(
|
||||
{ className: "flex flex-wrap gap-5" },
|
||||
t.span({ className: "txt", textContent: "Presets:" }),
|
||||
() => {
|
||||
return presetColumns?.map((col) => {
|
||||
const isSelected = data.lowerCasedIndexColumnNames.includes(col.toLowerCase());
|
||||
return t.button({
|
||||
type: "button",
|
||||
textContent: col,
|
||||
className: () => `label handle ${isSelected ? "success" : ""}`,
|
||||
onclick: () => toggleColumn(col),
|
||||
});
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
t.footer(
|
||||
{ className: "modal-footer gap-base" },
|
||||
t.button(
|
||||
{
|
||||
type: "button",
|
||||
className: "btn transparent m-r-auto",
|
||||
onclick: () => app.modals.close(modal),
|
||||
},
|
||||
t.span({ className: "txt" }, "Close"),
|
||||
),
|
||||
t.button(
|
||||
{
|
||||
hidden: () => data.isNew,
|
||||
type: "button",
|
||||
className: () => "btn sm circle transparent secondary",
|
||||
ariaDescription: app.attrs.tooltip("Delete index", "left"),
|
||||
onclick: () => {
|
||||
app.modals.confirm(
|
||||
"Do you really want to remove the selected index from the collection?",
|
||||
deleteIndex,
|
||||
);
|
||||
},
|
||||
},
|
||||
t.i({ className: "ri-delete-bin-7-line" }),
|
||||
),
|
||||
t.button(
|
||||
{
|
||||
"type": "submit",
|
||||
"html-form": uniqueId + "form",
|
||||
"disabled": () => !data.canSave,
|
||||
"className": () => "btn expanded",
|
||||
},
|
||||
t.span({ className: "txt" }, "Set index"),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return modal;
|
||||
}
|
||||
Reference in New Issue
Block a user