Add mantis summaries and start of email summaries... Need to figure out a way to get the emails since MS block IMAP :(
This commit is contained in:
parent
2d11d0bd79
commit
2ad9a63582
18 changed files with 1993 additions and 577 deletions
197
src/pages/MantisSummariesPage.vue
Normal file
197
src/pages/MantisSummariesPage.vue
Normal file
|
@ -0,0 +1,197 @@
|
|||
<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>
|
Loading…
Add table
Add a link
Reference in a new issue