working on functionality and layout design

This commit is contained in:
Corban-Lee Jones 2024-09-30 23:29:16 +01:00
parent 79384ff737
commit 12e358df29
9 changed files with 177 additions and 177 deletions

View File

@ -56,17 +56,23 @@
justify-content: flex-start;
align-items: center;
flex-wrap: nowrap;
color: var(--bs-text-body);
background-color: var(--bg-tertiary-bg);
transition: 0.3s;
}
.server-item-selector:hover {
.server-item-selector .font-monospace {
color: var(--bs-secondary-color)
}
.server-item-selector:hover,
.server-item-selector:focus,
.server-item-selector:active,
.server-item-selector.active {
background-color: var(--bs-tertiary-bg);
}
.server-item-selector:active, .server-item-selector.active {
background-color: var(--bs-tertiary-bg) !important;
}
/* widths */

View File

@ -25,6 +25,18 @@ td > .btn-link { padding-left: 0; }
}
/* Empty Table */
.table .dt-empty {
padding: 2rem 0;
border-bottom: none !important;
}
.table tr:hover > .dt-empty {
box-shadow: none !important;
}
/* Table Search */
.table-search-group {
@ -76,3 +88,31 @@ td > .btn-link { padding-left: 0; }
outline: 0;
box-shadow: none;
}
/* Button Controls */
.table-search-buttons > div {
margin-left: 1rem;
}
@media (max-width: 576px) {
.table-search-buttons > div {
margin-left: 0.25rem;
}
}
.table-search-buttons > div:first-of-type {
margin-left: 0 !important;
}
/* Table Border Colour */
table.dataTable > thead > tr > th, table.dataTable > thead > tr > td {
border-bottom: 1px solid var(--bs-border-color);
}
div.dt-container.dt-empty-footer tbody > tr:last-child > * {
border-bottom: 1px solid var(--bs-border-color);
}

View File

