feat(web): support markdown in notification messages

This commit is contained in:
Pujit Mehrotra
2024-11-18 15:27:39 -05:00
parent 4c663dc69c
commit abcaa5aedb
4 changed files with 43 additions and 14 deletions

View File

@@ -1,39 +1,47 @@
<script setup lang="ts">
import {
ArchiveBoxIcon,
ShieldExclamationIcon,
CheckBadgeIcon,
ExclamationTriangleIcon,
LinkIcon,
ShieldExclamationIcon,
TrashIcon,
} from "@heroicons/vue/24/solid";
import { useMutation } from "@vue/apollo-composable";
import type { NotificationFragmentFragment } from "~/composables/gql/graphql";
import { NotificationType } from "~/composables/gql/graphql";
} from '@heroicons/vue/24/solid';
import { useMutation } from '@vue/apollo-composable';
import type { NotificationFragmentFragment } from '~/composables/gql/graphql';
import { NotificationType } from '~/composables/gql/graphql';
import { safeParseMarkdown } from '~/helpers/markdown';
import {
archiveNotification as archiveMutation,
deleteNotification as deleteMutation,
} from "./graphql/notification.query";
} from './graphql/notification.query';
const props = defineProps<NotificationFragmentFragment>();
const descriptionMarkup = computedAsync(async () => {
try {
return await safeParseMarkdown(props.description);
} catch (e) {
return props.description;
}
}, '');
const icon = computed<{ component: Component; color: string } | null>(() => {
switch (props.importance) {
case "INFO":
case 'INFO':
return {
component: CheckBadgeIcon,
color: "text-green-500",
color: 'text-green-500',
};
case "WARNING":
case 'WARNING':
return {
component: ExclamationTriangleIcon,
color: "text-yellow-500",
color: 'text-yellow-500',
};
case "ALERT":
case 'ALERT':
return {
component: ShieldExclamationIcon,
color: "text-red-500",
color: 'text-red-500',
};
}
return null;
@@ -86,7 +94,7 @@ const mutationError = computed(() => {
<div
class="w-full flex flex-row items-center justify-between gap-2 opacity-75 group-hover/item:opacity-100 group-focus/item:opacity-100"
>
<p class="text-secondary-foreground">{{ description }}</p>
<div class="text-secondary-foreground" v-html="descriptionMarkup" />
</div>
<p v-if="mutationError" class="text-red-600">Error: {{ mutationError }}</p>

13
web/helpers/markdown.ts Normal file
View File

@@ -0,0 +1,13 @@
import DOMPurify from 'dompurify';
import { marked } from 'marked';
/**
* Parses arbitrary markdown content as sanitized html. May throw if parsing fails.
*
* @param markdownContent string of markdown content
* @returns safe, sanitized html content
*/
export async function safeParseMarkdown(markdownContent: string) {
const parsed = await marked.parse(markdownContent);
return DOMPurify.sanitize(parsed);
}

7
web/package-lock.json generated
View File

@@ -23,6 +23,7 @@
"clsx": "^2.1.1",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.11",
"dompurify": "^3.2.0",
"focus-trap": "^7.5.4",
"graphql": "^16.8.1",
"graphql-tag": "^2.12.6",
@@ -8329,6 +8330,12 @@
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/dompurify": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.0.tgz",
"integrity": "sha512-AMdOzK44oFWqHEi0wpOqix/fUNY707OmoeFDnbi3Q5I8uOpy21ufUA5cDJPr0bosxrflOVD/H2DMSvuGKJGfmQ==",
"license": "(MPL-2.0 OR Apache-2.0)"
},
"node_modules/domutils": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",

View File

@@ -69,6 +69,7 @@
"clsx": "^2.1.1",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.11",
"dompurify": "^3.2.0",
"focus-trap": "^7.5.4",
"graphql": "^16.8.1",
"graphql-tag": "^2.12.6",