+
+ {row.original.subject}
+
+ {tags.length > 0 && (
+
+ {tags.map((tag) => (
+
+ {tag}
+
+ ))}
+
+ )}
+
+ );
+ },
meta: { className: 'text-left text-xs' }
},
{
diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts
index 0549520..d7e2dca 100644
--- a/web/src/lib/utils.ts
+++ b/web/src/lib/utils.ts
@@ -88,12 +88,28 @@ export function validateTag(facetPath: string) {
};
}
- const invalidChars = /['"`;,()[\]{}<>]/;
-
- if (invalidChars.test(facetPath)) {
+ if (!facetPath.startsWith('/')) {
return {
valid: false,
- error: "Tag path contains invalid characters"
+ error: "Tag path must start with '/'"
+ };
+ }
+
+ let escaped = false;
+ for (let i = 1; i < facetPath.length; i++) {
+ const char = facetPath[i];
+
+ if (escaped) {
+ escaped = false;
+ } else if (char === '\\') {
+ escaped = true;
+ }
+ }
+
+ if (escaped) {
+ return {
+ valid: false,
+ error: "Tag path has unmatched escape character at the end"
};
}
@@ -101,6 +117,7 @@ export function validateTag(facetPath: string) {
}
+
export function formatTimestamp(milliseconds: number): string {
const date = new Date(milliseconds);
const year = date.getFullYear();