This commit is contained in:
vadim committed 2026-09-24 15:08:46 +03:00
commit fcec12e5ba
78 files changed
+9569

No files matched your search

+126
View File
@@ -0,0 +1,126 @@
<script setup lang="ts">
import { computed, ref, watchEffect } from 'vue'
import { useIssueStore } from '@/stores/issue.js'
import { useStatusStore } from '@/stores/status.ts'
import ExpansionPanel from '@/components/ExpansionPanel.vue'
import IssueContent from '@/components/IssueContent.vue'
import type { Issue } from '@/api/issue.api.ts'
import StatusMenu from '@/components/StatusMenu.vue'
import AssigneeMenu from '@/components/AssigneeMenu.vue'
import ReporterInfo from '@/components/ReporterInfo.vue'
interface Props {
ckey: string
}
const emit = defineEmits<{
statusChanged: [issue: Issue]
assigneeChanged: [issue: Issue]
}>()
const issueStore = useIssueStore()
const statusStore = useStatusStore()
const issue = ref<Issue>()
const { ckey } = defineProps<Props>()
const statusName = computed(() => {
return statusStore.statuses?.find((el) => el.alias === issue.value?.status)?.name ?? issue.value?.status
})
const createdAtFormatted = computed(() => {
if (!issue.value?.createdAt) return ''
return new Intl.DateTimeFormat('ru-RU', { dateStyle: 'medium', timeStyle: 'short' }).format(
new Date(issue.value.createdAt),
)
})
async function fetch() {
const res = await issueStore.getByKey(ckey)
if (!res) {
return
}
issue.value = res
}
watchEffect(async () => fetch())
const onContentChanged = async (content: string) => {
if (!issue.value) return
const updated = await issueStore.update(issue.value.id, { content })
if (updated) issue.value = updated
}
const onStatusChanged = async (status: Issue['status']) => {
if (!issue.value) return
const updated = await issueStore.update(issue.value.id, { status })
if (updated) {
issue.value = updated
emit('statusChanged', updated)
}
}
const onAssigneeChanged = async (assignee: string) => {
if (!issue.value) return
const updated = await issueStore.update(issue.value.id, { assignee })
if (updated) {
issue.value = updated
emit('assigneeChanged', updated)
}
}
defineExpose({
applyUpdate: (updated: Issue) => {
if (issue.value && issue.value.id === updated.id) {
issue.value = updated
}
},
})
</script>
<template>
<div v-if="issue" class="d-flex flex-column ga-4 pa-4">
<div>{{ ckey }}</div>
<div class="text-uppercase text-title-large">{{ issue.title }}</div>
<v-card elevation="0" border>
<v-card-text class="u-grid">
<div class="text-medium-emphasis">Status:</div>
<status-menu :value="issue.status" @changed="onStatusChanged" />
<div class="text-medium-emphasis">Reporter:</div>
<reporter-info :user="issue.reporter" />
<div class="text-medium-emphasis">Assignee:</div>
<assignee-menu :value="issue.assignee" :compact="false" @changed="onAssigneeChanged" />
<div class="text-medium-emphasis">Created At:</div>
<div>{{ createdAtFormatted }}</div>
</v-card-text>
</v-card>
<expansion-panel title="Details">
<issue-content :value="issue.content" @changed="onContentChanged" />
</expansion-panel>
<expansion-panel title="Activity">
<v-btn-group divided border density="compact">
<v-btn>comments</v-btn>
<v-btn>history</v-btn>
</v-btn-group>
</expansion-panel>
</div>
</template>
<style scoped lang="scss">
.u-grid {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
column-gap: 1rem;
row-gap: 0.75rem;
}
</style>