@ -9,6 +9,9 @@ function initializeDataTable(tableId, columns) {
searching: false,
autoWidth: false,
order: [],
language: {
emptyTable: "No results found"
},
select: {
style: "multi+shift",
selector: 'th:first-child input[type="checkbox"]'
@ -39,6 +42,7 @@ function initializeDataTable(tableId, columns) {
bindTablePageSizer(tableId);
bindTableSearch(tableId);
bindRefreshButton(tableId);
bindDeleteButton(tableId);
bindTableSelectColumn(tableId);
}
@ -263,12 +267,19 @@ function bindTableSearch(tableId) {
// region Button Controls
function bindRefreshButton(tableId) {
let $tableFilters = $(tableId).closest('.js-tableBody').siblings('.js-tableFilters');
const $tableFilters = $(tableId).closest('.js-tableBody').siblings('.js-tableFilters');
$tableFilters.on("click", ".table-refresh-btn", function() {
$(tableId).trigger("doDataLoad");
})
}
function bindDeleteButton(tableId) {
const $tableFilters = $(tableId).closest(".js-tableBody").siblings(".js-tableFilters");
$tableFilters.on("click", ".table-del-btn", function() {
alert("delete");
})
}
// region Select Checkboxes
@ -395,9 +406,53 @@ async function loadModalData($modal, url) {
});
}
async function onModalSubmit($modal, $table, url) {
if (!selectedServer) {
return;
}
let data = { server: selectedServer.id };
$modal.find("[data-field]").each(function() {
const type = $(this).attr("type");
const key = $(this).attr("data-field");
if (!key) {
return;
}
let value;
if (type === "checkbox") {
value = $(this).prop("checked");
}
else {
value = $(this).val();
}
data[key] = value;
});
const formData = objectToFormData(data);
const id = $modal.data("primary-key");
const isNewItem = parseInt(id) !== -1;
const method = isNewItem ? "PATCH" : "POST";
url = isNewItem ? url + `${id}/` : url;
ajaxRequest(url, method, formData)
.then(response => {
$modal.modal("hide");
$table.trigger("doDataLoad");
})
.catch(error => logError(error));
}
// region Table Column Types
function renderEditColumn(data) {
const name = sanitise(data);
return `<button type="button" class="btn btn-link text-start text-decoration-none edit-modal">${name}</button>`;
}
function renderBooleanColumn(data) {
const iconClass = data ? "bi-check-circle-fill text-success" : "bi-x-circle-fill text-danger";
return `<i class="bi ${iconClass}"></i>`;

View File

@ -10,7 +10,8 @@ function initFiltersModule() {
[
{
title: "Name",
data: "name"
data: "name",
render: renderEditColumn
},
{
title: "Match",
@ -79,3 +80,32 @@ $(filterTableId).on("click", ".edit-modal", async function() {
const id = $(filterTableId).DataTable().row($(this).closest("tr")).data().id;
await openDataModal(filterModalId, id, `/api/filters/${id}/`);
});
$(filterModalId).on("submit", async function(event) {
event.preventDefault();
await onModalSubmit(
$(filterModalId),
$(filterTableId),
"/api/filters/"
);
});
// region Load Modal Options
$(document).ready(async function() {
await loadMatchingAlgorithms();
});
async function loadMatchingAlgorithms() {
const data = await ajaxRequest("/api/filters/", "OPTIONS");
data.actions.GET.matching_algorithm.choices.forEach(algorithm => {
$(filterModalId).find('[data-field="matching_algorithm"]').append($(
"<option>",
{
text: algorithm.display_name,
value: algorithm.value > 0 ? algorithm.value : ""
}
));
});
}

View File

@ -11,10 +11,7 @@ function initMessageStylesModule() {
{
title: "Name",
data: "name",
render: function(data) {
const name = sanitise(data);
return `<button type="button" class="btn btn-link text-start text-decoration-none edit-modal">${name}</button>`;
}
render: renderEditColumn
},
{
title: "Is Embed",
@ -98,50 +95,11 @@ $(styleTableId).on("click", ".edit-modal", async function() {
$(styleModalId).on("submit", async function(event) {
event.preventDefault();
if (!selectedServer) {
throw new Error("Cannot submit form while no server is selected");
}
let data = { server: selectedServer.id };
$(this).find("[data-field]").each(function() {
const type = $(this).attr("type");
const key = $(this).attr("data-field");
if (!key) {
return;
}
let value;
if (type === "checkbox") {
value = $(this).prop("checked");
}
else {
value = $(this).val();
}
data[key] = value;
});
const formData = objectToFormData(data);
const id = $(this).data("primary-key");
if (parseInt(id) !== -1) {
ajaxRequest(`/api/message-styles/${id}/`, "PATCH", formData)
.then(response => {
$(this).modal("hide");
$(styleTableId).trigger("doDataLoad");
})
.catch(error => logError(error))
}
else {
ajaxRequest("/api/message-styles/", "POST", formData)
.then(response => {
$(this).modal("hide");
$(styleTableId).trigger("doDataLoad");
})
.catch(error => logError(error));
}
await onModalSubmit(
$(styleModalId),
$(styleTableId),
"/api/message-styles/"
);
});

View File

@ -13,10 +13,7 @@ function initSubscriptionsModule() {
title: "Name",
data: "name",
className: "text-truncate col-3",
render: function(data, type, row) {
const name = sanitise(data);
return `<button type="button" class="btn btn-link text-start text-decoration-none edit-modal">${name}</button>`;
}
render: renderEditColumn
},
{
title: "URL",
@ -112,56 +109,17 @@ $(subTableId).closest('.js-tableBody').siblings('.js-tableFilters').on("click",
});
$(subTableId).on("click", ".edit-modal", async function() {
let id = $(subTableId).DataTable().row($(this).closest("tr")).data().id;
const id = $(subTableId).DataTable().row($(this).closest("tr")).data().id;
await openDataModal(subModalId, id, `/api/subscriptions/${id}/`);
})
$(subModalId).on("submit", async function(event) {
event.preventDefault();
if (!selectedServer) {
throw new Error("Cannot submit form while no server is selected");
}
let data = { server: selectedServer.id };
$(this).find("[data-field]").each(function() {
const type = $(this).attr("type");
const key = $(this).attr("data-field");
if (!key) {
return;
}
let value;
if (type === "checkbox") {
value = $(this).prop("checked");
}
else {
value = $(this).val();
}
data[key] = value;
});
const formData = objectToFormData(data);
const id = $(this).data("primary-key");
if (parseInt(id) !== -1) {
ajaxRequest(`/api/subscriptions/${id}/`, "PATCH", formData)
.then(response => {
$(this).modal("hide");
$(subTableId).trigger("doDataLoad");
})
.catch(error => logError(error))
}
else {
ajaxRequest("/api/subscriptions/", "POST", formData)
.then(response => {
$(this).modal("hide");
$(subTableId).trigger("doDataLoad");
})
.catch(error => logError(error));
}
await onModalSubmit(
$(subModalId),
$(subTableId),
"/api/subscriptions/"
);
});

View File

@ -80,31 +80,6 @@
</div>
</div>
<div id="selectedServerContainer" class="row" style="display: none;">
<div class="col-12 bg-body-tertiary px-4 py-3 py-sm-4">
<div class="row d-none">
<div class="col-sm-7 col-md-6 d-flex align-items-center d-none">
<img alt="Server Icon" class="resolve-to-server-icon rounded-3 d-none d-sm-block">
<div class="ms-sm-3" style="min-width: 0">
<h3 class="mb-0 resolve-to-server-name text-truncate"></h3>
<h5 class="mb-0 resolve-to-server-id text-truncate text-body-secondary text-monospace"></h5>
</div>
</div>
<div class="col-sm-5 col-md-6 d-flex justify-content-sm-end align-items-center d-none">
<div class="mt-3 mt-sm-0">
<button type="button" id="serverSettingsBtn" class="btn btn-outline-secondary rounded-1 me-3">
<i class="bi bi-gear"></i>
</button>
<button type="button" id="deleteSelectedServerBtn" class="btn btn-outline-danger rounded-1">
<i class="bi bi-x-lg"></i>
</button>
<button type="button" id="backToSelectServer" class="btn btn-outline-secondary rounded-1 ms-3">
<i class="bi bi-box-arrow-right"></i>
</button>
</div>
</div>
</div>
</div>
<div id="serverJoinAlert" class="col-12 m-0">
<div class="alert alert-warning rounded-1 px-sm-3 mt-2 mt-sm-4 mx-sm-2">
<div class="row">
@ -138,18 +113,18 @@
Content Filters
</button>
</li>
<li class="nav-item" role="presentation">
<button id="contentTab" class="nav-link rounded-1" data-bs-toggle="tab" data-bs-target="#contentTabPane" type="button" aria-controls="contentTabPane" aria-selected="false">
<i class="bi bi-archive me-2"></i>
Tracked Content
</button>
</li>
<li class="nav-item" role="presentation">
<button id="stylesTab" class="nav-link rounded-1" data-bs-toggle="tab" data-bs-target="#stylesTabPane" type="button" aria-controls="stylesTabPane" aria-selected="false">
<i class="bi bi-border-style me-2"></i>
Message Styles
</button>
</li>
<li class="nav-item" role="presentation">
<button id="contentTab" class="nav-link rounded-1" data-bs-toggle="tab" data-bs-target="#contentTabPane" type="button" aria-controls="contentTabPane" aria-selected="false">
<i class="bi bi-archive me-2"></i>
Tracked Content
</button>
</li>
<li class="nav-item ms-auto">
<div class="dropdown">
<button class="nav-link rounded-1 dropdown-toggle" type="button" data-bs-toggle="dropdown">
@ -157,7 +132,10 @@
</button>
<ul class="dropdown-menu">
<li>
<button type="button" class="dropdown-item">-- todo --</button>
<button type="button" class="dropdown-item">Delete Server Data</button>
</li>
<li>
<button type="button" class="dropdown-item">Exit Server View</button>
</li>
</ul>
</div>
@ -173,12 +151,12 @@
<div id="filtersTabPane" class="tab-pane fade" role="tabpanel" aria-labelledby="filtersTab" tabindex="0">
{% include "home/tabs/filters.html" %}
</div>
<div id="contentTabPane" class="tab-pane fade" role="tabpanel" aria-labelledby="contentTab" tabindex="0">
{% include "home/tabs/content.html" %}
</div>
<div id="stylesTabPane" class="tab-pane fade" role="tabpanel" aria-labelledby="stylesTab" tabindex="0">
{% include "home/tabs/styles.html" %}
</div>
<div id="contentTabPane" class="tab-pane fade" role="tabpanel" aria-labelledby="contentTab" tabindex="0">
{% include "home/tabs/content.html" %}
</div>
</div>
</div>
</div>
@ -199,8 +177,8 @@
<div class="d-flex justify-content-start align-items-center w-100">
<img src="" alt="Guild Icon" class="rounded-1 small" width="45" height="45">
<div class="server-item-labels small text-start ps-2 w-100 flex-shrink-1 overflow-hidden">
<div class="js-guildName text-body fw-bold text-truncate"></div>
<div class="js-guildId text-body-secondary text-truncate font-monospace"></div>
<div class="js-guildName fw-bold text-truncate"></div>
<div class="js-guildId text-truncate font-monospace"></div>
</div>
</div>
</button>

View File

@ -7,6 +7,7 @@
<h5 class="modal-title ms-2">
<span class="form-create">Add</span>
<span class="form-edit">Edit</span>
Content Filter
</h5>
</div>
<div class="modal-body p-4">
@ -14,38 +15,36 @@
<div class="col-12">
<div class="mb-4">
<label for="filterName" class="form-label">Name</label>
<input type="text" name="filterName" id="filterName" class="form-control" data-field="name" tabindex="1">
<div class="form-text"></div>
<input type="text" name="filterName" id="filterName" class="form-control rounded-1" data-field="name" tabindex="1">
<div class="form-text">Human-readable name for this entry.</div>
</div>
</div>
<div class="col-12">
<div class="mb-4">
<label for="filterMatchingAlgorithm" class="form-label"></label>
<select name="filterMatchingAlgorithm" id="filterMatchingAlgorithm" class="select-2" data-field="matching_algorithm" tabindex="2">
<option value="">-----</option>
</select>
<div class="form-text"></div>
<label for="filterMatchingAlgorithm" class="form-label">Matching Algorithm</label>
<select name="filterMatchingAlgorithm" id="filterMatchingAlgorithm" class="select-2" data-dropdownparent="#filterFormModal" data-field="matching_algorithm" tabindex="2"></select>
<div class="form-text">The algorithm used to match against.</div>
</div>
</div>
<div class="col-12">
<div class="mb-4">
<label for="filterMatch" class="form-label">Match</label>
<input type="text" name="filterMatch" id="filterMatch" class="form-control" data-field="match" tabindex="3">
<div class="form-text"></div>
<input type="text" name="filterMatch" id="filterMatch" class="form-control rounded-1" data-field="match" tabindex="3">
<div class="form-text">The value to match against.</div>
</div>
</div>
<div class="col-12">
<div class="form-check form-switch mb-4">
<label for="filterIsInsensitive" class="form-check-label"></label>
<label for="filterIsInsensitive" class="form-check-label">Case-Insensitive</label>
<input type="checkbox" name="filterIsInsensitive" id="filterIsInsensitive" class="form-check-input" data-field="is_insensitive" tabindex="4">
<div class="form-text"></div>
<div class="form-text">Should case-sensitivity be ignored?</div>
</div>
</div>
<div class="col-12">
<div class="form-check form-switch">
<label for="filterIsWhitelist" class="form-check-label"></label>
<label for="filterIsWhitelist" class="form-check-label">Whitelist Mode</label>
<input type="checkbox" name="filterIsWhitelist" id="filterIsWhitelist" class="form-check-input" data-field="is_whitelist" tabindex="5">
<div class="form-text"></div>
<div class="form-text">Overrides the default blacklist behaviour.</div>
</div>
</div>
</div>

View File

@ -75,27 +75,3 @@
.w-xxl-100 { width: 100%; }
.w-xxl-auto { width: auto; }
}
.table-search-buttons > div {
margin-left: 1rem;
}
@media (max-width: 576px) {
.table-search-buttons > div {
margin-left: 0.25rem;
}
}
.table-search-buttons > div:first-of-type {
margin-left: 0 !important;
}
/* Table Border Colour */
table.dataTable > thead > tr > th, table.dataTable > thead > tr > td {
border-bottom: 1px solid var(--bs-border-color) !important;
}
div.dt-container.dt-empty-footer tbody > tr:last-child > * {
border-bottom: 1px solid var(--bs-border-color) !important;
}