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/
lib/
lib64/
parts/
sdist/
var/
wheels/

View File

@ -5,8 +5,10 @@ from geo_lib.types.feature import GeoFeatureSupported
def generate_auto_tags(feature: GeoFeatureSupported) -> List[str]:
tags = []
tags.append(f'type:{feature.type.value}')
tags = [
f'type:{feature.type.value.lower()}'
]
now = datetime.now()
tags.append(f'year:{now.year}')
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";
export const authMixin = {

View File

@ -1,6 +1,6 @@
import {createStore} from 'vuex'
import {UserInfo} from './store-types'
import {ImportQueueItem} from "@/assets/js/import/import-types";
import {UserInfo} from './types/store-types'
import {ImportQueueItem} from "@/assets/js/types/import-types";
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 {
username: String;

View File

@ -13,7 +13,7 @@ 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/import/import-types.ts"
import {ImportQueueItem} from "@/assets/js/types/import-types"
import Importqueue from "@/components/import/parts/importqueue.vue";
export default {
@ -51,9 +51,8 @@ export default {
}
}
},
async created() {
await this.fetchQueueList()
},
// async created() {
// },
// async mounted() {
// },
// beforeRouteEnter(to, from, next) {

View File

@ -18,6 +18,11 @@
</pre>
</li>
</div>
<div class="hidden">
<!-- Load the queue to populate it. -->
<Importqueue/>
</div>
</template>
<script>
@ -25,6 +30,9 @@ import {mapState} from "vuex";
import {authMixin} from "@/assets/js/authMixin.js";
import axios from "axios";
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: auto-refresh if still processing
@ -33,7 +41,7 @@ export default {
computed: {
...mapState(["userInfo"]),
},
components: {},
components: {Importqueue},
data() {
return {
msg: "",
@ -49,7 +57,16 @@ export default {
this.msg = capitalizeFirstLetter(responseMsg).trim(".") + "."
},
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) {

View File

@ -25,7 +25,7 @@ import {authMixin} from "@/assets/js/authMixin.js";
import axios from "axios";
import {capitalizeFirstLetter} from "@/assets/js/string.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";
// 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.disableUpload = false
vm.uploadMsg = ""
await vm.fetchQueueList()
})
},
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>