This commit is contained in:
j3d1 2026-09-04 15:04:13 +02:00
parent e88dc898b3
commit 78a1e0301f
20 changed files with 118 additions and 121 deletions

2
.gitignore vendored
View file

@ -14,7 +14,7 @@ dist/
downloads/
eggs/
.eggs/
lib/
#lib/
lib64/
parts/
sdist/

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "frontend/extras"]
path = frontend/extras
url = https://git.neulandlabor.de/j3d1/vue-extras.git

View file

@ -9,7 +9,7 @@ RUN mkdir /git
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package.json ./
COPY extras/ ./extras/
#COPY extras/ ./extras/
RUN npm install
CMD [ "npm", "run", "dev", "--", "--host"]

View file

@ -15,7 +15,7 @@ ARG GIT_COMMIT=unknown
ENV GIT_COMMIT=$GIT_COMMIT
COPY package.json package-lock.json ./
COPY extras/ ./extras/
#COPY extras/ ./extras/
RUN npm ci
COPY . .
RUN npm run build

@ -1 +0,0 @@
Subproject commit 21bf28a8b6293872f5f7a42c9ca0bc12ede5aaae

View file

@ -197,6 +197,93 @@
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
"wrap-ansi": "^8.1.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"string-width-cjs": {
"version": "npm:string-width@4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"dependencies": {
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
}
}
},
"strip-ansi-cjs": {
"version": "npm:strip-ansi@6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
},
"wrap-ansi-cjs": {
"version": "npm:wrap-ansi@7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"dependencies": {
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
}
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
}
}
}
}
},
"@jridgewell/sourcemap-codec": {
@ -887,9 +974,6 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
"extras": {
"version": "file:extras"
},
"fast-diff": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
@ -1620,40 +1704,6 @@
"strip-ansi": "^7.0.1"
}
},
"string-width-cjs": {
"version": "npm:string-width@4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
}
}
},
"strip-ansi": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
@ -1663,23 +1713,6 @@
"ansi-regex": "^6.2.2"
}
},
"strip-ansi-cjs": {
"version": "npm:strip-ansi@6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
}
}
},
"strip-literal": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz",
@ -1977,60 +2010,6 @@
"strip-ansi": "^7.0.1"
}
},
"wrap-ansi-cjs": {
"version": "npm:wrap-ansi@7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
}
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
}
}
},
"ws": {
"version": "8.21.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",

View file

@ -17,7 +17,6 @@
"vue-multiselect": "^2.1.7",
"vue-router": "^4.1.6",
"vuex": "^4.1.0",
"extras": "file:./extras",
"jquery": "^3.6.0",
"popper.js": "^1.16.1"
},

View file

@ -14,7 +14,7 @@
<div style="position: relative;">
<div class="image-list">
<deletable-wrapper v-for="file in only_images(item_files).filter(file => file.owner)" :key="file.id"
@delete="deleteFile(file)">
confirm-message="Delete this file? This cannot be undone." @delete="deleteFile(file)">
<authenticated-image :src="file.name" :owner="file.owner" class="img-thumbnail"/>
</deletable-wrapper>
<deletable-wrapper v-for="file in only_images(item_files).filter(file => file.data)" :key="file.id"

View file

@ -26,9 +26,17 @@ export default {
components: {
...BIcons
},
props: {
// No confirmation when omitted - e.g. removing a not-yet-saved staged file, see CombinedFileField.vue's deleteTempFile.
confirmMessage: {
type: String,
default: null
}
},
emits: ["delete"],
methods: {
triggerDelete() {
if (this.confirmMessage && !confirm(this.confirmMessage)) return;
this.$emit("delete");
}
}

View file

@ -30,7 +30,7 @@ import ShortId from '@/views/ShortId.vue';
import {
encodeShortId, serializeShortId, decodeShortId, deserializeShortId,
isDomainQualifiedShortId, decodeDomainQualifiedShortId
} from '@/short-id';
} from '@/lib/short-id';
import Account from '@/views/settings/Account.vue';
import Password from '@/views/settings/Password.vue';

View file

