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

Merge Dashboard branch into Staging #36

Merged
merged 23 commits into from
Feb 20, 2024
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d6ffaca
feat: ✨ redcap api link management done
greenstick Nov 2, 2023
3566c02
Merge branch 'staging' of https://github.com/AI-READI/fairhub.io into…
greenstick Nov 2, 2023
63d36e9
feat: ✨ first dashboard module complete
greenstick Nov 14, 2023
db73d87
Merge branch 'staging' of https://github.com/AI-READI/fairhub.io into…
greenstick Nov 14, 2023
6debdc0
merge: 🔀 dashboard cleanup
greenstick Nov 14, 2023
201ae22
chore: 🔨 yarn cleanup
greenstick Nov 14, 2023
45e5cd4
feat: ✨ more dashboard modules
greenstick Nov 15, 2023
533beee
fix: 🐛 EditDashboard loading prior state. WIP recruitment line chart
greenstick Dec 1, 2023
37d1df9
fix: 🐛 typescript cleanup
greenstick Dec 6, 2023
145884d
fix: 🐛 typescript fix
greenstick Dec 6, 2023
643ac8c
feat: ✨ dashboard module and report manifests
greenstick Dec 7, 2023
2d0ed24
feat: ✨ new chart types: groupedbar and groupedstackedbar
greenstick Dec 12, 2023
ec53272
feat: ✨ new recruitment visualization modules
greenstick Dec 12, 2023
bdeb1e4
style: 🎨 improvements to visualizations
greenstick Dec 13, 2023
c385ca1
fix: 🐛 minor fixes
greenstick Jan 23, 2024
454e9a2
Merge branch 'staging' of https://github.com/AI-READI/fairhub.io into…
greenstick Jan 23, 2024
67b9cfa
Merge branch 'staging' into dashboard
greenstick Jan 23, 2024
32e77cd
fix: 🐛 minor fixes
greenstick Jan 26, 2024
77ef9a6
feat: ✨ line chart done
greenstick Feb 4, 2024
42b1e74
chore: 🔨 lint, format, type-check
greenstick Feb 13, 2024
64b076b
feat: ✨ improved REDcap API structure (not yet merge ready)
greenstick Feb 20, 2024
1aebcd4
feat: ✨ improved REDcap & Dashboard API structure
greenstick Feb 20, 2024
39e35cb
Merge branch 'staging' into dashboard
greenstick Feb 20, 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
Prev Previous commit
Next Next commit
feat: ✨ first dashboard module complete
  • Loading branch information
greenstick committed Nov 14, 2023
commit 63d36e95fda274403b73ed5ebfced5e04b6a9007
582 changes: 578 additions & 4 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -129,6 +129,7 @@
"unplugin-vue-components": "^0.25.1",
"vfonts": "^0.0.3",
"vite": "^3.0.9",
"vite-plugin-node-polyfills": "^0.16.0",
"vitest": "^0.23.0",
"vue-loader": "^16.8.3",
"vue-tsc": "^0.40.7"
234 changes: 234 additions & 0 deletions src/components/dashboard/DashboardModule.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
<script lang="ts">
import type { VisualizationRenderer } from "@/types/DashboardModule";

export default {
name: "DashboardModule",
methods: {
setFilter(value) {
console.log(value);
},
},
props: {
vconfigs: [],
},
setup(props) {
const visualizations = reactive([]);
onMounted(() => {
const vconfigs = props.vconfigs as VisualizationRenderer[];
for (let i = 0; i < vconfigs.length; i++) {
let config = vconfigs[i];
let cls = config.class;
let cfg = config.config;
let obj = new cls(cfg).update();
console.log(obj);
visualizations.push(obj);
}
});
onUpdated(() => {
for (let i = 0; i < visualizations.length; i++) {
toRaw(visualizations[i]).update();
}
});
return { visualizations };
},
};
</script>

<template>
<div
v-for="(visualization, visualization_index) in visualizations"
:key="visualization_index"
class="visualization-container"
>
<svg
:id="`${visualization.setID}_visualization`"
class="visualization-element"
:viewBox="`0 0 ${visualization.width} ${visualization.height}`"
preserveAspectRatio="xMinYMid meet"
xmlns="http://www.w3.org/2000/svg"
/>
<n-grid :cols="3" :x-gap="20" :id="`${visualization.setID}_interface`" class="interface">
<n-grid-item v-if="visualization.legend">
<n-card :id="`${visualization.setID}_legend`" :segmented="true" :bordered="false"></n-card>
</n-grid-item>
<n-grid-item v-if="visualization.tooltip">
<n-card :id="`${visualization.setID}_tooltip`" :segmented="true" :bordered="false"></n-card>
</n-grid-item>
<n-grid-item v-if="visualization.filters">
<n-dropdown
trigger="click"
:options="visualization.Filters.data"
@select="visualization.update($event, filter)"
placement="right-start"
:id="`${visualization.setID}_filters`"
>
<n-button>{{ "Sites" }}</n-button>
</n-dropdown>
</n-grid-item>
</n-grid>
</div>
</template>

<style>
/*
Interaction Elements
*/

::marker {
display: none;
}

.interactable {
cursor: pointer;
}

/*
Visualization Background
*/

.visualization-background {
position: absolute;
}

/*
Visualization Elements
*/

