implement import editing
This commit is contained in:
parent
2d5525ccce
commit
613210beaa
|
@ -1,3 +1,3 @@
|
|||
Test Accounts:
|
||||
|
||||
admin:hei8iWae
|
||||
admin1:hei8iWae
|
|
@ -1,10 +1,11 @@
|
|||
from django.urls import path
|
||||
|
||||
from data.views.import_item import upload_item, fetch_import_queue, fetch_queued, delete_import_queue
|
||||
from data.views.import_item import upload_item, fetch_import_queue, fetch_queued, delete_import_queue, update_imported_item
|
||||
|
||||
urlpatterns = [
|
||||
path('item/import/upload/', upload_item, name='upload_file'),
|
||||
path('item/import/get/<int:id>', fetch_import_queue, name='fetch_import_queue'),
|
||||
path('item/import/get/<int:item_id>', fetch_import_queue, name='fetch_import_queue'),
|
||||
path('item/import/get/mine', fetch_queued, name='fetch_queued'),
|
||||
path('item/import/delete/<int:id>', delete_import_queue, name='delete_import_queue'),
|
||||
path('item/import/update/<int:item_id>', update_imported_item),
|
||||
]
|
||||
|
|
|
@ -6,10 +6,14 @@ from django import forms
|
|||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.db import IntegrityError
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from django.views.decorators.csrf import csrf_protect
|
||||
from django.views.decorators.http import require_http_methods
|
||||
|
||||
from data.models import ImportQueue
|
||||
from geo_lib.daemon.database.locking import DBLockManager
|
||||
from geo_lib.daemon.workers.workers_lib.importer.kml import kmz_to_kml
|
||||
from geo_lib.daemon.workers.workers_lib.importer.tagging import generate_auto_tags
|
||||
from geo_lib.types.feature import GeoPoint, GeoLineString, GeoPolygon
|
||||
from geo_lib.website.auth import login_required_401
|
||||
|
||||
|
||||
|
@ -63,12 +67,12 @@ def upload_item(request):
|
|||
|
||||
|
||||
@login_required_401
|
||||
def fetch_import_queue(request, id):
|
||||
if id is None:
|
||||
def fetch_import_queue(request, item_id):
|
||||
if item_id is None:
|
||||
return JsonResponse({'success': False, 'msg': 'ID not provided', 'code': 400}, status=400)
|
||||
lock_manager = DBLockManager()
|
||||
try:
|
||||
queue = ImportQueue.objects.get(id=id)
|
||||
queue = ImportQueue.objects.get(id=item_id)
|
||||
if queue.user_id != request.user.id:
|
||||
return JsonResponse({'success': False, 'msg': 'not authorized to view this item', 'code': 403}, status=400)
|
||||
if not lock_manager.is_locked('data_importqueue', queue.id) and (len(queue.geofeatures) or len(queue.log)):
|
||||
|
@ -80,7 +84,7 @@ def fetch_import_queue(request, id):
|
|||
|
||||
@login_required_401
|
||||
def fetch_queued(request):
|
||||
user_items = ImportQueue.objects.filter(user=request.user).values('id', 'geofeatures', 'original_filename', 'raw_kml_hash', 'data', 'log', 'timestamp')
|
||||
user_items = ImportQueue.objects.exclude(geofeatures__len=0).filter(user=request.user).values('id', 'geofeatures', 'original_filename', 'raw_kml_hash', 'data', 'log', 'timestamp')
|
||||
data = json.loads(json.dumps(list(user_items), cls=DjangoJSONEncoder))
|
||||
lock_manager = DBLockManager()
|
||||
for i, item in enumerate(data):
|
||||
|
@ -103,6 +107,50 @@ def delete_import_queue(request, id):
|
|||
return HttpResponse(status=405)
|
||||
|
||||
|
||||
@login_required_401
|
||||
@csrf_protect # TODO: put this on all routes
|
||||
@require_http_methods(["PUT"])
|
||||
def update_imported_item(request, item_id):
|
||||
try:
|
||||
queue = ImportQueue.objects.get(id=item_id)
|
||||
except ImportQueue.DoesNotExist:
|
||||
return JsonResponse({'success': False, 'msg': 'ID does not exist', 'code': 404}, status=400)
|
||||
if queue.user_id != request.user.id:
|
||||
return JsonResponse({'success': False, 'msg': 'not authorized to edit this item', 'code': 403}, status=403)
|
||||
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
if not isinstance(data, list):
|
||||
raise ValueError('Invalid data format. Expected a list.')
|
||||
except (json.JSONDecodeError, ValueError) as e:
|
||||
return JsonResponse({'success': False, 'msg': str(e), 'code': 400}, status=400)
|
||||
|
||||
parsed_data = []
|
||||
for feature in data:
|
||||
match feature['type'].lower():
|
||||
case 'point':
|
||||
c = GeoPoint(**feature)
|
||||
case 'linestring':
|
||||
c = GeoLineString(**feature)
|
||||
case 'polygon':
|
||||
c = GeoPolygon(**feature)
|
||||
case _:
|
||||
continue
|
||||
|
||||
# Generate the tags after the user has made their changes.
|
||||
c.properties.tags = generate_auto_tags(c)
|
||||
parsed_data.append(json.loads(c.model_dump_json()))
|
||||
|
||||
# Erase the geofeatures column
|
||||
queue.geofeatures = []
|
||||
|
||||
# Update the data column with the new data
|
||||
queue.data = parsed_data
|
||||
|
||||
queue.save()
|
||||
return JsonResponse({'success': True, 'msg': 'Item updated successfully'})
|
||||
|
||||
|
||||
def _hash_kml(b: str):
|
||||
if not isinstance(b, bytes):
|
||||
b = b.encode()
|
||||
|
|
|
@ -10,7 +10,6 @@ from geo_lib.daemon.database.connection import CursorFromConnectionFromPool
|
|||
from geo_lib.daemon.database.locking import DBLockManager
|
||||
from geo_lib.daemon.workers.workers_lib.importer.kml import kml_to_geojson
|
||||
from geo_lib.daemon.workers.workers_lib.importer.logging import create_import_log_msg
|
||||
from geo_lib.daemon.workers.workers_lib.importer.tagging import generate_auto_tags
|
||||
from geo_lib.logging.database import log_to_db, DatabaseLogLevel, DatabaseLogSource
|
||||
from geo_lib.time import get_time_ms
|
||||
from geo_lib.types.feature import geojson_to_geofeature
|
||||
|
@ -49,8 +48,6 @@ def import_worker():
|
|||
messages.extend(kml_conv_messages)
|
||||
geofetures, typing_messages = geojson_to_geofeature(geojson_data)
|
||||
messages.extend(typing_messages)
|
||||
for feature in geofetures:
|
||||
feature.tags = generate_auto_tags(feature)
|
||||
success = True
|
||||
except Exception as e:
|
||||
err_name = e.__class__.__name__
|
||||
|
|
|
@ -10,6 +10,6 @@ def generate_auto_tags(feature: GeoFeatureSupported) -> List[str]:
|
|||
]
|
||||
|
||||
now = datetime.now()
|
||||
tags.append(f'year:{now.year}')
|
||||
tags.append(f'month:{now.strftime("%B")}')
|
||||
tags.append(f'import-year:{now.year}')
|
||||
tags.append(f'import-month:{now.strftime("%B")}')
|
||||
return [str(x) for x in tags]
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
SOFTWARE_NAME = 'geo-backend'
|
||||
SOFTWARE_VERSION = '0.0.0'
|
|
@ -1,9 +1,12 @@
|
|||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Optional, List, Union, Tuple
|
||||
|
||||
import pytz
|
||||
from pydantic import Field, BaseModel
|
||||
|
||||
from geo_lib.daemon.workers.workers_lib.importer.logging import create_import_log_msg
|
||||
from geo_lib.geo_backend import SOFTWARE_NAME, SOFTWARE_VERSION
|
||||
|
||||
|
||||
class GeoFeatureType(str, Enum):
|
||||
|
@ -12,6 +15,13 @@ class GeoFeatureType(str, Enum):
|
|||
POLYGON = 'Polygon'
|
||||
|
||||
|
||||
class GeoFeatureProperties(BaseModel):
|
||||
tags: List[str] = Field(default_factory=list)
|
||||
created: datetime = datetime.utcnow().replace(tzinfo=pytz.utc)
|
||||
software: str = Field(SOFTWARE_NAME, frozen=True)
|
||||
software_version: str = Field(SOFTWARE_VERSION, frozen=True)
|
||||
|
||||
|
||||
class GeoFeature(BaseModel):
|
||||
"""
|
||||
A thing that's shown on the map.
|
||||
|
@ -21,8 +31,8 @@ class GeoFeature(BaseModel):
|
|||
id: int # From the database
|
||||
type: GeoFeatureType
|
||||
description: Optional[str] = None
|
||||
tags: List[str] = Field(default_factory=list)
|
||||
geometry: List
|
||||
properties: GeoFeatureProperties = Field(default_factory=GeoFeatureProperties)
|
||||
|
||||
|
||||
class GeoPoint(GeoFeature):
|
||||
|
|
|
@ -8,4 +8,5 @@ geojson==3.1.0
|
|||
pydantic==2.7.3
|
||||
sqlalchemy==2.0.30
|
||||
redis==5.0.5
|
||||
async_timeout==4.0.3
|
||||
async_timeout==4.0.3
|
||||
pytz
|
|
@ -11,8 +11,10 @@
|
|||
"@types/geojson": "^7946.0.14",
|
||||
"axios": "^1.7.2",
|
||||
"dropzone-vue": "^0.1.11",
|
||||
"flatpickr": "^4.6.13",
|
||||
"geojson": "^0.5.0",
|
||||
"vue": "^3.4.21",
|
||||
"vue-flatpickr-component": "^11.0.5",
|
||||
"vue-router": "^4.3.2",
|
||||
"vuex": "^4.1.0"
|
||||
},
|
||||
|
@ -943,9 +945,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
|
||||
"integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
|
||||
"version": "1.7.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
|
||||
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
|
@ -1330,6 +1333,12 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/flatpickr": {
|
||||
"version": "4.6.13",
|
||||
"resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.13.tgz",
|
||||
"integrity": "sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
|
||||
|
@ -1606,10 +1615,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
||||
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
|
@ -2434,6 +2444,21 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vue-flatpickr-component": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-flatpickr-component/-/vue-flatpickr-component-11.0.5.tgz",
|
||||
"integrity": "sha512-Vfwg5uVU+sanKkkLzUGC5BUlWd5wlqAMq/UpQ6lI2BCZq0DDrXhOMX7hrevt8bEgglIq2QUv0K2Nl84Me/VnlA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"flatpickr": "^4.6.13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-router": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.2.tgz",
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
"@types/geojson": "^7946.0.14",
|
||||
"axios": "^1.7.2",
|
||||
"dropzone-vue": "^0.1.11",
|
||||
"flatpickr": "^4.6.13",
|
||||
"geojson": "^0.5.0",
|
||||
"vue": "^3.4.21",
|
||||
"vue-flatpickr-component": "^11.0.5",
|
||||
"vue-router": "^4.3.2",
|
||||
"vuex": "^4.1.0"
|
||||
},
|
||||
|
|
|
@ -4,13 +4,20 @@ enum GeoFeatureType {
|
|||
POLYGON = 'Polygon'
|
||||
}
|
||||
|
||||
interface GeoFeatureProperties {
|
||||
created: Date;
|
||||
software: string;
|
||||
software_version: string;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
interface GeoFeatureProps {
|
||||
name: string;
|
||||
id: number;
|
||||
type: GeoFeatureType;
|
||||
description?: string;
|
||||
tags?: string[];
|
||||
geometry: any[];
|
||||
properties: GeoFeatureProperties;
|
||||
}
|
||||
|
||||
class GeoFeature {
|
||||
|
@ -20,40 +27,29 @@ class GeoFeature {
|
|||
description?: string;
|
||||
tags: string[] = [];
|
||||
geometry: any[];
|
||||
properties: GeoFeatureProperties;
|
||||
|
||||
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 || [];
|
||||
this.properties = props.properties;
|
||||
}
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,15 +11,72 @@
|
|||
<p class="font-bold">{{ item }}</p>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<li v-for="(item, index) in itemsForUser" :key="`item-${index}`">
|
||||
<h2>{{ item.name }}</h2>
|
||||
<pre>
|
||||
{{ item }}
|
||||
</pre>
|
||||
</li>
|
||||
<ul class="space-y-4">
|
||||
<li v-for="(item, index) in itemsForUser" :key="`item-${index}`" class="bg-white shadow-md rounded-md p-4">
|
||||
<div class="mb-4">
|
||||
<label class="block text-gray-700 font-bold mb-2">Name:</label>
|
||||
<div class="flex items-center">
|
||||
<input v-model="item.name" :placeholder="originalItems[index].name"
|
||||
class="border border-gray-300 rounded-md px-3 py-2 w-full"/>
|
||||
<button class="ml-2 bg-gray-200 hover:bg-gray-300 text-gray-700 font-bold py-2 px-4 rounded"
|
||||
@click="resetField(index, 'name')">Reset
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="block text-gray-700 font-bold mb-2">Description:</label>
|
||||
<div class="flex items-center">
|
||||
<input v-model="item.description" :placeholder="originalItems[index].description"
|
||||
class="border border-gray-300 rounded-md px-3 py-2 w-full"/>
|
||||
<button class="ml-2 bg-gray-200 hover:bg-gray-300 text-gray-700 font-bold py-2 px-4 rounded"
|
||||
@click="resetField(index, 'description')">Reset
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="">
|
||||
<label class="block text-gray-700 font-bold mb-2">Created:</label>
|
||||
<div class="flex items-center">
|
||||
<flat-pickr :config="flatpickrConfig" :value="item.properties.created"
|
||||
class="border border-gray-300 rounded-md px-3 py-2 w-full"
|
||||
@on-change="updateDate(index, $event)"></flat-pickr>
|
||||
<button class="ml-2 bg-gray-200 hover:bg-gray-300 text-gray-700 font-bold py-2 px-4 rounded"
|
||||
@click="resetNestedField(index, 'properties', 'created')">Reset
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-gray-700 font-bold mb-2">Tags:</label>
|
||||
<div v-for="(tag, tagIndex) in item.properties.tags" :key="`tag-${tagIndex}`" class="mb-2">
|
||||
<div class="flex items-center">
|
||||
<input v-model="item.properties.tags[tagIndex]" :placeholder="getTagPlaceholder(index, tag)"
|
||||
class="border rounded-md px-3 py-2 w-full bg-white"/>
|
||||
<button class="ml-2 bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded"
|
||||
@click="removeTag(index, tagIndex)">Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center mt-2">
|
||||
<button :class="{ 'opacity-50 cursor-not-allowed': isLastTagEmpty(index) }"
|
||||
:disabled="isLastTagEmpty(index)"
|
||||
class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded"
|
||||
@click="addTag(index)">Add Tag
|
||||
</button>
|
||||
<button class="ml-2 bg-gray-200 hover:bg-gray-300 text-gray-700 font-bold py-2 px-4 rounded"
|
||||
@click="resetTags(index)">Reset Tags
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<button class="m-2 bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded"
|
||||
@click="saveChanges">Save
|
||||
</button>
|
||||
|
||||
|
||||
<div class="hidden">
|
||||
<!-- Load the queue to populate it. -->
|
||||
<Importqueue/>
|
||||
|
@ -34,6 +91,9 @@ 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";
|
||||
import {getCookie} from "@/assets/js/auth.js";
|
||||
import flatPickr from 'vue-flatpickr-component';
|
||||
import 'flatpickr/dist/flatpickr.css';
|
||||
|
||||
// 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
|
||||
|
@ -42,13 +102,20 @@ export default {
|
|||
computed: {
|
||||
...mapState(["userInfo"]),
|
||||
},
|
||||
components: {Importqueue},
|
||||
components: {Importqueue, flatPickr},
|
||||
data() {
|
||||
return {
|
||||
msg: "",
|
||||
currentId: null,
|
||||
itemsForUser: [],
|
||||
workerLog: []
|
||||
originalItems: [],
|
||||
workerLog: [],
|
||||
flatpickrConfig: {
|
||||
enableTime: true,
|
||||
time_24hr: true,
|
||||
dateFormat: 'Y-m-d H:i',
|
||||
timezone: 'UTC',
|
||||
},
|
||||
}
|
||||
},
|
||||
mixins: [authMixin],
|
||||
|
@ -69,14 +136,63 @@ export default {
|
|||
default:
|
||||
throw new Error(`Invalid feature type: ${item.type}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
resetField(index, fieldName) {
|
||||
this.itemsForUser[index][fieldName] = this.originalItems[index][fieldName];
|
||||
},
|
||||
resetNestedField(index, nestedField, fieldName) {
|
||||
this.itemsForUser[index][nestedField][fieldName] = this.originalItems[index][nestedField][fieldName];
|
||||
},
|
||||
addTag(index) {
|
||||
if (!this.isLastTagEmpty(index)) {
|
||||
this.itemsForUser[index].tags.push('');
|
||||
}
|
||||
},
|
||||
getTagPlaceholder(index, tag) {
|
||||
const originalTagIndex = this.originalItems[index].tags.indexOf(tag);
|
||||
return originalTagIndex !== -1 ? this.originalItems[index].tags[originalTagIndex] : '';
|
||||
},
|
||||
isLastTagEmpty(index) {
|
||||
const tags = this.itemsForUser[index].tags;
|
||||
return tags.length > 0 && tags[tags.length - 1].trim().length === 0;
|
||||
},
|
||||
resetTags(index) {
|
||||
this.itemsForUser[index].tags = [...this.originalItems[index].tags];
|
||||
},
|
||||
removeTag(index, tagIndex) {
|
||||
this.itemsForUser[index].tags.splice(tagIndex, 1);
|
||||
},
|
||||
updateDate(index, selectedDates) {
|
||||
this.itemsForUser[index].properties.created = selectedDates[0];
|
||||
},
|
||||
saveChanges() {
|
||||
const csrftoken = getCookie('csrftoken');
|
||||
axios.put('/api/data/item/import/update/' + this.id, this.itemsForUser, {
|
||||
headers: {
|
||||
'X-CSRFToken': csrftoken
|
||||
}
|
||||
}).then(response => {
|
||||
if (response.data.success) {
|
||||
this.msg = 'Changes saved successfully';
|
||||
window.alert(this.msg);
|
||||
} else {
|
||||
this.msg = 'Error saving changes: ' + response.data.msg;
|
||||
window.alert(this.msg);
|
||||
}
|
||||
}).catch(error => {
|
||||
this.msg = 'Error saving changes: ' + error.message;
|
||||
window.alert(this.msg);
|
||||
});
|
||||
},
|
||||
}
|
||||
,
|
||||
beforeRouteEnter(to, from, next) {
|
||||
next(async vm => {
|
||||
if (vm.currentId !== vm.id) {
|
||||
vm.msg = ""
|
||||
vm.messages = []
|
||||
vm.itemsForUser = []
|
||||
vm.originalItems = []
|
||||
vm.currentId = null
|
||||
axios.get('/api/data/item/import/get/' + vm.id).then(response => {
|
||||
if (!response.data.success) {
|
||||
|
@ -87,6 +203,7 @@ export default {
|
|||
response.data.geofeatures.forEach((item) => {
|
||||
vm.itemsForUser.push(vm.parseGeoJson(item))
|
||||
})
|
||||
vm.originalItems = JSON.parse(JSON.stringify(vm.itemsForUser))
|
||||
}
|
||||
vm.msg = response.data.msg
|
||||
vm.workerLog = response.data.log
|
||||
|
@ -96,8 +213,10 @@ export default {
|
|||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
};
|
||||
}
|
||||
,
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
Loading…
Reference in New Issue