@ -9,7 +9,7 @@
</div>
<div class="card-body">
<span v-for="file in only_images(files)" :key="file.id">
<deletable-wrapper @delete="deleteFile(file)">
<deletable-wrapper confirm-message="Delete this file? This cannot be undone." @delete="deleteFile(file)">
<authenticated-image :src="thumbnailPathForHash(file.hash)" :owner="file.owner"
class="img-thumbnail"/>
</deletable-wrapper>

View file

@ -173,6 +173,7 @@ export default {
})
},
tryDropFriend(friend) {
if (!confirm(`Are you sure you want to remove "${friend.handle}" as a friend?`)) return
this.dropFriend(friend).then((ok) => {
if (ok) {
delete this.friends[friend.handle]

View file

@ -107,6 +107,7 @@ export default {
})
},
tryRemoveMember(member) {
if (!confirm(`Are you sure you want to remove "${member.handle}" from ${this.group.handle}?`)) return
this.removeGroupMember({groupHandle: this.group.handle, identityId: member.id})
.then(() => {
this.refresh()

View file

@ -196,6 +196,7 @@ export default {
return this.fetchFriendInventoryItems({friendHandle: this.selectedOwner})
},
tryDeleteItem(item) {
if (!confirm(`Are you sure you want to delete "${item.name}"? This cannot be undone.`)) return
this.deleteInventoryItem(item).then(() => {
this.fetchItemsForOwner()
})

View file

@ -46,7 +46,7 @@
Edit
</button>
<button type="submit" class="btn btn-danger"
@click="deleteInventoryItem(item).then(() => $router.push(ownerOverviewRoute(item)))">
@click="tryDeleteItem">
<b-icon-trash></b-icon-trash>
Delete
</button>
@ -116,6 +116,10 @@ export default {
...mapActions(["fetchItemByHandle", "deleteInventoryItem", "fetchGroupMemberships"]),
async loadItem() {
this.item = await this.fetchItemByHandle({handle: this.decodedHandle, id: this.id}) || {}
},
tryDeleteItem() {
if (!confirm(`Are you sure you want to delete "${this.item.name}"? This cannot be undone.`)) return
this.deleteInventoryItem(this.item).then(() => this.$router.push(ownerOverviewRoute(this.item)))
}
},
watch: {

View file

@ -184,6 +184,7 @@ export default {
: this.fetchGroupStorageLocations({groupHandle: this.selectedOwner})
},
tryDeleteLocation(location) {
if (!confirm(`Are you sure you want to delete "${location.name}"? This cannot be undone.`)) return
this.deleteStorageLocation(location).then(() => {
this.fetchLocationsForOwner()
})

View file

@ -39,7 +39,7 @@
Edit
</button>
<button type="submit" class="btn btn-danger"
@click="deleteStorageLocation(location).then(() => $router.push(ownerLocationOverviewRoute(location)))">
@click="tryDeleteLocation">
<b-icon-trash></b-icon-trash>
Delete
</button>
@ -103,6 +103,10 @@ export default {
...mapActions(["fetchStorageLocationByHandle", "deleteStorageLocation", "fetchGroupMemberships"]),
async loadLocation() {
this.location = await this.fetchStorageLocationByHandle({handle: this.decodedHandle, id: this.id}) || {}
},
tryDeleteLocation() {
if (!confirm(`Are you sure you want to delete "${this.location.name}"? This cannot be undone.`)) return
this.deleteStorageLocation(this.location).then(() => this.$router.push(ownerLocationOverviewRoute(this.location)))
}
},
watch: {

View file

@ -416,6 +416,8 @@ export default {
},
async abortWorkflow() {
const displayName = this.getWorkflowDisplayName || this.workflowInstance.title;
if (!confirm(`Are you sure you want to abort "${displayName}"?`)) return;
try {
this.loading = true;
await this.deleteWorkflow(this.workflowInstance.id);

View file

@ -130,6 +130,7 @@ export default {
await this.updateUserProfilePicture({file: image});
},
async removePicture() {
if (!confirm('Are you sure you want to remove your profile picture?')) return;
await this.updateUserProfilePicture({file: null});
}
},