Skip to content

Commit 3d3c604

Browse files
Show meta information of used datasets (#13)
* adjust loading only during data fetching, display popup correct name and type error. * add data folder into docker container * adjust legend option in input json files and add detail button for DB urls. * meta information feature * add license, organization details. * loading spinner and card width * add spaces after : * change detail button icon * use UModal for meta infroamtion, adjust spinner and nuxt-ui update * add name to the meta information * show series meta data * improve displaying of metainformations * improve used values of dataset meta information * fix modal close button in light mode * add some gap between header content --------- Co-authored-by: Marius Heine <m.heine@geprog.com>
1 parent 7def25b commit 3d3c604

File tree

13 files changed

+690
-517
lines changed

13 files changed

+690
-517
lines changed

app.config.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ export default defineAppConfig({
44
},
55
ui: {
66
button: {
7-
default: {
8-
size: 'md',
9-
},
107
},
118
},
129
});
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
<template>
2+
<UModal v-model:open="showModal" :ui="{ content: 'max-w-5xl' }">
3+
<template #content>
4+
<UCard>
5+
<div class="flex items-center justify-between p-4 border-b border-gray-200">
6+
<h3 class="text-lg font-semibold m-0">
7+
{{ t('datasetDetail') }}
8+
</h3>
9+
<UButton size="md" variant="text" class="text-xl hover:text-red-400" @click="closeCard">
10+
&times;
11+
</UButton>
12+
</div>
13+
<div class="relative max-h-[50vh]">
14+
<div
15+
v-if="loading"
16+
class="inset-0 z-[9999] flex items-center justify-center bg-white/50 backdrop-blur-sm cursor-not-allowed"
17+
>
18+
<LoadingSpinner />
19+
</div>
20+
<div class="overflow-y-auto max-h-[50vh] divide-y divide-gray-200">
21+
<div v-for="(item, index) in urls" :key="index" class="p-4 space-y-2">
22+
<p>
23+
<span class="font-semibold">{{ t('name') }}: </span>
24+
{{ item.name || 'N/A' }}
25+
</p>
26+
<p>
27+
<span class="font-semibold">{{ t('organization') }}: </span>
28+
{{ item.organization?.title || 'N/A' }}
29+
</p>
30+
<p>
31+
<span class="font-semibold">{{ t('license') }}: </span>
32+
<a
33+
v-if="item.license_url"
34+
:href="item.license_url"
35+
target="_blank"
36+
rel="noopener"
37+
class="text-blue-600 hover:underline"
38+
>
39+
{{ item.license_title }}
40+
</a>
41+
<span v-else>{{ item.license_title || 'N/A' }}</span>
42+
</p>
43+
<p>
44+
<span class="font-semibold">{{ t('datasetUrl') }}: </span>
45+
<a
46+
:href="item.url"
47+
target="_blank"
48+
rel="noopener"
49+
class="text-blue-600 hover:underline"
50+
>
51+
{{ item.url }}
52+
</a>
53+
</p>
54+
<div v-if="item.nested_series && item.nested_series.length > 0" class="mt-2">
55+
<details>
56+
<summary>
57+
{{ t('seriesDatasets') }}
58+
</summary>
59+
<div
60+
class="ml-6 mt-2 border-gray-200 pl-4 space-y-2 divide-y"
61+
>
62+
<div
63+
v-for="(nested, nestedIndex) in item.nested_series"
64+
:key="nestedIndex"
65+
class="space-y-1"
66+
>
67+
<p>
68+
<span class="font-semibold">{{ t('name') }}: </span>
69+
{{ nested.name || 'N/A' }}
70+
</p>
71+
<p>
72+
<span class="font-semibold">{{ t('organization') }}: </span>
73+
{{ nested.organization?.title || 'N/A' }}
74+
</p>
75+
<p>
76+
<span class="font-semibold">{{ t('license') }}: </span>
77+
<a
78+
v-if="nested.license_url"
79+
:href="nested.license_url"
80+
target="_blank"
81+
rel="noopener"
82+
class="text-blue-600 hover:underline"
83+
>
84+
{{ nested.license_title }}
85+
</a>
86+
<span v-else>{{ nested.license_title || 'N/A' }}</span>
87+
</p>
88+
<p>
89+
<span class="font-semibold">{{ t('datasetUrl') }}: </span>
90+
<a
91+
:href="nested.url"
92+
target="_blank"
93+
rel="noopener"
94+
class="text-blue-600 hover:underline"
95+
>
96+
{{ nested.url }}
97+
</a>
98+
</p>
99+
</div>
100+
</div>
101+
</details>
102+
</div>
103+
</div>
104+
</div>
105+
</div>
106+
</UCard>
107+
</template>
108+
</UModal>
109+
</template>
110+
111+
<script setup lang="ts">
112+
import LoadingSpinner from './LoadingSpinner.vue';
113+
114+
const props = defineProps<{
115+
fileName: string
116+
showUrlCard: boolean
117+
}>();
118+
119+
const emit = defineEmits(['close']);
120+
const { t } = useI18n();
121+
const showModal = ref(props.showUrlCard);
122+
123+
watch(() => props.showUrlCard, (val) => {
124+
showModal.value = val;
125+
});
126+
127+
watch(showModal, (val) => {
128+
if (!val)
129+
emit('close');
130+
});
131+
const loading = ref(false);
132+
const urls = ref<UrlInfo[]>([]);
133+
134+
watch(() => props.fileName, async (newFile) => {
135+
if (!newFile)
136+
return;
137+
138+
loading.value = true;
139+
try {
140+
urls.value = await $fetch<UrlInfo[]>(
141+
`/api/fetchOpenData/meta-information?feature=${encodeURIComponent(newFile)}`,
142+
);
143+
}
144+
catch (err) {
145+
console.error('Failed to fetch URLs', err);
146+
urls.value = [];
147+
}
148+
finally {
149+
loading.value = false;
150+
}
151+
}, { immediate: true });
152+
153+
function closeCard() {
154+
emit('close');
155+
}
156+
</script>

