Skip to content

Commit

Permalink
Merge branch 'reporting' of https://github.com/socfortress/CoPilot in…
Browse files Browse the repository at this point in the history
…to reporting
  • Loading branch information
taylorwalton committed Mar 4, 2024
2 parents 08c6541 + eb91762 commit cc5348d
Show file tree
Hide file tree
Showing 8 changed files with 613 additions and 543 deletions.
974 changes: 469 additions & 505 deletions frontend/package-lock.json

Large diffs are not rendered by default.

18 changes: 10 additions & 8 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
"dependencies": {
"@ajoelp/json-to-formdata": "^1.5.0",
"@f3ve/vue-markdown-it": "^0.2.0",
"@fontsource/jetbrains-mono": "^5.0.18",
"@fontsource/lexend": "^5.0.18",
"@fontsource/public-sans": "^5.0.16",
"@fontsource/jetbrains-mono": "^5.0.19",
"@fontsource/lexend": "^5.0.19",
"@fontsource/public-sans": "^5.0.17",
"@popperjs/core": "^2.11.8",
"@vueuse/components": "^10.9.0",
"@vueuse/core": "^10.9.0",
Expand All @@ -48,6 +48,8 @@
"dayjs": "^1.11.10",
"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 All @@ -74,8 +76,10 @@
"@rushstack/eslint-patch": "^1.7.2",
"@tsconfig/node18": "^18.2.2",
"@types/bytes": "^3.1.4",
"@types/file-saver": "^2.0.7",
"@types/fs-extra": "^11.0.4",
"@types/highlight.js": "^10.1.0",
"@types/html2canvas": "^1.0.0",
"@types/inquirer": "^9.0.7",
"@types/jsdom": "^21.1.6",
"@types/lodash": "^4.14.202",
Expand All @@ -89,7 +93,7 @@
"@vue/eslint-config-typescript": "^12.0.0",
"@vue/test-utils": "^2.4.4",
"@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.17",
"autoprefixer": "^10.4.18",
"cypress": "^13.6.6",
"eslint": "^8.57.0",
"eslint-plugin-cypress": "^2.15.1",
Expand All @@ -107,17 +111,15 @@
"tailwind-config-viewer": "^1.7.3",
"tailwindcss": "^3.4.1",
"taze": "^0.13.3",
"ts-node": "^10.9.2",
"typescript": "~5.3.3",
"unplugin-vue-components": "^0.26.0",
"vite": "^5.1.4",
"vite-bundle-analyzer": "^0.8.1",
"vite-bundle-visualizer": "^1.0.1",
"vite-svg-loader": "^5.1.0",
"vitest": "^1.3.1",
"vue-tsc": "^1.8.27"
"vue-tsc": "^2.0.4"
},
"engines": {
"node": ">=18.0.0"
}
}
}
25 changes: 12 additions & 13 deletions frontend/src/api/reporting.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Dashboard, Org, Panel, PanelLink } from "@/types/reporting"
import type { Dashboard, Org, Panel, PanelLink, PanelImage } from "@/types/reporting"
import { HttpClient } from "./httpClient"
import type { FlaskBaseResponse } from "@/types/flask.d"

Expand Down Expand Up @@ -26,18 +26,17 @@ export default {
return HttpClient.get<FlaskBaseResponse & { panels: Panel[] }>(`/reporting/dashboard_panels/${dashboardUID}`)
},
generatePanelsLinks(payload: PanelsLinksPayload) {
// TODO: remove
/* for test
const payload = {
org_id: 44,
dashboard_title: "string",
dashboard_uid: "fd4ba63e-9e67-42cd-8fe7-f638cea19d7a",
panel_ids: [5, 6, 7],
time_range: {
value: 1,
unit: "hours"
}
}*/
return HttpClient.post<FlaskBaseResponse & { links: PanelLink[] }>(`/reporting/generate_iframe_links`, payload)
},
generatePanelsImages(urls: string[]) {
return HttpClient.post<FlaskBaseResponse & { base64_images: PanelImage[] }>(
`/reporting/generate-report`,
{
urls
},
{
timeout: 0
}
)
}
}
119 changes: 105 additions & 14 deletions frontend/src/components/reportCreation/Panels.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
<template>
<div class="report-panels">
isDirty:{{ isDirty }},{{ linksList.length }}
<div class="panels-container grid grid-cols-2 gap-6" :class="{ printing }">
<div class="panel" v-for="panel of linksList" :key="panel.panel_id">
<iframe :src="panel.panel_url + '&theme=light'" v-show="panelTheme === 'light'"></iframe>
<iframe :src="panel.panel_url + '&theme=dark'" v-show="panelTheme === 'dark'"></iframe>
<div class="panels-container grid grid-cols-2 gap-6 p-6" :class="{ printing }" v-if="panelsList.length">
<div class="panel" v-for="panel of panelsList" :key="panel.id">
<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>
-->
</div>
</div>

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

