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

feat(UI & API): Manage views in the frontend #414

Merged
merged 28 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
45280ea
Serialize views in API layer
augustebaum Sep 30, 2024
eb6716b
Change "set report layout" endpoint to take a `key` argument
augustebaum Sep 30, 2024
3890ba2
Add "delete view" endpoint
augustebaum Sep 30, 2024
4190264
Change "Share report" endpoint to take only a view key rather than a …
augustebaum Sep 30, 2024
943c50b
Remove `LayoutItemSize`
augustebaum Sep 30, 2024
261c5be
add optional action button to the section header
rouk1 Sep 30, 2024
2e7af08
editable list: layout and events
rouk1 Sep 30, 2024
258727f
Merge branch 'main' into 336-ui-manage-views
rouk1 Sep 30, 2024
2560383
editable list item action and naming
rouk1 Sep 30, 2024
d69975e
use floating UI to enable dropdwon in scrolls 😓
rouk1 Oct 1, 2024
f498790
wip
rouk1 Oct 1, 2024
8728543
Merge branch 'main' into 336-ui-manage-views
rouk1 Oct 1, 2024
d9b0b7d
use model in editable list demo
rouk1 Oct 1, 2024
c2f164e
refactor to enable multi view
rouk1 Oct 1, 2024
26a6ea9
fix tests
rouk1 Oct 1, 2024
3408ccb
use ids in editable list items allowing straight forward views backen…
rouk1 Oct 2, 2024
7b70016
delete card from view + new card actions dropdown
rouk1 Oct 2, 2024
a1f967f
do not emit edit event if name does not change
rouk1 Oct 2, 2024
d5dfed2
add toasts feedbacks
rouk1 Oct 2, 2024
ae049db
re-enable polling
rouk1 Oct 2, 2024
fe836d2
no more report
rouk1 Oct 2, 2024
4fb8903
forgotten rename
rouk1 Oct 2, 2024
6c7193f
use query param instead of path param
rouk1 Oct 3, 2024
3dea59d
alert user that adding item when no view is selected is impossible
rouk1 Oct 3, 2024
0ba28ec
focus editable list item when isUnamed changes and remove focus on blur
rouk1 Oct 3, 2024
473d4cc
Make it impossible to create a view with a name that already exists
augustebaum Oct 3, 2024
2806205
hide editable item dropdown if renaming
rouk1 Oct 3, 2024
7f96f45
Merge branch 'main' into 336-ui-manage-views
augustebaum Oct 3, 2024
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
63 changes: 63 additions & 0 deletions frontend/package-lock.json

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

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"format": "prettier --write src/"
},
"dependencies": {
"@floating-ui/vue": "^1.1.5",
"@vscode/markdown-it-katex": "^1.1.0",
"date-fns": "^3.6.0",
"markdown-it": "^14.1.0",
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/ShareApp.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
<script setup lang="ts">
import Simplebar from "simplebar-vue";

import ReportCanvas from "@/components/ReportCanvas.vue";
import ProjectViewCanvas from "@/components/ProjectViewCanvas.vue";
import { useProjectStore } from "@/stores/project";

const projectStore = useProjectStore();
</script>

<template>
<div class="share">
<div class="share-header">
<h1>Report</h1>
<h1>{{ projectStore.currentView }}</h1>
</div>
<Simplebar class="canvas-wrapper">
<ReportCanvas :showCardButtons="false" />
<ProjectViewCanvas :showCardActions="false" />
</Simplebar>
</div>
</template>
Expand Down
Binary file modified frontend/src/assets/fonts/icomoon.eot
Binary file not shown.
51 changes: 24 additions & 27 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.
58 changes: 23 additions & 35 deletions frontend/src/assets/styles/_icons.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,109 +28,97 @@
}

.icon-branch::before {
content: "\e91a";
}

.icon-plus::before {
content: "\e900";
}

