Skip to content

Commit

Permalink
updated report page
Browse files Browse the repository at this point in the history
  • Loading branch information
Linko91 committed Mar 6, 2024
1 parent e85a030 commit c88ae02
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 133 deletions.
1 change: 0 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
"detect-touch-device": "^1.1.6",
"echarts": "^5.5.0",
"file-saver": "^2.0.5",
"html2canvas": "^1.4.1",
"jose": "^5.2.2",
"js-md5": "^0.8.3",
"lodash": "^4.17.21",
Expand Down
161 changes: 54 additions & 107 deletions frontend/src/components/reportCreation/Panels.vue
Original file line number Diff line number Diff line change
@@ -1,52 +1,35 @@
<template>
<div class="report-panels">
<div class="panels-container" v-if="panelsList.length">
<div class="panels-container" v-if="panelsBlock.length">
<div
class="panel"
v-for="panel of panelsList"
v-for="panel of panelsBlock"
:key="panel.id"
:style="panel.width ? `flex-basis:${panel.width}%` : ''"
>
<div class="toolbar">
<n-popover trigger="hover" overlap raw placement="right-start">
<n-popover trigger="hover" overlap raw placement="right-start" class="popover-report-panel-slider">
<template #trigger>
<n-button size="tiny">
<template #icon>
<Icon :name="MenuIcon"></Icon>
</template>
</n-button>
</template>
<div class="popover-input-container">
<div class="w-52 flex items-center gap-3 py-2 px-5">
<span class="font-mono w-12">{{ panel.width }}</span>
<n-slider :tooltip="false" v-model:value="panel.width" :min="0" :max="100" :step="10" />
</div>
<!--
<n-input-number
size="tiny"
v-model:value="panel.width"
:min="0"
:max="100"
:step="10"
class="max-w-32"
/>
-->
<div class="w-52 flex items-center gap-3 py-2 px-5">
<span class="font-mono w-12">{{ panel.width / 100 }}</span>
<n-slider :tooltip="false" v-model:value="panel.width" :min="0" :max="100" :step="10" />
</div>
</n-popover>
</div>
<div class="content">
<img :src="'data:image/png;base64,' + panel.image" v-if="panel.image" />
<iframe :src="panel.url + '&theme=' + panelTheme" v-else></iframe>
<!--
<iframe :src="panel.panel_url + '&theme=light'" v-show="panelTheme === 'light'"></iframe>
<iframe :src="panel.panel_url + '&theme=dark'" v-show="panelTheme === 'dark'"></iframe>
-->
{{ panel.name }}
</div>
</div>
</div>

<div class="toolbar mt-5">
<n-button type="success" v-if="linksList.length" @click="print()" :loading="loading">
<n-button type="success" v-if="panelsBlock.length" @click="print()" :loading="loading">
<template #icon>
<Icon :name="PrintIcon"></Icon>
</template>
Expand All @@ -57,97 +40,57 @@
</template>

