diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 75e5f429..bd36ee46 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -140,6 +140,7 @@ "@types/react-router-dom": "^4.3.1", "@types/react-transition-group": "^2.0.9", "@types/webpack-env": "^1.13.6", + "@types/xml2js": "^0.4.14", "@typescript-eslint/eslint-plugin": "^5.57.1", "@typescript-eslint/parser": "^5.57.1", "@vitejs/plugin-react": "^4.1.0", diff --git a/apps/frontend/src/App.tsx b/apps/frontend/src/App.tsx index 3239a6e8..244be6b6 100644 --- a/apps/frontend/src/App.tsx +++ b/apps/frontend/src/App.tsx @@ -42,6 +42,9 @@ import ResetScroll from "./components/ResetScroll"; import commonEN from "./locales/en/common.json"; import commonES from "./locales/es/common.json"; import commonFR from "./locales/fr/common.json"; +import commonHR from "./locales/hr/common.json"; +import commonRO from "./locales/ro/common.json"; +import commonID from "./locales/id/common.json"; import { About } from "./pages/about"; import { CreateProjectPage } from "./pages/create"; import { HomePage } from "./pages/home"; @@ -78,6 +81,15 @@ i18next es_ES: { translations: commonES, }, + hr_HR: { + translations: commonHR, + }, + ro_RO: { + translations: commonRO, + }, + id_ID: { + translations: commonID, + }, }, ns: ["translations"], defaultNS: "translations", diff --git a/apps/frontend/src/components/LanguageMenu.tsx b/apps/frontend/src/components/LanguageMenu.tsx index 3de7cfce..1983c1e0 100644 --- a/apps/frontend/src/components/LanguageMenu.tsx +++ b/apps/frontend/src/components/LanguageMenu.tsx @@ -47,6 +47,15 @@ export const LanguageMenu = () => { handleLangChange("es_ES")}> {t("language-menu.spanish")} + handleLangChange("hr_HR")}> + {t("language.croatian")} + + handleLangChange("ro_RO")}> + {t("language.romanian")} + + handleLangChange("id_ID")}> + {t("language.indonesian")} + ); diff --git a/apps/frontend/src/components/annotation/AnnotationPanel.tsx b/apps/frontend/src/components/annotation/AnnotationPanel.tsx index ce0eafb8..1f58c0d1 100644 --- a/apps/frontend/src/components/annotation/AnnotationPanel.tsx +++ b/apps/frontend/src/components/annotation/AnnotationPanel.tsx @@ -311,7 +311,7 @@ function AdvancedControls({ user?: UserMe; }) { const { mode, setMode } = usePlayerModeStore(); - + const { t } = useTranslation(); return ( - Show Only Mine + {t("annotation.show-only-mine")} @@ -340,7 +340,7 @@ function AdvancedControls({ inputProps={{ "aria-label": "ant design" }} /> - Performance Mode + {t("annotation.performance-mode")} diff --git a/apps/frontend/src/components/annotation/concept-selector.tsx b/apps/frontend/src/components/annotation/concept-selector.tsx index 5345cf66..91b6bb57 100644 --- a/apps/frontend/src/components/annotation/concept-selector.tsx +++ b/apps/frontend/src/components/annotation/concept-selector.tsx @@ -4,41 +4,55 @@ import FormControl from "@mui/material/FormControl"; import Select, { type SelectChangeEvent } from "@mui/material/Select"; import { useConceptsQuery } from "~utils/concepts"; import { grey } from "@mui/material/colors"; +import { InputLabel, OutlinedInput } from "@mui/material"; +import { useTranslation } from "react-i18next"; + +const ITEM_HEIGHT = 48; +const ITEM_PADDING_TOP = 8; +const MenuProps = { + PaperProps: { + style: { + maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, + width: 250, + }, + }, +}; export function ConceptSelector() { const { data } = useConceptsQuery(); const [concept, setConcept] = React.useState(""); + const { t } = useTranslation(); const handleChange = (event: SelectChangeEvent) => { setConcept(event.target.value); }; return ( - + + setNewMetadata((prev) => ({ ...prev, field: e.target.value })) + } + > + {availableMetadataFields + .filter((field) => !metadata[field as keyof DublinMetadata]) // Only show unused fields + .map((field) => ( + + {field.charAt(0).toUpperCase() + field.slice(1)} + + ))} + + + + setNewMetadata((prev) => ({ ...prev, value: e.target.value })) + } + margin="normal" + /> + + + + + + + + ); +}; diff --git a/apps/frontend/src/components/project/rfd-document.tsx b/apps/frontend/src/components/project/rfd-document.tsx deleted file mode 100644 index d9cf0b75..00000000 --- a/apps/frontend/src/components/project/rfd-document.tsx +++ /dev/null @@ -1,315 +0,0 @@ -import type React from "react"; -import { useState, useEffect } from "react"; -import { - Typography, - Box, - TextField, - Button, - Grid, - Snackbar, - Alert, - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - Paper, - Dialog, - DialogTitle, - DialogContent, - DialogActions, - Select, - MenuItem, - FormControl, - InputLabel, -} from "@mui/material"; -import { parseString, Builder } from "xml2js"; - -// Interface for RDF Metadata -interface RDFMetadata { - title: string; - creator: string; - subject: string; - description: string; - publisher: string; - contributor: string; - date: string; - type: string; - format: string; - identifier: string; - source: string; - language: string; - relation: string; - coverage: string; - rights: string; -} - -export const RDFDocumentEditor: React.FC = () => { - // Initial state with null values from the XML - const [metadata, setMetadata] = useState({ - title: "", - creator: "", - subject: "", - description: "", - publisher: "", - contributor: "", - date: "", - type: "", - format: "", - identifier: "", - source: "", - language: "", - relation: "", - coverage: "", - rights: "", - }); - - // State for XML file content and save status - const [xmlContent, setXmlContent] = useState(""); - const [openSnackbar, setOpenSnackbar] = useState(false); - const [snackbarMessage, setSnackbarMessage] = useState(""); - const [openDialog, setOpenDialog] = useState(false); - const [newMetadata, setNewMetadata] = useState<{ - field: string; - value: string; - }>({ - field: "", - value: "", - }); - - // Add this constant for available metadata fields - const availableMetadataFields = [ - "title", - "creator", - "subject", - "description", - "publisher", - "contributor", - "date", - "type", - "format", - "identifier", - "source", - "language", - "relation", - "coverage", - "rights", - ]; - - // Load XML file on component mount - useEffect(() => { - const xmlDoc = ` - -test -`; - - setXmlContent(xmlDoc); - - // Parse XML to set initial metadata - parseString(xmlDoc, (err, result) => { - if (err) { - console.error("Error parsing XML", err); - return; - } - - const rdfData = result?.["rdf:RDF"] || {}; - const newMetadata: RDFMetadata = { - title: rdfData["dcterms:title"]?.[0] ?? "", - creator: rdfData["dcterms:creator"]?.[0] ?? "", - subject: rdfData["dcterms:subject"]?.[0] ?? "", - description: rdfData["dcterms:description"]?.[0] ?? "", - publisher: rdfData["dcterms:publisher"]?.[0] ?? "", - contributor: rdfData["dcterms:contributor"]?.[0] ?? "", - date: rdfData["dcterms:date"]?.[0] ?? "", - type: rdfData["dcterms:type"]?.[0] ?? "", - format: rdfData["dcterms:format"]?.[0] ?? "", - identifier: rdfData["dcterms:identifier"]?.[0] ?? "", - source: rdfData["dcterms:source"]?.[0] ?? "", - language: rdfData["dcterms:language"]?.[0] ?? "", - relation: rdfData["dcterms:relation"]?.[0] ?? "", - coverage: rdfData["dcterms:coverage"]?.[0] ?? "", - rights: rdfData["dcterms:rights"]?.[0] ?? "", - }; - - setMetadata(newMetadata); - }); - }, []); - - // Handle metadata field changes - const handleMetadataChange = (field: keyof RDFMetadata, value: string) => { - setMetadata((prev) => ({ - ...prev, - [field]: value, - })); - }; - - // Save metadata to XML - const saveMetadata = () => { - const builder = new Builder({ - rootName: "rdf:RDF", - xmldec: { version: "1.0", encoding: "UTF-8" }, - attrs: { - "xmlns:rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", - "xmlns:dcterms": "http://purl.org/dc/terms/", - }, - }); - - const xmlObject = { - "dcterms:title": [metadata.title], - "dcterms:creator": [metadata.creator], - "dcterms:subject": [metadata.subject], - "dcterms:description": [metadata.description], - "dcterms:publisher": [metadata.publisher], - "dcterms:contributor": [metadata.contributor], - "dcterms:date": [metadata.date], - "dcterms:type": [metadata.type], - "dcterms:format": [metadata.format], - "dcterms:identifier": [metadata.identifier], - "dcterms:source": [metadata.source], - "dcterms:language": [metadata.language], - "dcterms:relation": [metadata.relation], - "dcterms:coverage": [metadata.coverage], - "dcterms:rights": [metadata.rights], - }; - - const newXmlContent = builder.buildObject(xmlObject); - setXmlContent(newXmlContent); - - // Simulate file save (in a real app, you'd use file system API) - console.log("Saved XML:", newXmlContent); - setSnackbarMessage("Metadata saved successfully!"); - setOpenSnackbar(true); - }; - - const handleAddMetadata = () => { - if (newMetadata.field && newMetadata.value) { - setMetadata((prev) => ({ - ...prev, - [newMetadata.field.toLowerCase()]: newMetadata.value, - })); - setNewMetadata({ field: "", value: "" }); - setOpenDialog(false); - } - }; - - return ( - - - Metadata Dublin - - - - - - - - Term - - - Value - - - - - {Object.entries(metadata) - .filter(([_, value]) => value !== "") // Only show non-empty fields - .map(([field, value]) => ( - - - {field.charAt(0).toUpperCase() + field.slice(1)} - - - - handleMetadataChange( - field as keyof RDFMetadata, - e.target.value - ) - } - size="small" - /> - - - ))} - -
-
- - - - - - - {/* Modified Dialog */} - setOpenDialog(false)}> - Add New Metadata Field - - - Term - - - - setNewMetadata((prev) => ({ ...prev, value: e.target.value })) - } - margin="normal" - /> - - - - - - - - {/* Existing Snackbar */} - setOpenSnackbar(false)} - > - setOpenSnackbar(false)} severity="success"> - {snackbarMessage} - - -
- ); -}; diff --git a/apps/frontend/src/lib/emotion/stats.ts b/apps/frontend/src/lib/emotion/stats.ts index e7c0f8e5..e36dc92c 100644 --- a/apps/frontend/src/lib/emotion/stats.ts +++ b/apps/frontend/src/lib/emotion/stats.ts @@ -12,6 +12,7 @@ export function calcEmotion(annotations?: AnnotationStatsItem[]) { "Fear", "Empathy", "ItsStrange", + "Neutral", ]; let happy = 0; let laugh = 0; @@ -23,6 +24,7 @@ export function calcEmotion(annotations?: AnnotationStatsItem[]) { let fearful = 0; let empathy = 0; let itsStrange = 0; + let neutral = 0; annotations?.map((annotation: AnnotationStatsItem) => { if (annotation.emotion) { if (annotation.emotion === "happy") { @@ -45,6 +47,8 @@ export function calcEmotion(annotations?: AnnotationStatsItem[]) { empathy++; } else if (annotation.emotion === "itsStrange") { itsStrange++; + } else if (annotation.emotion === "neutral") { + neutral++; } } }); @@ -65,6 +69,7 @@ export function calcEmotion(annotations?: AnnotationStatsItem[]) { fearful, empathy, itsStrange, + neutral ], maxBarThickness: 30, backgroundColor: ["#0B9A8D"], @@ -87,7 +92,8 @@ export function calcEmotionByMode(annotations?: AnnotationStatsItem[]) { 'Disgusted', 'Fear', 'Empathy', - 'ItsStrange', + "ItsStrange", + "Neutral", ]; let happy = 0; let laugh = 0; @@ -99,6 +105,7 @@ export function calcEmotionByMode(annotations?: AnnotationStatsItem[]) { let fearful = 0; let empathy = 0; let itsStrange = 0; + let neutral = 0; let happyAut = 0; let laughAut = 0; let smileAut = 0; @@ -109,6 +116,7 @@ export function calcEmotionByMode(annotations?: AnnotationStatsItem[]) { let fearfulAut = 0; let empathyAut = 0; let itsStrangeAut = 0; + let neutralAut = 0; annotations?.map((annotation: AnnotationStatsItem) => { if (annotation.emotion) { if (annotation.emotion === 'happy') { @@ -171,6 +179,12 @@ export function calcEmotionByMode(annotations?: AnnotationStatsItem[]) { } else { itsStrange++; } + } else if (annotation.emotion === 'neutral') { + if (annotation.detection === 'auto' || annotation.mode === "semi-auto") { + neutralAut++; + } else { + neutral++; + } } } }); @@ -191,6 +205,7 @@ export function calcEmotionByMode(annotations?: AnnotationStatsItem[]) { fearfulAut, empathyAut, itsStrangeAut, + neutralAut, ], maxBarThickness: 30, barPercentage: 0.5, @@ -209,10 +224,11 @@ export function calcEmotionByMode(annotations?: AnnotationStatsItem[]) { fearful, empathy, itsStrange, + neutral, ], maxBarThickness: 30, barPercentage: 0.5, - backgroundColor: ['#0B9A8D'], + backgroundColor: ["#0B9A8D"], }, ], }; diff --git a/apps/frontend/src/locales/en/common.json b/apps/frontend/src/locales/en/common.json index 6cefa5e6..0d217317 100644 --- a/apps/frontend/src/locales/en/common.json +++ b/apps/frontend/src/locales/en/common.json @@ -268,5 +268,25 @@ "emotion-detection.button.start": "Enable & Start", "language-menu.english": "English", "language-menu.french": "French", - "language-menu.spanish": "Spanish" + "language-menu.spanish": "Spanish", + "auto-detection.button.title": "Auto Detection", + "auto-detection.button.start": "Start", + "auto-detection.button.stop": "Stop", + "auto-detection.hint": "Emoji Recommendation", + "auto-detection.button.from-all": "From All", + "auto-detection.button.only-me": "Only Me", + "annotation.show-only-mine": "Show Only Mine", + "annotation.performance-mode": "Performance Mode", + "language.croatian": "Croatian", + "language.romanian": "Romanian", + "language.indonesian": "Indonesian", + "metadata.dublin.term": "Term", + "metadata.dublin.value": "Value", + "commun.button.save": "Save", + "metadata.dublin.option": "Options", + "metadata.dublin.menu.add-term": "Add Term", + "metadata.dublin.menu.export": "Export", + "metadata.dublin.menu.import": "Import", + "annotation.select-concept": "Select a concept", + "annotation.concept.label": "Concept" } \ No newline at end of file diff --git a/apps/frontend/src/locales/es/common.json b/apps/frontend/src/locales/es/common.json index 54290419..38819cac 100644 --- a/apps/frontend/src/locales/es/common.json +++ b/apps/frontend/src/locales/es/common.json @@ -1,5 +1,14 @@ { + "project.export": "Exportar anotaciones", + "project.export.success": "Anotación exportada exitosamente.", "language-menu.english": "Inglés", "language-menu.french": "Francés", - "language-menu.spanish": "Español" + "language-menu.spanish": "Español", + "metadata.dublin.term": "Término", + "metadata.dublin.value": "Valor", + "commun.button.save": "Ahorrar", + "metadata.dublin.option": "Opciones", + "metadata.dublin.menu.add-term": "Agregar término", + "metadata.dublin.menu.export": "Exportar", + "metadata.dublin.menu.import": "Importar" } \ No newline at end of file diff --git a/apps/frontend/src/locales/fr/common.json b/apps/frontend/src/locales/fr/common.json index 6870e64d..e4690160 100644 --- a/apps/frontend/src/locales/fr/common.json +++ b/apps/frontend/src/locales/fr/common.json @@ -268,5 +268,25 @@ "emotion-detection.button.start": "Activer et démarrer", "language-menu.english": "Anglais", "language-menu.french": "Français", - "language-menu.spanish": "Espagnol" + "language-menu.spanish": "Espagnol", + "auto-detection.button.title": "Détection auto", + "auto-detection.button.start": "Commencer", + "auto-detection.button.stop": "Arrêt", + "auto-detection.hint": "Recommandation d'émojis", + "auto-detection.button.from-all": "De tous", + "auto-detection.button.only-me": "Seulement moi", + "annotation.show-only-mine": "Uniquement les miens", + "annotation.performance-mode": "Mode Performance", + "language.croatian": "Croate", + "language.romanian": "Roumain", + "language.indonesian": "Indonésien", + "metadata.dublin.term": "Terme", + "metadata.dublin.value": "Valeur", + "commun.button.save": "Sauvegarder", + "metadata.dublin.option": "Options", + "metadata.dublin.menu.add-term": "Ajouter un terme", + "metadata.dublin.menu.export": "Exporter", + "metadata.dublin.menu.import": "Importer", + "annotation.select-concept": "Sélectionnez un concept", + "annotation.concept.label": "Concept" } \ No newline at end of file diff --git a/apps/frontend/src/locales/hr/common.json b/apps/frontend/src/locales/hr/common.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/apps/frontend/src/locales/hr/common.json @@ -0,0 +1 @@ +{} diff --git a/apps/frontend/src/locales/id/common.json b/apps/frontend/src/locales/id/common.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/apps/frontend/src/locales/id/common.json @@ -0,0 +1 @@ +{} diff --git a/apps/frontend/src/locales/ro/common.json b/apps/frontend/src/locales/ro/common.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/apps/frontend/src/locales/ro/common.json @@ -0,0 +1 @@ +{} diff --git a/apps/frontend/src/pages/project-stats.tsx b/apps/frontend/src/pages/project-stats.tsx index 90158fae..9aa85cc3 100644 --- a/apps/frontend/src/pages/project-stats.tsx +++ b/apps/frontend/src/pages/project-stats.tsx @@ -152,7 +152,10 @@ const ProjectStatsContent = ({ project, annotations }: Props) => ( > Résultats des annotations sémantiques - + @@ -165,7 +168,10 @@ const ProjectStatsContent = ({ project, annotations }: Props) => ( > Les types des annotations - + diff --git a/apps/frontend/src/pages/project.tsx b/apps/frontend/src/pages/project.tsx index 0df9b0c6..124b04ac 100644 --- a/apps/frontend/src/pages/project.tsx +++ b/apps/frontend/src/pages/project.tsx @@ -1,13 +1,8 @@ import type ReactPlayer from "@celluloid/react-player"; -import { - Box, - CircularProgress, - Container, - Grid, - Paper, -} from "@mui/material"; +import { Box, CircularProgress, Container, Grid, Paper } from "@mui/material"; import React, { Suspense, useEffect, useMemo, useRef, useState } from "react"; import { useParams } from "react-router-dom"; +import { DubinPanel } from "~/components/project/dubin-panel"; import { AnnotationHints } from "~components/annotation/AnnotationHints"; import { AnnotationPanel } from "~components/annotation/AnnotationPanel"; @@ -217,6 +212,7 @@ const ProjectContent = ({ project, user }: Props) => ( + diff --git a/packages/prisma/migrations/20250113153008_add_duplin_metadata/migration.sql b/packages/prisma/migrations/20250113153008_add_duplin_metadata/migration.sql new file mode 100644 index 00000000..0f620696 --- /dev/null +++ b/packages/prisma/migrations/20250113153008_add_duplin_metadata/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Project" ADD COLUMN "dublin" JSON DEFAULT '{}'; diff --git a/packages/prisma/migrations/migration_lock.toml b/packages/prisma/migrations/migration_lock.toml index fbffa92c..648c57fd 100644 --- a/packages/prisma/migrations/migration_lock.toml +++ b/packages/prisma/migrations/migration_lock.toml @@ -1,3 +1,3 @@ # Please do not edit this file manually -# It should be added in your version-control system (i.e. Git) +# It should be added in your version-control system (e.g., Git) provider = "postgresql" \ No newline at end of file diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index fa892805..6defb25e 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -84,6 +84,8 @@ model Project { chapterJobId BigInt? @db.BigInt chapters Chapter[] + + dublin Json? @default("{}") @db.Json } model Chapter { diff --git a/packages/prisma/src/index.ts b/packages/prisma/src/index.ts index b2f892cc..3a0c67b6 100644 --- a/packages/prisma/src/index.ts +++ b/packages/prisma/src/index.ts @@ -56,6 +56,36 @@ const prismaClient = new PrismaClient({ return null }, } + }, + project: { + dublin: { + needs: { dublin: true }, + compute(a) { + if (a.dublin && typeof a.dublin === 'object' && + !Array.isArray(a.dublin)) { + + const dublinObject = a.dublin as Prisma.JsonObject + return { + title: dublinObject.title as string, + creator: dublinObject.creator as string, + subject: dublinObject.subject as string, + description: dublinObject.description as string, + publisher: dublinObject.publisher as string, + contributor: dublinObject.contributor as string, + date: dublinObject.date as string, + type: dublinObject.type as string, + format: dublinObject.format as string, + identifier: dublinObject.identifier as string, + source: dublinObject.source as string, + language: dublinObject.language as string, + relation: dublinObject.relation as string, + coverage: dublinObject.coverage as string, + rights: dublinObject.rights as string, + } + } + return null + }, + } } }, }) diff --git a/packages/trpc/package.json b/packages/trpc/package.json index ce38162f..e8c0bb80 100644 --- a/packages/trpc/package.json +++ b/packages/trpc/package.json @@ -29,10 +29,10 @@ "dev": "tsc" }, "dependencies": { + "@celluloid/auth": "workspace:*", "@celluloid/prisma": "workspace:*", "@celluloid/queue": "workspace:*", "@celluloid/utils": "workspace:*", - "@celluloid/auth": "workspace:*", "@t3-oss/env-core": "^0.11.1", "@trpc/server": "^10.45.2", "bcryptjs": "^2.4.3", @@ -47,6 +47,7 @@ "trpc-openapi": "^1.2.0", "uuid": "^9.0.1", "ws": "^8.18.0", + "xlsx": "^0.18.5", "zod": "catalog:" }, "devDependencies": { diff --git a/packages/trpc/src/routers/annotation.ts b/packages/trpc/src/routers/annotation.ts index 263ca714..e4cad732 100644 --- a/packages/trpc/src/routers/annotation.ts +++ b/packages/trpc/src/routers/annotation.ts @@ -8,7 +8,7 @@ import { EventEmitter } from 'node:events'; import { parse as toXML } from 'js2xmlparser'; import Papa from 'papaparse'; import { z } from 'zod'; - +import * as XLSX from 'xlsx'; import { protectedProcedure, publicProcedure, router } from '../trpc'; @@ -223,15 +223,33 @@ export const annotationRouter = router({ .input( z.object({ projectId: z.string(), - format: z.enum(["csv", "xml", "srt"]) + format: z.enum(["csv", "xml", "srt", "xlsx"]) }) ).mutation(async ({ input }) => { const { format, projectId } = input; + + const project = await prisma.project.findUnique({ + where: { id: projectId }, + select: { + dublin: true, + title: true, + }, + }); + + if (!project) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Project not found" + }); + } + + const annotations = await prisma.annotation.findMany({ where: { projectId: projectId }, include: { comments: true, + user: true, }, orderBy: { createdAt: 'desc', @@ -243,10 +261,13 @@ export const annotationRouter = router({ endTime: a.stopTime, text: a.text, comments: a.comments.map((c) => c.text), + user: a.user.username, + project: project.title, contextX: a.extra ? a.extra.relativeX : null, contextY: a.extra ? a.extra.relativeY : null, emotion: a.emotion, mode: a.mode, + detection: a.detection, })) let content = ""; @@ -257,6 +278,19 @@ export const annotationRouter = router({ content = Papa.unparse(sorted); } else if (format === "srt") { content = toSrt(formated); + } else if (format === "xlsx") { + const sorted = formated.sort((a, b) => a.startTime - b.startTime); + const worksheet = XLSX.utils.json_to_sheet(sorted); + const dublinData = Object.entries(project.dublin as Record).reduce((acc, [key, value]) => { + acc[key] = value; + return acc; + }, {} as Record); + + const dublinMetadata = XLSX.utils.json_to_sheet([dublinData]); // Wrap in array for single row + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, "Annotations"); + XLSX.utils.book_append_sheet(workbook, dublinMetadata, "Metadata Dublin"); + content = XLSX.write(workbook, { type: 'base64', bookType: 'xlsx' }); } return content }), diff --git a/packages/trpc/src/routers/project.ts b/packages/trpc/src/routers/project.ts index 6674b931..00f371a8 100644 --- a/packages/trpc/src/routers/project.ts +++ b/packages/trpc/src/routers/project.ts @@ -26,7 +26,8 @@ export const defaultProjectSelect = Prisma.validator()({ duration: true, thumbnailURL: true, metadata: false, - keywords: true + keywords: true, + dublin: true }); export const defaultUserSelect = Prisma.validator()({ @@ -363,4 +364,39 @@ export const projectRouter = router({ return deletedProject; } }), + updateDublin: protectedProcedure + .input( + z.object({ + projectId: z.string(), + dublin: z.any() + }), + ) + .mutation(async ({ input, ctx }) => { + if (ctx.user?.id && ctx.requireRoles(['teacher', 'admin'])) { + + // Find the project by its ID (you need to replace 'projectId' with the actual ID) + const project = await prisma.project.findUnique({ + where: { + id: input.projectId, + userId: ctx.user.id + } + }); + + if (!project) { + throw new Error('Project not found'); + } + + const updatedProject = await prisma.project.update({ + where: { + id: project.id + }, + data: { + dublin: { ...project.dublin, ...input.dublin }, + }, + select: defaultProjectSelect + }); + + return updatedProject; + } + }), }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d034126f..5fca1994 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -111,7 +111,7 @@ importers: version: 2.0.8 ts-jest: specifier: ^27.0.1 - version: 27.1.5(@babel/core@7.26.0)(@types/jest@26.0.24)(babel-jest@27.5.1(@babel/core@7.26.0))(esbuild@0.24.0)(jest@27.5.1(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@20.5.1)(typescript@5.6.3)))(typescript@5.6.3) + version: 27.1.5(@babel/core@7.26.0)(@types/jest@26.0.24)(babel-jest@27.5.1(@babel/core@7.26.0))(jest@27.5.1(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@20.5.1)(typescript@5.6.3)))(typescript@5.6.3) tsup: specifier: ^8.3.0 version: 8.3.5(@swc/core@1.3.101(@swc/helpers@0.5.13))(jiti@1.21.6)(postcss@8.4.47)(tsx@4.19.2)(typescript@5.6.3)(yaml@2.6.0) @@ -327,7 +327,7 @@ importers: version: 6.27.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-scripts: specifier: 5.0.1 - version: 5.0.1(@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.0))(@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0))(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0))(esbuild@0.24.0)(eslint@8.57.1)(react@18.2.0)(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@16.18.119)(typescript@5.6.3))(type-fest@2.19.0)(typescript@5.6.3) + version: 5.0.1(@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.0))(@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0))(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13)))(eslint@8.57.1)(react@18.2.0)(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@16.18.119)(typescript@5.6.3))(type-fest@2.19.0)(typescript@5.6.3) react-transition-group: specifier: ^2.3.1 version: 2.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) @@ -443,6 +443,9 @@ importers: '@types/webpack-env': specifier: ^1.13.6 version: 1.18.5 + '@types/xml2js': + specifier: ^0.4.14 + version: 0.4.14 '@typescript-eslint/eslint-plugin': specifier: ^5.57.1 version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) @@ -709,6 +712,9 @@ importers: ws: specifier: ^8.18.0 version: 8.18.0 + xlsx: + specifier: ^0.18.5 + version: 0.18.5 zod: specifier: 'catalog:' version: 3.24.1 @@ -4457,6 +4463,9 @@ packages: '@types/ws@8.5.13': resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + '@types/xml2js@0.4.14': + resolution: {integrity: sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -4691,6 +4700,10 @@ packages: resolution: {integrity: sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==} engines: {node: '>=8.9'} + adler-32@1.3.1: + resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} + engines: {node: '>=0.8'} + adminjs@7.8.13: resolution: {integrity: sha512-xTmrU9K1VWoIPxHfJnfU8CeFj4f1bZFjyizBntVp0F9dVc8geEaDCOcRIiKbfzrvIk2/Yr5G6z0seLKa4hprIA==} engines: {node: '>=16.0.0'} @@ -5187,6 +5200,10 @@ packages: resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==} engines: {node: '>=4'} + cfb@1.2.2: + resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==} + engines: {node: '>=0.8'} + chalk-template@0.4.0: resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} engines: {node: '>=12'} @@ -5350,6 +5367,10 @@ packages: resolution: {integrity: sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==} engines: {node: '>= 4.0'} + codepage@1.15.0: + resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} + engines: {node: '>=0.8'} + collect-v8-coverage@1.0.2: resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} @@ -5568,6 +5589,11 @@ packages: typescript: optional: true + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + create-html-element@4.0.1: resolution: {integrity: sha512-K/wr7TGTPh4v2m5JpxNWQ/W4/lHkVjun7rTmg8ycNjbJE0ngjxvVYSiYzgq4iiJ+H5zq2FcPu6ZehCZHHcZtfA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6711,6 +6737,10 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + frac@1.1.2: + resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} + engines: {node: '>=0.8'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -10435,6 +10465,10 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + ssf@0.11.2: + resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} + engines: {node: '>=0.8'} + ssri@10.0.6: resolution: {integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -11440,10 +11474,18 @@ packages: resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} engines: {node: '>=12'} + wmf@1.0.2: + resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} + engines: {node: '>=0.8'} + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + word@0.3.0: + resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} + engines: {node: '>=0.8'} + workbox-background-sync@6.6.0: resolution: {integrity: sha512-jkf4ZdgOJxC9u2vztxLuPT/UjlH7m/nWRQ/MgGL0v8BJHoZdVGJd18Kck+a0e55wGXdqyHO+4IQTk0685g4MUw==} @@ -11551,6 +11593,11 @@ packages: utf-8-validate: optional: true + xlsx@0.18.5: + resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} + engines: {node: '>=0.8'} + hasBin: true + xml-name-validator@3.0.0: resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==} @@ -14324,7 +14371,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@pmmmwh/react-refresh-webpack-plugin@0.5.15(@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.15.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)))(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.15(@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.15.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))))(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)))': dependencies: ansi-html: 0.0.9 core-js-pure: 3.39.0 @@ -14334,11 +14381,11 @@ snapshots: react-refresh: 0.11.0 schema-utils: 4.2.0 source-map: 0.7.4 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) optionalDependencies: - '@types/webpack': 5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + '@types/webpack': 5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13)) type-fest: 2.19.0 - webpack-dev-server: 4.15.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + webpack-dev-server: 4.15.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) '@popperjs/core@2.11.8': {} @@ -15625,11 +15672,11 @@ snapshots: '@types/webpack-env@1.18.5': {} - '@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)': + '@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13))': dependencies: '@types/node': 18.19.64 tapable: 2.2.1 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) transitivePeerDependencies: - '@swc/core' - esbuild @@ -15641,6 +15688,10 @@ snapshots: dependencies: '@types/node': 18.19.64 + '@types/xml2js@0.4.14': + dependencies: + '@types/node': 18.19.64 + '@types/yargs-parser@21.0.3': {} '@types/yargs@15.0.19': @@ -15934,6 +15985,8 @@ snapshots: loader-utils: 2.0.4 regex-parser: 2.3.0 + adler-32@1.3.1: {} + adminjs@7.8.13(@types/babel__core@7.20.5)(@types/react-dom@18.3.1)(@types/react@18.3.12)(encoding@0.1.13): dependencies: '@adminjs/design-system': 4.1.1(@babel/core@7.26.0)(@types/react@18.3.12)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1) @@ -16257,14 +16310,14 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@8.4.1(@babel/core@7.26.0)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + babel-loader@8.4.1(@babel/core@7.26.0)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: '@babel/core': 7.26.0 find-cache-dir: 3.3.2 loader-utils: 2.0.4 make-dir: 3.1.0 schema-utils: 2.7.1 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) babel-plugin-istanbul@6.1.1: dependencies: @@ -16615,6 +16668,11 @@ snapshots: case-sensitive-paths-webpack-plugin@2.4.0: {} + cfb@1.2.2: + dependencies: + adler-32: 1.3.1 + crc-32: 1.2.2 + chalk-template@0.4.0: dependencies: chalk: 4.1.2 @@ -16796,6 +16854,8 @@ snapshots: chalk: 2.4.2 q: 1.5.1 + codepage@1.15.0: {} + collect-v8-coverage@1.0.2: {} color-convert@1.9.3: @@ -17006,6 +17066,8 @@ snapshots: optionalDependencies: typescript: 5.6.3 + crc-32@1.2.2: {} + create-html-element@4.0.1: dependencies: escape-goat: 4.0.0 @@ -17059,7 +17121,7 @@ snapshots: postcss: 8.4.47 postcss-selector-parser: 6.1.2 - css-loader@6.11.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + css-loader@6.11.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: icss-utils: 5.1.0(postcss@8.4.47) postcss: 8.4.47 @@ -17070,9 +17132,9 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.3 optionalDependencies: - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) - css-minimizer-webpack-plugin@3.4.1(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + css-minimizer-webpack-plugin@3.4.1(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: cssnano: 5.1.15(postcss@8.4.47) jest-worker: 27.5.1 @@ -17080,9 +17142,7 @@ snapshots: schema-utils: 4.2.0 serialize-javascript: 6.0.2 source-map: 0.6.1 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) - optionalDependencies: - esbuild: 0.24.0 + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) css-prefers-color-scheme@6.0.3(postcss@8.4.47): dependencies: @@ -18048,7 +18108,7 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint-webpack-plugin@3.2.0(eslint@8.57.1)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + eslint-webpack-plugin@3.2.0(eslint@8.57.1)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: '@types/eslint': 8.56.12 eslint: 8.57.1 @@ -18056,7 +18116,7 @@ snapshots: micromatch: 4.0.8 normalize-path: 3.0.0 schema-utils: 4.2.0 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) eslint@8.57.1: dependencies: @@ -18315,11 +18375,11 @@ snapshots: dependencies: flat-cache: 3.2.0 - file-loader@6.2.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + file-loader@6.2.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) file-saver@2.0.5: {} @@ -18403,7 +18463,7 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@6.5.3(eslint@8.57.1)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + fork-ts-checker-webpack-plugin@6.5.3(eslint@8.57.1)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: '@babel/code-frame': 7.26.2 '@types/json-schema': 7.0.15 @@ -18419,7 +18479,7 @@ snapshots: semver: 7.6.3 tapable: 1.1.3 typescript: 5.6.3 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) optionalDependencies: eslint: 8.57.1 @@ -18456,6 +18516,8 @@ snapshots: forwarded@0.2.0: {} + frac@1.1.2: {} + fraction.js@4.3.7: {} fresh@0.5.2: {} @@ -18792,7 +18854,7 @@ snapshots: htmlparser2: 8.0.2 selderee: 0.11.0 - html-webpack-plugin@5.6.3(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + html-webpack-plugin@5.6.3(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -18800,7 +18862,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) htmlparser2@6.1.0: dependencies: @@ -20297,11 +20359,11 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.9.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + mini-css-extract-plugin@2.9.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: schema-utils: 4.2.0 tapable: 2.2.1 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) minimalistic-assert@1.0.1: {} @@ -21223,13 +21285,13 @@ snapshots: tsx: 4.19.2 yaml: 2.6.0 - postcss-loader@6.2.1(postcss@8.4.47)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + postcss-loader@6.2.1(postcss@8.4.47)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 postcss: 8.4.47 semver: 7.6.3 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) postcss-logical@5.0.4(postcss@8.4.47): dependencies: @@ -21832,7 +21894,7 @@ snapshots: react-onclickoutside: 6.13.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-dev-utils@12.0.1(eslint@8.57.1)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + react-dev-utils@12.0.1(eslint@8.57.1)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: '@babel/code-frame': 7.26.2 address: 1.2.2 @@ -21843,7 +21905,7 @@ snapshots: escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@8.57.1)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@8.57.1)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -21858,7 +21920,7 @@ snapshots: shell-quote: 1.8.1 strip-ansi: 6.0.1 text-table: 0.2.0 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -22037,56 +22099,56 @@ snapshots: '@remix-run/router': 1.20.0 react: 18.3.1 - react-scripts@5.0.1(@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.0))(@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0))(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0))(esbuild@0.24.0)(eslint@8.57.1)(react@18.2.0)(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@16.18.119)(typescript@5.6.3))(type-fest@2.19.0)(typescript@5.6.3): + react-scripts@5.0.1(@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.0))(@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0))(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13)))(eslint@8.57.1)(react@18.2.0)(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@16.18.119)(typescript@5.6.3))(type-fest@2.19.0)(typescript@5.6.3): dependencies: '@babel/core': 7.26.0 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.15(@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.15.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)))(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.15(@types/webpack@5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.13)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.15.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))))(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) '@svgr/webpack': 5.5.0 babel-jest: 27.5.1(@babel/core@7.26.0) - babel-loader: 8.4.1(@babel/core@7.26.0)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + babel-loader: 8.4.1(@babel/core@7.26.0)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) babel-plugin-named-asset-import: 0.3.8(@babel/core@7.26.0) babel-preset-react-app: 10.0.1 bfj: 7.1.0 browserslist: 4.24.2 camelcase: 6.3.0 case-sensitive-paths-webpack-plugin: 2.4.0 - css-loader: 6.11.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) - css-minimizer-webpack-plugin: 3.4.1(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + css-loader: 6.11.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) + css-minimizer-webpack-plugin: 3.4.1(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) dotenv: 10.0.0 dotenv-expand: 5.1.0 eslint: 8.57.1 eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.0))(@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0))(eslint@8.57.1)(jest@27.5.1(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@16.18.119)(typescript@5.6.3)))(typescript@5.6.3) - eslint-webpack-plugin: 3.2.0(eslint@8.57.1)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) - file-loader: 6.2.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + eslint-webpack-plugin: 3.2.0(eslint@8.57.1)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) + file-loader: 6.2.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) fs-extra: 10.1.0 - html-webpack-plugin: 5.6.3(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + html-webpack-plugin: 5.6.3(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) identity-obj-proxy: 3.0.0 jest: 27.5.1(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@16.18.119)(typescript@5.6.3)) jest-resolve: 27.5.1 jest-watch-typeahead: 1.1.0(jest@27.5.1(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@16.18.119)(typescript@5.6.3))) - mini-css-extract-plugin: 2.9.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + mini-css-extract-plugin: 2.9.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) postcss: 8.4.47 postcss-flexbugs-fixes: 5.0.2(postcss@8.4.47) - postcss-loader: 6.2.1(postcss@8.4.47)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + postcss-loader: 6.2.1(postcss@8.4.47)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) postcss-normalize: 10.0.1(browserslist@4.24.2)(postcss@8.4.47) postcss-preset-env: 7.8.3(postcss@8.4.47) prompts: 2.4.2 react: 18.2.0 react-app-polyfill: 3.0.0 - react-dev-utils: 12.0.1(eslint@8.57.1)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + react-dev-utils: 12.0.1(eslint@8.57.1)(typescript@5.6.3)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) react-refresh: 0.11.0 resolve: 1.22.8 resolve-url-loader: 4.0.0 - sass-loader: 12.6.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + sass-loader: 12.6.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) semver: 7.6.3 - source-map-loader: 3.0.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) - style-loader: 3.3.4(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + source-map-loader: 3.0.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) + style-loader: 3.3.4(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@16.18.119)(typescript@5.6.3)) - terser-webpack-plugin: 5.3.10(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) - webpack-dev-server: 4.15.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) - webpack-manifest-plugin: 4.1.1(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) - workbox-webpack-plugin: 6.6.0(@types/babel__core@7.20.5)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + terser-webpack-plugin: 5.3.10(@swc/core@1.3.101(@swc/helpers@0.5.13))(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) + webpack-dev-server: 4.15.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) + webpack-manifest-plugin: 4.1.1(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) + workbox-webpack-plugin: 6.6.0(@types/babel__core@7.20.5)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) optionalDependencies: fsevents: 2.3.3 typescript: 5.6.3 @@ -22528,11 +22590,11 @@ snapshots: sanitize.css@13.0.0: {} - sass-loader@12.6.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + sass-loader@12.6.0(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: klona: 2.0.6 neo-async: 2.6.2 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) sax@1.2.4: {} @@ -22844,12 +22906,12 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@3.0.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + source-map-loader@3.0.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: abab: 2.0.6 iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) source-map-support@0.5.21: dependencies: @@ -22921,6 +22983,10 @@ snapshots: sprintf-js@1.1.3: {} + ssf@0.11.2: + dependencies: + frac: 1.1.2 + ssri@10.0.6: dependencies: minipass: 7.1.2 @@ -23090,9 +23156,9 @@ snapshots: strnum@1.0.5: {} - style-loader@3.3.4(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + style-loader@3.3.4(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) styled-components@5.3.9(@babel/core@7.26.0)(react-dom@18.2.0(react@18.2.0))(react-is@18.3.1)(react@18.2.0): dependencies: @@ -23261,17 +23327,16 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser-webpack-plugin@5.3.10(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + terser-webpack-plugin@5.3.10(@swc/core@1.3.101(@swc/helpers@0.5.13))(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.36.0 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) optionalDependencies: '@swc/core': 1.3.101(@swc/helpers@0.5.13) - esbuild: 0.24.0 terser@5.36.0: dependencies: @@ -23392,7 +23457,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@27.1.5(@babel/core@7.26.0)(@types/jest@26.0.24)(babel-jest@27.5.1(@babel/core@7.26.0))(esbuild@0.24.0)(jest@27.5.1(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@20.5.1)(typescript@5.6.3)))(typescript@5.6.3): + ts-jest@27.1.5(@babel/core@7.26.0)(@types/jest@26.0.24)(babel-jest@27.5.1(@babel/core@7.26.0))(jest@27.5.1(ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@20.5.1)(typescript@5.6.3)))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -23408,7 +23473,6 @@ snapshots: '@babel/core': 7.26.0 '@types/jest': 26.0.24 babel-jest: 27.5.1(@babel/core@7.26.0) - esbuild: 0.24.0 ts-node@10.9.2(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@16.18.119)(typescript@5.6.3): dependencies: @@ -23873,16 +23937,16 @@ snapshots: webidl-conversions@6.1.0: {} - webpack-dev-middleware@5.3.4(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + webpack-dev-middleware@5.3.4(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: colorette: 2.0.20 memfs: 3.5.3 mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.2.0 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) - webpack-dev-server@4.15.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + webpack-dev-server@4.15.2(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -23912,20 +23976,20 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 5.3.4(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + webpack-dev-middleware: 5.3.4(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) ws: 8.18.0 optionalDependencies: - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) transitivePeerDependencies: - bufferutil - debug - supports-color - utf-8-validate - webpack-manifest-plugin@4.1.1(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + webpack-manifest-plugin@4.1.1(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: tapable: 2.2.1 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) webpack-sources: 2.3.1 webpack-sources@1.4.3: @@ -23940,7 +24004,7 @@ snapshots: webpack-sources@3.2.3: {} - webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0): + webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.6 @@ -23962,7 +24026,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)) + terser-webpack-plugin: 5.3.10(@swc/core@1.3.101(@swc/helpers@0.5.13))(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -24063,8 +24127,12 @@ snapshots: dependencies: string-width: 5.1.2 + wmf@1.0.2: {} + word-wrap@1.2.5: {} + word@0.3.0: {} + workbox-background-sync@6.6.0: dependencies: idb: 7.1.1 @@ -24173,12 +24241,12 @@ snapshots: workbox-sw@6.6.0: {} - workbox-webpack-plugin@6.6.0(@types/babel__core@7.20.5)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0)): + workbox-webpack-plugin@6.6.0(@types/babel__core@7.20.5)(webpack@5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))): dependencies: fast-json-stable-stringify: 2.1.0 pretty-bytes: 5.6.0 upath: 1.2.0 - webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.3.101(@swc/helpers@0.5.13)) webpack-sources: 1.4.3 workbox-build: 6.6.0(@types/babel__core@7.20.5) transitivePeerDependencies: @@ -24217,6 +24285,16 @@ snapshots: ws@8.18.0: {} + xlsx@0.18.5: + dependencies: + adler-32: 1.3.1 + cfb: 1.2.2 + codepage: 1.15.0 + crc-32: 1.2.2 + ssf: 0.11.2 + wmf: 1.0.2 + word: 0.3.0 + xml-name-validator@3.0.0: {} xml2js@0.5.0: diff --git a/project.inlang/settings.json b/project.inlang/settings.json index d23eef2c..d7c9e1a0 100644 --- a/project.inlang/settings.json +++ b/project.inlang/settings.json @@ -4,7 +4,10 @@ "languageTags": [ "en", "fr", - "es" + "es", + "hr", + "id", + "ro" ], "modules": [ "https://cdn.jsdelivr.net/npm/@inlang/plugin-i18next@latest/dist/index.js",