refactor: filters client-side code
Some checks failed
Build / build (push) Failing after 45s

This commit is contained in:
Corban-Lee Jones 2025-05-09 17:17:32 +01:00
parent 9b6eb86cd8
commit fc24f05903
4 changed files with 285 additions and 111 deletions

View File

@ -1,12 +1,12 @@
import { formatTimestamp, verifyChannels } from "../main";
import HSDropdown from "preline/dist/dropdown";
import HSDataTable, { IDataTableOptions } from "preline/dist/datatable";
import HSSelect, { ISelectOptions } from "preline/dist/select";
import HSOverlay, { IOverlayOptions } from "preline/dist/overlay";
import HSDataTable, { IDataTableOptions } from "preline/dist/datatable";
import { Api, AjaxSettings, ConfigColumnDefs } from "datatables.net-dt";
import { TextChannel } from "discord.js";
import "datatables.net-select-dt"
import prisma from "../../../../../generated/prisma";
import { TextChannel } from "discord.js";
declare let guildId: string;
declare let channels: Array<any>;

View File

@ -1,12 +1,10 @@
import $ from "jquery";
import "datatables.net-select-dt";
import HSDropdown from "@preline/dropdown";
import HSOverlay, { IOverlayOptions } from "@preline/overlay";
import HSSelect, { ISelectOptions, ISingleOption } from "@preline/select";
import HSDataTable, { IDataTableOptions } from "@preline/datatable";
import DataTable, { Api, ConfigColumnDefs, AjaxSettings } from "datatables.net-dt";
import { autoUpdate, computePosition, offset } from "@floating-ui/dom";
import { formatTimestamp } from "../main";
import HSDropdown from "preline/dist/dropdown";
import HSSelect, { ISelectOptions } from "preline/dist/select";
import HSOverlay, { IOverlayOptions } from "preline/dist/overlay";
import HSDataTable, { IDataTableOptions } from "preline/dist/datatable";
import { Api, AjaxSettings, ConfigColumnDefs } from "datatables.net-dt";
import "datatables.net-select-dt"
import prisma from "../../../../../generated/prisma";
declare let guildId: string;
@ -14,9 +12,6 @@ declare const matchingAlgorithms: { [key: string]: string };
// #region DataTable
(window as any).DataTable = DataTable;
(window as any).$hsDataTableCollection = [];
const emptyTableHtml: string = `
<div class="max-w-md w-full min-h-[400px] flex flex-col justify-center mx-auto px-6 py-4">
<div class="flex justify-center items-center size-[46px] bg-gray-100 rounded-lg dark:bg-neutral-800">
@ -43,8 +38,7 @@ const emptyTableHtml: string = `
`;
const columnDefs: ConfigColumnDefs[] = [
// Select checkbox column
{
{ // Select checkbox column
target: 0,
orderable: false,
searchable: false,
@ -197,10 +191,20 @@ const tableOptions: IDataTableOptions = {
}
};
const table = new HSDataTable(
$("#table").get(0) as HTMLElement,
tableOptions
)
let table: HSDataTable;
window.addEventListener("preline:ready", () => {
const tableEl = $("#table").get(0);
if (HSDataTable.getInstance(tableEl, true)) return;
table = new HSDataTable(tableEl, tableOptions);
(table as any).dataTable
.on("select", onTableSelectChange)
.on("deselect", onTableSelectChange)
.on("draw", onTableSelectChange);
});
const onTableSelectChange = () => {
const selectedRowsCount = (table as any).dataTable.rows({ selected: true }).count();
@ -211,15 +215,11 @@ const onTableSelectChange = () => {
selectedRowsCount === 0 ? $elem.hide() : $elem.show();
};
(table as any).dataTable
.on("select", onTableSelectChange)
.on("deselect", onTableSelectChange)
.on("draw", onTableSelectChange);
$("#selectAllBox").on("change", function() {
const dt: Api = (table as any).dataTable;
(this as HTMLInputElement).checked
? (table as any).dataTable.rows().select()
: (table as any).dataTable.rows().deselect();
? dt.rows().select()
: dt.rows().deselect();
});
$("#deleteRowsBtn").on("click", async () => {
@ -244,20 +244,7 @@ $("#deleteRowsBtn").on("click", async () => {
// #endregion
// #region Page Size Select
(window as any).$hsSelectCollection = [];
(window as any)["FloatingUIDOM"] = {
computePosition: computePosition,
autoUpdate: autoUpdate,
offset: offset
};
// Close on click.
window.addEventListener('click', (evt) => {
const evtTarget = evt.target;
HSSelect.closeCurrentlyOpened(evtTarget as HTMLElement);
});
// #region Table Paging Select
const pageSelectOptions: ISelectOptions = {
toggleTag: '<button type="button" aria-expanded="false"></button>',
@ -270,35 +257,52 @@ const pageSelectOptions: ISelectOptions = {
</div>`,
toggleClasses: "cj-table-paging-select-toggle",
optionClasses: "cj-table-paging-select-option",
dropdownClasses: `cj-table-paging-select-dropdown`,
dropdownClasses: "cj-table-paging-select-dropdown",
dropdownSpace: 10,
dropdownScope: "parent",
dropdownPlacement: "top",
dropdownVerticalFixedPlacement: null
};
const pageSizeSelect: HSSelect = new HSSelect(
$("#selectPageSize-js").get(0) as HTMLElement,
pageSelectOptions
);
// #endregion
window.addEventListener("preline:ready", () => {
const selectEl = $("#selectPageSize-js").get(0);
if (!HSSelect.getInstance(selectEl, true)) {
new HSSelect(selectEl, pageSelectOptions);
}
});
// #region Edit Modal
(window as any).$hsOverlayCollection = [];
const closeEditModal = () => { editModal.close() };
const editModalOptions: IOverlayOptions = {};
const openEditModal = async (id: number | undefined) => {
$("#editForm").removeClass("submitted");
editModal.open();
const editModal: HSOverlay = new HSOverlay(
$("#editModal").get(0) as HTMLElement,
editModalOptions
);
id === undefined
? clearEditModalData()
: loadEditModalData(id);
};
$(document).on("click", ".open-edit-modal-js", async event => {
await openEditModal($(event.target).data("id"));
});
const editModalOptions: IOverlayOptions = {};
let editModal: HSOverlay;
window.addEventListener("preline:ready", () => {
const modalEl = $("#editModal").get(0);
if (!HSOverlay.getInstance(modalEl, true)) {
editModal = new HSOverlay(modalEl, editModalOptions);
}
});
// #endregion
// #region
const clearEditModalData = () => {
$(editModal.el).removeData("id");
@ -323,23 +327,45 @@ const loadEditModalData = async (id: number) => {
$("#formInsensitive").prop("checked", filter.is_insensitive);
$("#formWhitelist").prop("checked", filter.is_whitelist);
// BUG:
// Breaks the appearance & functionality of the select
algorithmSelect.setValue(filter.matching_algorithm);
}
const openEditModal = async (id: number | undefined) => {
$("#editForm").removeClass("submitted");
editModal.open();
id === undefined
? clearEditModalData()
: loadEditModalData(id);
};
const closeEditModal = () => {
editModal.close();
};
$("#editForm").on("submit", async event => {
event.preventDefault();
const form = $(event.target).get(0) as HTMLFormElement;
$(form).addClass("submitted");
const validity = form.checkValidity();
if (!validity) {
console.debug(`Submit form invalid: ${validity}`);
return;
};
let method = "post";
const data = $(event.target).serializeArray();
// If 'id' has a value, we are patching an existing entry
const id: number | undefined = $(editModal.el).data("id");
if (id !== undefined) {
data.push({ name: "id", value: `${id}` });
method = "patch";
}
await $.ajax({
url: `/guild/${guildId}/filters/api`,
dataType: "json",
method: method,
data: data,
success: () => {
(table as any).dataTable.draw();
closeEditModal();
},
error: error => {
alert(JSON.stringify(error, null, 4));
}
});
});
const algorithmSelectOptions: ISelectOptions = {
toggleTag: '<button type="button" aria-expanded="false"><span data-title></span></button>',
@ -360,52 +386,200 @@ const algorithmSelectOptions: ISelectOptions = {
dropdownVerticalFixedPlacement: null
};
const algorithmSelect = new HSSelect(
$("#formAlgorithm").get(0),
algorithmSelectOptions
);
let algorithmSelect: HSSelect;
// Add options to algorithm select
Object.entries(matchingAlgorithms).forEach(([key, description]) => {
algorithmSelect.addOption({
title: description,
val: key
} as ISingleOption)
})
window.addEventListener("preline:ready", () => {
const algorithmEl = $("#formAlgorithm").get(0)
$("#editForm").on("submit", async event => {
event.preventDefault();
if (HSSelect.getInstance(algorithmEl, true)) return;
const form = $(event.target).get(0) as HTMLFormElement;
$(form).addClass("submitted");
algorithmSelect = new HSSelect(algorithmEl, algorithmSelectOptions);
if (!form.checkValidity()) return;
let method = "post";
const data = $(event.target).serializeArray();
const id: number | undefined = $(editModal.el).data("id");
if (id !== undefined) {
data.push({
name: "id",
value: `${id}`
})
method = "patch";
}
await $.ajax({
url: `/guild/${guildId}/filters/api`,
dataType: "json",
method: method,
data: data,
success: () => {
(table as any).dataTable.draw();
closeEditModal();
},
error: error => {
alert(JSON.stringify(error, null, 4));
}
Object.entries(matchingAlgorithms).forEach(([key, description]) => {
algorithmSelect.addOption({
title: description,
val: key
});
});
});
// #endregion
// #endregion
// import $ from "jquery";
// import "datatables.net-select-dt";
// import HSDropdown from "@preline/dropdown";
// import HSOverlay, { IOverlayOptions } from "@preline/overlay";
// import HSSelect, { ISelectOptions, ISingleOption } from "@preline/select";
// import HSDataTable, { IDataTableOptions } from "@preline/datatable";
// import DataTable, { Api, ConfigColumnDefs, AjaxSettings } from "datatables.net-dt";
// import { autoUpdate, computePosition, offset } from "@floating-ui/dom";
// import { formatTimestamp } from "../main";
// import prisma from "../../../../../generated/prisma";
// // #region Page Size Select
// (window as any).$hsSelectCollection = [];
// (window as any)["FloatingUIDOM"] = {
// computePosition: computePosition,
// autoUpdate: autoUpdate,
// offset: offset
// };
// // Close on click.
// window.addEventListener('click', (evt) => {
// const evtTarget = evt.target;
// HSSelect.closeCurrentlyOpened(evtTarget as HTMLElement);
// });
// const pageSelectOptions: ISelectOptions = {
// toggleTag: '<button type="button" aria-expanded="false"></button>',
// optionTemplate: `
// <div class="flex justify-between items-center w-full">
// <span data-title></span>
// <span class="hidden hs-selected:block">
// <svg class="shrink-0 size-3.5 text-blue-600 dark:text-blue-500" xmlns="http:.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
// </span>
// </div>`,
// toggleClasses: "cj-table-paging-select-toggle",
// optionClasses: "cj-table-paging-select-option",
// dropdownClasses: `cj-table-paging-select-dropdown`,
// dropdownSpace: 10,
// dropdownScope: "parent",
// dropdownPlacement: "top",
// dropdownVerticalFixedPlacement: null
// };
// const pageSizeSelect: HSSelect = new HSSelect(
// $("#selectPageSize-js").get(0) as HTMLElement,
// pageSelectOptions
// );
// // #endregion
// // #region Edit Modal
// (window as any).$hsOverlayCollection = [];
// const editModalOptions: IOverlayOptions = {};
// const editModal: HSOverlay = new HSOverlay(
// $("#editModal").get(0) as HTMLElement,
// editModalOptions
// );
// $(document).on("click", ".open-edit-modal-js", async event => {
// await openEditModal($(event.target).data("id"));
// });
// const clearEditModalData = () => {
// $(editModal.el).removeData("id");
// $("#formName").val("");
// $("#formValue").val("");
// $("#formInsensitive").prop("checked", false);
// $("#formWhitelist").prop("checked", false);
// algorithmSelect.setValue("");
// };
// const loadEditModalData = async (id: number) => {
// const filter: prisma.Filter = await $.ajax({
// url: `/guild/${guildId}/filters/api?id=${id}`,
// method: "get"
// });
// $(editModal.el).data("id", filter.id);
// $("#formName").val(filter.name);
// $("#formValue").val(filter.value);
// $("#formInsensitive").prop("checked", filter.is_insensitive);
// $("#formWhitelist").prop("checked", filter.is_whitelist);
// // BUG:
// // Breaks the appearance & functionality of the select
// algorithmSelect.setValue(filter.matching_algorithm);
// }
// const openEditModal = async (id: number | undefined) => {
// $("#editForm").removeClass("submitted");
// editModal.open();
// id === undefined
// ? clearEditModalData()
// : loadEditModalData(id);
// };
// const closeEditModal = () => {
// editModal.close();
// };
// const algorithmSelectOptions: ISelectOptions = {
// toggleTag: '<button type="button" aria-expanded="false"><span data-title></span></button>',
// optionTemplate: `
// <div class="flex justify-between items-center w-full">
// <span data-title></span>
// <span class="hidden hs-selected:block">
// <svg class="shrink-0 size-3.5 text-blue-600 dark:text-blue-500" xmlns="http:.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
// </span>
// </div>`,
// toggleClasses: "cj-select-toggle select-input",
// optionClasses: "cj-select-option",
// dropdownClasses: "cj-select-dropdown",
// wrapperClasses: "peer",
// dropdownSpace: 10,
// dropdownScope: "parent",
// dropdownPlacement: "top",
// dropdownVerticalFixedPlacement: null
// };
// const algorithmSelect = new HSSelect(
// $("#formAlgorithm").get(0),
// algorithmSelectOptions
// );
// // Add options to algorithm select
// Object.entries(matchingAlgorithms).forEach(([key, description]) => {
// algorithmSelect.addOption({
// title: description,
// val: key
// } as ISingleOption)
// })
// $("#editForm").on("submit", async event => {
// event.preventDefault();
// const form = $(event.target).get(0) as HTMLFormElement;
// $(form).addClass("submitted");
// if (!form.checkValidity()) return;
// let method = "post";
// const data = $(event.target).serializeArray();
// const id: number | undefined = $(editModal.el).data("id");
// if (id !== undefined) {
// data.push({
// name: "id",
// value: `${id}`
// })
// method = "patch";
// }
// await $.ajax({
// url: `/guild/${guildId}/filters/api`,
// dataType: "json",
// method: method,
// data: data,
// success: () => {
// (table as any).dataTable.draw();
// closeEditModal();
// },
// error: error => {
// alert(JSON.stringify(error, null, 4));
// }
// });
// });
// // #endregion

View File

@ -142,7 +142,7 @@
</div>
</div>
<div id="editModal" class="hs-overlay hidden size-full fixed top-0 start-0 z-80 overflow-x-hidden overflow-y-auto pointer-events-none" role="dialog" tabindex="-1">
<div id="editModal" class="hidden size-full fixed top-0 start-0 z-80 overflow-x-hidden overflow-y-auto pointer-events-none" role="dialog" tabindex="-1">
<div class="hs-overlay-animation-target hs-overlay-open:scale-100 hs-overlay-open:opacity-100 scale-95 opacity-0 ease-in-out transition-all duration-200 lg:max-w-lg lg:w-full m-3 lg:mx-auto min-h-[calc(100%-3.5rem)] flex items-center">
<div class="w-full p-4 sm:p-7 flex flex-col bg-white border shadow-xs rounded-lg pointer-events-auto dark:bg-neutral-900 dark:border-neutral-800 dark:shadow-neutral-700/70">
<div class="mb-8">

View File

@ -174,7 +174,7 @@
</div>
</div>
<div id="editModal" class="hs-overlay hidden size-full fixed top-0 start-0 z-80 overflow-x-hidden overflow-y-auto pointer-events-none" role="dialog" tabindex="-1">
<div id="editModal" class="hidden size-full fixed top-0 start-0 z-80 overflow-x-hidden overflow-y-auto pointer-events-none" role="dialog" tabindex="-1">
<div class="hs-overlay-animation-target hs-overlay-open:scale-100 hs-overlay-open:opacity-100 scale-95 opacity-0 ease-in-out transition-all duration-200 lg:max-w-4xl lg:w-full m-3 lg:mx-auto min-h-[calc(100%-3.5rem)] flex items-center">
<div class="w-full p-4 sm:p-7 flex flex-col bg-white border shadow-xs rounded-lg pointer-events-auto dark:bg-neutral-900 dark:border-neutral-800 dark:shadow-neutral-700/70">
<div class="mb-8">