197 lines
5.9 KiB
Vue
197 lines
5.9 KiB
Vue
<template>
|
|
<q-page padding>
|
|
<q-card flat bordered>
|
|
<q-card-section class="row items-center justify-between">
|
|
<div class="text-h6">Mantis Summaries</div>
|
|
<q-btn
|
|
label="Generate Today's Summary"
|
|
color="primary"
|
|
@click="generateSummary"
|
|
:loading="generating"
|
|
:disable="generating"
|
|
/>
|
|
</q-card-section>
|
|
|
|
<q-separator />
|
|
|
|
<q-card-section v-if="generationError">
|
|
<q-banner inline-actions class="text-white bg-red">
|
|
<template v-slot:avatar>
|
|
<q-icon name="error" />
|
|
</template>
|
|
{{ generationError }}
|
|
</q-banner>
|
|
</q-card-section>
|
|
|
|
<q-card-section v-if="loading">
|
|
<q-spinner-dots size="40px" color="primary" />
|
|
<span class="q-ml-md">Loading summaries...</span>
|
|
</q-card-section>
|
|
|
|
<q-card-section v-if="error && !generationError">
|
|
<q-banner inline-actions class="text-white bg-red">
|
|
<template v-slot:avatar>
|
|
<q-icon name="error" />
|
|
</template>
|
|
{{ error }}
|
|
</q-banner>
|
|
</q-card-section>
|
|
|
|
<q-list separator v-if="!loading && !error && summaries.length > 0">
|
|
<q-item v-for="summary in summaries" :key="summary.id">
|
|
<q-item-section>
|
|
<q-item-label class="text-weight-bold">{{ formatDate(summary.summaryDate) }}</q-item-label>
|
|
<q-item-label caption>Generated: {{ formatDateTime(summary.generatedAt) }}</q-item-label>
|
|
<q-item-label class="q-mt-sm markdown-content" v-html="parseMarkdown(summary.summaryText)"></q-item-label>
|
|
</q-item-section>
|
|
</q-item>
|
|
</q-list>
|
|
|
|
<q-card-section v-if="totalPages > 1" class="flex flex-center q-mt-md">
|
|
<q-pagination
|
|
v-model="currentPage"
|
|
:max="totalPages"
|
|
@update:model-value="fetchSummaries"
|
|
direction-links
|
|
flat
|
|
color="primary"
|
|
active-color="primary"
|
|
/>
|
|
</q-card-section>
|
|
|
|
<q-card-section v-if="!loading && !error && summaries.length === 0">
|
|
<div class="text-center text-grey">No summaries found.</div>
|
|
</q-card-section>
|
|
|
|
</q-card>
|
|
</q-page>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted, computed } from 'vue';
|
|
import { date, useQuasar } from 'quasar'; // Import useQuasar
|
|
import axios from 'axios';
|
|
import { marked } from 'marked';
|
|
|
|
const $q = useQuasar(); // Initialize Quasar plugin usage
|
|
const summaries = ref([]);
|
|
const loading = ref(true);
|
|
const error = ref(null);
|
|
const generating = ref(false); // State for generation button
|
|
const generationError = ref(null); // State for generation error
|
|
const currentPage = ref(1);
|
|
const itemsPerPage = ref(10); // Or your desired page size
|
|
const totalItems = ref(0);
|
|
|
|
// Create a custom renderer
|
|
const renderer = new marked.Renderer();
|
|
const linkRenderer = renderer.link;
|
|
renderer.link = (href, title, text) => {
|
|
const html = linkRenderer.call(renderer, href, title, text);
|
|
// Add target="_blank" to the link
|
|
return html.replace(/^<a /, '<a target="_blank" rel="noopener noreferrer" ');
|
|
};
|
|
|
|
const fetchSummaries = async (page = 1) => {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
try {
|
|
const response = await axios.get(`/api/mantis-summaries`, {
|
|
params: {
|
|
page: page,
|
|
limit: itemsPerPage.value
|
|
}
|
|
});
|
|
summaries.value = response.data.summaries;
|
|
totalItems.value = response.data.total;
|
|
currentPage.value = page;
|
|
} catch (err) {
|
|
console.error('Error fetching Mantis summaries:', err);
|
|
error.value = err.response?.data?.error || 'Failed to load summaries. Please try again later.';
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
const generateSummary = async () => {
|
|
generating.value = true;
|
|
generationError.value = null;
|
|
error.value = null; // Clear previous loading errors
|
|
try {
|
|
await axios.post('/api/mantis-summaries/generate');
|
|
$q.notify({
|
|
color: 'positive',
|
|
icon: 'check_circle',
|
|
message: 'Summary generation started successfully. It may take a few moments to appear.',
|
|
});
|
|
// Optionally, refresh the list after a short delay or immediately
|
|
// Consider that generation might be async on the backend
|
|
setTimeout(() => fetchSummaries(1), 3000); // Refresh after 3 seconds
|
|
} catch (err) {
|
|
console.error('Error generating Mantis summary:', err);
|
|
generationError.value = err.response?.data?.error || 'Failed to start summary generation.';
|
|
$q.notify({
|
|
color: 'negative',
|
|
icon: 'error',
|
|
message: generationError.value,
|
|
});
|
|
} finally {
|
|
generating.value = false;
|
|
}
|
|
};
|
|
|
|
const formatDate = (dateString) => {
|
|
// Assuming dateString is YYYY-MM-DD
|
|
return date.formatDate(dateString + 'T00:00:00', 'DD MMMM YYYY');
|
|
};
|
|
|
|
const formatDateTime = (dateTimeString) => {
|
|
return date.formatDate(dateTimeString, 'DD MMMM YYYY HH:mm');
|
|
};
|
|
|
|
const parseMarkdown = (markdownText) => {
|
|
if (!markdownText) return '';
|
|
// Use the custom renderer with marked
|
|
return marked(markdownText, { renderer });
|
|
};
|
|
|
|
const totalPages = computed(() => {
|
|
return Math.ceil(totalItems.value / itemsPerPage.value);
|
|
});
|
|
|
|
onMounted(() => {
|
|
fetchSummaries(currentPage.value);
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
.markdown-content :deep(table) {
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
margin-top: 1em;
|
|
margin-bottom: 1em;
|
|
}
|
|
|
|
.markdown-content :deep(th),
|
|
.markdown-content :deep(td) {
|
|
border: 1px solid #ddd;
|
|
padding: 8px;
|
|
text-align: left;
|
|
}
|
|
|
|
.markdown-content :deep(th) {
|
|
background-color: rgba(0, 0, 0, 0.25);
|
|
}
|
|
|
|
.markdown-content :deep(a) {
|
|
color: var(--q-primary);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.markdown-content :deep(a:hover) {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* Add any specific styles if needed */
|
|
</style>
|