274 lines
9.3 KiB
JavaScript
274 lines
9.3 KiB
JavaScript
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;
|
|
}
|