components/MyLeafletMap.vue

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,13 @@ function findValueByKey(obj: unknown, key: string): string | number | undefined
4848
function generateLabels(data: GeoJSON.FeatureCollection): Map<string, string> {
4949
const colorMap = new Map<string, string>();
5050
const legend = new Control({ position: 'topleft' });
51-
5251
const legendDisplayOption: string[] = Array.from(
5352
new Set(
5453
data.features.map(
5554
f => f.properties?.options?.legend_option ?? 'default',
5655
),
5756
),
5857
);
59-
6058
const labelKey: string | undefined = data.features[0]?.properties?.options?.label_option;
6159
const key = labelKey ?? 'default';
6260
@@ -81,9 +79,9 @@ function generateLabels(data: GeoJSON.FeatureCollection): Map<string, string> {
8179
uniqueValues.forEach((value) => {
8280
const color = colorMap.get(value);
8381
div.innerHTML += `
84-
<div style="color:black; margin-bottom:4px;">
82+
<div style="color:black; margin-bottom:4px;">
8583
<i style="background:${color}; width:12px; height:12px; display:inline-block; margin-right:4px;"></i> ${value}
86-
</div>`;
84+
</div>`;
8785
});
8886
8987
return div;

composables/dataTypes.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,12 @@ export interface Options {
2929
popup_name?: string
3030
popup_details?: { label: string, prop: string | string[] }[]
3131
}
32+
33+
export interface UrlInfo {
34+
name: string
35+
organization?: { title: string }
36+
url: string
37+
license_title?: string
38+
license_url?: string
39+
nested_series?: UrlInfo[]
40+
}

i18n/locales/de.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,11 @@
66
"loadingText": "Laden der Daten, bitte warten...",
77
"github": "Github",
88
"featureRequest": "Feature-Anfrage",
9-
"startDiscussion": "Diskussion beginnen"
9+
"startDiscussion": "Diskussion beginnen",
10+
"datasetDetail": "Datensatzdetails",
11+
"license": "Lizenz",
12+
"organization": "Organisation",
13+
"datasetUrl": "Datensatz-URL",
14+
"name": "Name",
15+
"seriesDatasets": "Serien-Datensätze"
1016
}

i18n/locales/en.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,11 @@
66
"loadingText": "Loading data, please wait...",
77
"github": "Github",
88
"featureRequest": "Feature request",
9-
"startDiscussion": "Start a discussion"
9+
"startDiscussion": "Start a discussion",
10+
"datasetDetail": "Dataset detail",
11+
"license": "License",
12+
"organization": "Organization",
13+
"datasetUrl": "Dataset url",
14+
"name": "Name",
15+
"seriesDatasets": "Series Datasets"
1016
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
},
1919
"dependencies": {
2020
"@heroicons/vue": "^2.2.0",
21-
"@nuxt/ui": "3.1.0",
21+
"@nuxt/ui": "3.3.4",
2222
"@nuxtjs/i18n": "9.5.4",
2323
"chart.js": "^4.4.9",
2424
"chroma-js": "^3.1.2",

pages/index.vue

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@
1515
</button>
1616
<span class="text-lg font-semibold">{{ t('openMap') }}</span>
1717
</div>
18-
<div v-if="feature" class="text-lg font-semibold">
18+
<div v-if="feature" class="text-lg font-semibold flex gap-2">
1919
{{ featureOptions.find((opt: MapDisplayOptions) => opt.name === feature)?.title }}
20+
<UButton
21+
icon="i-heroicons-information-circle"
22+
color="neutral"
23+
variant="ghost"
24+
@click="showUrlCard = true"
25+
/>
2026
</div>
2127
<div class="flex gap-4 px-4">
2228
<UButton
@@ -102,6 +108,7 @@
102108
</div>
103109
</main>
104110
</div>
111+
<MetaInformationModal v-if="showUrlCard" :file-name="feature" :show-url-card="showUrlCard" @close="showUrlCard = false" />
105112
</div>
106113
</template>
107114

@@ -120,6 +127,7 @@ const featureOptions = featureOptionsJson.options;
120127
121128
const router = useRouter();
122129
const route = useRoute();
130+
const showUrlCard = ref(false);
123131
124132
const leafletMapRef = ref<InstanceType<typeof MyLeafletMap> | null>(null);
125133
const { t, locale, setLocale } = useI18n();

0 commit comments

Comments
 (0)