use awareness info inside form inputs
This commit is contained in:
parent
12772bfcfa
commit
27e3ed525b
9 changed files with 135 additions and 23 deletions
32
package-lock.json
generated
32
package-lock.json
generated
|
@ -30,6 +30,7 @@
|
|||
"uuid": "^9.0.0",
|
||||
"vue": "^3.4.29",
|
||||
"vue-router": "^4.3.3",
|
||||
"vue-tippy": "^6.6.0",
|
||||
"y-quill": "0.1.3",
|
||||
"yjs": "^13.6.23"
|
||||
},
|
||||
|
@ -2680,6 +2681,16 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-node-resolve": {
|
||||
"version": "15.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
|
||||
|
@ -9333,6 +9344,15 @@
|
|||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/tippy.js": {
|
||||
"version": "6.3.7",
|
||||
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
|
||||
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-data-view": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.1.0.tgz",
|
||||
|
@ -9953,6 +9973,18 @@
|
|||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-tippy": {
|
||||
"version": "6.6.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-tippy/-/vue-tippy-6.6.0.tgz",
|
||||
"integrity": "sha512-ISRIUQDlcEP05K1nCbvlVcd8yuWS6S3dI91qD0A2slgtwwWjih8Fn9Aymq4SNaHQsdiP5+MLRPZVDxFjKMPgKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tippy.js": "^6.3.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-tsc": {
|
||||
"version": "2.0.29",
|
||||
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.29.tgz",
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
"uuid": "^9.0.0",
|
||||
"vue": "^3.4.29",
|
||||
"vue-router": "^4.3.3",
|
||||
"vue-tippy": "^6.6.0",
|
||||
"y-quill": "0.1.3",
|
||||
"yjs": "^13.6.23"
|
||||
},
|
||||
|
|
|
@ -28,6 +28,7 @@ import { QuillBinding } from "y-quill";
|
|||
import { moduleOptions } from "@/helpers/quillConfig";
|
||||
import * as Y from "yjs";
|
||||
import "@lottiefiles/lottie-player";
|
||||
import { Awareness } from "@/helpers/awareness";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -37,6 +38,10 @@ export default defineComponent({
|
|||
type: Object as PropType<Y.Text>,
|
||||
required: true,
|
||||
},
|
||||
awareness: {
|
||||
type: Object as PropType<Partial<Awareness>>,
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: "",
|
||||
|
|
|
@ -2,16 +2,23 @@
|
|||
<div :class="growing ? 'grow' : 'w-full'">
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
<label :for="title">{{ title }}</label>
|
||||
<lottie-player src="/typing_animation.json" class="w-fit h-5" loop autoplay />
|
||||
<lottie-player
|
||||
v-if="currentEditors.length != 0"
|
||||
src="/typing_animation.json"
|
||||
class="w-fit h-5"
|
||||
loop
|
||||
autoplay
|
||||
v-tippy="currentEditors.map((c) => c.username).join(', ')"
|
||||
/>
|
||||
</div>
|
||||
<input :type="type" :id="title" v-model="value" :min="min" />
|
||||
<input :type="type" :id="title" v-model="value" :min="min" @focus="focused" @blur="blured" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import { mapActions, mapState, mapWritableState } from "pinia";
|
||||
import { defineComponent, type PropType } from "vue";
|
||||
import "@lottiefiles/lottie-player";
|
||||
import type { Awareness } from "@/helpers/awareness";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -37,8 +44,17 @@ export default defineComponent({
|
|||
type: String,
|
||||
default: "",
|
||||
},
|
||||
awareness: {
|
||||
type: Object as PropType<Awareness>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ["update:model-value"],
|
||||
data() {
|
||||
return {
|
||||
typing: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
value: {
|
||||
get() {
|
||||
|
@ -48,6 +64,28 @@ export default defineComponent({
|
|||
this.$emit("update:model-value", val);
|
||||
},
|
||||
},
|
||||
currentEditors() {
|
||||
return this.awareness.getEditorObjsByField(this.title);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.awareness.emitter.on("change", (d) => {});
|
||||
},
|
||||
methods: {
|
||||
focused() {
|
||||
this.awareness.publishMyState({
|
||||
field: this.title,
|
||||
cursor: undefined,
|
||||
range: undefined,
|
||||
});
|
||||
},
|
||||
blured() {
|
||||
this.awareness.publishMyState({
|
||||
field: "blured user",
|
||||
cursor: undefined,
|
||||
range: undefined,
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -17,11 +17,12 @@ export type AwarenessActions = "update" | "remove";
|
|||
|
||||
export type AwarenessEvents = {
|
||||
update: { data: EditorState };
|
||||
change: { socketId: string; action: AwarenessActions } & EditorState;
|
||||
};
|
||||
|
||||
export class Awareness {
|
||||
private editors = new Map<string, Editor>();
|
||||
private editorStates = new Map<string, EditorState>();
|
||||
public readonly editors = new Map<string, Editor>();
|
||||
public readonly editorStates = new Map<string, EditorState>();
|
||||
public readonly emitter = mitt<AwarenessEvents>();
|
||||
|
||||
public getEditors() {
|
||||
|
@ -38,6 +39,12 @@ export class Awareness {
|
|||
.map(([key, val]) => key);
|
||||
}
|
||||
|
||||
public getEditorObjsByField(field: string) {
|
||||
return Array.from(this.editors.entries())
|
||||
.filter(([key, val]) => this.getEditorsByField(field).includes(key))
|
||||
.map(([key, val]) => val);
|
||||
}
|
||||
|
||||
public getEditorStates() {
|
||||
return this.editorStates;
|
||||
}
|
||||
|
@ -56,6 +63,7 @@ export class Awareness {
|
|||
} else if (action == "remove") {
|
||||
this.editorStates.delete(socketId);
|
||||
}
|
||||
this.emitter.emit("change", { socketId, action, ...data });
|
||||
}
|
||||
|
||||
public publishMyState(data: EditorState) {
|
||||
|
|
|
@ -7,6 +7,8 @@ import NProgress from "nprogress";
|
|||
import "../node_modules/nprogress/nprogress.css";
|
||||
import { Quill } from "@vueup/vue-quill";
|
||||
import QuillCursors from "quill-cursors";
|
||||
import VueTippy from "vue-tippy";
|
||||
import "tippy.js/dist/tippy.css";
|
||||
|
||||
import { http } from "./serverCom";
|
||||
import "./main.css";
|
||||
|
@ -19,6 +21,7 @@ const app = createApp(App);
|
|||
|
||||
app.use(createPinia());
|
||||
app.use(router);
|
||||
app.use(VueTippy, { theme: "light", defaultProps: { placement: "right" } });
|
||||
app.config.globalProperties.$http = http;
|
||||
app.config.globalProperties.$progress = NProgress;
|
||||
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
<template>
|
||||
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto">
|
||||
<DetailFormInput title="Einsatztitel" v-model="title" />
|
||||
<DetailFormInput title="Einsatztitel" v-model="title" :awareness="awareness" />
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<ForceSelect title="Einsatzleiter" :available-forces="availableForces" v-model="command" />
|
||||
<ForceSelect title="Bericht Ersteller" :available-forces="availableForces" v-model="secretary" />
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<DetailFormInput title="Einsatzbeginn" v-model="start" type="datetime-local" growing />
|
||||
<DetailFormInput title="Einsatzende" v-model="end" type="datetime-local" :min="start" growing />
|
||||
<DetailFormInput title="Einsatzbeginn" v-model="start" type="datetime-local" growing :awareness="awareness" />
|
||||
<DetailFormInput
|
||||
title="Einsatzende"
|
||||
v-model="end"
|
||||
type="datetime-local"
|
||||
:min="start"
|
||||
growing
|
||||
:awareness="awareness"
|
||||
/>
|
||||
<div class="w-full sm:w-fit min-w-fit">
|
||||
<p>Dauer</p>
|
||||
<p
|
||||
|
@ -17,14 +24,30 @@
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<DetailFormInput title="Stichwort" v-model="mission_short" />
|
||||
<DetailFormInput title="Einsatzort" v-model="location" />
|
||||
<DetailFormInput title="Weitere Anwesende (andere Wehren, Polizei, Rettungsdienst)" v-model="others" />
|
||||
<DetailFormInput title="Stichwort" v-model="mission_short" :awareness="awareness" />
|
||||
<DetailFormInput title="Einsatzort" v-model="location" :awareness="awareness" />
|
||||
<DetailFormInput
|
||||
title="Weitere Anwesende (andere Wehren, Polizei, Rettungsdienst)"
|
||||
v-model="others"
|
||||
:awareness="awareness"
|
||||
/>
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<DetailFormInput title="Anzahl getretteter Personen" type="number" v-model="rescued" min="0" />
|
||||
<DetailFormInput title="Anzahl geborgener Personen" type="number" v-model="recovered" min="0" />
|
||||
<DetailFormInput
|
||||
title="Anzahl getretteter Personen"
|
||||
type="number"
|
||||
v-model="rescued"
|
||||
min="0"
|
||||
:awareness="awareness"
|
||||
/>
|
||||
<DetailFormInput
|
||||
title="Anzahl geborgener Personen"
|
||||
type="number"
|
||||
v-model="recovered"
|
||||
min="0"
|
||||
:awareness="awareness"
|
||||
/>
|
||||
</div>
|
||||
<DetailFormEditor title="Einsatzbeschreibung" :text="editor" />
|
||||
<DetailFormEditor title="Einsatzbeschreibung" :text="editor" :awareness="awareness" />
|
||||
<div class="flex flex-col">
|
||||
<p>Eingesetzte Fahrzeuge</p>
|
||||
</div>
|
||||
|
@ -41,17 +64,14 @@
|
|||
import { defineComponent, type PropType } from "vue";
|
||||
import { mapState } from "pinia";
|
||||
import { useAbilityStore } from "@/stores/ability";
|
||||
import { Quill, QuillEditor } from "@vueup/vue-quill";
|
||||
import type QuillCursors from "quill-cursors";
|
||||
import "@vueup/vue-quill/dist/vue-quill.snow.css";
|
||||
import { QuillBinding } from "y-quill";
|
||||
import { moduleOptions } from "@/helpers/quillConfig";
|
||||
import ForceSelect from "@/components/admin/ForceSelect.vue";
|
||||
import { useForceStore } from "@/stores/admin/configuration/force";
|
||||
import * as Y from "yjs";
|
||||
import "@lottiefiles/lottie-player";
|
||||
import DetailFormInput from "@/components/admin/operation/mission/DetailFormInput.vue";
|
||||
import DetailFormEditor from "@/components/admin/operation/mission/DetailFormEditor.vue";
|
||||
import { Awareness } from "@/helpers/awareness";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -62,8 +82,8 @@ export default defineComponent({
|
|||
required: true,
|
||||
},
|
||||
awareness: {
|
||||
type: Object as PropType<undefined>,
|
||||
default: undefined,
|
||||
type: Object as PropType<Awareness>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
</RouterLink>
|
||||
</div>
|
||||
|
||||
<MissionDetail v-show="routeHash == '#edit'" :document="yDoc" />
|
||||
<MissionPresence v-show="routeHash == '#presence'" :document="yDoc" />
|
||||
<MissionDetail v-show="routeHash == '#edit'" :document="yDoc" :awareness="awareness" />
|
||||
<MissionPresence v-show="routeHash == '#presence'" :document="yDoc" :awareness="awareness" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -68,6 +68,7 @@ import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
|||
import { useForceStore } from "@/stores/admin/configuration/force";
|
||||
import { mapState } from "pinia";
|
||||
import * as Y from "yjs";
|
||||
import { Awareness } from "@/helpers/awareness";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -77,6 +78,10 @@ export default defineComponent({
|
|||
type: Object as PropType<Y.Doc>,
|
||||
required: true,
|
||||
},
|
||||
awareness: {
|
||||
type: Object as PropType<Partial<Awareness>>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
Loading…
Add table
Reference in a new issue