<script setup lang="ts">
import { ref, nextTick, computed, toRefs, watch, onBeforeMount } from "vue"
import { useMessage, NButton, NInputNumber, NSlider, NPopover } from "naive-ui"
import type { PanelLink, PanelImage } from "@/types/reporting"
import { ref, computed, toRefs, watch } from "vue"
import { NButton, NSlider, NPopover } from "naive-ui"
import type { PanelLink, Panel } from "@/types/reporting"
import Icon from "@/components/common/Icon.vue"
import { type ThemeName } from "@/types/theme.d"
import { useThemeStore } from "@/stores/theme"
import Api from "@/api"
import { mockImage, mockLinks } from "./data"
import { saveAs } from "file-saver"
import html2canvas from "html2canvas"
// import Api from "@/api"
// import { saveAs } from "file-saver"
interface PanelBlock {
id: string | number
name: string
width: number
}
const props = defineProps<{
linksList: PanelLink[]
panelsList?: Panel[]
linksList?: PanelLink[]
}>()
const { linksList } = toRefs(props)
const { panelsList } = toRefs(props)
const MenuIcon = "carbon:overflow-menu-horizontal"
const PrintIcon = "carbon:printer"
const message = useMessage()
const imagesList = ref<PanelImage[]>([])
const panelTheme = computed<ThemeName>(() => useThemeStore().themeName)
// const message = useMessage()
const loadingImages = ref(false)
const loadingPrint = ref(false)
const loading = computed(() => loadingImages.value || loadingPrint.value)
const panelsList = ref([])
const panelsBlock = ref<PanelBlock[]>([])
watch(linksList, () => {
createPanels()
watch(panelsList, val => {
createPanels(val || [])
})
onBeforeMount(() => {
createPanels()
})
function createPanels(list: Panel[]) {
const panels: PanelBlock[] = []
function createPanels() {
const panels = []
for (const i in mockLinks /*linksList.value*/) {
for (const panel of list) {
panels.push({
id: mockLinks[i].panel_id, // linksList.value[i].panel_id,
url: mockLinks[i].panel_url, // linksList.value[i].panel_url,
image: imagesList.value[i]?.base64_image || mockImage,
id: panel.id,
name: panel.title,
width: 50
})
}
panelsList.value = panels
panelsBlock.value = panels
}
function print() {
loadingPrint.value = true
getImages(() => {
nextTick(() => {
setTimeout(() => {
html2canvas(document.querySelector(".panels-container"))
.then(canvas => {
//document.body.appendChild(canvas)
loadingPrint.value = false
const dataURL = canvas.toDataURL("image/png", 1)
console.log(dataURL)
saveAs(dataURL, "report.png")
})
.catch(() => {
loadingPrint.value = false
})
}, 2000)
})
})
}
function getImages(cb?: () => void) {
loadingImages.value = true
Api.reporting
.generatePanelsImages(linksList.value.map(o => o.panel_url + "&theme=" + panelTheme.value))
.then(res => {
if (res.data.success) {
imagesList.value = res.data?.base64_images || []
if (cb) {
cb()
}
} else {
message.warning(res.data?.message || "An error occurred. Please try again later.")
}
})
.catch(err => {
message.error(err.response?.data?.message || "An error occurred. Please try again later.")
})
.finally(() => {
loadingImages.value = false
})
setTimeout(() => {
loadingPrint.value = false
}, 2000)
}
</script>

Expand All @@ -159,41 +102,45 @@ function getImages(cb?: () => void) {
border: var(--border-small-050);
display: flex;
flex-wrap: wrap;
padding: 1vw;
padding: clamp(5px, 1vw, 10px);
.panel {
overflow: hidden;
flex-grow: 1;
min-width: 200px;
padding: 1vw;
padding: clamp(5px, 1vw, 10px);
position: relative;
.toolbar {
position: absolute;
top: 8px;
right: 8px;
top: 7px;
right: 7px;
backdrop-filter: blur(2px);
}
.content {
border-radius: var(--border-radius);
background-color: var(--bg-secondary-color);
background-color: var(--bg-color);
border: var(--border-small-050);
overflow: hidden;
}
iframe {
width: 100%;
aspect-ratio: 1;
}
img {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
aspect-ratio: 1.6;
font-size: clamp(12px, 1.7vw, 18px);
font-weight: bold;
padding: 3vw;
text-align: center;
}
}
}
}
</style>

.popover-input-container {
background-color: var(--bg-secondary-color);
<style lang="scss">
.popover-report-panel-slider {
background-color: rgba(var(--modal-color-rgb), 0.5);
border-radius: var(--border-radius);
overflow: hidden;
backdrop-filter: blur(5px);
}
</style>
41 changes: 24 additions & 17 deletions frontend/src/components/reportCreation/Wizard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@
<div class="flex">
<n-form-item label="Panels" v-if="canSelectPanels" class="grow">
<n-select
v-model:value="selectedPanels"
v-model:value="selectedPanelsIds"
:options="panelsOptions"
:loading="loadingPanels"
multiple
clearable
/>
</n-form-item>
</div>
<div class="flex justify-end gap-4 items-center">
<div class="flex justify-end gap-4 items-center" v-if="!hideGenerateButton">
<div v-if="isDirty && linksList.length" class="text-secondary-color">
Press the button to refresh the panels
</div>
Expand All @@ -61,7 +61,7 @@
</template>

<script setup lang="ts">
import { computed, onBeforeMount, ref, watch } from "vue"
import { computed, onBeforeMount, ref, toRefs, watch } from "vue"
import { NSpin, NForm, NFormItem, NInputGroup, NInputNumber, NButton, NSelect, useMessage } from "naive-ui"
import Api from "@/api"
import Icon from "@/components/common/Icon.vue"
Expand All @@ -70,12 +70,16 @@ import type { PanelsLinksPayload, PanelsLinksTimeUnit } from "@/api/reporting"
import { useStorage } from "@vueuse/core"
const emit = defineEmits<{
(e: "reset"): void
(e: "updated", value: Panel[]): void
(e: "generated", value: PanelLink[]): void
}>()
const GenerateLinksIcon = "carbon:report-data"
const props = defineProps<{
hideGenerateButton?: boolean
}>()
const { hideGenerateButton } = toRefs(props)
const GenerateLinksIcon = "carbon:report-data"
const message = useMessage()
const isDirty = ref(false)
const orgsList = ref<Org[]>([])
Expand All @@ -91,14 +95,13 @@ const selectedDashboardUID = ref<string | null>(null)
const selectedDashboard = computed(() =>
selectedDashboardUID.value ? dashboardsList.value.find(o => o.uid === selectedDashboardUID.value) || null : null
)
const selectedPanels = ref<number[]>([])
const selectedPanelsIds = ref<number[]>([])
const selectedPanels = computed(() =>
selectedPanelsIds.value ? panelsList.value.filter(o => selectedPanelsIds.value.includes(o.id)) : []
)
const timeUnit = useStorage<PanelsLinksTimeUnit>("report-wizard-time-unit", "hours", localStorage)
const timeValue = useStorage<number>("report-wizard-time-value", 1, localStorage)
const loading = computed(
() => loadingOrgs.value || loadingDashboards.value || loadingPanels.value || loadingLinks.value
)
const orgsOptions = computed(() => orgsList.value.map(o => ({ value: o.id, label: o.name })))
const dashboardsOptions = computed(() => dashboardsList.value.map(o => ({ value: o.uid, label: o.title })))
const panelsOptions = computed(() => panelsList.value.map(o => ({ value: o.id, label: o.title })))
Expand All @@ -110,18 +113,22 @@ const timeUnitOptions: { label: string; value: PanelsLinksTimeUnit }[] = [
const canSelectDashboard = computed(() => !!selectedOrgId.value)
const canSelectPanels = computed(() => canSelectDashboard.value && !!selectedDashboardUID.value)
const isValid = computed(() => canSelectPanels.value && selectedPanels.value.length)
const isValid = computed(() => canSelectPanels.value && selectedPanelsIds.value.length)
const loading = computed(
() => loadingOrgs.value || loadingDashboards.value || loadingPanels.value || loadingLinks.value
)
watch([selectedOrgId, selectedDashboardUID, selectedPanels, timeUnit, timeValue], () => {
watch([selectedOrgId, selectedDashboardUID, selectedPanelsIds, timeUnit, timeValue], () => {
isDirty.value = true
emit("reset")
emit("updated", selectedPanels.value)
})
watch(selectedOrgId, val => {
dashboardsList.value = []
panelsList.value = []
selectedDashboardUID.value = null
selectedPanels.value = []
selectedPanelsIds.value = []
if (val) {
getDashboards()
Expand All @@ -130,7 +137,7 @@ watch(selectedOrgId, val => {
watch(selectedDashboardUID, val => {
panelsList.value = []
selectedPanels.value = []
selectedPanelsIds.value = []
if (val) {
getPanels()
Expand Down Expand Up @@ -205,7 +212,7 @@ function getLinks() {
if (
selectedOrgId.value &&
selectedDashboard.value &&
selectedPanels.value.length &&
selectedPanelsIds.value.length &&
timeUnit.value &&
timeValue.value
) {
Expand All @@ -215,7 +222,7 @@ function getLinks() {
org_id: selectedOrgId.value,
dashboard_title: selectedDashboard.value.title,
dashboard_uid: selectedDashboard.value.uid,
panel_ids: selectedPanels.value,
panel_ids: selectedPanelsIds.value,
time_range: {
value: timeValue.value,
unit: timeUnit.value
Expand Down
Loading

0 comments on commit c88ae02

Please sign in to comment.