# HG changeset patch
# User ogiorgis <olivier.giorgis@logilab.fr>
# Date 1710420695 -3600
#      Thu Mar 14 13:51:35 2024 +0100
# Node ID d811be7221efa54386e048baf9f52355df735c58
# Parent  9cd175f2b87e8dad371df01cec80aed933862cce
feat: add virtuoso_user field

diff --git a/frontend/src/api/cubicweb.ts b/frontend/src/api/cubicweb.ts
--- a/frontend/src/api/cubicweb.ts
+++ b/frontend/src/api/cubicweb.ts
@@ -92,13 +92,14 @@
 export function useApiCreateProject() {
   const client = useClient();
   const rql =
-    "INSERT ImportProcedure X: X name %(name)s, X virtuoso_url %(virtuoso_url)s, X activated %(activated)s";
+    "INSERT ImportProcedure X: X name %(name)s, X virtuoso_url %(virtuoso_url)s, X virtuoso_user %(virtuoso_user)s, X activated %(activated)s";
 
   return async (data: Omit<Project, "import_recipes">) => {
     const transaction = new Transaction();
     const query = transaction.push(rql, {
       name: data.name,
       virtuoso_url: data.virtuoso_url,
+      virtuoso_user: data.virtuoso_user,
       activated: data.activated,
     });
     const eidRef = query.ref().row(0).column(0);
@@ -112,7 +113,7 @@
 export function useApiUpdateProject() {
   const client = useClient();
   const rql =
-    "SET X name %(name)s, X virtuoso_url %(virtuoso_url)s, X activated %(activated)s" +
+    "SET X name %(name)s, X virtuoso_url %(virtuoso_url)s, X virtuoso_user %(virtuoso_user)s, X activated %(activated)s" +
     "WHERE X is ImportProcedure, X eid %(eid)s";
   return (data: Omit<Project, "import_recipes">) => {
     const transaction = new Transaction();
@@ -120,6 +121,7 @@
       eid: data.eid,
       name: data.name,
       virtuoso_url: data.virtuoso_url,
+      virtuoso_user: data.virtuoso_user,
       activated: data.activated,
     });
     pushSetProjectFiles(transaction, data.eid, data);
@@ -201,8 +203,8 @@
 export function useApiGetProject(): (eid: number) => Promise<Project> {
   const client = useClient();
   const projectRql =
-    "Any X, ATTR_NAME, ATTR_VIRTUOSO_URL, ATTR_ACTIVATED, REL_ONTOLOGY.download_url(), REL_SHACL.download_url() " +
-    "WHERE X is ImportProcedure, X eid %(eid)s, X name ATTR_NAME, X virtuoso_url ATTR_VIRTUOSO_URL, X activated ATTR_ACTIVATED, X ontology_file REL_ONTOLOGY?, X shacl_files REL_SHACL?";
+    "Any X, ATTR_NAME, ATTR_VIRTUOSO_URL, ATTR_VIRTUOSO_USER, ATTR_ACTIVATED, REL_ONTOLOGY.download_url(), REL_SHACL.download_url() " +
+    "WHERE X is ImportProcedure, X eid %(eid)s, X name ATTR_NAME, X virtuoso_url ATTR_VIRTUOSO_URL,  X virtuoso_user ATTR_VIRTUOSO_USER, X activated ATTR_ACTIVATED, X ontology_file REL_ONTOLOGY?, X shacl_files REL_SHACL?";
 
   const recipeListRql =
     "Any X, ATTR_NAME, ATTR_PROCESS_TYPE , REL_DATASERVICE " +
@@ -236,10 +238,11 @@
         eid: r[0],
         name: r[1],
         virtuoso_url: r[2],
-        activated: r[3],
+        virtuoso_user: r[3],
+        activated: r[4],
         import_recipes: recipeListJsonResult,
-        ontology_file: { downloadUrl: r[4] } as CWFile,
-        shacl_files: { downloadUrl: r[5] } as CWFile,
+        ontology_file: { downloadUrl: r[5] } as CWFile,
+        shacl_files: { downloadUrl: r[6] } as CWFile,
       } as Project;
     } catch (e) {
       if (e && typeof e === "object" && "title" in e) {
@@ -369,7 +372,8 @@
         eid: r[0],
         name: r[1],
         virtuoso_url: r[2],
-        activated: r[3],
+        virtuoso_user: r[3],
+        activated: r[4],
       }) as Project,
   );
 }
@@ -381,8 +385,8 @@
     "WHERE X is DataService, X eid %(eid)s, X name ATTR_NAME, X data_url ATTR_DATA_URL, X refresh_period ATTR_REFRESH_PERIOD, X description ATTR_DESCRIPTION";
 
   const projectListRql =
-    "Any X, ATTR_NAME, ATTR_VIRTUOSO_URL, ATTR_ACTIVATED " +
-    "WHERE X is ImportProcedure, X name ATTR_NAME, X virtuoso_url ATTR_VIRTUOSO_URL, X activated ATTR_ACTIVATED, " +
+    "Any X, ATTR_NAME, ATTR_VIRTUOSO_URL, ATTR_VIRTUOSO_USER, ATTR_ACTIVATED " +
+    "WHERE X is ImportProcedure, X name ATTR_NAME, X virtuoso_url ATTR_VIRTUOSO_URL, X virtuoso_user ATTR_VIRTUOSO_USER, X activated ATTR_ACTIVATED, " +
     "X import_recipes R, R dataservice %(eid)s";
 
   return async (eid: number) => {
@@ -423,8 +427,8 @@
 export function useApiGetProjectList(): () => Promise<Array<Project>> {
   const client = useClient();
   const rql =
-    "Any X, ATTR_NAME, ATTR_VIRTUOSO_URL, ATTR_ACTIVATED " +
-    "WHERE X is ImportProcedure, X name ATTR_NAME, X virtuoso_url ATTR_VIRTUOSO_URL, X activated ATTR_ACTIVATED";
+    "Any X, ATTR_NAME, ATTR_VIRTUOSO_URL, ATTR_VIRTUOSO_USER, ATTR_ACTIVATED " +
+    "WHERE X is ImportProcedure, X name ATTR_NAME, X virtuoso_url ATTR_VIRTUOSO_URL, X virtuoso_user ATTR_VIRTUOSO_USER, X activated ATTR_ACTIVATED";
   return async () => {
     const result = await client.execute(rql, {});
     return projectListResultSetToObject(result);
diff --git a/frontend/src/components/ProjectForm.tsx b/frontend/src/components/ProjectForm.tsx
--- a/frontend/src/components/ProjectForm.tsx
+++ b/frontend/src/components/ProjectForm.tsx
@@ -107,6 +107,24 @@
           />
         </Stack>
         <Controller
+          name="virtuoso_user"
+          control={control}
+          rules={{ required: true }}
+          render={({ field, fieldState: { error } }) => (
+            <TextField
+              label="Virtuoso User"
+              required={true}
+              disabled={loading}
+              {...field}
+              error={error !== undefined}
+              helperText={
+                error?.type === "required" ? "Champ requis" : error?.message
+              }
+              fullWidth
+            />
+          )}
+        />
+        <Controller
           name="ontology_file"
           control={control}
           render={({ field }) => (
diff --git a/frontend/src/types.ts b/frontend/src/types.ts
--- a/frontend/src/types.ts
+++ b/frontend/src/types.ts
@@ -7,6 +7,7 @@
   eid: number;
   name: string;
   virtuoso_url: string;
+  virtuoso_user: string;
   activated: boolean;
   ontology_file?: CWFile;
   shacl_files?: CWFile;