diff --git a/__tests__/v2/task_group_utilities.test.js b/components/__tests__/tasks/task_group_utilities.test.js
similarity index 98%
rename from __tests__/v2/task_group_utilities.test.js
rename to components/__tests__/tasks/task_group_utilities.test.js
index 987009fe..01fa7f14 100644
--- a/__tests__/v2/task_group_utilities.test.js
+++ b/components/__tests__/tasks/task_group_utilities.test.js
@@ -3,7 +3,7 @@ import {
 	buildTaskTableRows,
 	buildWorkflowTaskTableRows,
 	removeIdenticalTaskGroups
-} from '$lib/components/v2/tasks/task_group_utilities.js';
+} from '../../src/lib/tasks/task_group_utilities.js';
 
 describe('task_group_utilities', () => {
 	it('buildTaskTableRows', async () => {
diff --git a/components/package-lock.json b/components/package-lock.json
index cad80984..72eded17 100644
--- a/components/package-lock.json
+++ b/components/package-lock.json
@@ -8,11 +8,15 @@
 			"bundleDependencies": [
 				"ajv/dist/ajv",
 				"ajv/dist/2020",
-				"ajv-formats"
+				"ajv-formats",
+				"semver",
+				"slim-select"
 			],
 			"dependencies": {
 				"ajv": "^8.12.0",
-				"ajv-formats": "^3.0.1"
+				"ajv-formats": "^3.0.1",
+				"semver": "^7.6.3",
+				"slim-select": "^2.8.1"
 			},
 			"devDependencies": {
 				"@sveltejs/adapter-static": "^3.0.0",
@@ -4711,7 +4715,7 @@
 			"version": "7.6.3",
 			"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
 			"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
-			"dev": true,
+			"inBundle": true,
 			"license": "ISC",
 			"bin": {
 				"semver": "bin/semver.js"
@@ -4838,6 +4842,13 @@
 				"node": ">= 10"
 			}
 		},
+		"node_modules/slim-select": {
+			"version": "2.10.0",
+			"resolved": "https://registry.npmjs.org/slim-select/-/slim-select-2.10.0.tgz",
+			"integrity": "sha512-sOKXH8YlgspTn+wy1jYbscVlFbBsAIOmtrmx1e16sV+NbYDTIyJCCdLH0EL9gDxDdHzBgE/s5XZ+VChaxz0JGg==",
+			"inBundle": true,
+			"license": "MIT"
+		},
 		"node_modules/sorcery": {
 			"version": "0.11.1",
 			"resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.1.tgz",
diff --git a/components/package.json b/components/package.json
index a656dc73..5cded0a0 100644
--- a/components/package.json
+++ b/components/package.json
@@ -48,7 +48,9 @@
 	},
 	"dependencies": {
 		"ajv": "^8.12.0",
-		"ajv-formats": "^3.0.1"
+		"ajv-formats": "^3.0.1",
+		"semver": "^7.6.3",
+		"slim-select": "^2.8.1"
 	},
 	"svelte": "./dist/index.js",
 	"types": "./dist/index.d.ts",
@@ -56,6 +58,8 @@
 	"bundleDependencies": [
 		"ajv/dist/ajv",
 		"ajv/dist/2020",
-		"ajv-formats"
+		"ajv-formats",
+		"semver",
+		"slim-select"
 	]
 }
diff --git a/src/lib/components/common/BooleanIcon.svelte b/components/src/lib/common/BooleanIcon.svelte
similarity index 100%
rename from src/lib/components/common/BooleanIcon.svelte
rename to components/src/lib/common/BooleanIcon.svelte
diff --git a/src/lib/components/common/ColouredBadge.svelte b/components/src/lib/common/ColouredBadge.svelte
similarity index 100%
rename from src/lib/components/common/ColouredBadge.svelte
rename to components/src/lib/common/ColouredBadge.svelte
diff --git a/src/lib/components/v2/tasks/FilteredTasksTable.svelte b/components/src/lib/tasks/FilteredTasksTable.svelte
similarity index 91%
rename from src/lib/components/v2/tasks/FilteredTasksTable.svelte
rename to components/src/lib/tasks/FilteredTasksTable.svelte
index 41449826..4221be84 100644
--- a/src/lib/components/v2/tasks/FilteredTasksTable.svelte
+++ b/components/src/lib/tasks/FilteredTasksTable.svelte
@@ -2,15 +2,15 @@
 	import { onMount } from 'svelte';
 	import { buildWorkflowTaskTableRows, sortVersions } from '../tasks/task_group_utilities';
 	import SlimSelect from 'slim-select';
-	import ColouredBadge from '$lib/components/common/ColouredBadge.svelte';
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import ColouredBadge from '../common/ColouredBadge.svelte';
+	import BooleanIcon from '../common/BooleanIcon.svelte';
 
-	/** @type {Array<import('$lib/types-v2').TaskGroupV2>} */
+	/** @type {Array<import('../types/api').TaskGroupV2>} */
 	export let taskGroups;
 
-	/** @type {import('$lib/types-v2').WorkflowTasksTableRowGroup[]} */
+	/** @type {import('../types/api').WorkflowTasksTableRowGroup[]} */
 	let allRows = [];
-	/** @type {import('$lib/types-v2').WorkflowTasksTableRowGroup[]} */
+	/** @type {import('../types/api').WorkflowTasksTableRowGroup[]} */
 	let filteredRows = [];
 	let groupBy = 'pkg_name';
 
@@ -74,7 +74,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TasksTableRow} row
+	 * @param {import('../types/api').TasksTableRow} row
 	 */
 	function filterRow(row) {
 		return (
@@ -88,7 +88,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TasksTableRow} row
+	 * @param {import('../types/api').TasksTableRow} row
 	 * @returns {boolean}
 	 */
 	function genericSearchMatch(row) {
@@ -108,7 +108,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TasksTableRow} row
+	 * @param {import('../types/api').TasksTableRow} row
 	 * @returns {boolean}
 	 */
 	function categoryMatch(row) {
@@ -119,7 +119,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TasksTableRow} row
+	 * @param {import('../types/api').TasksTableRow} row
 	 * @returns {boolean}
 	 */
 	function modalityMatch(row) {
@@ -130,7 +130,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TasksTableRow} row
+	 * @param {import('../types/api').TasksTableRow} row
 	 * @returns {boolean}
 	 */
 	function packageMatch(row) {
@@ -141,7 +141,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TasksTableRow} row
+	 * @param {import('../types/api').TasksTableRow} row
 	 * @returns {boolean}
 	 */
 	function tagMatch(row) {
@@ -152,7 +152,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TasksTableRow} row
+	 * @param {import('../types/api').TasksTableRow} row
 	 * @returns {boolean}
 	 */
 	function inputTypeMatch(row) {
@@ -173,7 +173,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TaskGroupV2[]} taskGroups
+	 * @param {import('../types/api').TaskGroupV2[]} taskGroups
 	 */
 	function setFiltersValues(taskGroups) {
 		setSelectorData(
@@ -224,8 +224,8 @@
 	}
 
 	/**
-	 * @param {Array<import('$lib/types-v2').TaskGroupV2>} taskGroups
-	 * @param {(task: import('$lib/types-v2').TaskV2) => string | null} mapper
+	 * @param {Array<import('../types/api').TaskGroupV2>} taskGroups
+	 * @param {(task: import('../types/api').TaskV2) => string | null} mapper
 	 * @returns {string[]}
 	 */
 	function extractSlimSelectTaskValues(taskGroups, mapper) {
@@ -247,7 +247,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TasksTableRow} taskProperties
+	 * @param {import('../types/api').TasksTableRow} taskProperties
 	 */
 	function getMetadataCell(taskProperties) {
 		const values = [];
diff --git a/components/src/lib/tasks/task_group_utilities.js b/components/src/lib/tasks/task_group_utilities.js
new file mode 100644
index 00000000..2589beee
--- /dev/null
+++ b/components/src/lib/tasks/task_group_utilities.js
@@ -0,0 +1,235 @@
+import compareLoose from 'semver/functions/compare-loose';
+
+/**
+ * @param {import('../types/api').TaskGroupV2[]} taskGroups
+ * @param {string} groupBy
+ * @returns {import('../types/api').WorkflowTasksTableRowGroup[]}
+ */
+export function buildWorkflowTaskTableRows(taskGroups, groupBy) {
+	/** @type {import('../types/api').WorkflowTasksTableRowGroup[]} */
+	const rows = [];
+	for (const taskGroup of taskGroups) {
+		for (const task of taskGroup.task_list) {
+			const groupValue = taskGroup[groupBy];
+			let groupRow = rows.find((r) => r.groupTitle === groupValue);
+			const taskProperties = getTaskTableProperties(taskGroup, task);
+			const taskVersion = taskGroup.version || '';
+			if (groupRow) {
+				let groupTask = groupRow.tasks.find((t) =>
+					Object.values(t.taskVersions).find((r) => r.task_name === task.name)
+				);
+				if (groupTask) {
+					groupTask.taskVersions[taskVersion] = taskProperties;
+				} else {
+					groupTask = {
+						selectedVersion: taskVersion,
+						taskVersions: { [taskVersion]: taskProperties }
+					};
+					groupRow.tasks.push(groupTask);
+				}
+			} else {
+				groupRow = {
+					groupTitle: taskGroup[groupBy],
+					tasks: [
+						{
+							selectedVersion: taskVersion,
+							taskVersions: { [taskVersion]: taskProperties }
+						}
+					]
+				};
+				rows.push(groupRow);
+			}
+		}
+	}
+	sortWorkflowTasksTableRows(rows);
+	return rows;
+}
+
+/**
+ * @param {import('../types/api').WorkflowTasksTableRowGroup[]} rows
+ */
+function sortWorkflowTasksTableRows(rows) {
+	for (const row of rows) {
+		for (const task of row.tasks) {
+			const validVersions = Object.keys(task.taskVersions).filter((v) => v !== '');
+			if (validVersions.length > 0) {
+				sortVersions(validVersions);
+				task.selectedVersion = validVersions[0];
+			}
+		}
+		row.tasks.sort((t1, t2) =>
+			t1.taskVersions[t1.selectedVersion].task_id < t2.taskVersions[t2.selectedVersion].task_id
+				? -1
+				: 1
+		);
+	}
+	rows.sort((r1, r2) =>
+		r1.groupTitle.localeCompare(r2.groupTitle, undefined, { sensitivity: 'base' })
+	);
+}
+
+/**
+ * @param {import('../types/api').TaskGroupV2[]} taskGroups
+ * @param {string} groupBy
+ * @returns {import('../types/api').TasksTableRowGroup[]}
+ */
+export function buildTaskTableRows(taskGroups, groupBy) {
+	/** @type {import('../types/api').TasksTableRowGroup[]} */
+	const rows = [];
+	for (const taskGroup of taskGroups) {
+		if (taskGroup.task_list.length > 0) {
+			const groupValue = taskGroup[groupBy];
+			let groupRow = rows.find((r) => r.groupTitle === groupValue);
+			const version = taskGroup.version || '';
+			if (groupRow) {
+				groupRow.groups[version] = taskGroup;
+			} else {
+				groupRow = {
+					groupTitle: groupValue,
+					selectedVersion: version,
+					groups: { [version]: taskGroup }
+				};
+				rows.push(groupRow);
+			}
+		}
+	}
+	sortTasksTableRows(rows);
+	return rows;
+}
+
+/**
+ * @param {import('../types/api').TasksTableRowGroup[]} rows
+ */
+function sortTasksTableRows(rows) {
+	for (const row of rows) {
+		const validVersions = Object.keys(row.groups).filter((v) => v !== '');
+		if (validVersions.length > 0) {
+			sortVersions(validVersions);
+			row.selectedVersion = validVersions[0];
+		}
+		for (const taskGroup of Object.values(row.groups)) {
+			taskGroup.task_list.sort((t1, t2) => (t1.id < t2.id ? -1 : 1));
+		}
+	}
+	rows.sort((r1, r2) =>
+		r1.groupTitle.localeCompare(r2.groupTitle, undefined, { sensitivity: 'base' })
+	);
+}
+
+/**
+ * @param {string[]} versions
+ */
+export function sortVersions(versions) {
+	try {
+		versions
+			.sort((v1, v2) => {
+				if (!v1) {
+					return -1;
+				}
+				if (!v2) {
+					return 1;
+				}
+				return compareLoose(v1, v2);
+			})
+			.reverse();
+	} catch (err) {
+		console.warn('Semver error:', err);
+	}
+	return versions;
+}
+
+/**
+ * @param {import('../types/api').TaskGroupV2} taskGroup
+ * @param {import('../types/api').TaskV2} task
+ * @returns {import('../types/api').TasksTableRow}
+ */
+function getTaskTableProperties(taskGroup, task) {
+	return {
+		pkg_name: taskGroup.pkg_name,
+		task_id: task.id,
+		task_name: task.name,
+		version: taskGroup.version || '',
+		category: task.category,
+		modality: task.modality,
+		authors: task.authors,
+		tags: task.tags,
+		input_types: task.input_types,
+		docs_info: task.docs_info || ''
+	};
+}
+
+/**
+ * @param {import('../types/api').TaskGroupV2[]} taskGroups
+ * @param {import('../types/api').User & {group_ids_names: Array<[number, string]>}} user
+ * @returns {import('../types/api').TaskGroupV2[]}
+ */
+export function removeIdenticalTaskGroups(taskGroups, user) {
+	/** @type {Map<string, Map<string|null, import('../types/api').TaskGroupV2>>}  */
+	const taskGroupsMap = new Map();
+	for (const taskGroup of taskGroups) {
+		let versionsMap = taskGroupsMap.get(taskGroup.pkg_name);
+		if (!versionsMap) {
+			/** @type {Map<string|null, import('../types/api').TaskGroupV2>}  */
+			versionsMap = new Map();
+			taskGroupsMap.set(taskGroup.pkg_name, versionsMap);
+		}
+		const duplicate = versionsMap.get(taskGroup.version);
+		if (duplicate) {
+			const preferredTaskGroup = selectTaskGroupToKeep(taskGroup, duplicate, user);
+			versionsMap.set(taskGroup.version, preferredTaskGroup);
+		} else {
+			versionsMap.set(taskGroup.version, taskGroup);
+		}
+	}
+	/** @type {import('../types/api').TaskGroupV2[]} */
+	const filteredTaskGroups = [];
+	for (const [, versionsMap] of taskGroupsMap) {
+		for (const [, taskGroup] of versionsMap) {
+			filteredTaskGroups.push(taskGroup);
+		}
+	}
+	return filteredTaskGroups;
+}
+
+/**
+ * @param {import('../types/api').TaskGroupV2} taskGroup1
+ * @param {import('../types/api').TaskGroupV2} taskGroup2
+ * @param {import('../types/api').User & {group_ids_names: Array<[number, string]>}} user
+ * @returns {import('../types/api').TaskGroupV2}
+ */
+function selectTaskGroupToKeep(taskGroup1, taskGroup2, user) {
+	if (taskGroup1.user_id === user.id) {
+		return taskGroup1;
+	}
+	for (const [userGroupId] of user.group_ids_names) {
+		if (taskGroup1.user_group_id === userGroupId) {
+			return taskGroup1;
+		}
+		if (taskGroup2.user_group_id === userGroupId) {
+			return taskGroup2;
+		}
+	}
+	console.warn(
+		'Unable to find a user group matching task groups',
+		taskGroup1,
+		taskGroup2,
+		user.group_ids_names
+	);
+	return taskGroup1;
+}
+
+/**
+ * @param {import('../types/api').TaskGroupActivityStatusV2} status
+ */
+export function getTaskActivityStatusBadgeClass(status) {
+	switch (status.toLowerCase()) {
+		case 'pending':
+			return 'text-bg-light';
+		case 'ongoing':
+			return 'text-bg-primary';
+		case 'failed':
+			return 'text-bg-danger';
+		case 'ok':
+			return 'text-bg-success';
+	}
+}
diff --git a/src/lib/types-v2.d.ts b/components/src/lib/types/api.d.ts
similarity index 90%
rename from src/lib/types-v2.d.ts
rename to components/src/lib/types/api.d.ts
index b0cf8d9a..2cdeb179 100644
--- a/src/lib/types-v2.d.ts
+++ b/components/src/lib/types/api.d.ts
@@ -1,5 +1,26 @@
-import type { JSONSchemaObjectProperty } from 'fractal-components/types/jschema';
-import { DatasetHistoryItem, type Task } from './types';
+import type { JSONSchemaObjectProperty } from './jschema';
+
+export type User = {
+  id?: number
+  email: string
+  is_active: boolean
+  is_superuser: boolean
+  is_verified: boolean
+  username: string | null
+  password?: string
+  group_ids_names : Array<[number, string]> | null
+  oauth_accounts: Array<{
+    id: number
+    account_email: string
+    oauth_name: string
+  }>
+}
+
+export type DatasetHistoryItem = {
+  workflowtask: WorkflowTask
+  status: string
+  parallelization: object
+}
 
 export type ProjectV2 = {
 	id: number;
diff --git a/src/lib/common/component_utilities.js b/src/lib/common/component_utilities.js
index df8a1614..cf4d9fad 100644
--- a/src/lib/common/component_utilities.js
+++ b/src/lib/common/component_utilities.js
@@ -226,7 +226,7 @@ export function removeDuplicatedItems(allItems) {
 }
 
 /**
- * @template {import('$lib/types').Project|import('$lib/types-v2').ProjectV2} T
+ * @template {import('$lib/types').Project|import('fractal-components/types/api').ProjectV2} T
  * @param {T[]} projects
  */
 export function sortProjectsByTimestampCreatedDesc(projects) {
diff --git a/src/lib/common/job_utilities.js b/src/lib/common/job_utilities.js
index 341ea600..7c77cf88 100644
--- a/src/lib/common/job_utilities.js
+++ b/src/lib/common/job_utilities.js
@@ -116,7 +116,7 @@ export function extractRelevantJobError(completeJobError, maxLines = undefined)
 }
 
 /**
- * @param {import("$lib/types-v2").DatasetV2[]} datasets
+ * @param {import("fractal-components/types/api").DatasetV2[]} datasets
  * @param {string} selectedDatasetName
  * @returns {string}
  */
@@ -135,7 +135,7 @@ export function generateNewUniqueDatasetName(datasets, selectedDatasetName) {
 }
 
 /**
- * @param {Array<import("$lib/types-v2").WorkflowTaskV2>} workflowTasks
+ * @param {Array<import("fractal-components/types/api").WorkflowTaskV2>} workflowTasks
  * @param {{[key: number]: import('$lib/types').JobStatus}} statuses
  * @returns {number|undefined}
  */
diff --git a/src/lib/common/task_utilities.js b/src/lib/common/task_utilities.js
index beac0eb4..98ef80b1 100644
--- a/src/lib/common/task_utilities.js
+++ b/src/lib/common/task_utilities.js
@@ -1,7 +1,7 @@
 /**
  * Sort task-group activities by timestamp_started.
- * @param {import('$lib/types-v2').TaskGroupActivityV2} a1
- * @param {import('$lib/types-v2').TaskGroupActivityV2} a2
+ * @param {import('fractal-components/types/api').TaskGroupActivityV2} a1
+ * @param {import('fractal-components/types/api').TaskGroupActivityV2} a2
  */
 export const sortActivitiesByTimestampStarted = function (a1, a2) {
 	return a1.timestamp_started < a2.timestamp_started ? 1 : -1;
diff --git a/src/lib/common/workflow_utilities.js b/src/lib/common/workflow_utilities.js
index c527531a..1a0c1bc7 100644
--- a/src/lib/common/workflow_utilities.js
+++ b/src/lib/common/workflow_utilities.js
@@ -1,6 +1,6 @@
 /**
- * @param {Array<import("$lib/types-v2").DatasetV2>} datasets
- * @param {Array<import("$lib/types-v2").ApplyWorkflowV2>} jobs
+ * @param {Array<import("fractal-components/types/api").DatasetV2>} datasets
+ * @param {Array<import("fractal-components/types/api").ApplyWorkflowV2>} jobs
  * @returns {number|undefined}
  */
 export function getDefaultWorkflowDataset(datasets, jobs) {
@@ -15,8 +15,8 @@ export function getDefaultWorkflowDataset(datasets, jobs) {
 }
 
 /**
- * @param {import("$lib/types-v2").WorkflowV2} workflow
- * @param {Array<import("$lib/types-v2").DatasetV2>} datasets
+ * @param {import("fractal-components/types/api").WorkflowV2} workflow
+ * @param {Array<import("fractal-components/types/api").DatasetV2>} datasets
  * @param {number|undefined} defaultDatasetId
  * @returns {number|undefined}
  */
@@ -36,7 +36,7 @@ export function getSelectedWorkflowDataset(workflow, datasets, defaultDatasetId)
 const LOCAL_STORAGE_SELECTED_DATASETS = 'SelectedDatasets';
 
 /**
- * @param {import("$lib/types-v2").WorkflowV2} workflow
+ * @param {import("fractal-components/types/api").WorkflowV2} workflow
  * @param {number|undefined} datasetId
  */
 export function saveSelectedDataset(workflow, datasetId) {
@@ -72,7 +72,7 @@ export function deleteDatasetSelectionsForProject(projectId) {
 }
 
 /**
- * @param {import("$lib/types-v2").WorkflowV2} workflow
+ * @param {import("fractal-components/types/api").WorkflowV2} workflow
  * @returns {number|undefined}
  */
 function getDatasetIdFromLocalStorage(workflow) {
diff --git a/src/lib/components/v2/jobs/JobInfoModal.svelte b/src/lib/components/v2/jobs/JobInfoModal.svelte
index f09c28e1..f3c46e22 100644
--- a/src/lib/components/v2/jobs/JobInfoModal.svelte
+++ b/src/lib/components/v2/jobs/JobInfoModal.svelte
@@ -4,7 +4,7 @@
 	import { page } from '$app/stores';
 	import Modal from '../../common/Modal.svelte';
 
-	/** @type {import('$lib/types-v2').ApplyWorkflowV2|undefined} */
+	/** @type {import('fractal-components/types/api').ApplyWorkflowV2|undefined} */
 	let job = undefined;
 
 	let errorAlert = undefined;
@@ -12,7 +12,7 @@
 	let modal;
 
 	/**
-	 * @param jobToDisplay {import('$lib/types-v2').ApplyWorkflowV2}
+	 * @param jobToDisplay {import('fractal-components/types/api').ApplyWorkflowV2}
 	 */
 	export async function show(jobToDisplay) {
 		job = jobToDisplay;
diff --git a/src/lib/components/v2/jobs/JobLogsModal.svelte b/src/lib/components/v2/jobs/JobLogsModal.svelte
index e9ff2f1c..ce7ecdf4 100644
--- a/src/lib/components/v2/jobs/JobLogsModal.svelte
+++ b/src/lib/components/v2/jobs/JobLogsModal.svelte
@@ -11,7 +11,7 @@
 	let modal;
 	/** Show/hide complete stack trace */
 	let showDetails = false;
-	/** @type {import('$lib/types-v2').ApplyWorkflowV2} */
+	/** @type {import('fractal-components/types/api').ApplyWorkflowV2} */
 	let job;
 	let admin = false;
 	let log = '';
@@ -24,7 +24,7 @@
 	let updateJobTimeout = undefined;
 
 	/**
-	 * @param {import('$lib/types-v2').ApplyWorkflowV2} selectedJob
+	 * @param {import('fractal-components/types/api').ApplyWorkflowV2} selectedJob
 	 * @param {boolean} isAdminPage
 	 */
 	export async function show(selectedJob, isAdminPage) {
diff --git a/src/lib/components/v2/jobs/JobsList.svelte b/src/lib/components/v2/jobs/JobsList.svelte
index 997ca7ad..ec4d7e75 100644
--- a/src/lib/components/v2/jobs/JobsList.svelte
+++ b/src/lib/components/v2/jobs/JobsList.svelte
@@ -13,7 +13,7 @@
 	import TimestampCell from '../../jobs/TimestampCell.svelte';
 	import SlimSelect from 'slim-select';
 
-	/** @type {() => Promise<import('$lib/types-v2').ApplyWorkflowV2[]>} */
+	/** @type {() => Promise<import('fractal-components/types/api').ApplyWorkflowV2[]>} */
 	export let jobUpdater;
 	/** @type {('project'|'workflow'|'user_email'|'id')[]} */
 	export let columnsToHide = [];
@@ -29,7 +29,7 @@
 	let projects = $page.data.projects;
 	/** @type {{id: number, name: string}[]} */
 	let workflows = $page.data.workflows || [];
-	/** @type {import('$lib/types-v2').ApplyWorkflowV2[]} */
+	/** @type {import('fractal-components/types/api').ApplyWorkflowV2[]} */
 	let jobs = $page.data.jobs || [];
 	/** @type {{ id: number, name: string }[]} */
 	let datasets = $page.data.datasets || [];
@@ -38,7 +38,7 @@
 	let tableHandler = new DataHandler(jobs);
 	tableHandler.sortDesc('id');
 
-	/** @type {import('svelte/store').Readable<import('$lib/types-v2').ApplyWorkflowV2[]>} */
+	/** @type {import('svelte/store').Readable<import('fractal-components/types/api').ApplyWorkflowV2[]>} */
 	let rows = tableHandler.getRows();
 
 	// Selectors
@@ -71,7 +71,7 @@
 	let errorAlert = undefined;
 
 	/**
-	 * @param {import('$lib/types-v2').ApplyWorkflowV2[]} newJobs
+	 * @param {import('fractal-components/types/api').ApplyWorkflowV2[]} newJobs
 	 */
 	export function setJobs(newJobs) {
 		jobs = newJobs;
@@ -92,7 +92,7 @@
 
 	/**
 	 * Requests the server to stop a job execution
-	 * @param {import('$lib/types-v2').ApplyWorkflowV2} job
+	 * @param {import('fractal-components/types/api').ApplyWorkflowV2} job
 	 * @returns {Promise<void>}
 	 */
 	async function handleJobCancel(job) {
@@ -142,7 +142,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').ApplyWorkflowV2} row
+	 * @param {import('fractal-components/types/api').ApplyWorkflowV2} row
 	 */
 	function getDownloadUrl(row) {
 		if (admin) {
@@ -228,7 +228,7 @@
 	/**
 	 * Rebuilds valid slim-select options according to the visible rows.
 	 * Example: if a project filter is selected the user can select only the workflows belonging to that project.
-	 * @param {import('$lib/types-v2').ApplyWorkflowV2[]} rows
+	 * @param {import('fractal-components/types/api').ApplyWorkflowV2[]} rows
 	 */
 	function rebuildSlimSelectOptions(rows) {
 		setValidSlimSelectOptions(
diff --git a/src/lib/components/v2/projects/CreateWorkflowModal.svelte b/src/lib/components/v2/projects/CreateWorkflowModal.svelte
index f9186e45..aa1779a4 100644
--- a/src/lib/components/v2/projects/CreateWorkflowModal.svelte
+++ b/src/lib/components/v2/projects/CreateWorkflowModal.svelte
@@ -5,7 +5,7 @@
 	import { goto } from '$app/navigation';
 	import { tick } from 'svelte';
 
-	/** @type {(workflow: import('$lib/types-v2').WorkflowV2) => void} */
+	/** @type {(workflow: import('fractal-components/types/api').WorkflowV2) => void} */
 	export let handleWorkflowImported;
 
 	// Component properties
@@ -92,7 +92,7 @@
 			}, 3000);
 			reset();
 
-			/** @type {import('$lib/types-v2').WorkflowV2} */
+			/** @type {import('fractal-components/types/api').WorkflowV2} */
 			const workflow = await response.json();
 
 			await tick();
diff --git a/src/lib/components/v2/projects/ProjectDatasetsList.svelte b/src/lib/components/v2/projects/ProjectDatasetsList.svelte
index c3710b8e..36d16795 100644
--- a/src/lib/components/v2/projects/ProjectDatasetsList.svelte
+++ b/src/lib/components/v2/projects/ProjectDatasetsList.svelte
@@ -5,7 +5,7 @@
 	import { onMount } from 'svelte';
 	import StandardDismissableAlert from '$lib/components/common/StandardDismissableAlert.svelte';
 
-	/** @type {import('$lib/types-v2').DatasetV2[]} */
+	/** @type {import('fractal-components/types/api').DatasetV2[]} */
 	export let datasets = [];
 
 	let datasetSearch = '';
@@ -15,7 +15,7 @@
 		p.name.toLowerCase().includes(datasetSearch.toLowerCase())
 	);
 
-	function createDatasetCallback(/** @type {import('$lib/types-v2').DatasetV2} */ newDataset) {
+	function createDatasetCallback(/** @type {import('fractal-components/types/api').DatasetV2} */ newDataset) {
 		datasetCreatedMessage = `Created new dataset with Zarr dir ${newDataset.zarr_dir}`;
 		datasets = [...datasets, newDataset].sort((a, b) =>
 			a.name < b.name ? -1 : a.name > b.name ? 1 : 0
diff --git a/src/lib/components/v2/projects/ProjectInfoModal.svelte b/src/lib/components/v2/projects/ProjectInfoModal.svelte
index ad8d2a91..adcbf986 100644
--- a/src/lib/components/v2/projects/ProjectInfoModal.svelte
+++ b/src/lib/components/v2/projects/ProjectInfoModal.svelte
@@ -7,11 +7,11 @@
 	import Modal from '../../common/Modal.svelte';
 
 	// Project to be displayed
-	/** @type {import('$lib/types-v2').ProjectV2|undefined} */
+	/** @type {import('fractal-components/types/api').ProjectV2|undefined} */
 	let project = undefined;
 
 	let loadingDatasets = true;
-	/** @type {import('$lib/types-v2').DatasetV2[]|undefined} */
+	/** @type {import('fractal-components/types/api').DatasetV2[]|undefined} */
 	let datasets = undefined;
 
 	/** @type {import('$lib/components/common/StandardErrorAlert.svelte').default|undefined} */
@@ -31,7 +31,7 @@
 				credentials: 'include'
 			});
 			if (response.ok) {
-				/** @type {import('$lib/types-v2.js').DatasetV2[]} */
+				/** @type {import('fractal-components/types/api.js').DatasetV2[]} */
 				const result = await response.json();
 				result.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
 				datasets = result;
diff --git a/src/lib/components/v2/projects/ProjectsList.svelte b/src/lib/components/v2/projects/ProjectsList.svelte
index e34ee661..03dde1ff 100644
--- a/src/lib/components/v2/projects/ProjectsList.svelte
+++ b/src/lib/components/v2/projects/ProjectsList.svelte
@@ -32,7 +32,7 @@
 	 * @param {number} projectId
 	 */
 	function setProjectInfoModal(projectId) {
-		/** @type {import('$lib/types-v2').ProjectV2} */
+		/** @type {import('fractal-components/types/api').ProjectV2} */
 		const project = projects.filter((p) => p.id === projectId)[0];
 		projectInfoModalV2.set(project);
 	}
diff --git a/src/lib/components/v2/projects/WorkflowsList.svelte b/src/lib/components/v2/projects/WorkflowsList.svelte
index 4d9bf655..b3e8102d 100644
--- a/src/lib/components/v2/projects/WorkflowsList.svelte
+++ b/src/lib/components/v2/projects/WorkflowsList.svelte
@@ -7,7 +7,7 @@
 	import { saveSelectedDataset } from '$lib/common/workflow_utilities';
 
 	// The list of workflows
-	/** @type {import('$lib/types-v2').WorkflowV2[]} */
+	/** @type {import('fractal-components/types/api').WorkflowV2[]} */
 	export let workflows = [];
 	// Set the projectId prop to reference a specific project for each workflow
 	export let projectId = undefined;
@@ -44,7 +44,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').WorkflowV2} importedWorkflow
+	 * @param {import('fractal-components/types/api').WorkflowV2} importedWorkflow
 	 */
 	function handleWorkflowImported(importedWorkflow) {
 		workflows.push(importedWorkflow);
diff --git a/src/lib/components/v2/projects/datasets/CreateDatasetModal.svelte b/src/lib/components/v2/projects/datasets/CreateDatasetModal.svelte
index e93f4277..09f83fe3 100644
--- a/src/lib/components/v2/projects/datasets/CreateDatasetModal.svelte
+++ b/src/lib/components/v2/projects/datasets/CreateDatasetModal.svelte
@@ -5,7 +5,7 @@
 	import Modal from '../../../common/Modal.svelte';
 	import AttributesTypesForm from './AttributesTypesForm.svelte';
 
-	/** @type {(dataset: import('$lib/types-v2').DatasetV2) => void} */
+	/** @type {(dataset: import('fractal-components/types/api').DatasetV2) => void} */
 	export let createDatasetCallback;
 
 	/** @type {Modal} */
@@ -125,7 +125,7 @@
 	}
 
 	/**
-	 * @returns {Promise<import('$lib/types-v2').DatasetV2|null>}
+	 * @returns {Promise<import('fractal-components/types/api').DatasetV2|null>}
 	 */
 	async function callCreateDataset() {
 		const projectId = $page.params.projectId;
diff --git a/src/lib/components/v2/projects/datasets/CreateUpdateImageModal.svelte b/src/lib/components/v2/projects/datasets/CreateUpdateImageModal.svelte
index 1e50c35e..78d007fe 100644
--- a/src/lib/components/v2/projects/datasets/CreateUpdateImageModal.svelte
+++ b/src/lib/components/v2/projects/datasets/CreateUpdateImageModal.svelte
@@ -3,7 +3,7 @@
 	import Modal from '$lib/components/common/Modal.svelte';
 	import AttributesTypesForm from './AttributesTypesForm.svelte';
 
-	/** @type {import('$lib/types-v2').DatasetV2} */
+	/** @type {import('fractal-components/types/api').DatasetV2} */
 	export let dataset;
 	/** @type {() => Promise<void>} */
 	export let onImageSave;
@@ -34,7 +34,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').Image} image
+	 * @param {import('fractal-components/types/api').Image} image
 	 */
 	export function openForEditing(image) {
 		isNew = false;
diff --git a/src/lib/components/v2/projects/datasets/DatasetFiltersModal.svelte b/src/lib/components/v2/projects/datasets/DatasetFiltersModal.svelte
index 2e7b143e..bf8d3e74 100644
--- a/src/lib/components/v2/projects/datasets/DatasetFiltersModal.svelte
+++ b/src/lib/components/v2/projects/datasets/DatasetFiltersModal.svelte
@@ -4,9 +4,9 @@
 	import Modal from '$lib/components/common/Modal.svelte';
 	import AttributesTypesForm from './AttributesTypesForm.svelte';
 
-	/** @type {import('$lib/types-v2').DatasetV2} */
+	/** @type {import('fractal-components/types/api').DatasetV2} */
 	export let dataset;
-	/** @type {(dataset: import('$lib/types-v2').DatasetV2) => void} */
+	/** @type {(dataset: import('fractal-components/types/api').DatasetV2) => void} */
 	export let updateDatasetCallback;
 
 	/** @type {Modal} */
diff --git a/src/lib/components/v2/projects/datasets/DatasetHistoryModal.svelte b/src/lib/components/v2/projects/datasets/DatasetHistoryModal.svelte
index 3a5f86c3..032a06d6 100644
--- a/src/lib/components/v2/projects/datasets/DatasetHistoryModal.svelte
+++ b/src/lib/components/v2/projects/datasets/DatasetHistoryModal.svelte
@@ -1,13 +1,13 @@
 <script>
 	import Modal from '$lib/components/common/Modal.svelte';
 
-	/** @type {import('$lib/types-v2').DatasetV2} */
+	/** @type {import('fractal-components/types/api').DatasetV2} */
 	export let dataset;
 
 	/**
 	 * Returns the dataset history formatted in JSON hiding some values.
 	 *
-	 * @param {import('$lib/types-v2').DatasetHistoryItemV2} historyItem
+	 * @param {import('fractal-components/types/api').DatasetHistoryItemV2} historyItem
 	 * @returns {string}
 	 */
 	function formatDatasetHistory(historyItem) {
diff --git a/src/lib/components/v2/projects/datasets/DatasetInfoModal.svelte b/src/lib/components/v2/projects/datasets/DatasetInfoModal.svelte
index 30527b8b..92d2ab4f 100644
--- a/src/lib/components/v2/projects/datasets/DatasetInfoModal.svelte
+++ b/src/lib/components/v2/projects/datasets/DatasetInfoModal.svelte
@@ -3,9 +3,9 @@
 	import { FormErrorHandler } from '$lib/common/errors';
 	import Modal from '$lib/components/common/Modal.svelte';
 
-	/** @type {import('$lib/types-v2').DatasetV2} */
+	/** @type {import('fractal-components/types/api').DatasetV2} */
 	export let dataset;
-	/** @type {(dataset: import('$lib/types-v2').DatasetV2) => void} */
+	/** @type {(dataset: import('fractal-components/types/api').DatasetV2) => void} */
 	export let updateDatasetCallback;
 
 	/** @type {Modal} */
diff --git a/src/lib/components/v2/tasks/AddSingleTask.svelte b/src/lib/components/v2/tasks/AddSingleTask.svelte
index 9ac49d66..54947c1a 100644
--- a/src/lib/components/v2/tasks/AddSingleTask.svelte
+++ b/src/lib/components/v2/tasks/AddSingleTask.svelte
@@ -6,7 +6,7 @@
 	import TypesEditor from './TypesEditor.svelte';
 	import { detectSchemaVersion, SchemaValidator } from 'fractal-components';
 
-	/** @type {(task: import('$lib/types-v2').TaskV2[]) => void} */
+	/** @type {(task: import('fractal-components/types/api').TaskV2[]) => void} */
 	export let addNewTasks;
 	/** @type {import('$lib/types').User} */
 	export let user;
@@ -22,7 +22,7 @@
 	let docs_link = '';
 	/** @type {'pydantic_v1'|'pydantic_v2'} */
 	let args_schema_version = 'pydantic_v2';
-	/** @type {import('$lib/types-v2').TaskV2Type} */
+	/** @type {import('fractal-components/types/api').TaskV2Type} */
 	let taskType = 'non_parallel';
 	let privateTask = false;
 	let selectedGroup = null;
diff --git a/src/lib/components/v2/tasks/CustomEnvTask.svelte b/src/lib/components/v2/tasks/CustomEnvTask.svelte
index 1d323dec..48b4c6f9 100644
--- a/src/lib/components/v2/tasks/CustomEnvTask.svelte
+++ b/src/lib/components/v2/tasks/CustomEnvTask.svelte
@@ -7,7 +7,7 @@
 	import StandardDismissableAlert from '$lib/components/common/StandardDismissableAlert.svelte';
 	import TaskGroupSelector from './TaskGroupSelector.svelte';
 
-	/** @type {(task: import('$lib/types-v2').TaskV2[]) => void} */
+	/** @type {(task: import('fractal-components/types/api').TaskV2[]) => void} */
 	export let addNewTasks;
 	/** @type {import('$lib/types').User} */
 	export let user;
diff --git a/src/lib/components/v2/tasks/TaskCollection.svelte b/src/lib/components/v2/tasks/TaskCollection.svelte
index 88833437..b2450174 100644
--- a/src/lib/components/v2/tasks/TaskCollection.svelte
+++ b/src/lib/components/v2/tasks/TaskCollection.svelte
@@ -4,16 +4,14 @@
 	import TaskGroupActivityLogsModal from '$lib/components/v2/tasks/TaskGroupActivityLogsModal.svelte';
 	import { FormErrorHandler } from '$lib/common/errors';
 	import TaskGroupSelector from './TaskGroupSelector.svelte';
-	import {
-		getTaskActivityStatusBadgeClass,
-		getTaskGroupActivitiesToUpdate
-	} from './task_group_utilities';
+	import { getTaskGroupActivitiesToUpdate } from './task_group_utilities';
+	import { getTaskActivityStatusBadgeClass } from 'fractal-components/tasks/task_group_utilities';
 	import { sortActivitiesByTimestampStarted } from '$lib/common/task_utilities';
 
 	// This component automatically fecthes updates for task collections activities
 	// in pending and ongoing status
 
-	/** @type {import('$lib/types-v2').TaskGroupActivityV2[]} */
+	/** @type {import('fractal-components/types/api').TaskGroupActivityV2[]} */
 	let recentActivities = [];
 
 	$: sortedRecentActivities = [...recentActivities].sort(sortActivitiesByTimestampStarted);
@@ -148,7 +146,7 @@
 		taskCollectionInProgress = false;
 
 		if (response.ok) {
-			const result = /** @type {import('$lib/types-v2').TaskGroupActivityV2} */ (
+			const result = /** @type {import('fractal-components/types/api').TaskGroupActivityV2} */ (
 				await response.json()
 			);
 			recentActivities = [...recentActivities, result];
@@ -182,7 +180,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TaskGroupActivityV2[]} activitiesToUpdate
+	 * @param {import('fractal-components/types/api').TaskGroupActivityV2[]} activitiesToUpdate
 	 */
 	async function updateTaskCollectionsState(activitiesToUpdate) {
 		recentActivities = recentActivities.map((a) => {
diff --git a/src/lib/components/v2/tasks/TaskEditModal.svelte b/src/lib/components/v2/tasks/TaskEditModal.svelte
index 38dfeac2..1892af6b 100644
--- a/src/lib/components/v2/tasks/TaskEditModal.svelte
+++ b/src/lib/components/v2/tasks/TaskEditModal.svelte
@@ -7,7 +7,7 @@
 
 	export let updateEditedTask;
 
-	/** @type {import('$lib/types-v2').TaskV2|undefined} */
+	/** @type {import('fractal-components/types/api').TaskV2|undefined} */
 	let task;
 
 	$: updateEnabled = !loading && !saving && task && task.name;
@@ -74,7 +74,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TaskV2} taskToEdit
+	 * @param {import('fractal-components/types/api').TaskV2} taskToEdit
 	 */
 	export async function open(taskToEdit) {
 		loading = true;
@@ -90,7 +90,7 @@
 		loading = false;
 
 		if (response.ok) {
-			task = /** @type {import('$lib/types-v2').TaskV2} */ (result);
+			task = /** @type {import('fractal-components/types/api').TaskV2} */ (result);
 			command_parallel = task.command_parallel;
 			command_non_parallel = task.command_non_parallel;
 			// wait the typesEditor element rendering, that happens after task is defined
diff --git a/src/lib/components/v2/tasks/TaskGroupActivities.svelte b/src/lib/components/v2/tasks/TaskGroupActivities.svelte
index 847ff819..d070f956 100644
--- a/src/lib/components/v2/tasks/TaskGroupActivities.svelte
+++ b/src/lib/components/v2/tasks/TaskGroupActivities.svelte
@@ -2,10 +2,8 @@
 	import { env } from '$env/dynamic/public';
 	import { displayStandardErrorAlert, getAlertErrorFromResponse } from '$lib/common/errors';
 	import { onDestroy, onMount } from 'svelte';
-	import {
-		getTaskActivityStatusBadgeClass,
-		getTaskGroupActivitiesToUpdate
-	} from './task_group_utilities';
+	import { getTaskGroupActivitiesToUpdate } from './task_group_utilities';
+	import { getTaskActivityStatusBadgeClass } from 'fractal-components/tasks/task_group_utilities';
 	import TaskGroupActivityLogsModal from './TaskGroupActivityLogsModal.svelte';
 	import { getTimestamp } from '$lib/common/component_utilities';
 	import { page } from '$app/stores';
@@ -22,7 +20,7 @@
 		sortedUsers = [...users].sort(sortUserByEmailComparator);
 	}
 
-	/** @type {import('$lib/types-v2').TaskGroupActivityV2[]} */
+	/** @type {import('fractal-components/types/api').TaskGroupActivityV2[]} */
 	let results = [];
 
 	let pkg_name = '';
@@ -100,7 +98,7 @@
 				);
 				return;
 			}
-			/** @type {import('$lib/types-v2').TaskGroupActivityV2[]} */
+			/** @type {import('fractal-components/types/api').TaskGroupActivityV2[]} */
 			const activities = await response.json();
 			activities.sort(sortActivitiesByTimestampStarted);
 			results = activities;
@@ -132,7 +130,7 @@
 	let updateTasksCollectionTimeout = undefined;
 
 	/**
-	 * @param {import('$lib/types-v2').TaskGroupActivityV2[]} activitiesToUpdate
+	 * @param {import('fractal-components/types/api').TaskGroupActivityV2[]} activitiesToUpdate
 	 */
 	async function updateTaskCollectionsState(activitiesToUpdate) {
 		results = results.map((a) => {
diff --git a/src/lib/components/v2/tasks/TaskGroupActivityLogsModal.svelte b/src/lib/components/v2/tasks/TaskGroupActivityLogsModal.svelte
index 43b75b08..c35bde63 100644
--- a/src/lib/components/v2/tasks/TaskGroupActivityLogsModal.svelte
+++ b/src/lib/components/v2/tasks/TaskGroupActivityLogsModal.svelte
@@ -38,7 +38,7 @@
 		);
 
 		if (response.ok) {
-			/** @type {import('$lib/types-v2').TaskGroupActivityV2[]} */
+			/** @type {import('fractal-components/types/api').TaskGroupActivityV2[]} */
 			const activities = await response.json();
 			if (activities.length === 0) {
 				errorAlert = displayStandardErrorAlert(
diff --git a/src/lib/components/v2/tasks/TaskGroupEditModal.svelte b/src/lib/components/v2/tasks/TaskGroupEditModal.svelte
index 95e6b492..868618f9 100644
--- a/src/lib/components/v2/tasks/TaskGroupEditModal.svelte
+++ b/src/lib/components/v2/tasks/TaskGroupEditModal.svelte
@@ -7,14 +7,14 @@
 	/** @type {Array<[number, string]>} */
 	export let groupIdsNames;
 	/**
-	 * @type {(updatedGroups: import('$lib/types-v2').TaskGroupV2) => void}
+	 * @type {(updatedGroups: import('fractal-components/types/api').TaskGroupV2) => void}
 	 */
 	export let updateEditedTaskGroup;
 
 	/** @type {Modal} */
 	let modal;
 
-	/** @type {import('$lib/types-v2').TaskGroupV2|undefined} */
+	/** @type {import('fractal-components/types/api').TaskGroupV2|undefined} */
 	let taskGroup = undefined;
 
 	let privateTask = false;
@@ -27,7 +27,7 @@
 	const validationErrors = formErrorHandler.getValidationErrorStore();
 
 	/**
-	 * @param {import('$lib/types-v2').TaskGroupV2} taskGroupToEdit
+	 * @param {import('fractal-components/types/api').TaskGroupV2} taskGroupToEdit
 	 */
 	export async function open(taskGroupToEdit) {
 		taskGroup = taskGroupToEdit;
diff --git a/src/lib/components/v2/tasks/TaskGroupInfoModal.svelte b/src/lib/components/v2/tasks/TaskGroupInfoModal.svelte
index 02176513..01749fe3 100644
--- a/src/lib/components/v2/tasks/TaskGroupInfoModal.svelte
+++ b/src/lib/components/v2/tasks/TaskGroupInfoModal.svelte
@@ -1,18 +1,18 @@
 <script>
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte';
 	import TimestampCell from '$lib/components/jobs/TimestampCell.svelte';
 	import Modal from '../../common/Modal.svelte';
 
 	/** @type {import('$lib/types').User} */
 	export let user;
-	/** @type {import('$lib/types-v2').TaskGroupV2|undefined} */
+	/** @type {import('fractal-components/types/api').TaskGroupV2|undefined} */
 	let taskGroup;
 
 	/** @type {Modal} */
 	let modal;
 
 	/**
-	 * @param {import('$lib/types-v2').TaskGroupV2} taskGroupToLoad
+	 * @param {import('fractal-components/types/api').TaskGroupV2} taskGroupToLoad
 	 */
 	export async function open(taskGroupToLoad) {
 		taskGroup = taskGroupToLoad;
@@ -20,7 +20,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TaskGroupV2} taskGroup
+	 * @param {import('fractal-components/types/api').TaskGroupV2} taskGroup
 	 */
 	function getGroupName(taskGroup) {
 		const group = user.group_ids_names?.find((i) => i[0] === taskGroup?.user_group_id);
diff --git a/src/lib/components/v2/tasks/TaskGroupManageModal.svelte b/src/lib/components/v2/tasks/TaskGroupManageModal.svelte
index 7ab7a6bb..dd6ebd23 100644
--- a/src/lib/components/v2/tasks/TaskGroupManageModal.svelte
+++ b/src/lib/components/v2/tasks/TaskGroupManageModal.svelte
@@ -9,7 +9,7 @@
 	/** @type {Modal} */
 	let modal;
 
-	/** @type {import('$lib/types-v2').TaskGroupV2|undefined} */
+	/** @type {import('fractal-components/types/api').TaskGroupV2|undefined} */
 	let taskGroup = undefined;
 	let originalActive = true;
 
@@ -20,7 +20,7 @@
 	let errorAlert = undefined;
 
 	/**
-	 * @param {import('$lib/types-v2').TaskGroupV2} taskGroupToEdit
+	 * @param {import('fractal-components/types/api').TaskGroupV2} taskGroupToEdit
 	 */
 	export async function open(taskGroupToEdit) {
 		taskGroup = taskGroupToEdit;
diff --git a/src/lib/components/v2/tasks/TaskGroupsTable.svelte b/src/lib/components/v2/tasks/TaskGroupsTable.svelte
index 9b3e5860..5c586060 100644
--- a/src/lib/components/v2/tasks/TaskGroupsTable.svelte
+++ b/src/lib/components/v2/tasks/TaskGroupsTable.svelte
@@ -1,25 +1,25 @@
 <script>
 	import ConfirmActionButton from '$lib/components/common/ConfirmActionButton.svelte';
 	import { onMount } from 'svelte';
-	import { buildTaskTableRows, sortVersions } from './task_group_utilities';
+	import { buildTaskTableRows, sortVersions } from 'fractal-components/tasks/task_group_utilities';
 	import { getAlertErrorFromResponse } from '$lib/common/errors';
 	import TaskInfoModal from './TaskInfoModal.svelte';
 	import TaskEditModal from './TaskEditModal.svelte';
 	import TaskGroupInfoModal from './TaskGroupInfoModal.svelte';
 	import TaskGroupEditModal from '$lib/components/v2/tasks/TaskGroupEditModal.svelte';
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte';
 	import TaskGroupManageModal from '$lib/components/v2/tasks/TaskGroupManageModal.svelte';
 
 	/** @type {import('$lib/types').User} */
 	export let user;
 	/**
-	 * @type {import('$lib/types-v2').TaskGroupV2[]}
+	 * @type {import('fractal-components/types/api').TaskGroupV2[]}
 	 */
 	export let taskGroups;
 	/** @type {string|undefined} */
 	export let expandedTaskGroupRow;
 	/**
-	 * @type {(updatedGroups: import('$lib/types-v2').TaskGroupV2[]) => void}
+	 * @type {(updatedGroups: import('fractal-components/types/api').TaskGroupV2[]) => void}
 	 */
 	export let updateTaskGroups;
 
@@ -35,7 +35,7 @@
 	let taskEditModal;
 
 	/**
-	 * @type {import('$lib/types-v2').TasksTableRowGroup[]}
+	 * @type {import('fractal-components/types/api').TasksTableRowGroup[]}
 	 */
 	let taskGroupRows = [];
 
@@ -94,14 +94,14 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TaskGroupV2} updatedGroup
+	 * @param {import('fractal-components/types/api').TaskGroupV2} updatedGroup
 	 */
 	function updateEditedTaskGroup(updatedGroup) {
 		updateTaskGroups(taskGroups.map((g) => (g.id === updatedGroup.id ? updatedGroup : g)));
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TaskV2} editedTask
+	 * @param {import('fractal-components/types/api').TaskV2} editedTask
 	 */
 	function updateEditedTask(editedTask) {
 		updateTaskGroups(
@@ -113,7 +113,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TaskGroupV2} taskGroup
+	 * @param {import('fractal-components/types/api').TaskGroupV2} taskGroup
 	 */
 	function getGroupName(taskGroup) {
 		const group = user.group_ids_names?.find((i) => i[0] === taskGroup?.user_group_id);
diff --git a/src/lib/components/v2/tasks/TaskInfoModal.svelte b/src/lib/components/v2/tasks/TaskInfoModal.svelte
index 256f480f..3acf2c7b 100644
--- a/src/lib/components/v2/tasks/TaskInfoModal.svelte
+++ b/src/lib/components/v2/tasks/TaskInfoModal.svelte
@@ -1,9 +1,9 @@
 <script>
 	import { formatMarkdown } from '$lib/common/component_utilities';
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte';
 	import Modal from '../../common/Modal.svelte';
 
-	/** @type {import('$lib/types-v2').TaskV2|undefined} */
+	/** @type {import('fractal-components/types/api').TaskV2|undefined} */
 	let task;
 	/** @type {string | null} */
 	let taskVersion;
@@ -14,7 +14,7 @@
 
 	/**
 	 *
-	 * @param {import('$lib/types-v2').TaskV2} taskToLoad
+	 * @param {import('fractal-components/types/api').TaskV2} taskToLoad
 	 * @param {string | null} taskGroupVersion
 	 */
 	export async function open(taskToLoad, taskGroupVersion) {
diff --git a/src/lib/components/v2/tasks/task_group_utilities.js b/src/lib/components/v2/tasks/task_group_utilities.js
index 2348a4a7..f9200456 100644
--- a/src/lib/components/v2/tasks/task_group_utilities.js
+++ b/src/lib/components/v2/tasks/task_group_utilities.js
@@ -1,244 +1,9 @@
 import { getAlertErrorFromResponse } from '$lib/common/errors';
-import compareLoose from 'semver/functions/compare-loose';
-
-/**
- * @param {import('$lib/types-v2').TaskGroupV2[]} taskGroups
- * @param {string} groupBy
- * @returns {import('$lib/types-v2').WorkflowTasksTableRowGroup[]}
- */
-export function buildWorkflowTaskTableRows(taskGroups, groupBy) {
-	/** @type {import('$lib/types-v2').WorkflowTasksTableRowGroup[]} */
-	const rows = [];
-	for (const taskGroup of taskGroups) {
-		for (const task of taskGroup.task_list) {
-			const groupValue = taskGroup[groupBy];
-			let groupRow = rows.find((r) => r.groupTitle === groupValue);
-			const taskProperties = getTaskTableProperties(taskGroup, task);
-			const taskVersion = taskGroup.version || '';
-			if (groupRow) {
-				let groupTask = groupRow.tasks.find((t) =>
-					Object.values(t.taskVersions).find((r) => r.task_name === task.name)
-				);
-				if (groupTask) {
-					groupTask.taskVersions[taskVersion] = taskProperties;
-				} else {
-					groupTask = {
-						selectedVersion: taskVersion,
-						taskVersions: { [taskVersion]: taskProperties }
-					};
-					groupRow.tasks.push(groupTask);
-				}
-			} else {
-				groupRow = {
-					groupTitle: taskGroup[groupBy],
-					tasks: [
-						{
-							selectedVersion: taskVersion,
-							taskVersions: { [taskVersion]: taskProperties }
-						}
-					]
-				};
-				rows.push(groupRow);
-			}
-		}
-	}
-	sortWorkflowTasksTableRows(rows);
-	return rows;
-}
-
-/**
- * @param {import('$lib/types-v2').WorkflowTasksTableRowGroup[]} rows
- */
-function sortWorkflowTasksTableRows(rows) {
-	for (const row of rows) {
-		for (const task of row.tasks) {
-			const validVersions = Object.keys(task.taskVersions).filter((v) => v !== '');
-			if (validVersions.length > 0) {
-				sortVersions(validVersions);
-				task.selectedVersion = validVersions[0];
-			}
-		}
-		row.tasks.sort((t1, t2) =>
-			t1.taskVersions[t1.selectedVersion].task_id < t2.taskVersions[t2.selectedVersion].task_id
-				? -1
-				: 1
-		);
-	}
-	rows.sort((r1, r2) =>
-		r1.groupTitle.localeCompare(r2.groupTitle, undefined, { sensitivity: 'base' })
-	);
-}
-
-/**
- * @param {import('$lib/types-v2').TaskGroupV2[]} taskGroups
- * @param {string} groupBy
- * @returns {import('$lib/types-v2').TasksTableRowGroup[]}
- */
-export function buildTaskTableRows(taskGroups, groupBy) {
-	/** @type {import('$lib/types-v2').TasksTableRowGroup[]} */
-	const rows = [];
-	for (const taskGroup of taskGroups) {
-		if (taskGroup.task_list.length > 0) {
-			const groupValue = taskGroup[groupBy];
-			let groupRow = rows.find((r) => r.groupTitle === groupValue);
-			const version = taskGroup.version || '';
-			if (groupRow) {
-				groupRow.groups[version] = taskGroup;
-			} else {
-				groupRow = {
-					groupTitle: groupValue,
-					selectedVersion: version,
-					groups: { [version]: taskGroup }
-				};
-				rows.push(groupRow);
-			}
-		}
-	}
-	sortTasksTableRows(rows);
-	return rows;
-}
-
-/**
- * @param {import('$lib/types-v2').TasksTableRowGroup[]} rows
- */
-function sortTasksTableRows(rows) {
-	for (const row of rows) {
-		const validVersions = Object.keys(row.groups).filter((v) => v !== '');
-		if (validVersions.length > 0) {
-			sortVersions(validVersions);
-			row.selectedVersion = validVersions[0];
-		}
-		for (const taskGroup of Object.values(row.groups)) {
-			taskGroup.task_list.sort((t1, t2) => (t1.id < t2.id ? -1 : 1));
-		}
-	}
-	rows.sort((r1, r2) =>
-		r1.groupTitle.localeCompare(r2.groupTitle, undefined, { sensitivity: 'base' })
-	);
-}
-
-/**
- * @param {string[]} versions
- */
-export function sortVersions(versions) {
-	try {
-		versions
-			.sort((v1, v2) => {
-				if (!v1) {
-					return -1;
-				}
-				if (!v2) {
-					return 1;
-				}
-				return compareLoose(v1, v2);
-			})
-			.reverse();
-	} catch (err) {
-		console.warn('Semver error:', err);
-	}
-	return versions;
-}
-
-/**
- * @param {import('$lib/types-v2').TaskGroupV2} taskGroup
- * @param {import('$lib/types-v2').TaskV2} task
- * @returns {import('$lib/types-v2').TasksTableRow}
- */
-function getTaskTableProperties(taskGroup, task) {
-	return {
-		pkg_name: taskGroup.pkg_name,
-		task_id: task.id,
-		task_name: task.name,
-		version: taskGroup.version || '',
-		category: task.category,
-		modality: task.modality,
-		authors: task.authors,
-		tags: task.tags,
-		input_types: task.input_types,
-		docs_info: task.docs_info || ''
-	};
-}
-
-/**
- * @param {import('$lib/types-v2').TaskGroupV2[]} taskGroups
- * @param {import('$lib/types').User & {group_ids_names: Array<[number, string]>}} user
- * @returns {import('$lib/types-v2').TaskGroupV2[]}
- */
-export function removeIdenticalTaskGroups(taskGroups, user) {
-	/** @type {Map<string, Map<string|null, import('$lib/types-v2').TaskGroupV2>>}  */
-	const taskGroupsMap = new Map();
-	for (const taskGroup of taskGroups) {
-		let versionsMap = taskGroupsMap.get(taskGroup.pkg_name);
-		if (!versionsMap) {
-			/** @type {Map<string|null, import('$lib/types-v2').TaskGroupV2>}  */
-			versionsMap = new Map();
-			taskGroupsMap.set(taskGroup.pkg_name, versionsMap);
-		}
-		const duplicate = versionsMap.get(taskGroup.version);
-		if (duplicate) {
-			const preferredTaskGroup = selectTaskGroupToKeep(taskGroup, duplicate, user);
-			versionsMap.set(taskGroup.version, preferredTaskGroup);
-		} else {
-			versionsMap.set(taskGroup.version, taskGroup);
-		}
-	}
-	/** @type {import('$lib/types-v2').TaskGroupV2[]} */
-	const filteredTaskGroups = [];
-	for (const [, versionsMap] of taskGroupsMap) {
-		for (const [, taskGroup] of versionsMap) {
-			filteredTaskGroups.push(taskGroup);
-		}
-	}
-	return filteredTaskGroups;
-}
-
-/**
- * @param {import('$lib/types-v2').TaskGroupV2} taskGroup1
- * @param {import('$lib/types-v2').TaskGroupV2} taskGroup2
- * @param {import('$lib/types').User & {group_ids_names: Array<[number, string]>}} user
- * @returns {import('$lib/types-v2').TaskGroupV2}
- */
-function selectTaskGroupToKeep(taskGroup1, taskGroup2, user) {
-	if (taskGroup1.user_id === user.id) {
-		return taskGroup1;
-	}
-	for (const [userGroupId] of user.group_ids_names) {
-		if (taskGroup1.user_group_id === userGroupId) {
-			return taskGroup1;
-		}
-		if (taskGroup2.user_group_id === userGroupId) {
-			return taskGroup2;
-		}
-	}
-	console.warn(
-		'Unable to find a user group matching task groups',
-		taskGroup1,
-		taskGroup2,
-		user.group_ids_names
-	);
-	return taskGroup1;
-}
-
-/**
- * @param {import('$lib/types-v2').TaskGroupActivityStatusV2} status
- */
-export function getTaskActivityStatusBadgeClass(status) {
-	switch (status.toLowerCase()) {
-		case 'pending':
-			return 'text-bg-light';
-		case 'ongoing':
-			return 'text-bg-primary';
-		case 'failed':
-			return 'text-bg-danger';
-		case 'ok':
-			return 'text-bg-success';
-	}
-}
 
 /**
  * Fetches a task collection from the server
  * @param {number} taskGroupActivityId
- * @returns {Promise<import('$lib/types-v2').TaskGroupActivityV2|undefined>}
+ * @returns {Promise<import('fractal-components/types/api').TaskGroupActivityV2|undefined>}
  */
 async function getTaskActivity(taskGroupActivityId) {
 	const response = await fetch(`/api/v2/task-group/activity/${taskGroupActivityId}`, {
@@ -261,7 +26,7 @@ async function getTaskActivity(taskGroupActivityId) {
 /**
  * Fetches a task collection from the server
  * @param {number} taskGroupActivityId
- * @returns {Promise<import('$lib/types-v2').TaskGroupActivityV2|undefined>}
+ * @returns {Promise<import('fractal-components/types/api').TaskGroupActivityV2|undefined>}
  */
 async function getAdminTaskActivity(taskGroupActivityId) {
 	const response = await fetch(
@@ -272,7 +37,7 @@ async function getAdminTaskActivity(taskGroupActivityId) {
 		}
 	);
 	if (response.ok) {
-		/** @type {import('$lib/types-v2').TaskGroupActivityV2[]} */
+		/** @type {import('fractal-components/types/api').TaskGroupActivityV2[]} */
 		const activities = await response.json();
 		if (activities.length === 0) {
 			return undefined;
@@ -284,9 +49,9 @@ async function getAdminTaskActivity(taskGroupActivityId) {
 }
 
 /**
- * @param {import('$lib/types-v2').TaskGroupActivityV2[]} activities
+ * @param {import('fractal-components/types/api').TaskGroupActivityV2[]} activities
  * @param {boolean} admin
- * @returns {Promise<import('$lib/types-v2').TaskGroupActivityV2[]>}
+ * @returns {Promise<import('fractal-components/types/api').TaskGroupActivityV2[]>}
  */
 export async function getTaskGroupActivitiesToUpdate(activities, admin) {
 	const activitiesToCheck = activities.filter((a) => a.status !== 'OK' && a.status !== 'failed');
@@ -306,11 +71,11 @@ export async function getTaskGroupActivitiesToUpdate(activities, admin) {
 	}
 
 	const successfulUpdates =
-		/** @type {PromiseFulfilledResult<import('$lib/types-v2').TaskGroupActivityV2|undefined>[]} */ (
+		/** @type {PromiseFulfilledResult<import('fractal-components/types/api').TaskGroupActivityV2|undefined>[]} */ (
 			updates.filter((u) => u.status === 'fulfilled')
 		)
 			.map((u) => u.value)
 			.filter((u) => u !== undefined);
 
-	return /** @type {import('$lib/types-v2').TaskGroupActivityV2[]} */ (successfulUpdates);
+	return /** @type {import('fractal-components/types/api').TaskGroupActivityV2[]} */ (successfulUpdates);
 }
diff --git a/src/lib/components/v2/workflow/AddWorkflowTaskModal.svelte b/src/lib/components/v2/workflow/AddWorkflowTaskModal.svelte
index 96b60b06..a28f2d08 100644
--- a/src/lib/components/v2/workflow/AddWorkflowTaskModal.svelte
+++ b/src/lib/components/v2/workflow/AddWorkflowTaskModal.svelte
@@ -2,15 +2,15 @@
 	import { getAlertErrorFromResponse } from '$lib/common/errors';
 	import Modal from '$lib/components/common/Modal.svelte';
 	import PropertyDescription from 'fractal-components/jschema/properties/PropertyDescription.svelte';
-	import FilteredTasksTable from '../tasks/FilteredTasksTable.svelte';
-	import { removeIdenticalTaskGroups } from '../tasks/task_group_utilities';
+	import FilteredTasksTable from 'fractal-components/tasks/FilteredTasksTable.svelte';
+	import { removeIdenticalTaskGroups } from 'fractal-components/tasks/task_group_utilities';
 	import { formatMarkdown } from '$lib/common/component_utilities';
 
-	/** @type {import('$lib/types-v2').WorkflowV2} */
+	/** @type {import('fractal-components/types/api').WorkflowV2} */
 	export let workflow;
 	/** @type {import('$lib/types').User & {group_ids_names: Array<[number, string]>}} */
 	export let user;
-	/** @type {(workflow: import('$lib/types-v2').WorkflowV2) => Promise<void>} */
+	/** @type {(workflow: import('fractal-components/types/api').WorkflowV2) => Promise<void>} */
 	export let onWorkflowTaskAdded;
 
 	/** @type {Modal} */
@@ -19,7 +19,7 @@
 	let loading = false;
 	let addingTask = false;
 
-	/** @type {Array<import('$lib/types-v2').TaskGroupV2>} */
+	/** @type {Array<import('fractal-components/types/api').TaskGroupV2>} */
 	let taskGroups = [];
 
 	export async function show() {
diff --git a/src/lib/components/v2/workflow/ArgumentsSchema.svelte b/src/lib/components/v2/workflow/ArgumentsSchema.svelte
index 758cbbff..ab2e6ff2 100644
--- a/src/lib/components/v2/workflow/ArgumentsSchema.svelte
+++ b/src/lib/components/v2/workflow/ArgumentsSchema.svelte
@@ -22,9 +22,9 @@
 	/** @type {import('$lib/components/common/StandardErrorAlert.svelte').default|undefined} */
 	let errorAlert = undefined;
 
-	/** @type {import('$lib/types-v2').WorkflowTaskV2}  */
+	/** @type {import('fractal-components/types/api').WorkflowTaskV2}  */
 	export let workflowTask;
-	/** @type {(wft: import('$lib/types-v2').WorkflowTaskV2) => void} */
+	/** @type {(wft: import('fractal-components/types/api').WorkflowTaskV2) => void} */
 	export let onWorkflowTaskUpdated;
 
 	/** @type {JSchema|undefined} */
diff --git a/src/lib/components/v2/workflow/ImportExportArgs.svelte b/src/lib/components/v2/workflow/ImportExportArgs.svelte
index ca0de872..5e495b16 100644
--- a/src/lib/components/v2/workflow/ImportExportArgs.svelte
+++ b/src/lib/components/v2/workflow/ImportExportArgs.svelte
@@ -2,7 +2,7 @@
 	import { downloadBlob } from '$lib/common/component_utilities';
 	import Modal from '$lib/components/common/Modal.svelte';
 
-	/** @type {import('$lib/types-v2').WorkflowTaskV2} */
+	/** @type {import('fractal-components/types/api').WorkflowTaskV2} */
 	export let workflowTask;
 	/** @type {(json: object) => Promise<void>} */
 	export let onImport;
diff --git a/src/lib/components/v2/workflow/InputFiltersTab.svelte b/src/lib/components/v2/workflow/InputFiltersTab.svelte
index 607daab1..0958d54a 100644
--- a/src/lib/components/v2/workflow/InputFiltersTab.svelte
+++ b/src/lib/components/v2/workflow/InputFiltersTab.svelte
@@ -4,13 +4,13 @@
 	import { displayStandardErrorAlert, getAlertErrorFromResponse } from '$lib/common/errors';
 	import Modal from '$lib/components/common/Modal.svelte';
 
-	/** @type {import("$lib/types-v2").WorkflowV2} */
+	/** @type {import("fractal-components/types/api").WorkflowV2} */
 	export let workflow;
-	/** @type {import("$lib/types-v2").WorkflowTaskV2} */
+	/** @type {import("fractal-components/types/api").WorkflowTaskV2} */
 	export let workflowTask;
 	/** @type {number|undefined} */
 	export let selectedDatasetId;
-	/** @type {(wft: import("$lib/types-v2").WorkflowTaskV2) => void} */
+	/** @type {(wft: import("fractal-components/types/api").WorkflowTaskV2) => void} */
 	export let updateWorkflowTaskCallback;
 
 	/** @type {AttributesTypesForm} */
@@ -59,7 +59,7 @@
 				}
 			);
 			if (response.ok) {
-				/** @type {import('$lib/types-v2').ImagePage} */
+				/** @type {import('fractal-components/types/api').ImagePage} */
 				const imagePage = await response.json();
 				datasetAttributes = imagePage.attributes;
 				datasetTypes = imagePage.types;
diff --git a/src/lib/components/v2/workflow/MetaPropertiesForm.svelte b/src/lib/components/v2/workflow/MetaPropertiesForm.svelte
index a6aeec36..fcf0669d 100644
--- a/src/lib/components/v2/workflow/MetaPropertiesForm.svelte
+++ b/src/lib/components/v2/workflow/MetaPropertiesForm.svelte
@@ -10,9 +10,9 @@
 	import FormBuilder from '$lib/components/v2/workflow/FormBuilder.svelte';
 	import { displayStandardErrorAlert, getAlertErrorFromResponse } from '$lib/common/errors';
 
-	/** @type {import('$lib/types-v2').WorkflowTaskV2} */
+	/** @type {import('fractal-components/types/api').WorkflowTaskV2} */
 	export let workflowTask;
-	/** @type {(wft: import('$lib/types-v2').WorkflowTaskV2) => void} */
+	/** @type {(wft: import('fractal-components/types/api').WorkflowTaskV2) => void} */
 	export let onWorkflowTaskUpdated;
 
 	/** @type {FormBuilder|undefined} */
diff --git a/src/lib/components/v2/workflow/RunWorkflowModal.svelte b/src/lib/components/v2/workflow/RunWorkflowModal.svelte
index b0b5ec95..f3ff72ac 100644
--- a/src/lib/components/v2/workflow/RunWorkflowModal.svelte
+++ b/src/lib/components/v2/workflow/RunWorkflowModal.svelte
@@ -5,19 +5,19 @@
 		generateNewUniqueDatasetName,
 		getFirstTaskIndexForContinuingWorkflow
 	} from '$lib/common/job_utilities';
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte';
 	import Modal from '$lib/components/common/Modal.svelte';
 	import { onMount } from 'svelte';
 
-	/** @type {import('$lib/types-v2').DatasetV2[]} */
+	/** @type {import('fractal-components/types/api').DatasetV2[]} */
 	export let datasets;
-	/** @type {import('$lib/types-v2').WorkflowV2} */
+	/** @type {import('fractal-components/types/api').WorkflowV2} */
 	export let workflow;
 	/** @type {number|undefined} */
 	export let selectedDatasetId;
-	/** @type {(job: import('$lib/types-v2').ApplyWorkflowV2) => Promise<void>} */
+	/** @type {(job: import('fractal-components/types/api').ApplyWorkflowV2) => Promise<void>} */
 	export let onJobSubmitted;
-	/** @type {(updatedDatasets: import('$lib/types-v2').DatasetV2[], newSelectedDatasetId: number) => void} */
+	/** @type {(updatedDatasets: import('fractal-components/types/api').DatasetV2[], newSelectedDatasetId: number) => void} */
 	export let onDatasetsUpdated;
 	/** @type {{[key: number]: import('$lib/types').JobStatus}} */
 	export let statuses;
@@ -128,7 +128,7 @@
 	}
 
 	async function replaceDataset() {
-		const { id, name, zarr_dir } = /** @type {import('$lib/types-v2').DatasetV2} */ (
+		const { id, name, zarr_dir } = /** @type {import('fractal-components/types/api').DatasetV2} */ (
 			selectedDataset
 		);
 		await handleDatasetDelete(id);
@@ -139,7 +139,7 @@
 	}
 
 	async function createNewDataset() {
-		const { zarr_dir } = /** @type {import('$lib/types-v2').DatasetV2} */ (selectedDataset);
+		const { zarr_dir } = /** @type {import('fractal-components/types/api').DatasetV2} */ (selectedDataset);
 		const newDataset = await handleDatasetCreate(newDatasetName, zarr_dir);
 		onDatasetsUpdated([...datasets, newDataset], newDataset.id);
 	}
@@ -147,7 +147,7 @@
 	/**
 	 * @param {string} datasetName
 	 * @param {string} zarrDir
-	 * @returns {Promise<import('$lib/types-v2').DatasetV2>}
+	 * @returns {Promise<import('fractal-components/types/api').DatasetV2>}
 	 */
 	async function handleDatasetCreate(datasetName, zarrDir) {
 		const headers = new Headers();
@@ -204,14 +204,14 @@
 			appliedAttributeFilters = { ...wft.input_filters.attributes };
 			appliedTypeFilters = { ...wft.input_filters.types };
 		} else {
-			const dataset = /** @type {import('$lib/types-v2').DatasetV2} */ (selectedDataset);
+			const dataset = /** @type {import('fractal-components/types/api').DatasetV2} */ (selectedDataset);
 			appliedAttributeFilters = { ...dataset.filters.attributes, ...wft.input_filters.attributes };
 			appliedTypeFilters = { ...dataset.filters.types, ...wft.input_filters.types };
 		}
 	}
 
 	function computeNewDatasetName() {
-		const dataset = /** @type {import('$lib/types-v2').DatasetV2} */ (selectedDataset);
+		const dataset = /** @type {import('fractal-components/types/api').DatasetV2} */ (selectedDataset);
 		newDatasetName = generateNewUniqueDatasetName(datasets, dataset.name);
 	}
 
diff --git a/src/lib/components/v2/workflow/TaskInfoTab.svelte b/src/lib/components/v2/workflow/TaskInfoTab.svelte
index 27906191..a08190d8 100644
--- a/src/lib/components/v2/workflow/TaskInfoTab.svelte
+++ b/src/lib/components/v2/workflow/TaskInfoTab.svelte
@@ -1,8 +1,8 @@
 <script>
 	import { formatMarkdown } from '$lib/common/component_utilities';
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte';
 
-	/** @type {import("$lib/types-v2").TaskV2} */
+	/** @type {import("fractal-components/types/api").TaskV2} */
 	export let task;
 	/** @type {string | null} */
 	export let taskVersion;
diff --git a/src/lib/components/v2/workflow/TasksOrderModal.svelte b/src/lib/components/v2/workflow/TasksOrderModal.svelte
index b304f2e5..c3eff8be 100644
--- a/src/lib/components/v2/workflow/TasksOrderModal.svelte
+++ b/src/lib/components/v2/workflow/TasksOrderModal.svelte
@@ -3,10 +3,10 @@
 
 	/** @type {number} */
 	export let projectId;
-	/** @type {import('$lib/types-v2').WorkflowV2} */
+	/** @type {import('fractal-components/types/api').WorkflowV2} */
 	export let workflow;
 
-	/** @type {(workflow: import('$lib/types-v2').WorkflowV2) => void} */
+	/** @type {(workflow: import('fractal-components/types/api').WorkflowV2) => void} */
 	export let workflowUpdater;
 
 	/** @type {Modal} */
@@ -16,7 +16,7 @@
 	let editableTasksList = [];
 
 	/**
-	 * @param {import('$lib/types-v2').WorkflowTaskV2[]} originalTasksList
+	 * @param {import('fractal-components/types/api').WorkflowTaskV2[]} originalTasksList
 	 */
 	export function show(originalTasksList) {
 		editableTasksList = originalTasksList.map((wt) => ({
diff --git a/src/lib/components/v2/workflow/VersionUpdate.svelte b/src/lib/components/v2/workflow/VersionUpdate.svelte
index 70ca3939..4de4b358 100644
--- a/src/lib/components/v2/workflow/VersionUpdate.svelte
+++ b/src/lib/components/v2/workflow/VersionUpdate.svelte
@@ -5,12 +5,12 @@
 	import { tick } from 'svelte';
 	import { getNewVersions } from './version-checker';
 
-	/** @type {import('$lib/types-v2').WorkflowV2} */
+	/** @type {import('fractal-components/types/api').WorkflowV2} */
 	export let workflow;
-	/** @type {import('$lib/types-v2').WorkflowTaskV2} */
+	/** @type {import('fractal-components/types/api').WorkflowTaskV2} */
 	export let workflowTask;
 
-	/** @type {(workflowTask: import('$lib/types-v2').WorkflowTaskV2) => void} */
+	/** @type {(workflowTask: import('fractal-components/types/api').WorkflowTaskV2) => void} */
 	export let updateWorkflowCallback;
 	/** @type {(count: number) => Promise<void>} */
 	export let updateNewVersionsCount;
@@ -31,7 +31,7 @@
 	$: task = workflowTask.task;
 	let taskVersion = '';
 
-	/** @type {Array<import('$lib/types-v2').TaskV2 & { version: string }>} */
+	/** @type {Array<import('fractal-components/types/api').TaskV2 & { version: string }>} */
 	let updateCandidates = [];
 	let selectedUpdateVersion = '';
 
@@ -166,7 +166,7 @@
 	}
 
 	/**
-	 * @returns {Promise<import('$lib/types-v2').WorkflowTaskV2>}
+	 * @returns {Promise<import('fractal-components/types/api').WorkflowTaskV2>}
 	 */
 	async function createNewWorkflowTask() {
 		const newTaskId = updateCandidates.filter((t) => t.version === selectedUpdateVersion)[0].id;
@@ -199,7 +199,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').WorkflowTaskV2}  newWorkflowTask
+	 * @param {import('fractal-components/types/api').WorkflowTaskV2}  newWorkflowTask
 	 */
 	async function setNewWorkflowTaskPosition(newWorkflowTask) {
 		const reordered_workflowtask_ids = workflow.task_list.map((wft) =>
diff --git a/src/lib/components/v2/workflow/VersionUpdateFixArgs.svelte b/src/lib/components/v2/workflow/VersionUpdateFixArgs.svelte
index 1f46e8b4..7bca943e 100644
--- a/src/lib/components/v2/workflow/VersionUpdateFixArgs.svelte
+++ b/src/lib/components/v2/workflow/VersionUpdateFixArgs.svelte
@@ -3,9 +3,9 @@
 	import { AlertError } from '$lib/common/errors';
 	import { stripIgnoredProperties, getPropertiesToIgnore, SchemaValidator } from 'fractal-components';
 
-	/** @type {import('$lib/types-v2').WorkflowTaskV2} */
+	/** @type {import('fractal-components/types/api').WorkflowTaskV2} */
 	export let workflowTask;
-	/** @type {import('$lib/types').Task|import('$lib/types-v2').TaskV2} */
+	/** @type {import('$lib/types').Task|import('fractal-components/types/api').TaskV2} */
 	export let updateCandidate;
 	/** @type {boolean} */
 	export let parallel;
diff --git a/src/lib/components/v2/workflow/version-checker.js b/src/lib/components/v2/workflow/version-checker.js
index 102e1be4..cf3c6046 100644
--- a/src/lib/components/v2/workflow/version-checker.js
+++ b/src/lib/components/v2/workflow/version-checker.js
@@ -2,10 +2,10 @@ import { greatestVersionAsc, greatestVersionDesc } from '$lib/common/component_u
 import { getAlertErrorFromResponse } from '$lib/common/errors';
 
 /**
- * @param {import('$lib/types-v2').TaskV2} task
+ * @param {import('fractal-components/types/api').TaskV2} task
  * @returns {Promise<{
- *  updateCandidates: Array<import('$lib/types-v2').TaskV2 & { version: string }>
- *  enrichedTask: import('$lib/types-v2').TaskV2 & { version: string | null, pkg_name: string }
+ *  updateCandidates: Array<import('fractal-components/types/api').TaskV2 & { version: string }>
+ *  enrichedTask: import('fractal-components/types/api').TaskV2 & { version: string | null, pkg_name: string }
  * }>} updateCandidates is the list of update candidates for the given task,
  * enrichedTask it the task passed as input with additional fields extracted from related task group
  */
@@ -18,10 +18,10 @@ export async function getNewVersions(task) {
 }
 
 /**
- * @param {import('$lib/types-v2').TaskV2[]} tasks list of tasks inserted into a workflow
+ * @param {import('fractal-components/types/api').TaskV2[]} tasks list of tasks inserted into a workflow
  * @returns {Promise<{
- *  updateCandidates: { [id: string]: Array<import('$lib/types-v2').TaskV2 & { version: string }> }
- *  enrichedTasks: Array<import('$lib/types-v2').TaskV2 & { version: string | null, pkg_name: string }>
+ *  updateCandidates: { [id: string]: Array<import('fractal-components/types/api').TaskV2 & { version: string }> }
+ *  enrichedTasks: Array<import('fractal-components/types/api').TaskV2 & { version: string | null, pkg_name: string }>
  * }>} updateCandidates is a map having tasks ids as keys and update candidates list as values;
  * enrichedTasks is the list of tasks passed as input with additional fields extracted from related task groups
  */
@@ -32,11 +32,11 @@ export async function getAllNewVersions(tasks) {
 		throw await getAlertErrorFromResponse(response);
 	}
 
-	/** @type {import('$lib/types-v2').TaskGroupV2[]} */
+	/** @type {import('fractal-components/types/api').TaskGroupV2[]} */
 	const taskGroups = await response.json();
 
 	const enrichedTasks = tasks.map((t) => {
-		const taskGroup = /** @type {import('$lib/types-v2').TaskGroupV2} */ (
+		const taskGroup = /** @type {import('fractal-components/types/api').TaskGroupV2} */ (
 			taskGroups.find((tg) => tg.id === t.taskgroupv2_id)
 		);
 		return {
diff --git a/src/lib/server/api/v2/admin_api.js b/src/lib/server/api/v2/admin_api.js
index e4495598..68a2d7cc 100644
--- a/src/lib/server/api/v2/admin_api.js
+++ b/src/lib/server/api/v2/admin_api.js
@@ -7,7 +7,7 @@ const logger = getLogger('admin API [v2]');
 /**
  * Fetches the list of projects from the server
  * @param {typeof fetch} fetch
- * @returns {Promise<import('$lib/types-v2').ProjectV2[]>}
+ * @returns {Promise<import('fractal-components/types/api').ProjectV2[]>}
  */
 export async function listProjects(fetch) {
 	logger.debug('Fetching the list of projects');
diff --git a/src/lib/server/api/v2/dataset_api.js b/src/lib/server/api/v2/dataset_api.js
index 8f48ca4f..3080a3d0 100644
--- a/src/lib/server/api/v2/dataset_api.js
+++ b/src/lib/server/api/v2/dataset_api.js
@@ -12,7 +12,7 @@ const logger = getLogger('dataset API [v2]');
  * @param {number} page
  * @param {number} pageSize
  * @param {object} params
- * @returns {Promise<import('$lib/types-v2').ImagePage>}
+ * @returns {Promise<import('fractal-components/types/api').ImagePage>}
  */
 export async function getDatasetImages(fetch, projectId, datasetId, page, pageSize, params) {
 	logger.debug(
diff --git a/src/lib/server/api/v2/project_api.js b/src/lib/server/api/v2/project_api.js
index d714b6df..70521ab8 100644
--- a/src/lib/server/api/v2/project_api.js
+++ b/src/lib/server/api/v2/project_api.js
@@ -9,7 +9,7 @@ const logger = getLogger('projects API [v2]');
 /**
  * Fetches the list of projects from the server
  * @param {typeof fetch} fetch
- * @returns {Promise<import('$lib/types-v2').ProjectV2[]>}
+ * @returns {Promise<import('fractal-components/types/api').ProjectV2[]>}
  */
 export async function listProjects(fetch) {
 	logger.debug('Fetching the list of projects');
@@ -30,7 +30,7 @@ export async function listProjects(fetch) {
  * Fetches a project from the server
  * @param {typeof fetch} fetch
  * @param {string} projectId
- * @returns {Promise<import('$lib/types-v2').ProjectV2>}
+ * @returns {Promise<import('fractal-components/types/api').ProjectV2>}
  */
 export async function getProject(fetch, projectId) {
 	logger.debug('Fetching project [project_id=%d]', projectId);
@@ -53,7 +53,7 @@ export async function getProject(fetch, projectId) {
  * Fetches all the project's datasets from the server
  * @param {typeof fetch} fetch
  * @param {number|string} projectId
- * @returns {Promise<Array<import('$lib/types-v2').DatasetV2>>}
+ * @returns {Promise<Array<import('fractal-components/types/api').DatasetV2>>}
  */
 export async function getProjectDatasets(fetch, projectId) {
 	logger.debug('Retrieving project datasets [project_id=%d]', projectId);
@@ -70,7 +70,7 @@ export async function getProjectDatasets(fetch, projectId) {
 		await responseError(response);
 	}
 
-	/** @type {import('$lib/types-v2').DatasetV2[]} */
+	/** @type {import('fractal-components/types/api').DatasetV2[]} */
 	const datasets = await response.json();
 	datasets.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
 	return datasets;
@@ -81,7 +81,7 @@ export async function getProjectDatasets(fetch, projectId) {
  * @param {typeof fetch} fetch
  * @param {number|string} projectId
  * @param {number|string} datasetId
- * @returns {Promise<import('$lib/types-v2').DatasetV2>}
+ * @returns {Promise<import('fractal-components/types/api').DatasetV2>}
  */
 export async function getDataset(fetch, projectId, datasetId) {
 	logger.debug('Retrieving dataset [dataset_id=%d] [project_id=%d]', datasetId, projectId);
@@ -106,7 +106,7 @@ export async function getDataset(fetch, projectId, datasetId) {
 /**
  * Fetches the list of all the jobs belonging to the current user
  * @param {typeof fetch} fetch
- * @returns {Promise<Array<import('$lib/types-v2').ApplyWorkflowV2>>}
+ * @returns {Promise<Array<import('fractal-components/types/api').ApplyWorkflowV2>>}
  */
 export async function getUserJobs(fetch) {
 	logger.debug('Fetching user jobs');
diff --git a/src/lib/server/api/v2/task_api.js b/src/lib/server/api/v2/task_api.js
index 18e26d3b..56c3a2b0 100644
--- a/src/lib/server/api/v2/task_api.js
+++ b/src/lib/server/api/v2/task_api.js
@@ -9,7 +9,7 @@ const logger = getLogger('task API [v2]');
  * @param {typeof fetch} fetch
  * @param {boolean|false=} loadArgsSchema
  * @param {boolean|false=} onlyActive
- * @returns {Promise<Array<import('$lib/types-v2').TaskGroupV2>>}
+ * @returns {Promise<Array<import('fractal-components/types/api').TaskGroupV2>>}
  */
 export async function listTaskGroups(fetch, loadArgsSchema = false, onlyActive = false) {
 	logger.debug('Fetching task groups');
diff --git a/src/lib/server/api/v2/workflow_api.js b/src/lib/server/api/v2/workflow_api.js
index e2002d4a..32e37691 100644
--- a/src/lib/server/api/v2/workflow_api.js
+++ b/src/lib/server/api/v2/workflow_api.js
@@ -8,7 +8,7 @@ const logger = getLogger('workflow API [v2]');
  * Fetches the list of workflows of a project from the server
  * @param {typeof fetch} fetch
  * @param {number|string} projectId
- * @returns {Promise<Array<import('$lib/types-v2').WorkflowV2>>}
+ * @returns {Promise<Array<import('fractal-components/types/api').WorkflowV2>>}
  */
 export async function getWorkflows(fetch, projectId) {
 	logger.debug('Fetching project workflows [project_id=%d]', projectId);
@@ -30,7 +30,7 @@ export async function getWorkflows(fetch, projectId) {
  * @param {typeof fetch} fetch
  * @param {string} projectId
  * @param {string} workflowId
- * @returns {Promise<import('$lib/types-v2').WorkflowV2>}
+ * @returns {Promise<import('fractal-components/types/api').WorkflowV2>}
  */
 export async function getWorkflow(fetch, projectId, workflowId) {
 	logger.debug('Fetching workflow [workflow_id=%d] [project_id=%d]', workflowId, projectId);
@@ -59,7 +59,7 @@ export async function getWorkflow(fetch, projectId, workflowId) {
  * @param {typeof fetch} fetch
  * @param {number|string} projectId
  * @param {number|string} workflowId
- * @returns {Promise<Array<import('$lib/types-v2').ApplyWorkflowV2>>}
+ * @returns {Promise<Array<import('fractal-components/types/api').ApplyWorkflowV2>>}
  */
 export async function getWorkflowJobs(fetch, projectId, workflowId) {
 	logger.debug('Fetching workflow jobs [workflow_id=%d] [project_id=%d]', workflowId, projectId);
diff --git a/src/lib/stores/projectStores.js b/src/lib/stores/projectStores.js
index 9846249d..8b2bca60 100644
--- a/src/lib/stores/projectStores.js
+++ b/src/lib/stores/projectStores.js
@@ -5,7 +5,7 @@ import { writable } from 'svelte/store';
 // inside the store, will also update the to-be-displayed project in a modal.
 /** @type {import('svelte/store').Writable<import('$lib/types').Project|undefined>}} */
 export const projectInfoModal = writable(undefined);
-/** @type {import('svelte/store').Writable<import('$lib/types-v2').ProjectV2|undefined>}} */
+/** @type {import('svelte/store').Writable<import('fractal-components/types/api').ProjectV2|undefined>}} */
 export const projectInfoModalV2 = writable(undefined);
 
 // Context project store
diff --git a/src/routes/profile/+page.svelte b/src/routes/profile/+page.svelte
index a0b7895e..12e94bf9 100644
--- a/src/routes/profile/+page.svelte
+++ b/src/routes/profile/+page.svelte
@@ -1,6 +1,6 @@
 <script>
 	import { page } from '$app/stores';
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte';
 
 	/** @type {import('$lib/types').User & {group_ids_names: Array<[number, string]>}} */
 	$: user = $page.data.user;
diff --git a/src/routes/v2/admin/jobs/+page.svelte b/src/routes/v2/admin/jobs/+page.svelte
index 1073e74f..7ede050c 100644
--- a/src/routes/v2/admin/jobs/+page.svelte
+++ b/src/routes/v2/admin/jobs/+page.svelte
@@ -13,7 +13,7 @@
 
 	/** @type {JobsList} */
 	let jobsListComponent;
-	/** @type {import('$lib/types-v2').ApplyWorkflowV2[]} */
+	/** @type {import('fractal-components/types/api').ApplyWorkflowV2[]} */
 	let jobs = [];
 
 	let status;
@@ -35,12 +35,12 @@
 	let datasetId;
 
 	/**
-	 * @returns {Promise<import('$lib/types-v2').ApplyWorkflowV2[]>}
+	 * @returns {Promise<import('fractal-components/types/api').ApplyWorkflowV2[]>}
 	 */
 	async function jobUpdater() {
-		/** @type {import('$lib/types-v2').ApplyWorkflowV2[]} */
+		/** @type {import('fractal-components/types/api').ApplyWorkflowV2[]} */
 		const jobsToCheck = jobs.filter((j) => j.status === 'submitted');
-		/** @type {import('$lib/types-v2').ApplyWorkflowV2[]} */
+		/** @type {import('fractal-components/types/api').ApplyWorkflowV2[]} */
 		const updatedJobs = [];
 		for (const job of jobsToCheck) {
 			const url = new URL('/api/admin/v2/job', window.location.origin);
@@ -198,11 +198,11 @@
 
 	/** @type {Modal} */
 	let statusModal;
-	/** @type {import('$lib/types-v2').ApplyWorkflowV2|undefined} */
+	/** @type {import('fractal-components/types/api').ApplyWorkflowV2|undefined} */
 	let jobInEditing;
 
 	/**
-	 * @param {import('$lib/types-v2').ApplyWorkflowV2} row
+	 * @param {import('fractal-components/types/api').ApplyWorkflowV2} row
 	 */
 	function openEditStatusModal(row) {
 		jobInEditing = row;
@@ -215,7 +215,7 @@
 		statusModal.confirmAndHide(
 			async () => {
 				updatingStatus = true;
-				const jobId = /** @type {import('$lib/types-v2').ApplyWorkflowV2} */ (jobInEditing).id;
+				const jobId = /** @type {import('fractal-components/types/api').ApplyWorkflowV2} */ (jobInEditing).id;
 
 				const headers = new Headers();
 				headers.append('Content-Type', 'application/json');
diff --git a/src/routes/v2/admin/task-groups/+page.svelte b/src/routes/v2/admin/task-groups/+page.svelte
index 9aa5bc06..0afdf707 100644
--- a/src/routes/v2/admin/task-groups/+page.svelte
+++ b/src/routes/v2/admin/task-groups/+page.svelte
@@ -2,7 +2,7 @@
 	import { page } from '$app/stores';
 	import { getTimestamp } from '$lib/common/component_utilities';
 	import { displayStandardErrorAlert, getAlertErrorFromResponse } from '$lib/common/errors';
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte';
 	import ConfirmActionButton from '$lib/components/common/ConfirmActionButton.svelte';
 	import Modal from '$lib/components/common/Modal.svelte';
 	import TimestampCell from '$lib/components/jobs/TimestampCell.svelte';
@@ -32,12 +32,12 @@
 	/** @type {import('$lib/components/common/StandardErrorAlert.svelte').default|undefined} */
 	let searchErrorAlert;
 
-	/** @type {import('$lib/types-v2').TaskGroupV2[]} */
+	/** @type {import('fractal-components/types/api').TaskGroupV2[]} */
 	let results = [];
 
 	/** @type {Modal} */
 	let infoModal;
-	/** @type {import('$lib/types-v2').TaskGroupV2|null} */
+	/** @type {import('fractal-components/types/api').TaskGroupV2|null} */
 	let selectedTaskGroup = null;
 
 	/** @type {import('$lib/components/v2/tasks/TaskGroupEditModal.svelte').default} */
@@ -113,7 +113,7 @@
 
 	/**
 	 *
-	 * @param {import('$lib/types-v2').TaskGroupV2} taskGroup
+	 * @param {import('fractal-components/types/api').TaskGroupV2} taskGroup
 	 */
 	function openInfoModal(taskGroup) {
 		selectedTaskGroup = taskGroup;
diff --git a/src/routes/v2/admin/tasks/+page.svelte b/src/routes/v2/admin/tasks/+page.svelte
index 8eea6fff..31e6a913 100644
--- a/src/routes/v2/admin/tasks/+page.svelte
+++ b/src/routes/v2/admin/tasks/+page.svelte
@@ -13,12 +13,12 @@
 	/** @type {import('$lib/components/common/StandardErrorAlert.svelte').default|undefined} */
 	let searchErrorAlert;
 
-	/** @type {import('$lib/types-v2').TaskV2Info[]} */
+	/** @type {import('fractal-components/types/api').TaskV2Info[]} */
 	let results = [];
 
 	/** @type {Modal} */
 	let infoModal;
-	/** @type {import('$lib/types-v2').TaskV2Info|null} */
+	/** @type {import('fractal-components/types/api').TaskV2Info|null} */
 	let selectedTaskInfo = null;
 
 	async function searchTasks() {
@@ -69,7 +69,7 @@
 
 	/**
 	 *
-	 * @param {import('$lib/types-v2').TaskV2Info} taskInfo
+	 * @param {import('fractal-components/types/api').TaskV2Info} taskInfo
 	 */
 	function openInfoModal(taskInfo) {
 		selectedTaskInfo = taskInfo;
@@ -93,7 +93,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TaskV2Info} taskInfo
+	 * @param {import('fractal-components/types/api').TaskV2Info} taskInfo
 	 */
 	function getUsers(taskInfo) {
 		const allEntries = /** @type {string[]} */ (
diff --git a/src/routes/v2/admin/users/+page.svelte b/src/routes/v2/admin/users/+page.svelte
index 3b938440..d7d4a0fb 100644
--- a/src/routes/v2/admin/users/+page.svelte
+++ b/src/routes/v2/admin/users/+page.svelte
@@ -2,7 +2,7 @@
 	import { page } from '$app/stores';
 	import { getAlertErrorFromResponse } from '$lib/common/errors';
 	import { sortUsers } from '$lib/components/admin/user_utilities';
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte';
 	import ConfirmActionButton from '$lib/components/common/ConfirmActionButton.svelte';
 	import { onMount } from 'svelte';
 
diff --git a/src/routes/v2/admin/users/[userId]/+page.svelte b/src/routes/v2/admin/users/[userId]/+page.svelte
index 1f38a74c..474afde2 100644
--- a/src/routes/v2/admin/users/[userId]/+page.svelte
+++ b/src/routes/v2/admin/users/[userId]/+page.svelte
@@ -1,7 +1,7 @@
 <script>
 	import { page } from '$app/stores';
 	import { sortGroupByNameAllFirstComparator } from '$lib/components/admin/user_utilities.js';
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte';
 
 	/** @type {import('$lib/types').User & {group_ids_names: Array<[number, string]>}} */
 	const user = $page.data.user;
diff --git a/src/routes/v2/jobs/+page.svelte b/src/routes/v2/jobs/+page.svelte
index 0040f7be..60197561 100644
--- a/src/routes/v2/jobs/+page.svelte
+++ b/src/routes/v2/jobs/+page.svelte
@@ -3,7 +3,7 @@
 	import { getAlertErrorFromResponse } from '$lib/common/errors';
 
 	/**
-	 * @returns {Promise<import('$lib/types-v2').ApplyWorkflowV2[]>}
+	 * @returns {Promise<import('fractal-components/types/api').ApplyWorkflowV2[]>}
 	 */
 	async function jobUpdater() {
 		const response = await fetch(`/api/v2/job?log=false`, {
diff --git a/src/routes/v2/projects/[projectId]/datasets/[datasetId]/+page.svelte b/src/routes/v2/projects/[projectId]/datasets/[datasetId]/+page.svelte
index d44ede12..42905645 100644
--- a/src/routes/v2/projects/[projectId]/datasets/[datasetId]/+page.svelte
+++ b/src/routes/v2/projects/[projectId]/datasets/[datasetId]/+page.svelte
@@ -7,7 +7,7 @@
 	import DatasetInfoModal from '$lib/components/v2/projects/datasets/DatasetInfoModal.svelte';
 	import DatasetHistoryModal from '$lib/components/v2/projects/datasets/DatasetHistoryModal.svelte';
 	import CreateUpdateImageModal from '$lib/components/v2/projects/datasets/CreateUpdateImageModal.svelte';
-	import BooleanIcon from '$lib/components/common/BooleanIcon.svelte';
+	import BooleanIcon from 'fractal-components/common/BooleanIcon.svelte';
 	import SlimSelect from 'slim-select';
 	import { onMount, tick } from 'svelte';
 	import { objectChanged } from '$lib/common/component_utilities';
@@ -19,9 +19,9 @@
 
 	let projectId = $page.params.projectId;
 
-	/** @type {import('$lib/types-v2').DatasetV2} */
+	/** @type {import('fractal-components/types/api').DatasetV2} */
 	let dataset = $page.data.dataset;
-	/** @type {import('$lib/types-v2').ImagePage} */
+	/** @type {import('fractal-components/types/api').ImagePage} */
 	let imagePage = $page.data.imagePage;
 	let showTable = $page.data.imagePage.total_count > 0;
 	let searching = false;
@@ -88,7 +88,7 @@
 	}
 
 	/**
-	 * @returns {Promise<import('$lib/types-v2').Image|undefined>}
+	 * @returns {Promise<import('fractal-components/types/api').Image|undefined>}
 	 */
 	async function loadImageForSelectedPlate() {
 		const params = { filters: { attributes: { plate: selectedPlate } } };
@@ -107,7 +107,7 @@
 			console.error(`Unable to load image for plate ${selectedPlate}`);
 			return undefined;
 		}
-		/** @type {import('$lib/types-v2').ImagePage}*/
+		/** @type {import('fractal-components/types/api').ImagePage}*/
 		const result = await response.json();
 		if (result.images.length === 0) {
 			console.error(
@@ -236,12 +236,12 @@
 
 	let resetBtnActive = false;
 
-	/** @param {import('$lib/types-v2').ImagePage} imagePage */
+	/** @param {import('fractal-components/types/api').ImagePage} imagePage */
 	function getAttributeFilterBaseValues(imagePage) {
 		return Object.fromEntries(Object.keys(imagePage.attributes).map((k) => [k, null]));
 	}
 
-	/** @param {import('$lib/types-v2').ImagePage} imagePage */
+	/** @param {import('fractal-components/types/api').ImagePage} imagePage */
 	function getTypeFilterBaseValues(imagePage) {
 		return Object.fromEntries(imagePage.types.map((k) => [k, null]));
 	}
@@ -249,7 +249,7 @@
 	/**
 	 * Reload the attribute filters according to the received imagePage
 	 * preserving the values selected by the user
-	 * @param {import('$lib/types-v2').ImagePage} imagePage
+	 * @param {import('fractal-components/types/api').ImagePage} imagePage
 	 */
 	function reloadAttributeFilters(imagePage) {
 		attributeFilters = Object.fromEntries(
@@ -264,7 +264,7 @@
 	/**
 	 * Reload the type filters according to the received imagePage
 	 * preserving the values selected by the user
-	 * @param {import('$lib/types-v2').ImagePage} imagePage
+	 * @param {import('fractal-components/types/api').ImagePage} imagePage
 	 */
 	function reloadTypeFilters(imagePage) {
 		typeFilters = Object.fromEntries(
@@ -420,7 +420,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').DatasetV2} updatedDataset
+	 * @param {import('fractal-components/types/api').DatasetV2} updatedDataset
 	 */
 	async function updateDatasetFiltersCallback(updatedDataset) {
 		dataset = updatedDataset;
diff --git a/src/routes/v2/projects/[projectId]/workflows/[workflowId]/+page.svelte b/src/routes/v2/projects/[projectId]/workflows/[workflowId]/+page.svelte
index cb3e2fee..65ecb13f 100644
--- a/src/routes/v2/projects/[projectId]/workflows/[workflowId]/+page.svelte
+++ b/src/routes/v2/projects/[projectId]/workflows/[workflowId]/+page.svelte
@@ -21,19 +21,19 @@
 	import { getSelectedWorkflowDataset, saveSelectedDataset } from '$lib/common/workflow_utilities';
 	import AddWorkflowTaskModal from '$lib/components/v2/workflow/AddWorkflowTaskModal.svelte';
 
-	/** @type {import('$lib/types-v2').WorkflowV2} */
+	/** @type {import('fractal-components/types/api').WorkflowV2} */
 	let workflow = $page.data.workflow;
 	/** @type {number|undefined} */
 	let defaultDatasetId = $page.data.defaultDatasetId;
 	$: project = workflow.project;
-	/** @type {import('$lib/types-v2').DatasetV2[]} */
+	/** @type {import('fractal-components/types/api').DatasetV2[]} */
 	let datasets = $page.data.datasets;
 
 	/** @type {number|undefined} */
 	let selectedDatasetId = undefined;
 
 	let jobError = '';
-	/** @type {import('$lib/types-v2').ApplyWorkflowV2|undefined} */
+	/** @type {import('fractal-components/types/api').ApplyWorkflowV2|undefined} */
 	let failedJob;
 	/** @type {JobLogsModal} */
 	let jobLogsModal;
@@ -43,7 +43,7 @@
 
 	let workflowTabContextId = 0;
 	let workflowSuccessMessage = '';
-	/** @type {import('$lib/types-v2').WorkflowTaskV2|undefined} */
+	/** @type {import('fractal-components/types/api').WorkflowTaskV2|undefined} */
 	let selectedWorkflowTask = undefined;
 	let preventedSelectedTaskChange = undefined;
 
@@ -76,12 +76,12 @@
 	/** @type {Modal} */
 	let editWorkflowModal;
 
-	/** @type {{ [id: string]: import('$lib/types-v2').TaskV2[] }} */
+	/** @type {{ [id: string]: import('fractal-components/types/api').TaskV2[] }} */
 	let newVersionsMap = {};
 	/** @type {{ [id: string]: string | null }} */
 	let tasksVersions = {};
 
-	/** @type {import('$lib/types-v2').ApplyWorkflowV2|undefined} */
+	/** @type {import('fractal-components/types/api').ApplyWorkflowV2|undefined} */
 	let selectedSubmittedJob;
 
 	$: updatableWorkflowList = workflow.task_list || [];
@@ -225,7 +225,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').WorkflowV2} updatedWorkflow
+	 * @param {import('fractal-components/types/api').WorkflowV2} updatedWorkflow
 	 */
 	async function onWorkflowTaskAdded(updatedWorkflow) {
 		workflow = updatedWorkflow;
@@ -276,7 +276,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').WorkflowTaskV2} wft
+	 * @param {import('fractal-components/types/api').WorkflowTaskV2} wft
 	 */
 	async function setSelectedWorkflowTask(wft) {
 		await tick();
@@ -331,7 +331,7 @@
 
 	/**
 	 *
-	 * @param {import('$lib/types-v2').ApplyWorkflowV2} job
+	 * @param {import('fractal-components/types/api').ApplyWorkflowV2} job
 	 */
 	async function onJobSubmitted(job) {
 		selectedSubmittedJob = job;
@@ -340,7 +340,7 @@
 
 	/**
 	 * Called by VersionUpdate component at the end of the update to reload the workflow.
-	 * @param workflowTask {import('$lib/types-v2').WorkflowTaskV2}
+	 * @param workflowTask {import('fractal-components/types/api').WorkflowTaskV2}
 	 */
 	async function taskUpdated(workflowTask) {
 		if (!workflow) {
@@ -473,7 +473,7 @@
 			console.error('Error retrieving workflow jobs', await response.json());
 			return;
 		}
-		const jobs = /** @type {import('$lib/types-v2').ApplyWorkflowV2[]} */ (await response.json());
+		const jobs = /** @type {import('fractal-components/types/api').ApplyWorkflowV2[]} */ (await response.json());
 		const failedJobs = jobs
 			.filter((j) => j.dataset_id === selectedDatasetId && j.status === 'failed')
 			.sort((j1, j2) => (j1.start_timestamp < j2.start_timestamp ? 1 : -1));
@@ -495,7 +495,7 @@
 
 	/**
 	 * @param {number} datasetId
-	 * @return {Promise<import('$lib/types-v2').ApplyWorkflowV2|undefined>}
+	 * @return {Promise<import('fractal-components/types/api').ApplyWorkflowV2|undefined>}
 	 */
 	async function getSelectedSubmittedJob(datasetId) {
 		if (selectedSubmittedJob && selectedSubmittedJob.dataset_id === datasetId) {
@@ -506,7 +506,7 @@
 			credentials: 'include'
 		});
 		if (response.ok) {
-			/** @type {import('$lib/types-v2').ApplyWorkflowV2[]} */
+			/** @type {import('fractal-components/types/api').ApplyWorkflowV2[]} */
 			const allJobs = await response.json();
 			const jobs = allJobs
 				.filter((j) => j.dataset_id === datasetId)
@@ -545,7 +545,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').WorkflowTaskV2} updatedWft
+	 * @param {import('fractal-components/types/api').WorkflowTaskV2} updatedWft
 	 */
 	function onWorkflowTaskUpdated(updatedWft) {
 		selectedWorkflowTask = updatedWft;
@@ -557,7 +557,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').WorkflowTaskV2} updatedWft
+	 * @param {import('fractal-components/types/api').WorkflowTaskV2} updatedWft
 	 */
 	function onInputFiltersUpdated(updatedWft) {
 		selectedWorkflowTask = updatedWft;
diff --git a/src/routes/v2/projects/[projectId]/workflows/[workflowId]/jobs/+page.svelte b/src/routes/v2/projects/[projectId]/workflows/[workflowId]/jobs/+page.svelte
index e68b8d6d..21efe9c4 100644
--- a/src/routes/v2/projects/[projectId]/workflows/[workflowId]/jobs/+page.svelte
+++ b/src/routes/v2/projects/[projectId]/workflows/[workflowId]/jobs/+page.svelte
@@ -3,13 +3,13 @@
 	import { page } from '$app/stores';
 	import { getAlertErrorFromResponse } from '$lib/common/errors';
 
-	/** @type {import('$lib/types-v2').ProjectV2} */
+	/** @type {import('fractal-components/types/api').ProjectV2} */
 	let project = $page.data.project;
 	/** @type {import('$lib/types').Workflow} */
 	let workflow = $page.data.workflow;
 
 	/**
-	 * @returns {Promise<import('$lib/types-v2').ApplyWorkflowV2[]>}
+	 * @returns {Promise<import('fractal-components/types/api').ApplyWorkflowV2[]>}
 	 */
 	async function jobUpdater() {
 		const response = await fetch(`/api/v2/project/${project.id}/workflow/${workflow.id}/job`, {
diff --git a/src/routes/v2/tasks/+page.server.js b/src/routes/v2/tasks/+page.server.js
index 801cf6d2..48026073 100644
--- a/src/routes/v2/tasks/+page.server.js
+++ b/src/routes/v2/tasks/+page.server.js
@@ -1,4 +1,4 @@
-import { removeIdenticalTaskGroups } from '$lib/components/v2/tasks/task_group_utilities';
+import { removeIdenticalTaskGroups } from 'fractal-components/tasks/task_group_utilities';
 import { getCurrentUser } from '$lib/server/api/auth_api.js';
 import { listTaskGroups } from '$lib/server/api/v2/task_api';
 
diff --git a/src/routes/v2/tasks/+page.svelte b/src/routes/v2/tasks/+page.svelte
index bc00008d..2c91d1b9 100644
--- a/src/routes/v2/tasks/+page.svelte
+++ b/src/routes/v2/tasks/+page.svelte
@@ -2,19 +2,19 @@
 	import { page } from '$app/stores';
 	import { formatMarkdown } from '$lib/common/component_utilities';
 	import Modal from '$lib/components/common/Modal.svelte';
-	import FilteredTasksTable from '$lib/components/v2/tasks/FilteredTasksTable.svelte';
+	import FilteredTasksTable from 'fractal-components/tasks/FilteredTasksTable.svelte';
 
-	/** @type {import('$lib/types-v2').TaskGroupV2[]} */
+	/** @type {import('fractal-components/types/api').TaskGroupV2[]} */
 	let taskGroups = $page.data.taskGroups;
 
 	/** @type {Modal} */
 	let modal;
 
-	/** @type {import('$lib/types-v2').TasksTableRow|null} */
+	/** @type {import('fractal-components/types/api').TasksTableRow|null} */
 	let selectedTaskRow = null;
 
 	/**
-	 * @param {import('$lib/types-v2').TasksTableRow} taskRow
+	 * @param {import('fractal-components/types/api').TasksTableRow} taskRow
 	 */
 	function showDocsInfoModal(taskRow) {
 		selectedTaskRow = taskRow;
diff --git a/src/routes/v2/tasks/management/+page.server.js b/src/routes/v2/tasks/management/+page.server.js
index 9d2eba87..c9136a26 100644
--- a/src/routes/v2/tasks/management/+page.server.js
+++ b/src/routes/v2/tasks/management/+page.server.js
@@ -1,4 +1,4 @@
-import { removeIdenticalTaskGroups } from '$lib/components/v2/tasks/task_group_utilities';
+import { removeIdenticalTaskGroups } from 'fractal-components/tasks/task_group_utilities';
 import { getCurrentUser } from '$lib/server/api/auth_api.js';
 import { listTaskGroups } from '$lib/server/api/v2/task_api';
 
diff --git a/src/routes/v2/tasks/management/+page.svelte b/src/routes/v2/tasks/management/+page.svelte
index f1bdda45..ceca0fc5 100644
--- a/src/routes/v2/tasks/management/+page.svelte
+++ b/src/routes/v2/tasks/management/+page.svelte
@@ -6,7 +6,7 @@
 	import CustomEnvTask from '$lib/components/v2/tasks/CustomEnvTask.svelte';
 	import TaskGroupsTable from '$lib/components/v2/tasks/TaskGroupsTable.svelte';
 
-	/** @type {import('$lib/types-v2').TaskGroupV2[]} */
+	/** @type {import('fractal-components/types/api').TaskGroupV2[]} */
 	let taskGroups = $page.data.taskGroups;
 
 	/** @type {'pypi'|'local'|'single'|'custom_env'} */
@@ -32,7 +32,7 @@
 	}
 
 	/**
-	 * @param {import('$lib/types-v2').TaskGroupV2[]} updatedGroups
+	 * @param {import('fractal-components/types/api').TaskGroupV2[]} updatedGroups
 	 */
 	function updateTaskGroups(updatedGroups) {
 		taskGroups = updatedGroups;
diff --git a/tests/v2/add_single_task.spec.js b/tests/v2/add_single_task.spec.js
index 984b2214..7a66d4f7 100644
--- a/tests/v2/add_single_task.spec.js
+++ b/tests/v2/add_single_task.spec.js
@@ -239,7 +239,7 @@ test('Add single tasks [v2]', async ({ page }) => {
 /**
  * @param {import('@playwright/test').Page} page
  * @param {string} taskName
- * @param {import('$lib/types-v2.js').TaskV2Type} taskType
+ * @param {import('fractal-components/types/api.js').TaskV2Type} taskType
  */
 async function getCreatedTaskModalData(page, taskName, taskType) {
 	const row = await getCreatedTaskRow(page, taskName);
diff --git a/tests/v2/task_utils.js b/tests/v2/task_utils.js
index c3b04e4d..0706166f 100644
--- a/tests/v2/task_utils.js
+++ b/tests/v2/task_utils.js
@@ -9,7 +9,7 @@ const __dirname = path.dirname(__filename);
 
 /**
  * @param {import('@playwright/test').Page} page
- * @param {Partial<import('$lib/types-v2').TaskV2 & { version: string | null }>} task
+ * @param {Partial<import('fractal-components/types/api').TaskV2 & { version: string | null }>} task
  * @returns {Promise<string>} the name of the created task
  */
 export async function createFakeTask(page, task) {