-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Updated results, now resultList with precalculated categories and nesting * Benchmarking added uses new result structure to read result quickly * Minor usability fixes * Updated Github actions to be more streamlined in building live page --------- Co-authored-by: sultanahmed-7bb <[email protected]>
- Loading branch information
1 parent
eaf800b
commit 1af18ad
Showing
53 changed files
with
4,351 additions
and
621 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
name: TODO Issue | ||
on: | ||
workflow_dispatch: | ||
inputs: | ||
importAll: | ||
default: false | ||
required: false | ||
type: boolean | ||
description: Enable, if you want to import all TODOs. Runs on checked out branch! Only use if you're sure what you are doing. | ||
push: | ||
branches: # do not set multiple branches, todos might be added and then get referenced by themselves in case of a merge | ||
- main | ||
|
||
permissions: | ||
issues: write | ||
repository-projects: read | ||
contents: read | ||
|
||
jobs: | ||
todos: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- name: Run Issue Bot | ||
uses: juulsn/todo-issue@main | ||
with: | ||
excludePattern: '^(node_modules/)' | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
<template> | ||
<div class="flex-1 p-6"> | ||
<div class="bg-white p-4 shadow-md rounded-md"> | ||
<Dropdown | ||
:items="graphParameters" | ||
name="graphParameter" | ||
:dropdownName="dropdownName" | ||
@selectedItem="handleResultListSelection" | ||
class="pb-6" | ||
/> | ||
<ul | ||
role="list" | ||
class="max-h-screen grid grid-cols-1 gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 items-start overflow-auto" | ||
> | ||
<li | ||
v-for="(resultLog, index) in resultLogs" | ||
:key="resultLog.name" | ||
class="col-span-1 flex flex-col divide-y divide-gray-200 rounded-lg bg-white text-center shadow" | ||
> | ||
<!-- Project Iterator. --> | ||
<div class="flex flex-1 flex-col p-8"> | ||
<dd class="text-m text text-gray-500">{{ resultLog.name }}</dd> | ||
<div class="h-[20vh]"> | ||
<GraphContainer | ||
:resultItem="displayResultList[index]" | ||
/> | ||
</div> | ||
<dd class="mt-3"> | ||
<span | ||
class="inline-flex items-center rounded-full bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20" | ||
> | ||
{{ displayResultList[index].displayName }} | ||
</span> | ||
</dd> | ||
</div> | ||
|
||
<!-- Stats. --> | ||
<div> | ||
<div class="-mt-px flex divide-x divide-gray-200"> | ||
<div class="flex w-0 flex-1"> | ||
<a | ||
class="relative -mr-px inline-flex w-0 flex-1 items-center justify-center gap-x-3 rounded-bl-lg border border-transparent py-4 text-sm font-semibold text-green-900 text-center" | ||
> | ||
{{ aggregatedEmission[index] }} kg-co² / m² | ||
</a> | ||
</div> | ||
|
||
<div class="-ml-px flex w-0 flex-1"> | ||
<a | ||
class="relative inline-flex w-0 flex-1 items-center justify-center gap-x-3 rounded-br-lg border border-transparent py-4 text-sm font-semibold text-gray-800 text-center" | ||
> | ||
<td | ||
:class="{'text-red-600' : emissionPercentage[index] >= 100, 'text-green-600' : emissionPercentage[index] < 100}" | ||
> | ||
{{ emissionPercentage[index] }}% | ||
</td> | ||
</a> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
|
||
<!-- Expand Button --> | ||
<button | ||
class="mt-4 w-full rounded bg-green-500 text-white py-2 text-sm font-medium hover:bg-green-600" | ||
@click="toggleExpansion(index)" | ||
> | ||
{{ expanded[index] ? 'Hide Details' : 'Show Details' }} | ||
</button> | ||
|
||
<!-- Expandable Data Table --> | ||
<div v-if="expanded[index]" class="overflow-auto max-h-80"> | ||
<DataTable :resultItem="displayResultList[index]" /> | ||
</div> | ||
</li> | ||
</ul> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import Dropdown from '@/components/Misc/Dropdown.vue' | ||
import GraphContainer from '@/components/Graphs/GraphContainer.vue' | ||
import DataTable from '@/components/Graphs/DataTable.vue' | ||
import { useResultStore } from '@/stores/result' | ||
import { useFirebaseStore } from '@/stores/firebase' | ||
import { useProjectStore } from '@/stores/main' | ||
import { useSettingsStore } from '@/stores/settings' | ||
import { defineComponent, ref, reactive, computed, watch } from 'vue' | ||
import type { ResultItem } from '@/models/result' | ||
import type { ResultsLog } from '@/models/firebase' | ||
import type { dropdownItem } from '@/components/Misc/DropdownMenuItem.vue' | ||
import { getResultLogEmissions, emissionToNumber } from '@/utils/resultUtils' | ||
export default defineComponent({ | ||
name: 'BenchmarkGrid', | ||
components: { | ||
Dropdown, | ||
GraphContainer, | ||
DataTable, | ||
}, | ||
setup() { | ||
const resultStore = useResultStore() | ||
const firebaseStore = useFirebaseStore() | ||
const projectStore = useProjectStore() | ||
const settingsStore = useSettingsStore() | ||
const resultLogs = ref<ResultsLog[]>([]) | ||
const benchmarkParameter = ref<string>('parameters.speckle_type') | ||
// Create a boolean array to track expansion state | ||
const expanded = reactive(resultLogs.value.map(() => false)) | ||
// Fetches results from firebase | ||
firebaseStore.fetchResults(projectStore.currProject.id).then((logs) => { | ||
resultLogs.value = logs | ||
}) | ||
// Dropdown items from resultList | ||
const graphParameters = ref<dropdownItem[]>( | ||
resultStore.resultList.map((result) => ({ | ||
name: result.displayName, | ||
data: JSON.stringify(result), // Passing the entire result as JSON for flexibility | ||
})) | ||
) | ||
// Selected result | ||
const selectedResult = ref<ResultItem | null>(null) | ||
const dropdownName = ref(selectedResult.value ? selectedResult.value.displayName : 'Select a result') | ||
// Handler for selecting a dropdown item | ||
const handleResultListSelection = (selectedItem: dropdownItem) => { | ||
resultStore.setReloadData(true) | ||
projectStore.clearSelectedObjects() | ||
const parsedResult = JSON.parse(selectedItem.data) as ResultItem | ||
benchmarkParameter.value = parsedResult.parameter | ||
} | ||
const aggregatedEmission = computed(() => { | ||
const resultLogEmission = resultLogs.value.map((log: ResultsLog) => { | ||
const emission = getResultLogEmissions(log, benchmarkParameter.value) | ||
return Math.round(emissionToNumber(emission) / (settingsStore.appSettings.area ?? 100)) | ||
}) | ||
return resultLogEmission | ||
}) | ||
const emissionPercentage = computed(() => { | ||
const maxEmission = Math.max(...aggregatedEmission.value) | ||
return aggregatedEmission.value.map((emission) => { | ||
return Math.round((emission / maxEmission) * 100) | ||
}) | ||
}) | ||
const displayResultList = computed(() => { | ||
return resultLogs.value.map((resultLog) => { | ||
return resultLog.resultList.find((item: ResultItem) => item.parameter === benchmarkParameter.value) | ||
}) | ||
}) | ||
function toggleExpansion(index) { | ||
expanded[index] = !expanded[index] | ||
} | ||
watch(graphParameters, (newGraphParameters) => { | ||
if (newGraphParameters.length > 0) { | ||
// If selectedResult is null or no longer matches an item in graphParameters, update it | ||
if ( | ||
!selectedResult.value || | ||
!newGraphParameters.some( | ||
(item) => item.name === selectedResult.value?.displayName | ||
) | ||
) { | ||
const parsedResult = JSON.parse(newGraphParameters[0].data) as ResultItem | ||
selectedResult.value = parsedResult | ||
// Update the dropdownName to reflect the new selection | ||
dropdownName.value = parsedResult.displayName | ||
} | ||
} else { | ||
// If graphParameters is empty, reset selectedResult and dropdownName | ||
selectedResult.value = null | ||
dropdownName.value = 'Select a result' | ||
} | ||
}) | ||
return { | ||
handleResultListSelection, | ||
toggleExpansion, | ||
expanded, | ||
resultLogs, | ||
aggregatedEmission, | ||
graphParameters, | ||
dropdownName, | ||
displayResultList, | ||
emissionPercentage, | ||
} | ||
}, | ||
}) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<template> | ||
<!-- Table --> | ||
<table class="divide-y divide-gray-200 max-w-full block table-fixed"> | ||
<thead class="w-full block"> | ||
<tr class="w-full flex bg-gray-200 text-gray-700 text-left text-xs leading-4 font-medium uppercase tracking-wider whitespace-nowrap"> | ||
<th class="m-3 w-3/6"> | ||
{{ resultItem.displayName }} | ||
</th> | ||
<th class="m-3 w-1/6"> | ||
Amount | ||
</th> | ||
<th class="m-3 w-2/6"> | ||
Emission | ||
</th> | ||
</tr> | ||
</thead> | ||
<tr | ||
v-for="(groupedResult) in resultItem.data" | ||
:key="groupedResult.parameter" | ||
class="text-xs whitespace-no-wrap w-full flex hover:bg-gray-200" | ||
> | ||
<td scope="row" class="m-2 w-3/6 line-clamp-3"> | ||
{{ groupedResult.parameter }} | ||
</td> | ||
<td class="m-2 w-1/6"> | ||
{{ getAmountWithUnit(groupedResult) }} | ||
</td> | ||
<!-- Arbitrary numbers for red vs green, this needs to be threshold or dynamic and--> | ||
<td | ||
:class="{'text-red-600' : getRoundedEmissions(groupedResult) >= 100, 'text-green-600' : getRoundedEmissions(groupedResult) < 100 }" | ||
class="m-2 w-2/6" | ||
> | ||
{{ getRoundedEmissions(groupedResult) }} | ||
<br> | ||
kg/CO<sub>2</sub> | ||
</td> | ||
</tr> | ||
</table> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { defineComponent } from 'vue' | ||
import { emissionToNumber } from '@/utils/resultUtils' | ||
import type { PropType } from 'vue' | ||
import type { ResultItem, GroupedResults } from '@/models/result' | ||
export default defineComponent({ | ||
name: 'ResultTable', | ||
components: { | ||
}, | ||
props: { | ||
resultItem: { | ||
type: Object as PropType<ResultItem>, | ||
required: true, | ||
}, | ||
}, | ||
methods: { | ||
/** | ||
* Return formated and rounded amount of the grouped result | ||
* Order is m3 -> m2 -> m -> pcs | ||
* @param groupedResult | ||
*/ | ||
getAmountWithUnit(groupedResult: GroupedResults) { | ||
const quantity = groupedResult.quantity; | ||
if (quantity?.m3) return `${Math.round(quantity.m3 * 1e2) / 1e2 } m3` | ||
if (quantity?.m2) return `${Math.round(quantity.m2 * 1e2) / 1e2 } m2` | ||
if (quantity?.m) return `${Math.round(quantity.m * 1e2) / 1e2 } m` | ||
if (quantity?.pcs) return `${quantity.pcs} pcs` | ||
return '0' | ||
}, | ||
/** | ||
* Gets rounded emission for a grouped result | ||
* TODO: This should be a threshold or dynamic and atleast noramlized to sqm | ||
* @param groupedResult | ||
*/ | ||
getRoundedEmissions(groupedResult: GroupedResults) { | ||
return Math.round(emissionToNumber(groupedResult.data.emission) * 1e2) / 1e2 | ||
}, | ||
}, | ||
setup() { | ||
return { | ||
} | ||
}, | ||
}) | ||
</script> |
Oops, something went wrong.