Skip to content

Commit

Permalink
Add CSV export option
Browse files Browse the repository at this point in the history
  • Loading branch information
cdauth committed Mar 7, 2024
1 parent 03072a2 commit 81b05e5
Show file tree
Hide file tree
Showing 23 changed files with 1,151 additions and 661 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module.exports = {
"vue/multi-word-component-names": ["off"],
"@typescript-eslint/no-base-to-string": ["error"],
"@typescript-eslint/no-misused-promises": ["error", { checksVoidReturn: false }],
"vue/return-in-computed-property": ["off"],

"constructor-super": ["error"],
"for-direction": ["error"],
Expand Down
10 changes: 5 additions & 5 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@
},
"dependencies": {
"facilmap-types": "workspace:^",
"socket.io-client": "^4.7.2"
"socket.io-client": "^4.7.4"
},
"devDependencies": {
"@types/geojson": "^7946.0.13",
"@types/geojson": "^7946.0.14",
"rimraf": "^5.0.5",
"typescript": "^5.3.3",
"vite": "^5.0.12",
"vite-plugin-dts": "^3.7.0"
"typescript": "^5.4.2",
"vite": "^5.1.5",
"vite-plugin-dts": "^3.7.3"
}
}
28 changes: 14 additions & 14 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@
"dependencies": {
"@ckpack/vue-color": "^1.5.0",
"@tmcw/togeojson": "^5.8.1",
"@vitejs/plugin-vue": "^5.0.1",
"@vitejs/plugin-vue": "^5.0.4",
"blob": "^0.1.0",
"bootstrap": "^5.3.2",
"bootstrap": "^5.3.3",
"copy-to-clipboard": "^3.3.3",
"decode-uri-component": "^0.4.1",
"facilmap-client": "workspace:^",
Expand All @@ -70,10 +70,10 @@
"popper-max-size-modifier": "^0.2.0",
"qrcode.vue": "^3.4.1",
"tablesorter": "^2.31.3",
"vite": "^5.0.12",
"vite-plugin-css-injected-by-js": "^3.3.1",
"vite-plugin-dts": "^3.7.0",
"vue": "^3.4.0",
"vite": "^5.1.5",
"vite-plugin-css-injected-by-js": "^3.4.0",
"vite-plugin-dts": "^3.7.3",
"vue": "^3.4.21",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
Expand All @@ -87,14 +87,14 @@
"@types/leaflet.locatecontrol": "^0.74.4",
"@types/lodash-es": "^4.17.12",
"@types/pluralize": "^0.0.33",
"happy-dom": "^12.10.3",
"happy-dom": "^13.6.2",
"rimraf": "^5.0.5",
"sass": "^1.69.6",
"svgo": "^3.1.0",
"tsx": "^4.7.0",
"typescript": "^5.3.3",
"vite-tsconfig-paths": "^4.2.3",
"vitest": "^1.1.0",
"vue-tsc": "^1.8.27"
"sass": "^1.71.1",
"svgo": "^3.2.0",
"tsx": "^4.7.1",
"typescript": "^5.4.2",
"vite-tsconfig-paths": "^4.3.1",
"vitest": "^1.3.1",
"vue-tsc": "^2.0.5"
}
}
64 changes: 57 additions & 7 deletions frontend/src/lib/components/export-dialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import HelpPopover from "./ui/help-popover.vue";
import CopyToClipboardInput from "./ui/copy-to-clipboard-input.vue";
import type { ComponentProps } from "../utils/vue";
import type { ID } from "facilmap-types";
import validatedField from "./ui/validated-form/validated-field.vue";
const emit = defineEmits<{
hidden: [];
Expand All @@ -25,7 +26,8 @@
const formatOptions = {
gpx: "GPX",
geojson: "GeoJSON",
table: "HTML"
table: "HTML",
csv: "CSV"
};
const hideOptions = computed(() => new Set([
Expand All @@ -41,6 +43,7 @@
const useTracks = ref<"1" | "0">("1");
const filter = ref(true);
const hide = ref(new Set<string>());
const typeId = ref<ID>();
const methodOptions = computed(() => ({
download: format.value === "table" ? "Open file" : "Download file",
Expand All @@ -49,12 +52,32 @@
const method = ref<keyof typeof methodOptions["value"]>((Object.keys(methodOptions.value) as Array<keyof typeof methodOptions["value"]>)[0]);
const resolvedTypeId = computed(() => typeId.value != null && client.value.types[typeId.value] ? typeId.value : undefined);
const canSelectUseTracks = computed(() => format.value === "gpx");
const canSelectType = computed(() => format.value === "csv");
const mustSelectType = computed(() => format.value === "csv");
const canSelectHide = computed(() => ["table", "csv"].includes(format.value));
const validateImmediate = computed(() => method.value === "link"); // No submit button
function validateTypeId(typeId: ID | undefined) {
if (mustSelectType.value && resolvedTypeId.value == null) {
return "Please select a type.";
}
}
const url = computed(() => {
const params = new URLSearchParams();
if (format.value === "gpx") {
if (canSelectUseTracks.value) {
params.set("useTracks", useTracks.value);
}
if (format.value === "table" && hide.value.size > 0) {
if (canSelectType.value) {
if (resolvedTypeId.value == null) {
return undefined;
}
params.set("typeId", `${resolvedTypeId.value}`);
}
if (canSelectHide.value && hide.value.size > 0) {
params.set("hide", [...hide.value].join(","));
}
if (mapContext.value.filter) {
Expand Down Expand Up @@ -117,6 +140,10 @@
attributes of all markers and lines. This table can also be copy&pasted into a spreadsheet application for
further processing.
</p>
<p>
<strong>CSV</strong> files can be imported into most spreadsheet applications and only contain the data attributes of the objects
one type of marker or line.
</p>
</HelpPopover>
</label>
<div class="col-sm-9">
Expand All @@ -126,7 +153,7 @@
</div>
</div>

<div v-if="format === 'gpx'" class="row mb-3">
<div v-if="canSelectUseTracks" class="row mb-3">
<label class="col-sm-3 col-form-label" :for="`${id}-route-type-select`">
Route type
<HelpPopover>
Expand Down Expand Up @@ -163,7 +190,30 @@
</div>
</div>

<div v-if="format === 'table'" class="row mb-3">
<div v-if="canSelectType" class="row mb-3">
<label class="col-sm-3 col-form-label" :for="`${id}-type-select`">
Type
</label>
<validatedField
:value="typeId"
:validators="[
validateTypeId
]"
class="col-sm-9 position-relative"
:immediate="validateImmediate"
>
<template #default="slotProps">
<select class="form-select" v-model="typeId" :id="`${id}-type-select`" :ref="slotProps.inputRef">
<option v-for="(type, typeId) of client.types" :key="typeId" :value="typeId">{{type.name}}</option>
</select>
<div class="invalid-tooltip">
{{slotProps.validationError}}
</div>
</template>
</ValidatedField>
</div>

<div v-if="canSelectHide" class="row mb-3">
<label class="col-sm-3 col-form-label">Include columns</label>
<div class="col-sm-9 fm-export-dialog-hide-options">
<template v-for="key in hideOptions" :key="key">
Expand All @@ -190,7 +240,7 @@
</div>
</div>

<template v-if="method === 'link'">
<template v-if="method === 'link' && url != null">
<hr />

<CopyToClipboardInput
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/components/line-info/line-info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@
<template v-if="line.ascent == null || !showElevationPlot">
<template v-for="field in client.types[line.typeId].fields" :key="field.name">
<dt>{{field.name}}</dt>
<dd v-html="formatField(field, line.data[field.name])"></dd>
<dd v-html="formatField(field, line.data[field.name], true)"></dd>
</template>
</template>
</dl>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/components/marker-info/marker-info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@

<template v-for="field in client.types[marker.typeId].fields" :key="field.name">
<dt>{{field.name}}</dt>
<dd v-html="formatField(field, marker.data[field.name])"></dd>
<dd v-html="formatField(field, marker.data[field.name], true)"></dd>
</template>
</dl>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@
const touched = ref(false);
function handleTouched() {
touched.value = true;
setTimeout(() => { // Give validators a chance to run on the updated value first
touched.value = true;
}, 0);
}
useDomEventListener(inputRef, "input", handleTouched);
Expand Down
22 changes: 20 additions & 2 deletions frontend/src/lib/components/ui/validated-form/validated-form.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { type Ref, onScopeDispose, reactive, readonly, ref, watchEffect, toRef } from "vue";
import { type Ref, onScopeDispose, reactive, readonly, ref, watchEffect, toRef, computed } from "vue";
import { type ExtendableEventMixin, extendableEventMixin, useDomEventListener } from "../../../utils/utils";
import { useToasts } from "../toasts/toasts.vue";
Expand Down Expand Up @@ -131,17 +131,35 @@
formValidationError: toRef(() => props.formValidationError)
});
const actionWithoutQuery = computed(() => {
if (props.action != null) {
const url = new URL(props.action);
url.search = "";
return url.toString();
}
});
const actionParams = computed(() => {
if (props.action != null) {
const url = new URL(props.action);
return url.searchParams;
}
});
defineExpose({ formData });
</script>

<template>
<form
novalidate
ref="formRef"
:action="props.action ?? 'javascript:'"
:action="actionWithoutQuery ?? 'javascript:'"
:target="props.target"
:class="{ 'fm-was-validated': formData.isTouched }"
>
<template v-for="[key, value] in actionParams?.entries()" :key="key">
<input type="hidden" :name="key" :value="value" />
</template>

<slot :formData="formData"/>
</form>
</template>
2 changes: 1 addition & 1 deletion frontend/src/table/table.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
for(let field of type.fields) {
if(!hide.includes(field.name)) {
-%>
<td><%-utils.formatField(field, object.data[field.name]).trim()%></td>
<td><%-utils.formatField(field, object.data[field.name], true).trim()%></td>
<%
}
}
Expand Down
10 changes: 5 additions & 5 deletions integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
"facilmap-types": "workspace:^",
"facilmap-utils": "workspace:^",
"lodash-es": "^4.17.21",
"socket.io-client": "^4.7.2",
"vitest": "^1.1.1"
"socket.io-client": "^4.7.4",
"vitest": "^1.3.1"
},
"devDependencies": {
"@types/lodash-es": "^4.17.12",
"typescript": "^5.3.3",
"vite": "^5.0.12",
"vite-plugin-dts": "^3.7.1",
"typescript": "^5.4.2",
"vite": "^5.1.5",
"vite-plugin-dts": "^3.7.3",
"vite-tsconfig-paths": "^4.3.1"
}
}
27 changes: 13 additions & 14 deletions leaflet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,27 +55,26 @@
},
"devDependencies": {
"@fortawesome/fontawesome-free": "^6.5.1",
"@types/cheerio": "^0.22.35",
"@types/geojson": "^7946.0.13",
"@types/geojson": "^7946.0.14",
"@types/leaflet": "^1.9.8",
"@types/leaflet.markercluster": "^1.5.4",
"@types/lodash-es": "^4.17.12",
"@types/node-fetch": "^2.6.10",
"@types/yauzl-promise": "^2.1.4",
"@types/node-fetch": "^2.6.11",
"@types/yauzl-promise": "^4.0.0",
"cheerio": "^1.0.0-rc.12",
"fast-glob": "^3.3.2",
"happy-dom": "^12.10.3",
"happy-dom": "^13.6.2",
"node-fetch": "^3.3.2",
"rimraf": "^5.0.5",
"rollup": "^4.9.1",
"svgo": "^3.1.0",
"tsx": "^4.7.0",
"typescript": "^5.3.3",
"vite": "^5.0.12",
"vite-plugin-css-injected-by-js": "^3.3.1",
"vite-plugin-dts": "^3.7.0",
"vite-tsconfig-paths": "^4.2.3",
"vitest": "^1.1.0",
"rollup": "^4.12.1",
"svgo": "^3.2.0",
"tsx": "^4.7.1",
"typescript": "^5.4.2",
"vite": "^5.1.5",
"vite-plugin-css-injected-by-js": "^3.4.0",
"vite-plugin-dts": "^3.7.3",
"vite-tsconfig-paths": "^4.3.1",
"vitest": "^1.3.1",
"yauzl-promise": "^4.0.0"
},
"peerDependencies": {
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
"test": "yarn workspaces foreach -v run test"
},
"devDependencies": {
"@types/eslint": "^8.56.0",
"@typescript-eslint/eslint-plugin": "^6.16.0",
"@typescript-eslint/parser": "^6.16.0",
"eslint": "^8.56.0",
"@types/eslint": "^8.56.5",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
"eslint": "^8.57.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-vue": "^9.19.2"
"eslint-plugin-vue": "^9.22.0"
},
"version": "0.0.0",
"packageManager": "[email protected]"
Expand Down
Loading

0 comments on commit 81b05e5

Please sign in to comment.