server side filters
This commit is contained in:
parent
dede2ee06e
commit
ae53457344
@ -917,6 +917,11 @@ video {
|
|||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx-\[1px\] {
|
||||||
|
margin-left: 1px;
|
||||||
|
margin-right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.mx-auto {
|
.mx-auto {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
@ -1075,6 +1080,11 @@ video {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.size-16 {
|
||||||
|
width: 4rem;
|
||||||
|
height: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
.size-2\.5 {
|
.size-2\.5 {
|
||||||
width: 0.625rem;
|
width: 0.625rem;
|
||||||
height: 0.625rem;
|
height: 0.625rem;
|
||||||
@ -1254,14 +1264,14 @@ video {
|
|||||||
min-width: 15rem;
|
min-width: 15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.min-w-\[40px\] {
|
|
||||||
min-width: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.min-w-full {
|
.min-w-full {
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.max-w-\[120rem\] {
|
||||||
|
max-width: 120rem;
|
||||||
|
}
|
||||||
|
|
||||||
.max-w-\[28rem\] {
|
.max-w-\[28rem\] {
|
||||||
max-width: 28rem;
|
max-width: 28rem;
|
||||||
}
|
}
|
||||||
@ -1286,6 +1296,10 @@ video {
|
|||||||
flex: none;
|
flex: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex-shrink-0 {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.shrink-0 {
|
.shrink-0 {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
@ -1396,6 +1410,10 @@ video {
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gap-5 {
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.gap-x-1 {
|
.gap-x-1 {
|
||||||
-moz-column-gap: 0.25rem;
|
-moz-column-gap: 0.25rem;
|
||||||
column-gap: 0.25rem;
|
column-gap: 0.25rem;
|
||||||
@ -1525,6 +1543,10 @@ video {
|
|||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rounded-2xl {
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.rounded-full {
|
.rounded-full {
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
}
|
}
|
||||||
@ -1587,6 +1609,10 @@ video {
|
|||||||
border-style: solid;
|
border-style: solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.border-none {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
.\!border-gray-200 {
|
.\!border-gray-200 {
|
||||||
--tw-border-opacity: 1 !important;
|
--tw-border-opacity: 1 !important;
|
||||||
border-color: rgb(229 231 235 / var(--tw-border-opacity, 1)) !important;
|
border-color: rgb(229 231 235 / var(--tw-border-opacity, 1)) !important;
|
||||||
@ -1774,6 +1800,10 @@ video {
|
|||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.\!pb-1 {
|
||||||
|
padding-bottom: 0.25rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
.pb-1 {
|
.pb-1 {
|
||||||
padding-bottom: 0.25rem;
|
padding-bottom: 0.25rem;
|
||||||
}
|
}
|
||||||
@ -1834,6 +1864,10 @@ video {
|
|||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pt-5 {
|
||||||
|
padding-top: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.text-center {
|
.text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@ -2449,6 +2483,16 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
|
|||||||
inset-inline-start: 0px;
|
inset-inline-start: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.before\:top-0::before {
|
||||||
|
content: var(--tw-content);
|
||||||
|
top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.before\:-z-10::before {
|
||||||
|
content: var(--tw-content);
|
||||||
|
z-index: -10;
|
||||||
|
}
|
||||||
|
|
||||||
.before\:z-\[1\]::before {
|
.before\:z-\[1\]::before {
|
||||||
content: var(--tw-content);
|
content: var(--tw-content);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@ -2470,6 +2514,11 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
|
|||||||
height: 1rem;
|
height: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.before\:h-\[200px\]::before {
|
||||||
|
content: var(--tw-content);
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
.before\:w-full::before {
|
.before\:w-full::before {
|
||||||
content: var(--tw-content);
|
content: var(--tw-content);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -2964,6 +3013,11 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sm\:size-20 {
|
||||||
|
width: 5rem;
|
||||||
|
height: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.sm\:grid-cols-2 {
|
.sm\:grid-cols-2 {
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
@ -2972,6 +3026,10 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sm\:items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.sm\:gap-6 {
|
.sm\:gap-6 {
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
}
|
}
|
||||||
@ -3001,6 +3059,10 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
|
|||||||
margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
|
margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sm\:rounded-3xl {
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.sm\:p-5 {
|
.sm\:p-5 {
|
||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
}
|
}
|
||||||
@ -3100,6 +3162,11 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
|
|||||||
padding-top: 0px;
|
padding-top: 0px;
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:text-3xl {
|
||||||
|
font-size: 1.875rem;
|
||||||
|
line-height: 2.25rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
@media (min-width: 1024px) {
|
||||||
@ -3499,13 +3566,3 @@ hs-accordion-toggle w-full text-start flex items-center gap-x-3.5 py-2 px-2.5 te
|
|||||||
.\[\&\:\:-webkit-scrollbar\]\:w-2::-webkit-scrollbar {
|
.\[\&\:\:-webkit-scrollbar\]\:w-2::-webkit-scrollbar {
|
||||||
width: 0.5rem;
|
width: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.\[\&\>\.active\]\:bg-gray-100>.active {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark\:\[\&\>\.active\]\:bg-neutral-700>.active:where(.dark, .dark *) {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(64 64 64 / var(--tw-bg-opacity, 1));
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
|
||||||
|
// const { dataTable } = HSDataTable.getInstance("#table");
|
||||||
|
|
||||||
// // Filter by status
|
// // Filter by status
|
||||||
// (function () {
|
// (function () {
|
||||||
// const radioButtons = document.querySelectorAll('input[type="radio"][name="filter"]');
|
// const radioButtons = document.querySelectorAll('input[type="radio"][name="filter"]');
|
||||||
// const { dataTable } = new HSDataTable('#table');
|
|
||||||
|
|
||||||
// dataTable.search.fixed('status', function (searchStr, data, index) {
|
// dataTable.search.fixed('status', function (searchStr, data, index) {
|
||||||
// const status = data[2].trim().toLowerCase(); // Adjust index based on your dataset
|
// const status = data[2].trim().toLowerCase(); // Adjust index based on your dataset
|
||||||
@ -17,7 +18,6 @@
|
|||||||
// });
|
// });
|
||||||
// })();
|
// })();
|
||||||
|
|
||||||
// const { dataTable } = HSDataTable.getInstance("#table");
|
|
||||||
|
|
||||||
// dataTable.on("draw.dt", () => {
|
// dataTable.on("draw.dt", () => {
|
||||||
// console.log("Table redrawn")
|
// console.log("Table redrawn")
|
||||||
@ -34,17 +34,24 @@ const formatTimestamp = timestamp => {
|
|||||||
: `${d.getDate()} ${d.toLocaleString("en-GB", { month: "short" })} ${d.getFullYear()}`;
|
: `${d.getDate()} ${d.toLocaleString("en-GB", { month: "short" })} ${d.getFullYear()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var table;
|
||||||
const defineTable = () => {
|
const defineTable = () => {
|
||||||
new HSDataTable("#table", {
|
table = new HSDataTable("#table", {
|
||||||
ajax: {
|
ajax: {
|
||||||
url: `/guild/${guild}/subscriptions/api/datatable`,
|
url: `/guild/${guild}/subscriptions/api/datatable`,
|
||||||
dataSrc: "data"
|
dataSrc: "data",
|
||||||
|
data: (d) => {
|
||||||
|
d.filters = {};
|
||||||
|
|
||||||
|
const active = $("input[name='filterActive']:checked").val();
|
||||||
|
d.filters.active = active;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
serverSide: true,
|
serverSide: true,
|
||||||
processing: true,
|
processing: true,
|
||||||
selecting: true,
|
selecting: true,
|
||||||
pagingOptions: {
|
pagingOptions: {
|
||||||
pageBtnClasses: "min-w-[40px] flex justify-center items-center text-gray-800 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 py-2.5 text-sm rounded-full disabled:opacity-50 disabled:pointer-events-none dark:text-white dark:focus:bg-neutral-700 dark:hover:bg-neutral-700"
|
pageBtnClasses: "hidden"
|
||||||
},
|
},
|
||||||
rowSelectingOptions: {
|
rowSelectingOptions: {
|
||||||
selectAllSelector: "#selectAllBox"
|
selectAllSelector: "#selectAllBox"
|
||||||
@ -63,7 +70,7 @@ const defineTable = () => {
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="mt-5 flex flex-col sm:flex-row gap-2">
|
<div class="mt-5 flex flex-col sm:flex-row gap-2">
|
||||||
<button type="button" class="openSubModal-js py-2 px-3 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none">
|
<button type="button" class="openSubModal-js py-2 px-3 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none" data-hs-overlay="#subModal">
|
||||||
<svg class="shrink-0 size-4" xmlns="http://www.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"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
|
<svg class="shrink-0 size-4" xmlns="http://www.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"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
|
||||||
Create a subscription
|
Create a subscription
|
||||||
</button>
|
</button>
|
||||||
@ -135,9 +142,9 @@ const defineTable = () => {
|
|||||||
orderable: false,
|
orderable: false,
|
||||||
searchable: false,
|
searchable: false,
|
||||||
render: (data, type, row) => {
|
render: (data, type, row) => {
|
||||||
|
// ${data.length} channels
|
||||||
return `
|
return `
|
||||||
<span class="block px-6 py-4 text-nowrap">
|
<span class="block px-6 py-4 text-nowrap">
|
||||||
${data.length} channels
|
|
||||||
</span>
|
</span>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -226,7 +233,6 @@ $(window).ready(() => {
|
|||||||
|
|
||||||
const submitForm = async event => {
|
const submitForm = async event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const formData = new FormData($("#subForm"));
|
const formData = new FormData($("#subForm"));
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<nav class="bg-white dark:bg-neutral-900 border dark:border-none m-4 sm:m-6 !mb-0 rounded-md">
|
<!-- <nav class="bg-white dark:bg-neutral-900 border dark:border-none m-4 sm:m-6 !mb-0 rounded-md">
|
||||||
<div class="w-full mx-auto md:flex md:flex-row md:justify-between md:items-center sm:gap-x-3 py-3 sm:py-5 px-4 sm:px-6 lg:px-8">
|
<div class="w-full mx-auto md:flex md:flex-row md:justify-between md:items-center sm:gap-x-3 py-3 sm:py-5 px-4 sm:px-6 lg:px-8">
|
||||||
<div class="flex justify-between items-center gap-x-3">
|
<div class="flex justify-between items-center gap-x-3">
|
||||||
<div class="grow flex items-center gap-x-4">
|
<div class="grow flex items-center gap-x-4">
|
||||||
@ -34,4 +34,58 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav> -->
|
||||||
|
|
||||||
|
<!-- bg-neutral-100 dark:bg-neutral-900 -->
|
||||||
|
<div class="max-w-[120rem]">
|
||||||
|
<div class="relative pt-5 before:w-full before:h-[200px] before:-z-10 before:top-0 before:start-0 before:absolute">
|
||||||
|
<div class="flex sm:items-center gap-5 p-4 sm:p-6 !pb-1">
|
||||||
|
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<div class="relative">
|
||||||
|
<% if (guild.icon) { %>
|
||||||
|
<img src="<%= guild.iconURL() %>" class="rounded-2xl sm:rounded-3xl size-16 sm:size-20" alt="">
|
||||||
|
<% } else { %>
|
||||||
|
<div class="size-16 sm:size-20 rounded-2xl sm:rounded-3xl flex shrink-0 justify-center items-center bg-white dark:bg-neutral-800">
|
||||||
|
<span class="text-2xl"><%= guild.nameAcronym %></span>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grow">
|
||||||
|
<h1 class="text-2xl md:text-3xl font-semibold text-gray-800 dark:text-neutral-200">
|
||||||
|
<%= guild.name %>
|
||||||
|
</h1>
|
||||||
|
<ul class="flex flex-wrap items-center gap-3 mt-2">
|
||||||
|
<li class="relative">
|
||||||
|
<span class="text-sm">ID:</span>
|
||||||
|
<span class="text-sm inline-flex items-center gap-2 text-gray-800 dark:text-neutral-200"><%= guild.id %></span>
|
||||||
|
</li>
|
||||||
|
<li class="relative">
|
||||||
|
<span class="text-sm">Members:</span>
|
||||||
|
<span class="text-sm inline-flex items-center gap-2 text-gray-800 dark:text-neutral-200"><%= guild.memberCount %></span>
|
||||||
|
</li>
|
||||||
|
<li class="relative">
|
||||||
|
<span class="text-sm">Channels:</span>
|
||||||
|
<span class="text-sm inline-flex items-center gap-2 text-gray-800 dark:text-neutral-200"><%= guild.channels.channelCountWithoutThreads %></span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col justify-center items-center mx-auto p-4 sm:p-6">
|
||||||
|
<div class="flex flex-row w-full pb-1 whitespace-nowrap overflow-x-auto overflow-y-hidden">
|
||||||
|
<!-- <a href="/guild/<%= guild.id %>" class="inline-flex items-center gap-2 whitespace-nowrap rounded-md px-3 py-2 text-sm text-gray-800 dark:text-neutral-200 dark:hover:text-neutral-400 dark:focus:text-neutral-400 <%= !isNaN(+guildPage) ? 'bg-white dark:bg-neutral-800 dark:!border-neutral-700 border shadow-sm' : 'mx-[1px]' %>">Overview</a> -->
|
||||||
|
<a href="/guild/<%= guild.id %>/subscriptions" class="inline-flex items-center gap-2 whitespace-nowrap rounded-md px-3 py-2 text-sm text-gray-800 dark:text-neutral-200 dark:hover:text-neutral-400 dark:focus:text-neutral-400 <%= guildPage === 'subscriptions' ? 'bg-white dark:bg-neutral-800 dark:!border-neutral-700 border shadow-sm' : 'mx-[1px]' %>">Subscriptions</a>
|
||||||
|
<a href="/guild/<%= guild.id %>/filters" class="inline-flex items-center gap-2 whitespace-nowrap rounded-md px-3 py-2 text-sm text-gray-800 dark:text-neutral-200 dark:hover:text-neutral-400 dark:focus:text-neutral-400 <%= guildPage === 'filters' ? 'bg-white dark:bg-neutral-800 dark:!border-neutral-700 border shadow-sm' : 'mx-[1px]' %>">Filters</a>
|
||||||
|
<a href="/guild/<%= guild.id %>/styles" class="inline-flex items-center gap-2 whitespace-nowrap rounded-md px-3 py-2 text-sm text-gray-800 dark:text-neutral-200 dark:hover:text-neutral-400 dark:focus:text-neutral-400 <%= guildPage === 'styles' ? 'bg-white dark:bg-neutral-800 dark:!border-neutral-700 border shadow-sm' : 'mx-[1px]' %>">Styles</a>
|
||||||
|
<a href="/guild/<%= guild.id %>/content" class="inline-flex items-center gap-2 whitespace-nowrap rounded-md px-3 py-2 text-sm text-gray-800 dark:text-neutral-200 dark:hover:text-neutral-400 dark:focus:text-neutral-400 <%= guildPage === 'content' ? 'bg-white dark:bg-neutral-800 dark:!border-neutral-700 border shadow-sm' : 'mx-[1px]' %>">Content</a>
|
||||||
|
<a href="#" class="inline-flex items-center gap-2 whitespace-nowrap rounded-md px-3 py-2 text-sm text-gray-800 dark:text-neutral-200 dark:hover:text-neutral-400 dark:focus:text-neutral-400">Settings</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -2,23 +2,15 @@
|
|||||||
|
|
||||||
<%- include("guildHeader") -%>
|
<%- include("guildHeader") -%>
|
||||||
|
|
||||||
<div class="flex flex-col justify-center items-center mx-auto px-4 sm:px-6">
|
|
||||||
<div class="flex flex-row w-full pb-1 whitespace-nowrap overflow-x-auto overflow-y-hidden">
|
|
||||||
<a href="#" class="inline-flex items-center gap-2 whitespace-nowrap rounded-md px-3 py-2 text-sm text-gray-800 dark:text-neutral-200 dark:hover:text-neutral-400 dark:focus:text-neutral-400 bg-white dark:bg-neutral-800 dark:!border-neutral-700 border shadow-sm">Subscriptions</a>
|
|
||||||
<a href="#" class="inline-flex items-center gap-2 whitespace-nowrap rounded-md px-3 py-2 text-sm text-gray-800 dark:text-neutral-200 dark:hover:text-neutral-400 dark:focus:text-neutral-400">Filters</a>
|
|
||||||
<a href="#" class="inline-flex items-center gap-2 whitespace-nowrap rounded-md px-3 py-2 text-sm text-gray-800 dark:text-neutral-200 dark:hover:text-neutral-400 dark:focus:text-neutral-400">Style</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Table Section -->
|
<!-- Table Section -->
|
||||||
<div id="table" class="max-w-full overflow-hidden p-4 sm:p-6"> <!-- px-4 py-10 sm:px-6 lg:px-8 lg:py-14 -->
|
<div id="table" class="--prevent-on-load-init max-w-full overflow-hidden px-4 sm:px-6"> <!-- px-4 py-10 sm:px-6 lg:px-8 lg:py-14 -->
|
||||||
<!-- Card -->
|
<!-- Card -->
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="-m-1.5">
|
<div class="-m-1.5">
|
||||||
<div class="max-w-full p-1.5 min-w-full inline-block align-middle">
|
<div class="max-w-full p-1.5 min-w-full inline-block align-middle">
|
||||||
<div class="bg-white border border-gray-200 rounded-md shadow-sm overflow-hidden dark:bg-neutral-900 dark:border-neutral-700">
|
<div class="bg-white border border-gray-200 rounded-md shadow-sm overflow-hidden dark:bg-neutral-900 dark:border-neutral-700">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="px-6 py-4 gap-3 flex flex-nowrap justify-between items-center border-gray-200 dark:border-neutral-700">
|
<div class="px-6 py-4 gap-3 flex flex-nowrap justify-between items-center border-b border-gray-200 dark:border-neutral-700">
|
||||||
<!-- Input -->
|
<!-- Input -->
|
||||||
<div class="hidden sm:block sm:col-span-1">
|
<div class="hidden sm:block sm:col-span-1">
|
||||||
<label for="search" class="sr-only">Search</label>
|
<label for="search" class="sr-only">Search</label>
|
||||||
@ -53,22 +45,22 @@
|
|||||||
<div class="hs-dropdown-menu transition-[opacity,margin] duration hs-dropdown-open:opacity-100 opacity-0 hidden divide-y divide-gray-200 min-w-48 z-10 bg-white shadow-md rounded-md mt-2 dark:divide-neutral-700 dark:bg-neutral-800 dark:border dark:border-neutral-700" role="menu" aria-orientation="vertical" aria-labelledby="hs-as-table-table-filter-dropdown">
|
<div class="hs-dropdown-menu transition-[opacity,margin] duration hs-dropdown-open:opacity-100 opacity-0 hidden divide-y divide-gray-200 min-w-48 z-10 bg-white shadow-md rounded-md mt-2 dark:divide-neutral-700 dark:bg-neutral-800 dark:border dark:border-neutral-700" role="menu" aria-orientation="vertical" aria-labelledby="hs-as-table-table-filter-dropdown">
|
||||||
<div class="divide-y divide-gray-200 dark:divide-neutral-700">
|
<div class="divide-y divide-gray-200 dark:divide-neutral-700">
|
||||||
<label for="hs-as-filters-dropdown-all" class="flex py-2.5 px-3">
|
<label for="hs-as-filters-dropdown-all" class="flex py-2.5 px-3">
|
||||||
<input type="radio" name="filter" class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800" id="hs-as-filters-dropdown-all" checked>
|
<input type="radio" name="filterActive" class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800" id="hs-as-filters-dropdown-all" checked value="1">
|
||||||
<span class="ms-3 text-sm text-gray-800 dark:text-neutral-200">All</span>
|
<span class="ms-3 text-sm text-gray-800 dark:text-neutral-200">All</span>
|
||||||
</label>
|
</label>
|
||||||
<label for="hs-as-filters-dropdown-published" class="flex py-2.5 px-3">
|
<label for="hs-as-filters-dropdown-published" class="flex py-2.5 px-3">
|
||||||
<input type="radio" name="filter" class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800" id="hs-as-filters-dropdown-published">
|
<input type="radio" name="filterActive" class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800" id="hs-as-filters-dropdown-published" value="1">
|
||||||
<span class="ms-3 text-sm text-gray-800 dark:text-neutral-200">Enabled</span>
|
<span class="ms-3 text-sm text-gray-800 dark:text-neutral-200">Active</span>
|
||||||
</label>
|
</label>
|
||||||
<label for="hs-as-filters-dropdown-pending" class="flex py-2.5 px-3">
|
<label for="hs-as-filters-dropdown-pending" class="flex py-2.5 px-3">
|
||||||
<input type="radio" name="filter" class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800" id="hs-as-filters-dropdown-pending">
|
<input type="radio" name="filterActive" class="shrink-0 mt-0.5 border-gray-200 rounded-full text-blue-600 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800" id="hs-as-filters-dropdown-pending" value="0">
|
||||||
<span class="ms-3 text-sm text-gray-800 dark:text-neutral-200">Disabled</span>
|
<span class="ms-3 text-sm text-gray-800 dark:text-neutral-200">Inactive</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none" data-hs-overlay="#hs-scale-animation-modal">
|
<button type="button" class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none" data-hs-overlay="#subModal">
|
||||||
<svg class="shrink-0 size-4" xmlns="http://www.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"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
|
<svg class="shrink-0 size-4" xmlns="http://www.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"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
|
||||||
<span>
|
<span>
|
||||||
Add
|
Add
|
||||||
@ -84,7 +76,7 @@
|
|||||||
<div class="min-w-full overflow-x-auto">
|
<div class="min-w-full overflow-x-auto">
|
||||||
<!-- Table -->
|
<!-- Table -->
|
||||||
<table class="min-w-full divide-y divide-gray-200 dark:divide-neutral-700">
|
<table class="min-w-full divide-y divide-gray-200 dark:divide-neutral-700">
|
||||||
<thead class="bg-gray-50 dark:bg-neutral-800">
|
<thead class="bg-gray-50 dark:bg-neutral-800 border-none">
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" class="ps-6 py-3 text-start --exclude-from-ordering">
|
<th scope="col" class="ps-6 py-3 text-start --exclude-from-ordering">
|
||||||
<label for="hs-at-with-checkboxes-main" class="flex ml-[1px]">
|
<label for="hs-at-with-checkboxes-main" class="flex ml-[1px]">
|
||||||
@ -240,7 +232,7 @@
|
|||||||
<!-- End Table Section -->
|
<!-- End Table Section -->
|
||||||
|
|
||||||
<!-- Popup -->
|
<!-- Popup -->
|
||||||
<div id="hs-scale-animation-modal" 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" aria-labelledby="hs-scale-animation-modal-label">
|
<div id="subModal" 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" aria-labelledby="hs-scale-animation-modal-label">
|
||||||
<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="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-sm rounded-md pointer-events-auto dark:bg-neutral-800 dark:border-neutral-700 dark:shadow-neutral-700/70">
|
<div class="w-full p-4 sm:p-7 flex flex-col bg-white border shadow-sm rounded-md pointer-events-auto dark:bg-neutral-800 dark:border-neutral-700 dark:shadow-neutral-700/70">
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
@ -371,7 +363,7 @@
|
|||||||
<button type="button" class="me-auto py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 focus:outline-none focus:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700">
|
<button type="button" class="me-auto py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 focus:outline-none focus:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700">
|
||||||
Templates
|
Templates
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 focus:outline-none focus:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700" data-hs-overlay="#hs-scale-animation-modal">
|
<button type="button" class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 focus:outline-none focus:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700" data-hs-overlay="#subModal">
|
||||||
Close
|
Close
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" form="subForm" class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none">
|
<button type="submit" form="subForm" class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-md border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none">
|
||||||
|
@ -3,17 +3,21 @@ import { client as bot } from "@bot/bot";
|
|||||||
|
|
||||||
export const get = async (request: Request, response: Response) => {
|
export const get = async (request: Request, response: Response) => {
|
||||||
const guildId = request.params.guildId;
|
const guildId = request.params.guildId;
|
||||||
const guild = bot.guilds.cache.get(guildId);
|
|
||||||
|
|
||||||
if (!guild) {
|
response.redirect(`/guild/${guildId}/subscriptions`);
|
||||||
response.status(404).send("404: guild not found");
|
return
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
response.render("guild/overview", {
|
// const guild = bot.guilds.cache.get(guildId);
|
||||||
title: `${guild.name} - Relay`,
|
|
||||||
guild: guild,
|
// if (!guild) {
|
||||||
});
|
// response.status(404).send("404: guild not found");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// response.render("guild/overview", {
|
||||||
|
// title: `${guild.name} - Relay`,
|
||||||
|
// guild: guild,
|
||||||
|
// });
|
||||||
};
|
};
|
||||||
|
|
||||||
export default { get };
|
export default { get };
|
@ -1,39 +1,43 @@
|
|||||||
import { NextFunction, Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { buildDatatableQuery } from "@utils/datatable";
|
import { buildDatatableQuery } from "@utils/datatable";
|
||||||
import { db } from "@db/db";
|
import { db } from "@db/db";
|
||||||
import { client as bot } from "@bot/bot";
|
import { client as bot } from "@bot/bot";
|
||||||
|
|
||||||
const isPostgres = db.client.config.client === "pg";
|
const isPostgres = db.client.config.client === "pg";
|
||||||
|
const TABLE = "subscriptions";
|
||||||
|
|
||||||
export const datatable = async (request: Request, response: Response) => {
|
export const datatable = async (request: Request, response: Response) => {
|
||||||
try {
|
try {
|
||||||
const { query, recordsTotal, recordsFiltered } = await buildDatatableQuery(
|
|
||||||
request as any,
|
|
||||||
"subscriptions"
|
|
||||||
);
|
|
||||||
|
|
||||||
query.select("subscriptions.*")
|
let query = db(TABLE).where({ guild_id: request.params.guildId });
|
||||||
.leftJoin("channels", "subscriptions.id", "=", "channels.subscription_id")
|
// query.select("subscriptions.*")
|
||||||
.select(db.raw(isPostgres
|
// .leftJoin("channels", "subscriptions.id", "=", "channels.subscription_id")
|
||||||
? "json_agg(channels.channel_id) as channels"
|
// .select(db.raw(isPostgres
|
||||||
:"JSON_GROUP_ARRAY(channels.channel_id) as channels"
|
// ? "json_agg(channels.channel_id) as channels"
|
||||||
))
|
// :"JSON_GROUP_ARRAY(channels.channel_id) as channels"
|
||||||
.groupBy("subscriptions.id")
|
// ))
|
||||||
|
// .groupBy("subscriptions.id")
|
||||||
|
|
||||||
const data = await query.where({ guild_id: request.params.guildId });
|
const datatableQuery = await buildDatatableQuery(request as any, query, TABLE);
|
||||||
|
const { recordsTotal, recordsFiltered } = datatableQuery;
|
||||||
|
query = datatableQuery.query;
|
||||||
|
|
||||||
|
const data = await query;
|
||||||
|
|
||||||
data.forEach((item: any) => {
|
console.log(`total: ${recordsTotal} filtered: ${recordsFiltered} filtered+paged: ${data.length}`);
|
||||||
item.channels = item.channels === "[null]"
|
|
||||||
? []
|
// data.forEach((item: any) => {
|
||||||
: JSON.parse(item.channels);
|
// item.channels = item.channels === "[null]"
|
||||||
|
// ? []
|
||||||
|
// : JSON.parse(item.channels);
|
||||||
|
|
||||||
// item.channels.forEach((channel: any) => {
|
// // item.channels.forEach((channel: any) => {
|
||||||
// channel = {
|
// // channel = {
|
||||||
// "channel_id": channel,
|
// // "channel_id": channel,
|
||||||
// "name": bot.channels.cache.filter(a => a.id === id).first().name;
|
// // "name": bot.channels.cache.filter(a => a.id === id).first().name;
|
||||||
// }
|
// // }
|
||||||
// })
|
// // })
|
||||||
});
|
// });
|
||||||
|
|
||||||
response.json({
|
response.json({
|
||||||
data,
|
data,
|
||||||
|
@ -7,6 +7,7 @@ export interface RequestQuery {
|
|||||||
order: { column: string; dir: string }[];
|
order: { column: string; dir: string }[];
|
||||||
columns: { [key: string]: { data: string; searchable: string } };
|
columns: { [key: string]: { data: string; searchable: string } };
|
||||||
search: { value: string };
|
search: { value: string };
|
||||||
|
filters: { [key: string]: any };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResponseQuery {
|
export interface ResponseQuery {
|
||||||
@ -15,7 +16,11 @@ export interface ResponseQuery {
|
|||||||
recordsFiltered: number | string;
|
recordsFiltered: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const buildDatatableQuery = async (request: { query: RequestQuery }, tableName: string): Promise<ResponseQuery> => {
|
type FilterConfig = {
|
||||||
|
[key: string]: (value: any) => Knex.QueryBuilder;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildDatatableQuery = async (request: { query: RequestQuery }, query: Knex.QueryBuilder, tableName: string): Promise<ResponseQuery> => {
|
||||||
const size: number = parseInt(request.query.length) || 10;
|
const size: number = parseInt(request.query.length) || 10;
|
||||||
const start: number = parseInt(request.query.start);
|
const start: number = parseInt(request.query.start);
|
||||||
const order: string = (
|
const order: string = (
|
||||||
@ -25,7 +30,18 @@ export const buildDatatableQuery = async (request: { query: RequestQuery }, tabl
|
|||||||
const direction: string = (request.query.order && request.query.order[0].dir) || "asc";
|
const direction: string = (request.query.order && request.query.order[0].dir) || "asc";
|
||||||
const search: string = request.query.search.value;
|
const search: string = request.query.search.value;
|
||||||
|
|
||||||
let query = db(tableName);
|
const filterConfig: FilterConfig = {
|
||||||
|
active: (value: number) => query.where('active', '=', value),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (request.query.filters) {
|
||||||
|
Object.keys(request.query.filters).forEach((filterName: any) => {
|
||||||
|
const filterValue = request.query.filters[filterName];
|
||||||
|
if (filterConfig[filterName] && filterValue) {
|
||||||
|
query = filterConfig[filterName](filterValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (search) {
|
if (search) {
|
||||||
console.log("applying search: " + search)
|
console.log("applying search: " + search)
|
||||||
@ -39,7 +55,6 @@ export const buildDatatableQuery = async (request: { query: RequestQuery }, tabl
|
|||||||
: builder.orWhere(`${tableName}.${col.data}`, "like", `%${search}%`)
|
: builder.orWhere(`${tableName}.${col.data}`, "like", `%${search}%`)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
console.log(query.toSQL());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const recordsTotalResult = await db(tableName).count("* as count").first();
|
const recordsTotalResult = await db(tableName).count("* as count").first();
|
||||||
@ -48,6 +63,9 @@ export const buildDatatableQuery = async (request: { query: RequestQuery }, tabl
|
|||||||
const recordsFilteredResult = await query.clone().count("* as count").first();
|
const recordsFilteredResult = await query.clone().count("* as count").first();
|
||||||
const recordsFiltered = recordsFilteredResult ? recordsFilteredResult.count : 0;
|
const recordsFiltered = recordsFilteredResult ? recordsFilteredResult.count : 0;
|
||||||
|
|
||||||
|
console.log(query.toSQL())
|
||||||
|
console.log(query.clone().count("* as count").toSQL())
|
||||||
|
|
||||||
query = query.orderBy(`${tableName}.${order}`, direction).limit(size).offset(start);
|
query = query.orderBy(`${tableName}.${order}`, direction).limit(size).offset(start);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user