.visualization-container {
max-height: 760px;
}
.visualization-container svg {
shape-rendering: geometricPrecision;
}
.visualization-container svg:path,
.visualization-container svg:rect,
.visualization-container svg:circle {
cursor: pointer !important;
}
.visualization-container text,
.visualization-container span {
text-transform: capitalize;
}
.visualization-container .visualization-element {
}
.visualization-container .visualization-element .data-elements {
}
.visualization-container .visualization-element .data-elements .data-element {
}
.visualization-container .visualization-element .x-axis {
}
.visualization-container .visualization-element .y-axis {
}
.visualization-container .visualization-element.unrotated .x-axis .label {
text-anchor: start;
vertical-align: middle;
line-height: 20px;
}
.visualization-container .visualization-element.unrotated .y-axis .label {
text-anchor: center;
}
.visualization-container .visualization-element.isrotated .x-axis .label {
text-anchor: center;
}
.visualization-container .visualization-element.isrotated .y-axis .label {
text-anchor: center;
vertical-align: middle;
line-height: 20px;
}

/*
Visualization Interface
*/

.visualization-container .interface {
display: flex;
flex-direction: row;
align-content: flex-start;
justify-content: flex-start;
align-items: flex-start;
flex-wrap: nowrap;
width: 100%;
min-height: 80px;
}
.visualization-container .interface-element {
display: inline-flex;
flex-direction: column;
align-content: flex-start;
justify-content: flex-start;
align-items: flex-start;
margin-right: 5%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

/*
Visualization Interface – Tooltip
*/

.visualization-container .interface-element.tooltip {
}
.visualization-container .interface-element.tooltip .tooltip-items .tooltip-item {
line-height: 1.4em;
}
.visualization-container .interface-element.tooltip .tooltip-items .tooltip-label {
display: inline-flex;
flex-direction: row;
align-content: flex-start;
justify-content: flex-start;
align-items: flex-start;
font-weight: bold;
margin-right: 8px;
}
.visualization-container .interface-element.tooltip .tooltip-items .tooltip-value {
display: inline-flex;
flex-direction: row;
align-content: flex-start;
justify-content: flex-start;
align-items: flex-start;
}

/*
Visualization Interface – Legend
*/

.visualization-container .interface-element.legend {
list-style: none;
}
.visualization-container .interface-element.legend .legend-items {
padding-left: 0px;
}
.visualization-container .interface-element.legend .legend-items .legend-item {
padding-left: 0px;
line-height: 1.4em;
margin-right: 8px;
}
.visualization-container .interface-element.legend .legend-items .legend-item .legend-color {
display: inline-flex;
flex-direction: row;
align-content: flex-start;
justify-content: flex-start;
align-items: flex-start;
margin-right: 8px;
}
.visualization-container .interface-element.legend .legend-items .legend-item .legend-label {
padding-left: 8px;
text-anchor: left;
vertical-align: top;
font-weight: bold;
}

/*
Visualization Interface – Filters
*/

.visualization-container .interface-element.filters {
}
.visualization-container .interface-element.filters .filterbank .filter {
line-height: 1.4em;
}
.visualization-container .interface-element.filters .filterbank .filter .filter-value {
font-weight: bold;
vertical-align: middle;
}
</style>
137 changes: 137 additions & 0 deletions src/configs/dashboards/modules/devices.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
{
"name": "Devices",
"id": "devices",
"title": "Devices",
"subtitle": "Devices subtitle",
"width": 1280,
"height": 720,
"visualizations": [{
"type": "StackedBar",
"config": {
"id": "#devices_stacked-bar",
"rotate": true,
"width": 1080,
"height": 500,
"position": {
"top": 0,
"left": 0,
"right": 0,
"bottom": 0
},
"margin": {
"top": 20,
"left": 20,
"right": 20,
"bottom": 20
},
"padding": {
"top": 0,
"left": 0,
"right": 200,
"bottom": 0
},
"transitions": {
"opacity": {
"from": 0.8,
"to": 1.0
},
"translate": {
"from": "left",
"to": "left"
}
},
"animations": {
"opacity": {
"delay": 0,
"duration": 200,
"easing": "expOut"
},
"translate": {
"delay": 0,
"duration": 600,
"easing": "expOut"
}
},
"legend": {
"width": 120,
"height": 140,
"itemsize": 20,
"fontsize": 12,
"vposition": "bottom",
"hposition": "left",
"padding": {
"top": 0,
"left": 0,
"right": 0,
"bottom": 0
}
},
"tooltip": {
"width": 720,
"height": 140,
"itemsize": 20,
"fontsize": 12,
"vposition": "bottom",
"hposition": "left",
"padding": {
"top": 0,
"left": 320,
"right": 0,
"bottom": 0
}
},
"filters": {
"width": 720,
"height": 140,
"itemsize": 20,
"fontsize": 12,
"vposition": "bottom",
"hposition": "left",
"padding": {
"top": 0,
"left": 320,
"right": 0,
"bottom": 0
}
},
"palette": [
"#5DD462",
"#FE7E6D",
"#C79F38",
"#82C5E6",
"#999EEB",
"#7F8C9F",
"#727272"
],
"ordering": "descending",
"accessors": {
"filterby": {
"name": "Site",
"key": "group",
"type": "String"
},
"group": {
"name": "Survey",
"key": "group",
"type": "String"
},
"subgroup": {
"name": "Status",
"key": "subgroup",
"type": "String"
},
"color": {
"name": "Status",
"key": "subgroup",
"type": "String"
},
"value": {
"name": "Count (n)",
"key": "value",
"type": "Number"
}
},
"data": []
}
}]
}
Loading
Oops, something went wrong.