Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Admin panel #33

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4e4bae9
Added admin panel route and restriction for Styret role
Sigurvar Dec 12, 2021
958ac95
Added admin panel and api call to fetch all users
Sigurvar Dec 14, 2021
1418f0c
Added table with user info, with ordering and opening capability'
Sigurvar Dec 14, 2021
4b4779c
linting
Sigurvar Dec 14, 2021
9a5f8ed
Added possibility to search and filter users
Sigurvar Dec 15, 2021
22bc4cc
added user info box
Sigurvar Dec 15, 2021
4e779f2
linting
Sigurvar Dec 15, 2021
fd3d0b2
Added function to fetch all applications and groups
Sigurvar Dec 16, 2021
56c0e37
re-added dependencie
Sigurvar Dec 16, 2021
64c6c0e
added view to see groups and applications
Sigurvar Dec 16, 2021
0718bd8
cleaned up code and added advanced search filter
Sigurvar Dec 17, 2021
fa9fce9
cleaned up code
Sigurvar Dec 17, 2021
7563350
Added support for pageination
Sigurvar Dec 17, 2021
3a77e7f
lint
Sigurvar Dec 17, 2021
e63ce4f
added icons for sorting
Sigurvar Dec 17, 2021
4b92318
cleaned code
Sigurvar Dec 17, 2021
73ba3f4
cleaned up code
Sigurvar Dec 18, 2021
d566137
added support to edit displayName, study year and program
Sigurvar Dec 18, 2021
ab025da
Code refactor
Sigurvar Dec 18, 2021
564878c
added support to add and remove groups for users
Sigurvar Dec 19, 2021
f14cad5
made it possible to add application registration and add roles
Sigurvar Dec 20, 2021
629b3d7
made it possible to remove application roles
Sigurvar Dec 20, 2021
091e217
cleaned up in code
Sigurvar Dec 20, 2021
5ce9b33
removed option to delete and add application roles and cleaned up in …
Sigurvar Dec 21, 2021
c1c7392
Added support to see discord username and if user is discord member i…
Sigurvar Dec 21, 2021
dc7128a
refactor
Sigurvar Dec 21, 2021
aa0c142
added support to filter on discord members
Sigurvar Dec 21, 2021
61dd14a
format
Sigurvar Dec 21, 2021
962a583
refactor
Sigurvar Dec 21, 2021
eb0a7af
Added support for confimration and error message on edits
Sigurvar Dec 22, 2021
b30bbc4
format
Sigurvar Dec 22, 2021
5b13b48
formating working !
Sigurvar Dec 23, 2021
19e15ad
added support for update of user roles on update of applications and …
Sigurvar Dec 26, 2021
4f72b38
added chack of changevalue before confirm, and fixed formating
Sigurvar Dec 26, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@rollup/plugin-commonjs": "^14.0.0",
"@rollup/plugin-node-resolve": "^8.0.0",
"@rollup/plugin-replace": "^2.2.0",
"@zerodevx/svelte-toast": "^0.6.2",
"depcheck": "^1.4.2",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
Expand Down
268 changes: 268 additions & 0 deletions src/components/AdminPanelTable.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
<!-- ORIGINAL SOURCE: https://github.com/dasDaniel/svelte-table/blob/develop/src/SvelteTable.svelte -->
<script>
import MultiSelect from '../components/MultiSelect.svelte';
import FaSortUp from 'svelte-icons/fa/FaSortUp.svelte';
import FaSortDown from 'svelte-icons/fa/FaSortDown.svelte';
import FaSort from 'svelte-icons/fa/FaSort.svelte';

export let columns;
export let rows;
export let simpleFilterOptions = {};
export let expandRowKey = null;
export let filters = [];

let sortBy = '';
let sortOrder = 1;
let expanded = [];

let iconExpand = '⌄';
let iconExpanded = '⌃';
let maxPerPage = 10;
let page = 1;
let advancedSearch = false;
let sortFunction = () => '';
let searchValue = '';

const increasePage = () => {
page += page * maxPerPage >= c_rows.length ? 0 : 1;
};
const decreasePage = () => {
page -= page == 1 ? 0 : 1;
};

let filterValues = {};
filters.forEach((el) => (filterValues[el.title] = el.defaultFiltering));
let columnByKey = {};
$: {
columnByKey = {};
columns.forEach((col) => {
columnByKey[col.key] = col;
});
}
const unsetBoolFilter = (input, title) => {
if (input.__value === filterValues[title]) {
filterValues[title] = '';
}
};

$: colspan = 1 + columns.length;

const simpleFilter = (rows, searchValue) => {
page = 1;
return rows.filter((r) => simpleFilterOptions.filter(r, searchValue));
};
const advancedFilter = (rows, filterValues) => {
page = 1;
return rows.filter((r) => filters.every((e) => e.filter(r, filterValues[e.title])));
};
// Filter rows
$: c_rows = (advancedSearch ? advancedFilter(rows, filterValues) : simpleFilter(rows, searchValue))
.map((r) =>
Object.assign({}, r, {
// internal row property for sort order
$sortOn: sortFunction(r),
// internal row property for expanded rows
$expanded: expandRowKey !== null && expanded.indexOf(r[expandRowKey]) >= 0
})
)
.sort((a, b) => {
if (a.$sortOn > b.$sortOn) return sortOrder;
else if (a.$sortOn < b.$sortOn) return -sortOrder;
return 0;
});

