Skip to content
New issue

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

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

Already on GitHub? # to your account

use a home made datatable component #337

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
60 changes: 0 additions & 60 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
},
"dependencies": {
"@vscode/markdown-it-katex": "^1.1.0",
"datatables.net-buttons-dt": "^3.1.2",
"datatables.net-vue3": "^3.0.2",
"date-fns": "^3.6.0",
"markdown-it": "^14.1.0",
"markdown-it-emoji": "^3.0.0",
Expand Down
Binary file modified frontend/src/assets/fonts/icomoon.eot
Binary file not shown.
28 changes: 15 additions & 13 deletions frontend/src/assets/fonts/icomoon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/src/assets/fonts/icomoon.ttf
Binary file not shown.
Binary file modified frontend/src/assets/fonts/icomoon.woff
Binary file not shown.
52 changes: 30 additions & 22 deletions frontend/src/assets/styles/_icons.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,54 +27,62 @@
text-transform: none;
}

.icon-left::before {
content: "\e908";
.icon-magnifying-glass::before {
content: "\e900";
}

.icon-down::before {
content: "\e909";
.icon-grid-layout-large::before {
content: "\e901";
}

.icon-right::before {
content: "\e90a";
.icon-grid-layout-medium::before {
content: "\e902";
}

.icon-up::before {
content: "\e90b";
.icon-grid-layout-small::before {
content: "\e903";
}

.icon-focus::before {
content: "\e90c";
content: "\e904";
}

.icon-grid-layout-large::before {
.icon-folder::before {
content: "\e905";
}

.icon-grid-layout-medium::before {
.icon-plot::before {
content: "\e906";
}

.icon-grid-layout-small::before {
.icon-text-size::before {
content: "\e907";
}

.icon-text::before {
content: "\e900";
.icon-gift::before {
content: "\e908";
}

.icon-plot::before {
content: "\e901";
.icon-pie-chart::before {
content: "\e909";
}

.icon-gift::before {
content: "\e902";
.icon-equal::before {
content: "\e90a";
}

.icon-pie-chart::before {
content: "\e903";
.icon-left::before {
content: "\e90b";
}

.icon-folder::before {
content: "\e904";
.icon-down::before {
content: "\e90c";
}

.icon-right::before {
content: "\e90d";
}

.icon-up::before {
content: "\e90e";
}
203 changes: 189 additions & 14 deletions frontend/src/components/DataFrameWidget.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,200 @@
<script setup lang="ts">
import "datatables.net-dt/css/dataTables.dataTables.min.css";

import DataTablesCore from "datatables.net";
import DataTable from "datatables.net-vue3";

DataTable.use(DataTablesCore);
import Simplebar from "simplebar-vue";
import { computed, ref, watch } from "vue";
import TextInput from "./TextInput.vue";

export interface DataFrameWidgetProps {
columns: string[];
data: any[][];
}

const props = defineProps<DataFrameWidgetProps>();

const rowPerPage = ref(10);
const currentPage = ref(0);
const search = defineModel<string>("search");

const rows = computed(() => {
if (search.value !== undefined && search.value.length > 0) {
const searchToken = search.value.toLowerCase();
return props.data.filter((row) => {
const text = row.join(" ").toLowerCase();
return text.includes(searchToken);
});
}
return props.data;
});

const totalPages = computed(() => {
return Math.ceil(rows.value.length / rowPerPage.value);
});

const pageStart = computed(() => {
return currentPage.value * rowPerPage.value;
});

const pageEnd = computed(() => {
return (currentPage.value + 1) * rowPerPage.value;
});

const visibleRows = computed(() => {
return rows.value.slice(pageStart.value, pageEnd.value);
});

function nextPage() {
if (currentPage.value < totalPages.value - 1) {
currentPage.value++;
}
}

function previousPage() {
if (currentPage.value > 0) {
currentPage.value--;
}
}

function onPageSizeChange(event: Event) {
currentPage.value = 0;
rowPerPage.value = parseInt((event.target as HTMLSelectElement).value);
}

watch(props.data, () => {
currentPage.value = 0;
});

watch(props.columns, () => {
currentPage.value = 0;
});
</script>

<template>
<DataTable :data="props.data" :options="{ paging: props.data.length > 10 }">
<thead>
<tr>
<th v-for="(name, index) in props.columns" :key="index">{{ name }}</th>
</tr>
</thead>
</DataTable>
<TextInput v-model="search" icon="icon-magnifying-glass" placeholder="Search" />
<Simplebar>
<table>
<thead>
<tr>
<th v-for="(name, index) in props.columns" :key="index">{{ name }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in visibleRows" :key="index">
<td v-for="(value, index) in row" :key="index">{{ value }}</td>
</tr>
</tbody>
</table>
</Simplebar>
<div class="pagination" v-if="totalPages > 1 || rowPerPage == rows.length">
<div class="pagination-page-size">
Page size
<select @change="onPageSizeChange">
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
</select>
</div>
<div class="pagination-buttons" v-if="totalPages > 1">
<button @click="currentPage = 0" :disabled="currentPage == 0">&lt;&lt;</button>
<button @click="previousPage" :disabled="currentPage == 0">&lt;</button>
<button @click="nextPage" :disabled="currentPage == totalPages - 1">&gt;</button>
<button @click="currentPage = totalPages - 1" :disabled="currentPage == totalPages - 1">
&gt;&gt;
</button>
</div>
<div class="page-info">
Results: {{ pageStart + 1 }}-{{ Math.min(pageEnd, rows.length) }} of {{ rows.length }}
<span v-if="search && search.length > 0">
(filtered from {{ props.data.length }} results)</span
>
</div>
</div>
</template>

<style scoped>
table {
width: 100%;
border: 1px solid var(--border-color-normal);
border-radius: var(--border-radius);
margin-top: var(--spacing-gap-small);
border-collapse: separate;
border-spacing: 0;
text-align: right;

& thead {
background-color: var(--background-color-elevated);
color: var(--text-color-normal);
font-size: var(--text-size-normal);
font-weight: var(--text-weight-normal);

& tr {
& th {
padding: var(--spacing-padding-small);
}
}
}

& tbody {
& tr {
padding: var(--spacing-padding-small);

& td {
padding: var(--spacing-padding-small);
color: var(--text-color-highlight);
font-size: var(--text-size-highlight);
font-weight: var(--text-weight-highlight);
}

&:last-child {
border-bottom: none;
}
}
}

& > thead > tr:not(:last-child) > th,
& > thead > tr:not(:last-child) > td,
& > tbody > tr:not(:last-child) > th,
& > tbody > tr:not(:last-child) > td,
& > tfoot > tr:not(:last-child) > th,
& > tfoot > tr:not(:last-child) > td,
& > thead:not(:last-child),
& > tbody:not(:last-child),
& > tfoot:not(:last-child) {
border-bottom: 1px solid var(--border-color-normal);
}
}

.pagination {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: var(--spacing-gap-normal);
color: var(--text-color-normal);
font-size: var(--text-size-normal);
font-weight: var(--text-weight-normal);

.pagination-buttons {
display: flex;
align-items: center;
gap: var(--spacing-gap-normal);

& button {
border: none;
background-color: transparent;
cursor: pointer;
font-size: var(--text-size-highlight);
font-weight: var(--text-weight-highlight);
}
}

& select {
padding: var(--spacing-padding-small);
border: 1px solid var(--border-color-lower);
border-radius: var(--border-radius);
margin-left: var(--spacing-gap-normal);
background-color: var(--background-color-elevated-high);
box-shadow: 0 1px 2px var(--background-color-selected);
color: var(--text-color-highlight);
cursor: pointer;
font-size: var(--text-size-highlight);
font-weight: var(--text-weight-highlight);
}
}
</style>
Loading