.icon-trash::before {
.icon-more::before {
content: "\e901";
}

.icon-rename::before {
.icon-trash::before {
content: "\e902";
}

.icon-duplicate::before {
.icon-edit::before {
content: "\e903";
}

.icon-pill::before {
.icon-copy::before {
content: "\e904";
}

.icon-new-file::before {
.icon-pill::before {
content: "\e905";
}

.icon-recent-file::before {
.icon-new-document::before {
content: "\e906";
}

.icon-warning::before {
.icon-recent-document::before {
content: "\e907";
}

.icon-info::before {
.icon-plus-circle::before {
content: "\e908";
}

.icon-error::before {
.icon-warning::before {
content: "\e909";
}

.icon-success::before {
.icon-info::before {
content: "\e90a";
}

.icon-grid-layout-large::before {
.icon-error::before {
content: "\e90b";
}

.icon-grid-layout-medium::before {
.icon-success::before {
content: "\e90c";
}

.icon-grid-layout-small::before {
.icon-search::before {
content: "\e90d";
}

.icon-magnifying-glass::before {
.icon-maximize::before {
content: "\e90e";
}

.icon-focus::before {
.icon-folder::before {
content: "\e90f";
}

.icon-folder::before {
.icon-plot::before {
content: "\e910";
}

.icon-plot::before {
.icon-text::before {
content: "\e911";
}

.icon-text-size::before {
content: "\e912";
}

.icon-gift::before {
content: "\e913";
content: "\e912";
}

.icon-pie-chart::before {
content: "\e914";
}

.icon-equal::before {
content: "\e915";
content: "\e913";
}

.icon-chevron-left::before {
content: "\e916";
content: "\e914";
}

.icon-chevron-down::before {
content: "\e917";
content: "\e915";
}

.icon-chevron-right::before {
content: "\e918";
content: "\e916";
}

.icon-chevron-up::before {
content: "\e919";
content: "\e917";
}
1 change: 1 addition & 0 deletions frontend/src/assets/styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@import url("./_typography.css");
@import url("./_animations.css");
@import url("./_icons.css");
@import url("simplebar-vue/dist/simplebar.min.css");
@import url("highlight.js/styles/atom-one-dark.css") screen and (prefers-color-scheme: dark);
@import url("highlight.js/styles/atom-one-light.css") screen and (prefers-color-scheme: light);

Expand Down
7 changes: 1 addition & 6 deletions frontend/src/components/DataFrameWidget.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,7 @@ watch([() => toValue(props.data), () => toValue(props.columns)], () => {

<template>
<div class="data-frame-widget">
<TextInput
v-model="search"
icon="icon-magnifying-glass"
placeholder="Search"
class="search-input"
/>
<TextInput v-model="search" icon="icon-search" placeholder="Search" class="search-input" />
<Simplebar>
<table>
<thead>
Expand Down
76 changes: 57 additions & 19 deletions frontend/src/components/DropdownButton.vue
Original file line number Diff line number Diff line change
@@ -1,31 +1,77 @@
<script setup lang="ts">
import SimpleButton from "@/components/SimpleButton.vue";
import { autoUpdate, useFloating } from "@floating-ui/vue";
import { onBeforeUnmount, onMounted, ref } from "vue";

import SimpleButton from "@/components/SimpleButton.vue";

interface DropdownProps {
label?: string;
icon?: string;
isPrimary?: boolean;
align?: "left" | "right";
isInline?: boolean;
}

const props = withDefaults(defineProps<DropdownProps>(), { isPrimary: false, align: "left" });

const isOpen = ref(false);
const el = ref<HTMLDivElement>();
const reference = ref<HTMLElement>();
const floating = ref<HTMLDivElement>();
const { floatingStyles } = useFloating(reference, floating, {
placement: props.align === "right" ? "bottom-end" : "bottom-start",
strategy: "fixed",
whileElementsMounted: autoUpdate,
});

function onClick(e: Event) {
if (el.value && floating.value) {
// is it a click outside or a click on an item ?
if (!el.value.contains(e.target as Node) || floating.value.contains(e.target as Node)) {
isOpen.value = false;
}
}
}

function closeDropdown(e: Event) {
if (el.value && !el.value.contains(e.target as Node)) {
// Mouse move listener to close the dropdown when the mouse moves
function onMouseMove() {
if (
el.value &&
!el.value.checkVisibility({
opacityProperty: true,
contentVisibilityAuto: true,
visibilityProperty: true,
})
) {
isOpen.value = false;
}
}

// Intersection observer to close the dropdown when it is not visible
const intersectionObserver = new IntersectionObserver(
([entry]) => {
if (!entry.isIntersecting) {
isOpen.value = false;
}
},
{
root: document.body,
threshold: 0,
}
);

onMounted(() => {
document.addEventListener("click", closeDropdown);
document.addEventListener("click", onClick);
document.addEventListener("mousemove", onMouseMove);
if (el.value) {
intersectionObserver.observe(el.value);
}
});

onBeforeUnmount(() => {
document.removeEventListener("click", closeDropdown);
document.removeEventListener("click", onClick);
document.removeEventListener("mousemove", onMouseMove);
intersectionObserver.disconnect();
});
</script>

Expand All @@ -35,10 +81,12 @@ onBeforeUnmount(() => {
:is-primary="props.isPrimary"
:label="props.label"
:icon="props.icon"
:is-inline="props.isInline"
@click="isOpen = !isOpen"
ref="reference"
/>
<Transition name="fade">
<div class="items" v-if="isOpen">
<div class="items" v-if="isOpen" ref="floating" :style="floatingStyles">
<slot></slot>
</div>
</Transition>
Expand All @@ -51,26 +99,16 @@ onBeforeUnmount(() => {
display: inline-block;

& .items {
position: absolute;
z-index: 1000;
top: 100%;
left: 0;
position: fixed;
z-index: 9999;
display: flex;
overflow: visible;
width: max-content;
flex-direction: column;
padding: var(--spacing-padding-small);
border: solid 1px var(--border-color-normal);
border-radius: var(--border-radius);
background-color: var(--background-color-normal);
box-shadow: 4px 10px 20px var(--background-color-selected);
gap: var(--spacing-padding-small);
}

&.align-right {
& .items {
right: 0;
left: unset;
}
}
}
</style>
Loading