@@ -143,7 +178,7 @@ const exportPack = async () => {
- Select files and folders to include in pack
+ {{ formatMessage(messages.selectFilesLabel) }}
diff --git a/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue b/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue
index 93cf9bc553..fa1055e514 100644
--- a/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue
+++ b/apps/app-frontend/src/components/ui/instance_settings/InstallationSettings.vue
@@ -1,22 +1,18 @@
diff --git a/apps/app-frontend/src/components/ui/modal/ShareModalWrapper.vue b/apps/app-frontend/src/components/ui/modal/ShareModalWrapper.vue
index 9358ee908c..3ac556f5a0 100644
--- a/apps/app-frontend/src/components/ui/modal/ShareModalWrapper.vue
+++ b/apps/app-frontend/src/components/ui/modal/ShareModalWrapper.vue
@@ -1,12 +1,8 @@
+
@@ -56,7 +46,5 @@ function onModalHide() {
:share-text="shareText"
:link="link"
:open-in-new-tab="openInNewTab"
- :on-hide="onModalHide"
- :noblur="!themeStore.advancedRendering"
/>
diff --git a/apps/app-frontend/src/helpers/cache.js b/apps/app-frontend/src/helpers/cache.js
index 6c63126646..d19be21693 100644
--- a/apps/app-frontend/src/helpers/cache.js
+++ b/apps/app-frontend/src/helpers/cache.js
@@ -51,3 +51,17 @@ export async function get_search_results_many(ids, cacheBehaviour) {
export async function purge_cache_types(cacheTypes) {
return await invoke('plugin:cache|purge_cache_types', { cacheTypes })
}
+
+/**
+ * Get versions for a project (without changelogs for fast loading).
+ * Uses the cache system - versions are cached for 30 minutes.
+ * @param {string} projectId - The project ID
+ * @param {string} [cacheBehaviour] - Cache behaviour ('must_revalidate', etc.)
+ * @returns {Promise} Array of version objects (without changelogs) or null
+ */
+export async function get_project_versions(projectId, cacheBehaviour) {
+ return await invoke('plugin:cache|get_project_versions', {
+ projectId,
+ cacheBehaviour,
+ })
+}
diff --git a/apps/app-frontend/src/helpers/profile.js b/apps/app-frontend/src/helpers/profile.js
deleted file mode 100644
index 7c3f1090f4..0000000000
--- a/apps/app-frontend/src/helpers/profile.js
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * All theseus API calls return serialized values (both return values and errors);
- * So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
- * and deserialized into a usable JS object.
- */
-import { invoke } from '@tauri-apps/api/core'
-
-import { install_to_existing_profile } from '@/helpers/pack.js'
-
-/// Add instance
-/*
- name: String, // the name of the profile, and relative path to create
- game_version: String, // the game version of the profile
- modloader: ModLoader, // the modloader to use
- - ModLoader is an enum, with the following variants: Vanilla, Forge, Fabric, Quilt
- loader_version: String, // the modloader version to use, set to "latest", "stable", or the ID of your chosen loader
- icon: Path, // the icon for the profile
- - icon is a path to an image file, which will be copied into the profile directory
-*/
-
-export async function create(name, gameVersion, modloader, loaderVersion, icon, skipInstall) {
- //Trim string name to avoid "Unable to find directory"
- name = name.trim()
- return await invoke('plugin:profile-create|profile_create', {
- name,
- gameVersion,
- modloader,
- loaderVersion,
- icon,
- skipInstall,
- })
-}
-
-// duplicate a profile
-export async function duplicate(path) {
- return await invoke('plugin:profile-create|profile_duplicate', { path })
-}
-
-// Remove a profile
-export async function remove(path) {
- return await invoke('plugin:profile|profile_remove', { path })
-}
-
-// Get a profile by path
-// Returns a Profile
-export async function get(path) {
- return await invoke('plugin:profile|profile_get', { path })
-}
-
-export async function get_many(paths) {
- return await invoke('plugin:profile|profile_get_many', { paths })
-}
-
-// Get a profile's projects
-// Returns a map of a path to profile file
-export async function get_projects(path, cacheBehaviour) {
- return await invoke('plugin:profile|profile_get_projects', { path, cacheBehaviour })
-}
-
-// Get a profile's full fs path
-// Returns a path
-export async function get_full_path(path) {
- return await invoke('plugin:profile|profile_get_full_path', { path })
-}
-
-// Get's a mod's full fs path
-// Returns a path
-export async function get_mod_full_path(path, projectPath) {
- return await invoke('plugin:profile|profile_get_mod_full_path', { path, projectPath })
-}
-
-// Get optimal java version from profile
-// Returns a java version
-export async function get_optimal_jre_key(path) {
- return await invoke('plugin:profile|profile_get_optimal_jre_key', { path })
-}
-
-// Get a copy of the profile set
-// Returns hashmap of path -> Profile
-export async function list() {
- return await invoke('plugin:profile|profile_list')
-}
-
-export async function check_installed(path, projectId) {
- return await invoke('plugin:profile|profile_check_installed', { path, projectId })
-}
-
-// Installs/Repairs a profile
-export async function install(path, force) {
- return await invoke('plugin:profile|profile_install', { path, force })
-}
-
-// Updates all of a profile's projects
-export async function update_all(path) {
- return await invoke('plugin:profile|profile_update_all', { path })
-}
-
-// Updates a specified project
-export async function update_project(path, projectPath) {
- return await invoke('plugin:profile|profile_update_project', { path, projectPath })
-}
-
-// Add a project to a profile from a version
-// Returns a path to the new project file
-export async function add_project_from_version(path, versionId) {
- return await invoke('plugin:profile|profile_add_project_from_version', { path, versionId })
-}
-
-// Add a project to a profile from a path + project_type
-// Returns a path to the new project file
-export async function add_project_from_path(path, projectPath, projectType) {
- return await invoke('plugin:profile|profile_add_project_from_path', {
- path,
- projectPath,
- projectType,
- })
-}
-
-// Toggle disabling a project
-export async function toggle_disable_project(path, projectPath) {
- return await invoke('plugin:profile|profile_toggle_disable_project', { path, projectPath })
-}
-
-// Remove a project
-export async function remove_project(path, projectPath) {
- return await invoke('plugin:profile|profile_remove_project', { path, projectPath })
-}
-
-// Update a managed Modrinth profile to a specific version
-export async function update_managed_modrinth_version(path, versionId) {
- return await invoke('plugin:profile|profile_update_managed_modrinth_version', {
- path,
- versionId,
- })
-}
-
-// Repair a managed Modrinth profile
-export async function update_repair_modrinth(path) {
- return await invoke('plugin:profile|profile_repair_managed_modrinth', { path })
-}
-
-// Export a profile to .mrpack
-/// included_overrides is an array of paths to override folders to include (ie: 'mods', 'resource_packs')
-// Version id is optional (ie: 1.1.5)
-export async function export_profile_mrpack(
- path,
- exportLocation,
- includedOverrides,
- versionId,
- description,
- name,
-) {
- return await invoke('plugin:profile|profile_export_mrpack', {
- path,
- exportLocation,
- includedOverrides,
- versionId,
- description,
- name,
- })
-}
-
-// Given a folder path, populate an array of all the subfolders
-// Intended to be used for finding potential override folders
-// profile
-// -- mods
-// -- resourcepacks
-// -- file1
-// => [mods, resourcepacks]
-// allows selection for 'included_overrides' in export_profile_mrpack
-export async function get_pack_export_candidates(profilePath) {
- return await invoke('plugin:profile|profile_get_pack_export_candidates', { profilePath })
-}
-
-// Run Minecraft using a pathed profile
-// Returns PID of child
-export async function run(path) {
- return await invoke('plugin:profile|profile_run', { path })
-}
-
-export async function kill(path) {
- return await invoke('plugin:profile|profile_kill', { path })
-}
-
-// Edits a profile
-export async function edit(path, editProfile) {
- return await invoke('plugin:profile|profile_edit', { path, editProfile })
-}
-
-// Edits a profile's icon
-export async function edit_icon(path, iconPath) {
- return await invoke('plugin:profile|profile_edit_icon', { path, iconPath })
-}
-
-export async function finish_install(instance) {
- if (instance.install_stage !== 'pack_installed') {
- let linkedData = instance.linked_data
- await install_to_existing_profile(
- linkedData.project_id,
- linkedData.version_id,
- instance.name,
- instance.path,
- )
- } else {
- await install(instance.path, false)
- }
-}
diff --git a/apps/app-frontend/src/helpers/profile.ts b/apps/app-frontend/src/helpers/profile.ts
new file mode 100644
index 0000000000..96b6676712
--- /dev/null
+++ b/apps/app-frontend/src/helpers/profile.ts
@@ -0,0 +1,287 @@
+/**
+ * All theseus API calls return serialized values (both return values and errors);
+ * So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
+ * and deserialized into a usable JS object.
+ */
+import type { Labrinth } from '@modrinth/api-client'
+import type { ContentItem, ContentOwner } from '@modrinth/ui'
+import { invoke } from '@tauri-apps/api/core'
+
+import { install_to_existing_profile } from '@/helpers/pack.js'
+
+import type {
+ CacheBehaviour,
+ ContentFile,
+ ContentFileProjectType,
+ GameInstance,
+ InstanceLoader,
+} from './types'
+
+// Add instance
+/*
+ name: String, // the name of the profile, and relative path to create
+ game_version: String, // the game version of the profile
+ modloader: ModLoader, // the modloader to use
+ - ModLoader is an enum, with the following variants: Vanilla, Forge, Fabric, Quilt
+ loader_version: String, // the modloader version to use, set to "latest", "stable", or the ID of your chosen loader
+ icon: Path, // the icon for the profile
+ - icon is a path to an image file, which will be copied into the profile directory
+*/
+
+export async function create(
+ name: string,
+ gameVersion: string,
+ modloader: InstanceLoader,
+ loaderVersion: string | null,
+ icon: string | null,
+ skipInstall: boolean,
+): Promise {
+ // Trim string name to avoid "Unable to find directory"
+ name = name.trim()
+ return await invoke('plugin:profile-create|profile_create', {
+ name,
+ gameVersion,
+ modloader,
+ loaderVersion,
+ icon,
+ skipInstall,
+ })
+}
+
+// duplicate a profile
+export async function duplicate(path: string): Promise {
+ return await invoke('plugin:profile-create|profile_duplicate', { path })
+}
+
+// Remove a profile
+export async function remove(path: string): Promise {
+ return await invoke('plugin:profile|profile_remove', { path })
+}
+
+// Get a profile by path
+// Returns a Profile
+export async function get(path: string): Promise {
+ return await invoke('plugin:profile|profile_get', { path })
+}
+
+export async function get_many(paths: string[]): Promise {
+ return await invoke('plugin:profile|profile_get_many', { paths })
+}
+
+// Get a profile's projects
+// Returns a map of a path to profile file
+export async function get_projects(
+ path: string,
+ cacheBehaviour?: CacheBehaviour,
+): Promise> {
+ return await invoke('plugin:profile|profile_get_projects', { path, cacheBehaviour })
+}
+
+// Get content items with rich metadata for a profile
+// Returns content items filtered to exclude modpack files (if linked),
+// sorted alphabetically by project name
+export async function get_content_items(
+ path: string,
+ cacheBehaviour?: CacheBehaviour,
+): Promise {
+ return await invoke('plugin:profile|profile_get_content_items', { path, cacheBehaviour })
+}
+
+// Linked modpack info returned from backend
+export interface LinkedModpackInfo {
+ project: Labrinth.Projects.v2.Project
+ version: Labrinth.Versions.v2.Version
+ owner: ContentOwner | null
+ has_update: boolean
+ update_version_id: string | null
+ update_version: Labrinth.Versions.v2.Version | null
+}
+
+// Get linked modpack info for a profile
+// Returns project, version, and owner information for the linked modpack,
+// or null if the profile is not linked to a modpack
+export async function get_linked_modpack_info(
+ path: string,
+ cacheBehaviour?: CacheBehaviour,
+): Promise {
+ return await invoke('plugin:profile|profile_get_linked_modpack_info', { path, cacheBehaviour })
+}
+
+// Get content items that are part of the linked modpack
+// Returns the modpack's dependencies as ContentItem list
+// Returns empty array if the profile is not linked to a modpack
+export async function get_linked_modpack_content(
+ path: string,
+ cacheBehaviour?: CacheBehaviour,
+): Promise {
+ return await invoke('plugin:profile|profile_get_linked_modpack_content', { path, cacheBehaviour })
+}
+
+// Convert a list of dependencies into ContentItems with rich metadata
+export async function get_dependencies_as_content_items(
+ dependencies: Labrinth.Versions.v3.Dependency[],
+ cacheBehaviour?: CacheBehaviour,
+): Promise {
+ return await invoke('plugin:profile|profile_get_dependencies_as_content_items', {
+ dependencies,
+ cacheBehaviour,
+ })
+}
+
+// Get a profile's full fs path
+// Returns a path
+export async function get_full_path(path: string): Promise {
+ return await invoke('plugin:profile|profile_get_full_path', { path })
+}
+
+// Get's a mod's full fs path
+// Returns a path
+export async function get_mod_full_path(path: string, projectPath: string): Promise {
+ return await invoke('plugin:profile|profile_get_mod_full_path', { path, projectPath })
+}
+
+// Get optimal java version from profile
+// Returns a java version
+export async function get_optimal_jre_key(path: string): Promise {
+ return await invoke('plugin:profile|profile_get_optimal_jre_key', { path })
+}
+
+// Get a copy of the profile set
+// Returns hashmap of path -> Profile
+export async function list(): Promise {
+ return await invoke('plugin:profile|profile_list')
+}
+
+export async function check_installed(path: string, projectId: string): Promise {
+ return await invoke('plugin:profile|profile_check_installed', { path, projectId })
+}
+
+// Installs/Repairs a profile
+export async function install(path: string, force: boolean): Promise {
+ return await invoke('plugin:profile|profile_install', { path, force })
+}
+
+// Updates all of a profile's projects
+export async function update_all(path: string): Promise> {
+ return await invoke('plugin:profile|profile_update_all', { path })
+}
+
+// Updates a specified project
+export async function update_project(path: string, projectPath: string): Promise {
+ return await invoke('plugin:profile|profile_update_project', { path, projectPath })
+}
+
+// Add a project to a profile from a version
+// Returns a path to the new project file
+export async function add_project_from_version(path: string, versionId: string): Promise {
+ return await invoke('plugin:profile|profile_add_project_from_version', { path, versionId })
+}
+
+// Add a project to a profile from a path + project_type
+// Returns a path to the new project file
+export async function add_project_from_path(
+ path: string,
+ projectPath: string,
+ projectType?: ContentFileProjectType,
+): Promise {
+ return await invoke('plugin:profile|profile_add_project_from_path', {
+ path,
+ projectPath,
+ projectType,
+ })
+}
+
+// Toggle disabling a project
+export async function toggle_disable_project(path: string, projectPath: string): Promise {
+ return await invoke('plugin:profile|profile_toggle_disable_project', { path, projectPath })
+}
+
+// Remove a project
+export async function remove_project(path: string, projectPath: string): Promise {
+ return await invoke('plugin:profile|profile_remove_project', { path, projectPath })
+}
+
+// Update a managed Modrinth profile to a specific version
+export async function update_managed_modrinth_version(
+ path: string,
+ versionId: string,
+): Promise {
+ return await invoke('plugin:profile|profile_update_managed_modrinth_version', {
+ path,
+ versionId,
+ })
+}
+
+// Repair a managed Modrinth profile
+export async function update_repair_modrinth(path: string): Promise {
+ return await invoke('plugin:profile|profile_repair_managed_modrinth', { path })
+}
+
+// Export a profile to .mrpack
+// included_overrides is an array of paths to override folders to include (ie: 'mods', 'resource_packs')
+// Version id is optional (ie: 1.1.5)
+export async function export_profile_mrpack(
+ path: string,
+ exportLocation: string,
+ includedOverrides: string[],
+ versionId?: string,
+ description?: string,
+ name?: string,
+): Promise {
+ return await invoke('plugin:profile|profile_export_mrpack', {
+ path,
+ exportLocation,
+ includedOverrides,
+ versionId,
+ description,
+ name,
+ })
+}
+
+// Given a folder path, populate an array of all the subfolders
+// Intended to be used for finding potential override folders
+// profile
+// -- mods
+// -- resourcepacks
+// -- file1
+// => [mods, resourcepacks]
+// allows selection for 'included_overrides' in export_profile_mrpack
+export async function get_pack_export_candidates(profilePath: string): Promise {
+ return await invoke('plugin:profile|profile_get_pack_export_candidates', { profilePath })
+}
+
+// Run Minecraft using a pathed profile
+// Returns PID of child
+export async function run(path: string): Promise {
+ return await invoke('plugin:profile|profile_run', { path })
+}
+
+export async function kill(path: string): Promise {
+ return await invoke('plugin:profile|profile_kill', { path })
+}
+
+// Edits a profile
+export async function edit(path: string, editProfile: Partial): Promise {
+ return await invoke('plugin:profile|profile_edit', { path, editProfile })
+}
+
+// Edits a profile's icon
+export async function edit_icon(path: string, iconPath: string | null): Promise {
+ return await invoke('plugin:profile|profile_edit_icon', { path, iconPath })
+}
+
+export async function finish_install(instance: GameInstance): Promise {
+ if (instance.install_stage !== 'pack_installed') {
+ const linkedData = instance.linked_data
+ if (linkedData) {
+ await install_to_existing_profile(
+ linkedData.project_id,
+ linkedData.version_id,
+ instance.name,
+ instance.path,
+ )
+ }
+ } else {
+ await install(instance.path, false)
+ }
+}
diff --git a/apps/app-frontend/src/helpers/types.d.ts b/apps/app-frontend/src/helpers/types.d.ts
index 8e6ac8b416..c3b46e3d49 100644
--- a/apps/app-frontend/src/helpers/types.d.ts
+++ b/apps/app-frontend/src/helpers/types.d.ts
@@ -49,17 +49,10 @@ type LinkedData = {
type InstanceLoader = 'vanilla' | 'forge' | 'fabric' | 'quilt' | 'neoforge'
type ContentFile = {
- hash: string
- file_name: string
- size: number
- metadata?: FileMetadata
- update_version_id?: string
- project_type: ContentFileProjectType
-}
-
-type FileMetadata = {
- project_id: string
- version_id: string
+ metadata?: {
+ project_id: string
+ version_id: string
+ }
}
type ContentFileProjectType = 'mod' | 'datapack' | 'resourcepack' | 'shaderpack'
diff --git a/apps/app-frontend/src/locales/en-US/index.json b/apps/app-frontend/src/locales/en-US/index.json
index d621401151..81c3e9ce82 100644
--- a/apps/app-frontend/src/locales/en-US/index.json
+++ b/apps/app-frontend/src/locales/en-US/index.json
@@ -5,6 +5,66 @@
"app.auth-servers.unreachable.header": {
"message": "Cannot reach authentication servers"
},
+ "app.export-modal.description-placeholder": {
+ "message": "Enter modpack description..."
+ },
+ "app.export-modal.export-button": {
+ "message": "Export"
+ },
+ "app.export-modal.header": {
+ "message": "Export modpack"
+ },
+ "app.export-modal.modpack-name-label": {
+ "message": "Modpack Name"
+ },
+ "app.export-modal.modpack-name-placeholder": {
+ "message": "Modpack name"
+ },
+ "app.export-modal.select-files-label": {
+ "message": "Select files and folders to include in pack"
+ },
+ "app.export-modal.version-number-label": {
+ "message": "Version number"
+ },
+ "app.export-modal.version-number-placeholder": {
+ "message": "1.0.0"
+ },
+ "app.instance.mods.content-type-project": {
+ "message": "project"
+ },
+ "app.instance.mods.copy-link": {
+ "message": "Copy link"
+ },
+ "app.instance.mods.installing": {
+ "message": "Installing..."
+ },
+ "app.instance.mods.modpack-fallback": {
+ "message": "Modpack"
+ },
+ "app.instance.mods.project-was-added": {
+ "message": "\"{name}\" was added"
+ },
+ "app.instance.mods.projects-were-added": {
+ "message": "{count} projects were added"
+ },
+ "app.instance.mods.share-text": {
+ "message": "Check out the projects I'm using in my modpack!"
+ },
+ "app.instance.mods.share-title": {
+ "message": "Sharing modpack content"
+ },
+ "app.instance.mods.show-file": {
+ "message": "Show file"
+ },
+ "app.instance.mods.successfully-uploaded": {
+ "message": "Successfully uploaded"
+ },
+ "app.instance.mods.unknown-version": {
+ "message": "Unknown"
+ },
+ "app.instance.mods.updating": {
+ "message": "Updating..."
+ },
"app.modal.install-to-play.header": {
"message": "Install to play"
},
@@ -230,12 +290,6 @@
"instance.edit-world.title": {
"message": "Edit world"
},
- "instance.filter.disabled": {
- "message": "Disabled projects"
- },
- "instance.filter.updates-available": {
- "message": "Updates available"
- },
"instance.server-modal.address": {
"message": "Address"
},
@@ -350,30 +404,12 @@
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
"message": "Vanilla {game_version} already installed"
},
- "instance.settings.tabs.installation.change-version.button": {
- "message": "Change version"
- },
"instance.settings.tabs.installation.change-version.button.install": {
"message": "Install"
},
"instance.settings.tabs.installation.change-version.button.installing": {
"message": "Installing"
},
- "instance.settings.tabs.installation.change-version.cannot-while-fetching": {
- "message": "Fetching modpack versions"
- },
- "instance.settings.tabs.installation.change-version.in-progress": {
- "message": "Installing new version"
- },
- "instance.settings.tabs.installation.currently-installed": {
- "message": "Currently installed"
- },
- "instance.settings.tabs.installation.debug-information": {
- "message": "Debug information:"
- },
- "instance.settings.tabs.installation.fetching-modpack-details": {
- "message": "Fetching modpack details"
- },
"instance.settings.tabs.installation.game-version": {
"message": "Game version"
},
@@ -386,18 +422,9 @@
"instance.settings.tabs.installation.loader-version": {
"message": "{loader} version"
},
- "instance.settings.tabs.installation.minecraft-version": {
- "message": "Minecraft {version}"
- },
- "instance.settings.tabs.installation.no-connection": {
- "message": "Cannot fetch linked modpack details. Please check your internet connection."
- },
"instance.settings.tabs.installation.no-loader-versions": {
"message": "{loader} is not available for Minecraft {version}. Try another mod loader."
},
- "instance.settings.tabs.installation.no-modpack-found": {
- "message": "This instance is linked to a modpack, but the modpack could not be found on Modrinth."
- },
"instance.settings.tabs.installation.platform": {
"message": "Platform"
},
@@ -431,18 +458,21 @@
"instance.settings.tabs.installation.repair.confirm.title": {
"message": "Repair instance?"
},
+ "instance.settings.tabs.installation.repair.description": {
+ "message": "Reinstalls Minecraft dependencies and checks for corruption. This may resolve issues if your game is not launching due to launcher-related errors."
+ },
"instance.settings.tabs.installation.repair.in-progress": {
"message": "Repair in progress"
},
+ "instance.settings.tabs.installation.repair.title": {
+ "message": "Repair instance"
+ },
"instance.settings.tabs.installation.reset-selections": {
"message": "Reset to current"
},
"instance.settings.tabs.installation.show-all-versions": {
"message": "Show all versions"
},
- "instance.settings.tabs.installation.tooltip.action.change-version": {
- "message": "change version"
- },
"instance.settings.tabs.installation.tooltip.action.install": {
"message": "install"
},
@@ -464,21 +494,6 @@
"instance.settings.tabs.installation.unknown-version": {
"message": "(unknown version)"
},
- "instance.settings.tabs.installation.unlink.button": {
- "message": "Unlink instance"
- },
- "instance.settings.tabs.installation.unlink.confirm.description": {
- "message": "If you proceed, you will not be able to re-link it without creating an entirely new instance. You will no longer receive modpack updates and it will become a normal."
- },
- "instance.settings.tabs.installation.unlink.confirm.title": {
- "message": "Are you sure you want to unlink this instance?"
- },
- "instance.settings.tabs.installation.unlink.description": {
- "message": "This instance is linked to a modpack, which means mods can't be updated and you can't change the mod loader or Minecraft version. Unlinking will permanently disconnect this instance from the modpack."
- },
- "instance.settings.tabs.installation.unlink.title": {
- "message": "Unlink from modpack"
- },
"instance.settings.tabs.java": {
"message": "Java and memory"
},
diff --git a/apps/app-frontend/src/pages/instance/Mods.vue b/apps/app-frontend/src/pages/instance/Mods.vue
index 5e8b0a856e..1db2068fa8 100644
--- a/apps/app-frontend/src/pages/instance/Mods.vue
+++ b/apps/app-frontend/src/pages/instance/Mods.vue
@@ -1,849 +1,650 @@
-
-
-
-
-
-
-
-
-
(currentPage = page)"
- />
-
-
-
+
+
+
-
-
-
-
-
-
-
- Share
- Project names
- File names
- Project links
- Markdown links
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Show file
- Copy link
-
-
-
-
-
-
(currentPage = page)"
- />
-
+ :is-app="true"
+ :is-modpack="updatingModpack"
+ :project-icon-url="
+ updatingModpack ? linkedModpackProject?.icon_url : updatingProject?.project?.icon_url
+ "
+ :project-name="
+ updatingModpack
+ ? (linkedModpackProject?.title ?? formatMessage(messages.modpackFallback))
+ : (updatingProject?.project?.title ?? updatingProject?.file_name)
+ "
+ :loading="loadingVersions"
+ :loading-changelog="loadingChangelog"
+ @update="handleModalUpdate"
+ @version-select="handleVersionSelect"
+ @version-hover="handleVersionHover"
+ />
-
-
-
-

-
You haven't added any content to this instance yet.
-
-
-
-
-
-
-
-
+
+
-
-
-
-
diff --git a/apps/app/build.rs b/apps/app/build.rs
index aacad57720..81aaeb5dd3 100644
--- a/apps/app/build.rs
+++ b/apps/app/build.rs
@@ -40,6 +40,7 @@ fn main() {
"get_search_results",
"get_search_results_many",
"purge_cache_types",
+ "get_project_versions",
])
.default_permission(
DefaultPermissionRule::AllowAllCommands,
@@ -160,6 +161,10 @@ fn main() {
"profile_get",
"profile_get_many",
"profile_get_projects",
+ "profile_get_content_items",
+ "profile_get_dependencies_as_content_items",
+ "profile_get_linked_modpack_info",
+ "profile_get_linked_modpack_content",
"profile_get_optimal_jre_key",
"profile_get_full_path",
"profile_get_mod_full_path",
diff --git a/apps/app/src/api/cache.rs b/apps/app/src/api/cache.rs
index d1e671813f..6197c59c2a 100644
--- a/apps/app/src/api/cache.rs
+++ b/apps/app/src/api/cache.rs
@@ -53,6 +53,7 @@ pub fn init() -> tauri::plugin::TauriPlugin {
get_search_results,
get_search_results_many,
purge_cache_types,
+ get_project_versions,
])
.build()
}
@@ -61,3 +62,14 @@ pub fn init() -> tauri::plugin::TauriPlugin {
pub async fn purge_cache_types(cache_types: Vec) -> Result<()> {
Ok(theseus::cache::purge_cache_types(&cache_types).await?)
}
+
+#[tauri::command]
+pub async fn get_project_versions(
+ project_id: &str,
+ cache_behaviour: Option,
+) -> Result