$: {
let col = columnByKey[sortBy];
if (col !== undefined && typeof col.value === 'function') {
if (typeof col.value(rows[0]) === 'string') {
sortFunction = (r) => col.value(r).toLocaleLowerCase();
} else {
sortFunction = (r) => col.value(r);
}
}
}

const handleClickCol = (event, col) => {
sortOrder = col.key === sortBy ? sortOrder * -1 : 1;
sortBy = col.key;
};

const handleClickExpand = (event, row) => {
row.$expanded = !row.$expanded;
if (row.$expanded) {
expanded = [row[expandRowKey]];
} else {
expanded = [];
}
};
</script>

<div class="filterOptions">
{#if !advancedSearch}
<p>{simpleFilterOptions.title}</p>
<input bind:value={searchValue} />
{:else}
{#each filters as filter}
{#if filter.isDate}
<span>
<p>{filter.title} før:</p>
<input onfocus="(this.type='date')" onblur="(this.type='text')" bind:value={filterValues[filter.title][0]} />
</span>
<span>
<p>{filter.title} etter:</p>
<input onfocus="(this.type='date')" onblur="(this.type='text')" bind:value={filterValues[filter.title][1]} />
</span>
{:else if filter.isBoolean}
<span class="radio">
<p>{filter.title}:</p>
<label for="html">Ja</label>
<input name="yes" value={true} on:click={unsetBoolFilter(this, filter.title)} bind:group={filterValues[filter.title]} type="radio" />
<label for="html">Nei</label>
<input name="yes" value={undefined} on:click={unsetBoolFilter(this, filter.title)} bind:group={filterValues[filter.title]} type="radio" />
</span>
{:else}
<span>
<p>{filter.title}:</p>
{#if filter.filterValues}
<MultiSelect bind:selected={filterValues[filter.title]} options={filter.filterValues} />
{:else}
<input bind:value={filterValues[filter.title]} />
{/if}
</span>
{/if}
{/each}
{/if}
<br />

<button on:click={() => (advancedSearch = !advancedSearch)}>{advancedSearch ? 'Skjul a' : 'A'}vansert søk</button>
</div>
<table>
<thead>
<tr>
{#each columns as col}
<th on:click={(e) => handleClickCol(e, col)} class="pointer header">
{col.title}
<span>
{#if sortBy === col.key}
{#if sortOrder === 1}
<FaSortUp />
{:else}
<FaSortDown />
{/if}
{:else}
<FaSort />
{/if}
</span>
</th>
{/each}
<th />
</tr>
</thead>

<tbody>
{#each c_rows.slice((page - 1) * maxPerPage, page * maxPerPage) as row, n}
<tr on:click={(e) => handleClickExpand(e, row)} class="expand pointer">
{#each columns as col}
<td>{col.value(row)}</td>
{/each}
<td>{@html row.$expanded ? iconExpand : iconExpanded}</td>
</tr>
{#if row.$expanded}
<tr>
<td {colspan}><slot name="expanded" {row} {n} /></td>
</tr>
{/if}
{/each}
</tbody>
</table>
<div class="pageination" style="display:grid;grid-template-columns: 33% 33% 34% ">
<p style="text-align:left" on:click={decreasePage}>←</p>
<p style="text-align:center">{(page - 1) * maxPerPage + (c_rows.length != 0 ? 1 : 0)}-{Math.min(page * maxPerPage, c_rows.length)} av {c_rows.length}</p>

<p style="text-align:right " on:click={increasePage}>→</p>
<span>
<p>Resultater per side:</p>
<select bind:value={maxPerPage} style="margin-left:10px;width:70px">
{#each [5, 10, 15, 20, 40, 60, 100] as num}
<option value={num}>{num}</option>
{/each}
</select>
</span>
</div>

<style>
.radio > input {
width: min-content;
transition: none;
background-color: #777;
margin-right: 1em;
}
.radio > input:checked {
background-color: var(--green-2);
}
.pageination p,
select {
margin: 0px;
margin-top: 15px;
}
.pageination span * {
display: inline;
}
.filterOptions p {
display: inline;
margin: 0px;
margin-right: 10px;
}
.filterOptions span {
display: inline;
width: 100%;
padding: 0.4em;
}
button {
position: absolute;
right: 0;
bottom: 0;
font-size: smaller;
width: auto;
}
.filterOptions {
width: 100%;
position: relative;
display: grid;
grid-template-columns: 50% 50%;
padding: 0.6em;
padding-bottom: 2em;
}
table {
width: 100%;
}
.pointer {
cursor: pointer;
}
tbody,
td {
border: 0px solid #666;
border-bottom-width: 1px;
}
th {
border: 0px solid #bbb;
border-bottom-width: 2px;
text-align: left;
}
table {
caption-side: bottom;
border-collapse: collapse;
}

.header > span {
display: inline-block;
height: 0.75em;
vertical-align: sub;
margin-left: 4px;
color: #fff;
transition: 0.4s linear;
}
.header > span:hover {
color: var(--green-2);
}
</style>
Loading