start working on import frontend processing

This commit is contained in:
Cyberes 2024-08-20 16:35:22 -06:00
parent d2a4c49f7b
commit 03fe3d8eb4
12 changed files with 179 additions and 15 deletions

1
.gitignore vendored
View File

@ -22,7 +22,6 @@ eggs/
.eggs/ .eggs/
lib/ lib/
lib64/ lib64/
parts/
sdist/ sdist/
var/ var/
wheels/ wheels/

View File

@ -5,8 +5,10 @@ from geo_lib.types.feature import GeoFeatureSupported
def generate_auto_tags(feature: GeoFeatureSupported) -> List[str]: def generate_auto_tags(feature: GeoFeatureSupported) -> List[str]:
tags = [] tags = [
tags.append(f'type:{feature.type.value}') f'type:{feature.type.value.lower()}'
]
now = datetime.now() now = datetime.now()
tags.append(f'year:{now.year}') tags.append(f'year:{now.year}')
tags.append(f'month:{now.strftime("%B")}') tags.append(f'month:{now.strftime("%B")}')

View File

@ -1,4 +1,4 @@
import {UserInfo} from "@/assets/js/store-types.ts"; import {UserInfo} from "@/assets/js/types/store-types";
import {getUserInfo} from "@/assets/js/auth.js"; import {getUserInfo} from "@/assets/js/auth.js";
export const authMixin = { export const authMixin = {

View File

@ -1,6 +1,6 @@
import {createStore} from 'vuex' import {createStore} from 'vuex'
import {UserInfo} from './store-types' import {UserInfo} from './types/store-types'
import {ImportQueueItem} from "@/assets/js/import/import-types"; import {ImportQueueItem} from "@/assets/js/types/import-types";
export default createStore({ export default createStore({

View File

@ -0,0 +1,5 @@
export const GeoFeatureTypeStrings = {
Point: "Point",
LineString: "LineString",
Polygon: "Polygon"
}

View File

@ -0,0 +1,59 @@
enum GeoFeatureType {
POINT = 'Point',
LINESTRING = 'LineString',
POLYGON = 'Polygon'
}
interface GeoFeatureProps {
name: string;
id: number;
type: GeoFeatureType;
description?: string;
tags?: string[];
geometry: any[];
}
class GeoFeature {
name: string;
id: number;
type: GeoFeatureType;
description?: string;
tags: string[] = [];
geometry: any[];
constructor(props: GeoFeatureProps) {
this.name = props.name;
this.id = props.id;
this.type = props.type;
this.description = props.description;
this.tags = props.tags || [];
this.geometry = props.geometry || [];
}
}
export class GeoPoint extends GeoFeature {
type: GeoFeatureType = GeoFeatureType.POINT;
geometry: number[];
constructor(props: GeoFeatureProps) {
super({...props, type: GeoFeatureType.POINT});
}
}
export class GeoLineString extends GeoFeature {
type: GeoFeatureType = GeoFeatureType.LINESTRING;
geometry: number[][];
constructor(props: GeoFeatureProps) {
super({...props, type: GeoFeatureType.LINESTRING});
}
}
export class GeoPolygon extends GeoFeature {
type: GeoFeatureType = GeoFeatureType.POLYGON;
geometry: number[][][];
constructor(props: GeoFeatureProps) {
super({...props, type: GeoFeatureType.POLYGON});
}
}

View File

@ -1,4 +1,4 @@
import {getCookie} from "./auth.js" import {getCookie} from "../auth.js"
export class UserInfo { export class UserInfo {
username: String; username: String;

View File

@ -13,7 +13,7 @@ import {mapState} from "vuex"
import {authMixin} from "@/assets/js/authMixin.js"; import {authMixin} from "@/assets/js/authMixin.js";
import axios from "axios"; import axios from "axios";
import {IMPORT_QUEUE_LIST_URL} from "@/assets/js/import/url.js"; import {IMPORT_QUEUE_LIST_URL} from "@/assets/js/import/url.js";
import {ImportQueueItem} from "@/assets/js/import/import-types.ts" import {ImportQueueItem} from "@/assets/js/types/import-types"
import Importqueue from "@/components/import/parts/importqueue.vue"; import Importqueue from "@/components/import/parts/importqueue.vue";
export default { export default {
@ -51,9 +51,8 @@ export default {
} }
} }
}, },
async created() { // async created() {
await this.fetchQueueList() // },
},
// async mounted() { // async mounted() {
// }, // },
// beforeRouteEnter(to, from, next) { // beforeRouteEnter(to, from, next) {

View File

@ -18,6 +18,11 @@
</pre> </pre>
</li> </li>
</div> </div>
<div class="hidden">
<!-- Load the queue to populate it. -->
<Importqueue/>
</div>
</template> </template>
<script> <script>
@ -25,6 +30,9 @@ import {mapState} from "vuex";
import {authMixin} from "@/assets/js/authMixin.js"; import {authMixin} from "@/assets/js/authMixin.js";
import axios from "axios"; import axios from "axios";
import {capitalizeFirstLetter} from "@/assets/js/string.js"; import {capitalizeFirstLetter} from "@/assets/js/string.js";
import Importqueue from "@/components/import/parts/importqueue.vue";
import {GeoFeatureTypeStrings} from "@/assets/js/types/geofeature-strings";
import {GeoPoint, GeoLineString, GeoPolygon} from "@/assets/js/types/geofeature-types";
// TODO: for each feature, query the DB and check if there is a duplicate. For points that's duplicate coords, for linestrings and polygons that's duplicate points // TODO: for each feature, query the DB and check if there is a duplicate. For points that's duplicate coords, for linestrings and polygons that's duplicate points
// TODO: auto-refresh if still processing // TODO: auto-refresh if still processing
@ -33,7 +41,7 @@ export default {
computed: { computed: {
...mapState(["userInfo"]), ...mapState(["userInfo"]),
}, },
components: {}, components: {Importqueue},
data() { data() {
return { return {
msg: "", msg: "",
@ -49,7 +57,16 @@ export default {
this.msg = capitalizeFirstLetter(responseMsg).trim(".") + "." this.msg = capitalizeFirstLetter(responseMsg).trim(".") + "."
}, },
parseGeoJson(item) { parseGeoJson(item) {
return item switch (item.type) {
case GeoFeatureTypeStrings.Point:
return new GeoPoint(item);
case GeoFeatureTypeStrings.LineString:
return new GeoLineString(item);
case GeoFeatureTypeStrings.Polygon:
return new GeoPolygon(item);
default:
throw new Error(`Invalid feature type: ${item.type}`);
}
} }
}, },
beforeRouteEnter(to, from, next) { beforeRouteEnter(to, from, next) {

View File

@ -25,7 +25,7 @@ import {authMixin} from "@/assets/js/authMixin.js";
import axios from "axios"; import axios from "axios";
import {capitalizeFirstLetter} from "@/assets/js/string.js"; import {capitalizeFirstLetter} from "@/assets/js/string.js";
import {IMPORT_QUEUE_LIST_URL} from "@/assets/js/import/url.js"; import {IMPORT_QUEUE_LIST_URL} from "@/assets/js/import/url.js";
import {ImportQueueItem} from "@/assets/js/import/import-types.ts" import {ImportQueueItem} from "@/assets/js/types/import-types"
import Importqueue from "@/components/import/parts/importqueue.vue"; import Importqueue from "@/components/import/parts/importqueue.vue";
// TODO: after import, don't disable the upload, instead add the new item to a table at the button and then prompt the user to continue // TODO: after import, don't disable the upload, instead add the new item to a table at the button and then prompt the user to continue
@ -97,7 +97,6 @@ export default {
vm.file = null vm.file = null
vm.disableUpload = false vm.disableUpload = false
vm.uploadMsg = "" vm.uploadMsg = ""
await vm.fetchQueueList()
}) })
}, },
watch: {}, watch: {},

View File

@ -0,0 +1,84 @@
<template>
<div>
<button @click="fetchQueueList">Refresh</button>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>File Name</th>
<th>Features</th>
<th></th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in importQueue" :key="`item-${index}`">
<td>
<a :href="`/#/import/process/${item.id}`">{{ item.id }}</a>
</td>
<td>
<a :href="`/#/import/process/${item.id}`">{{ item.original_filename }}</a>
</td>
<td>
{{ item.processing === true ? "processing" : item.feature_count }}
</td>
<td>
<button @click="deleteItem(item, index)">Delete</button>
</td>
</tr>
</tbody>
</table>
</template>
<script>
import {mapState} from "vuex";
import {authMixin} from "@/assets/js/authMixin.js";
import axios from "axios";
import {IMPORT_QUEUE_LIST_URL} from "@/assets/js/import/url.js";
import {ImportQueueItem} from "@/assets/js/types/import-types";
export default {
computed: {
...mapState(["userInfo", "importQueue"]),
},
components: {},
mixins: [authMixin],
data() {
return {}
},
methods: {
async fetchQueueList() {
const response = await axios.get(IMPORT_QUEUE_LIST_URL)
const ourImportQueue = response.data.data.map((item) => new ImportQueueItem(item))
this.$store.commit('importQueue', ourImportQueue)
},
async deleteItem(item, index) {
if (window.confirm(`Delete "${item.original_filename}" (#${item.id})`))
try {
this.importQueue.splice(index, 1)
// TODO: add a message popup when delete is completed
const response = await axios.delete('/api/data/item/import/delete/' + item.id, {
headers: {
'X-CSRFToken': this.userInfo.csrftoken
}
})
if (!response.data.success) {
throw new Error("server reported failure")
}
await this.fetchQueueList()
} catch (error) {
alert(`Failed to delete ${item.id}: ${error.message}`)
this.importQueue.splice(index, 0, item)
}
}
},
async created() {
await this.fetchQueueList()
},
}
</script>
<style scoped>
</style>