<script setup lang="ts">
import { NButton } from "naive-ui"
import type { PanelLink } from "@/types/reporting"
import { ref, nextTick, computed, toRefs } from "vue"
import { NButton, useMessage } from "naive-ui"
import type { PanelLink, PanelImage } from "@/types/reporting"
import Icon from "@/components/common/Icon.vue"
import { ref, nextTick } from "vue"
// import html2canvas from "html2canvas"
import { type ThemeName } from "@/types/theme.d"
import { useThemeStore } from "@/stores/theme"
import Api from "@/api"
import { mockImage } from "./data"
import { saveAs } from "file-saver"
import html2canvas from "html2canvas"
// @ts-ignore
// import domtoimage from "dom-to-image-more"
const isDirty = defineModel<boolean>("isDirty", { default: false })
const printing = ref(false)
const panelTheme = ref<"light" | "dark">("light")
const { linksList } = defineProps<{
const props = defineProps<{
linksList: PanelLink[]
}>()
const { linksList } = toRefs(props)
const PrintIcon = "carbon:printer"
const message = useMessage()
const imagesList = ref<PanelImage[]>([])
const printing = ref(false)
// const panelTheme = ref<"light" | "dark">("light")
const panelTheme = computed<ThemeName>(() => useThemeStore().themeName)
const loadingImages = ref(false)
const loadingPrint = ref(false)
const loading = computed(() => loadingImages.value || loadingPrint.value)
const panelsList = computed(() => {
const panels = []
for (const i in linksList.value) {
panels.push({
id: linksList.value[i].panel_id,
url: linksList.value[i].panel_url,
image: imagesList.value[i]?.base64_image // || mockImage
})
}
return panels
})
function print() {
/*
html2canvas(document.querySelector(".panels-container")).then(canvas => {
//document.body.appendChild(canvas)
console.log(canvas.toDataURL("image/jpeg", 0.9))
})
*/
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)
})
})
/*
printing.value = true
// panelTheme.value = "light"
Expand All @@ -49,6 +106,7 @@ function print() {
printing.value = false
}, 2000)
})
*/
/*
// @ts-ignore
Expand All @@ -73,12 +131,45 @@ function print() {
})
*/
}
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
})
}
</script>

<style lang="scss" scoped>
.report-panels {
.panels-container {
border-radius: var(--border-radius);
background-color: var(--bg-secondary-color);
border: var(--border-small-050);
.panel {
border-radius: var(--border-radius);
background-color: var(--bg-secondary-color);
border: var(--border-small-050);
overflow: hidden;
iframe {
width: 100%;
height: 500px;
Expand Down
11 changes: 9 additions & 2 deletions frontend/src/components/reportCreation/Wizard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@
/>
</n-form-item>
</div>
<div class="flex justify-end">
<div class="flex justify-end gap-4 items-center">
<div v-if="isDirty && linksList.length" class="text-secondary-color">
Press the button to refresh the panels
</div>
<n-button type="success" @click="getLinks()" :loading="loadingLinks" v-if="isValid">
<template #icon>
<Icon :name="GenerateLinksIcon"></Icon>
Expand All @@ -58,7 +61,7 @@
</template>

<script setup lang="ts">
import { computed, onBeforeMount, ref, watchEffect, watch } from "vue"
import { computed, onBeforeMount, ref, 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 @@ -74,6 +77,7 @@ const emit = defineEmits<{
const GenerateLinksIcon = "carbon:report-data"
const message = useMessage()
const isDirty = ref(false)
const orgsList = ref<Org[]>([])
const dashboardsList = ref<Dashboard[]>([])
const panelsList = ref<Panel[]>([])
Expand Down Expand Up @@ -109,6 +113,7 @@ const canSelectPanels = computed(() => canSelectDashboard.value && !!selectedDas
const isValid = computed(() => canSelectPanels.value && selectedPanels.value.length)
watch([selectedOrgId, selectedDashboardUID, selectedPanels, timeUnit, timeValue], () => {
isDirty.value = true
emit("reset")
})
Expand Down Expand Up @@ -222,6 +227,8 @@ function getLinks() {
.then(res => {
if (res.data.success) {
linksList.value = res.data?.links || []
isDirty.value = false
emit("generated", linksList.value)
} else {
message.warning(res.data?.message || "An error occurred. Please try again later.")
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/reportCreation/data.ts

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions frontend/src/types/reporting.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,8 @@ export interface PanelLink {
panel_id: number
panel_url: string
}

export interface PanelImage {
base64_image: string
url: string
}
2 changes: 1 addition & 1 deletion frontend/src/views/ReportCreation.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div class="page">
<ReportWizard @generated="setLinks($event)" @reset="isDirty = true" />
<ReportPanels :links-list="linksList" v-model:is-dirty="isDirty" />
<ReportPanels :links-list="linksList" v-model:is-dirty="isDirty" class="mt-5" />
</div>
</template>

Expand Down

0 comments on commit cc5348d

Please sign in to comment.