Misc bugs 4 (#381)
* bug fixes * fixed jres being undetected * cleanup * prettier * fixed folders not displaying windows exporting * fixes, more bugs * missed function * clippy, fmt * prettier
This commit is contained in:
parent
744d11f09e
commit
87449f91c3
@ -94,6 +94,19 @@ pub async fn get_by_uuid(
|
|||||||
Ok(profile)
|
Ok(profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get profile's full path in the filesystem
|
||||||
|
#[tracing::instrument]
|
||||||
|
pub async fn get_full_path(path: &ProfilePathId) -> crate::Result<PathBuf> {
|
||||||
|
let _ = get(path, Some(true)).await?.ok_or_else(|| {
|
||||||
|
crate::ErrorKind::OtherError(format!(
|
||||||
|
"Tried to get the full path of a nonexistent or unloaded profile at path {}!",
|
||||||
|
path
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
let full_path = io::canonicalize(path.get_full_path().await?)?;
|
||||||
|
Ok(full_path)
|
||||||
|
}
|
||||||
|
|
||||||
/// Edit a profile using a given asynchronous closure
|
/// Edit a profile using a given asynchronous closure
|
||||||
pub async fn edit<Fut>(
|
pub async fn edit<Fut>(
|
||||||
path: &ProfilePathId,
|
path: &ProfilePathId,
|
||||||
@ -373,6 +386,7 @@ pub async fn update_project(
|
|||||||
profile.projects.insert(path.clone(), project);
|
profile.projects.insert(path.clone(), project);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drop(profiles);
|
||||||
|
|
||||||
if !skip_send_event.unwrap_or(false) {
|
if !skip_send_event.unwrap_or(false) {
|
||||||
emit_profile(
|
emit_profile(
|
||||||
@ -409,7 +423,7 @@ pub async fn add_project_from_version(
|
|||||||
version_id: String,
|
version_id: String,
|
||||||
) -> crate::Result<ProjectPathId> {
|
) -> crate::Result<ProjectPathId> {
|
||||||
if let Some(profile) = get(profile_path, None).await? {
|
if let Some(profile) = get(profile_path, None).await? {
|
||||||
let (path, _) = profile.add_project_version(version_id).await?;
|
let (project_path, _) = profile.add_project_version(version_id).await?;
|
||||||
|
|
||||||
emit_profile(
|
emit_profile(
|
||||||
profile.uuid,
|
profile.uuid,
|
||||||
@ -418,9 +432,7 @@ pub async fn add_project_from_version(
|
|||||||
ProfilePayloadType::Edited,
|
ProfilePayloadType::Edited,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
State::sync().await?;
|
Ok(project_path)
|
||||||
|
|
||||||
Ok(path)
|
|
||||||
} else {
|
} else {
|
||||||
Err(
|
Err(
|
||||||
crate::ErrorKind::UnmanagedProfileError(profile_path.to_string())
|
crate::ErrorKind::UnmanagedProfileError(profile_path.to_string())
|
||||||
|
@ -143,6 +143,8 @@ impl Children {
|
|||||||
mc_exit_status = t;
|
mc_exit_status = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// sleep for 10ms
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -204,6 +206,9 @@ impl Children {
|
|||||||
mc_exit_status = t;
|
mc_exit_status = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// sleep for 10ms
|
||||||
|
tokio::time::sleep(tokio::time::Duration::from_millis(10))
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ pub async fn init_watcher() -> crate::Result<Debouncer<RecommendedWatcher>> {
|
|||||||
let (mut tx, mut rx) = channel(1);
|
let (mut tx, mut rx) = channel(1);
|
||||||
|
|
||||||
let file_watcher = new_debouncer(
|
let file_watcher = new_debouncer(
|
||||||
Duration::from_secs(2),
|
Duration::from_secs_f32(0.25),
|
||||||
None,
|
None,
|
||||||
move |res: DebounceEventResult| {
|
move |res: DebounceEventResult| {
|
||||||
futures::executor::block_on(async {
|
futures::executor::block_on(async {
|
||||||
|
@ -107,7 +107,8 @@ impl ProjectPathId {
|
|||||||
let profiles_dir: PathBuf = io::canonicalize(
|
let profiles_dir: PathBuf = io::canonicalize(
|
||||||
State::get().await?.directories.profiles_dir().await,
|
State::get().await?.directories.profiles_dir().await,
|
||||||
)?;
|
)?;
|
||||||
path.strip_prefix(profiles_dir)
|
let path = path
|
||||||
|
.strip_prefix(profiles_dir)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|p| p.components().skip(1).collect::<PathBuf>())
|
.map(|p| p.components().skip(1).collect::<PathBuf>())
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
@ -458,7 +459,6 @@ impl Profile {
|
|||||||
version_id: String,
|
version_id: String,
|
||||||
) -> crate::Result<(ProjectPathId, ModrinthVersion)> {
|
) -> crate::Result<(ProjectPathId, ModrinthVersion)> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
|
|
||||||
let version = fetch_json::<ModrinthVersion>(
|
let version = fetch_json::<ModrinthVersion>(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
&format!("{MODRINTH_API_URL}version/{version_id}"),
|
&format!("{MODRINTH_API_URL}version/{version_id}"),
|
||||||
@ -467,7 +467,6 @@ impl Profile {
|
|||||||
&state.fetch_semaphore,
|
&state.fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let file = if let Some(file) = version.files.iter().find(|x| x.primary)
|
let file = if let Some(file) = version.files.iter().find(|x| x.primary)
|
||||||
{
|
{
|
||||||
file
|
file
|
||||||
@ -486,7 +485,6 @@ impl Profile {
|
|||||||
&state.fetch_semaphore,
|
&state.fetch_semaphore,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let path = self
|
let path = self
|
||||||
.add_project_bytes(
|
.add_project_bytes(
|
||||||
&file.filename,
|
&file.filename,
|
||||||
@ -494,7 +492,6 @@ impl Profile {
|
|||||||
ProjectType::get_from_loaders(version.loaders.clone()),
|
ProjectType::get_from_loaders(version.loaders.clone()),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok((path, version))
|
Ok((path, version))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,7 +566,6 @@ impl Profile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Toggle a project's disabled state.
|
/// Toggle a project's disabled state.
|
||||||
/// 'path' should be relative to the profile's path.
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
#[theseus_macros::debug_pin]
|
#[theseus_macros::debug_pin]
|
||||||
pub async fn toggle_disable_project(
|
pub async fn toggle_disable_project(
|
||||||
@ -662,11 +658,11 @@ impl Profile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(crate::ErrorKind::InputError(format!(
|
// If we are removing a project that doesn't exist, allow it to pass through without error, but warn
|
||||||
"Project path does not exist: {:?}",
|
tracing::warn!(
|
||||||
|
"Attempted to remove non-existent project: {:?}",
|
||||||
relative_path
|
relative_path
|
||||||
))
|
);
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -272,6 +272,16 @@ pub async fn infer_data_from_files(
|
|||||||
|
|
||||||
// TODO: Make this concurrent and use progressive hashing to avoid loading each JAR in memory
|
// TODO: Make this concurrent and use progressive hashing to avoid loading each JAR in memory
|
||||||
for path in paths {
|
for path in paths {
|
||||||
|
if !path.exists() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(ext) = path.extension() {
|
||||||
|
// Ignore txt configuration files
|
||||||
|
if ext == "txt" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut file = tokio::fs::File::open(path.clone())
|
let mut file = tokio::fs::File::open(path.clone())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| IOError::with_path(e, &path))?;
|
.map_err(|e| IOError::with_path(e, &path))?;
|
||||||
@ -460,9 +470,7 @@ pub async fn infer_data_from_files(
|
|||||||
.await
|
.await
|
||||||
.is_ok()
|
.is_ok()
|
||||||
{
|
{
|
||||||
if let Ok(pack) =
|
if let Ok(pack) = toml::from_str::<ForgeModInfo>(&file_str) {
|
||||||
serde_json::from_str::<ForgeModInfo>(&file_str)
|
|
||||||
{
|
|
||||||
if let Some(pack) = pack.mods.first() {
|
if let Some(pack) = pack.mods.first() {
|
||||||
let icon = read_icon_from_file(
|
let icon = read_icon_from_file(
|
||||||
pack.logo_file.clone(),
|
pack.logo_file.clone(),
|
||||||
|
@ -2,11 +2,9 @@ use super::io;
|
|||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::Write;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::{collections::HashSet, path::Path};
|
use std::{collections::HashSet, path::Path};
|
||||||
use tempfile::NamedTempFile;
|
|
||||||
use tokio::task::JoinError;
|
use tokio::task::JoinError;
|
||||||
|
|
||||||
use crate::State;
|
use crate::State;
|
||||||
@ -280,20 +278,17 @@ pub async fn check_java_at_filepath(path: &Path) -> Option<JavaVersion> {
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut file = NamedTempFile::new().ok()?;
|
let bytes = include_bytes!("../../library/JavaInfo.class");
|
||||||
file.write_all(include_bytes!("../../library/JavaInfo.class"))
|
let tempdir: PathBuf = tempfile::tempdir().ok()?.into_path();
|
||||||
.ok()?;
|
if !tempdir.exists() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let file_path = tempdir.join("JavaInfo.class");
|
||||||
|
io::write(&file_path, bytes).await.ok()?;
|
||||||
|
|
||||||
let original_path = file.path().to_path_buf();
|
|
||||||
let mut new_path = original_path.clone();
|
|
||||||
new_path.set_file_name("JavaInfo");
|
|
||||||
new_path.set_extension("class");
|
|
||||||
tokio::fs::rename(&original_path, &new_path).await.ok()?;
|
|
||||||
|
|
||||||
// Run java checker on java binary
|
|
||||||
let output = Command::new(&java)
|
let output = Command::new(&java)
|
||||||
.arg("-cp")
|
.arg("-cp")
|
||||||
.arg(file.path().parent().unwrap())
|
.arg(file_path.parent().unwrap())
|
||||||
.arg("JavaInfo")
|
.arg("JavaInfo")
|
||||||
.output()
|
.output()
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
@ -12,6 +12,7 @@ pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
|||||||
profile_remove,
|
profile_remove,
|
||||||
profile_get,
|
profile_get,
|
||||||
profile_get_optimal_jre_key,
|
profile_get_optimal_jre_key,
|
||||||
|
profile_get_full_path,
|
||||||
profile_list,
|
profile_list,
|
||||||
profile_check_installed,
|
profile_check_installed,
|
||||||
profile_install,
|
profile_install,
|
||||||
@ -55,6 +56,14 @@ pub async fn profile_get(
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get a profile's full path
|
||||||
|
// invoke('plugin:profile|profile_get_full_path',path)
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn profile_get_full_path(path: ProfilePathId) -> Result<PathBuf> {
|
||||||
|
let res = profile::get_full_path(&path).await?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
// Get optimal java version from profile
|
// Get optimal java version from profile
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn profile_get_optimal_jre_key(
|
pub async fn profile_get_optimal_jre_key(
|
||||||
|
@ -59,7 +59,7 @@ pub fn show_in_folder(path: String) -> Result<()> {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
Command::new("explorer")
|
Command::new("explorer")
|
||||||
.args(["/select,", &path]) // The comma after select is not a typo
|
.args([&path]) // The comma after select is not a typo
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ pub fn show_in_folder(path: String) -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
Command::new("open").args(["-R", &path]).spawn()?;
|
Command::new("open").args([&path]).spawn()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok::<(), theseus::Error>(())
|
Ok::<(), theseus::Error>(())
|
||||||
|
@ -26,6 +26,19 @@ fn is_dev() -> bool {
|
|||||||
cfg!(debug_assertions)
|
cfg!(debug_assertions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggles decorations
|
||||||
|
#[tauri::command]
|
||||||
|
async fn toggle_decorations(b: bool, window: tauri::Window) -> api::Result<()> {
|
||||||
|
window.set_decorations(b).map_err(|e| {
|
||||||
|
theseus::Error::from(theseus::ErrorKind::OtherError(format!(
|
||||||
|
"Failed to toggle decorations: {}",
|
||||||
|
e
|
||||||
|
)))
|
||||||
|
})?;
|
||||||
|
println!("Toggled decorations!");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, serde::Serialize)]
|
#[derive(Clone, serde::Serialize)]
|
||||||
struct Payload {
|
struct Payload {
|
||||||
args: Vec<String>,
|
args: Vec<String>,
|
||||||
@ -84,16 +97,12 @@ fn main() {
|
|||||||
}
|
}
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
|
win.set_decorations(true).unwrap();
|
||||||
|
|
||||||
use macos::window_ext::WindowExt;
|
use macos::window_ext::WindowExt;
|
||||||
win.set_transparent_titlebar(true);
|
win.set_transparent_titlebar(true);
|
||||||
win.position_traffic_lights(9.0, 16.0);
|
win.position_traffic_lights(9.0, 16.0);
|
||||||
}
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
{
|
|
||||||
win.set_decorations(false).unwrap();
|
|
||||||
}
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
{
|
|
||||||
macos::delegate::register_open_file(|filename| {
|
macos::delegate::register_open_file(|filename| {
|
||||||
tauri::async_runtime::spawn(api::utils::handle_command(
|
tauri::async_runtime::spawn(api::utils::handle_command(
|
||||||
filename,
|
filename,
|
||||||
@ -102,6 +111,9 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show app now that we are setup
|
||||||
|
win.show().unwrap();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -129,7 +141,11 @@ fn main() {
|
|||||||
.plugin(api::settings::init())
|
.plugin(api::settings::init())
|
||||||
.plugin(api::tags::init())
|
.plugin(api::tags::init())
|
||||||
.plugin(api::utils::init())
|
.plugin(api::utils::init())
|
||||||
.invoke_handler(tauri::generate_handler![initialize_state, is_dev]);
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
initialize_state,
|
||||||
|
is_dev,
|
||||||
|
toggle_decorations
|
||||||
|
]);
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
|
@ -101,7 +101,9 @@
|
|||||||
"title": "Modrinth App",
|
"title": "Modrinth App",
|
||||||
"width": 1280,
|
"width": 1280,
|
||||||
"minHeight": 630,
|
"minHeight": 630,
|
||||||
"minWidth": 1100
|
"minWidth": 1100,
|
||||||
|
"visible": false,
|
||||||
|
"decorations": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -308,7 +308,7 @@ const accounts = ref(null)
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
background: var(--color-raised-bg);
|
background: var(--color-raised-bg);
|
||||||
box-shadow: inset 0px -3px 0px black;
|
box-shadow: var(--shadow-inset-sm), var(--shadow-floating);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: var(--gap-md);
|
padding: var(--gap-md);
|
||||||
height: 3.25rem;
|
height: 3.25rem;
|
||||||
|
@ -27,7 +27,7 @@ import {
|
|||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { remove, run } from '@/helpers/profile.js'
|
import { remove, run } from '@/helpers/profile.js'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { showInFolder } from '@/helpers/utils.js'
|
import { showProfileInFolder } from '@/helpers/utils.js'
|
||||||
import { useFetch } from '@/helpers/fetch.js'
|
import { useFetch } from '@/helpers/fetch.js'
|
||||||
import { install as pack_install } from '@/helpers/pack.js'
|
import { install as pack_install } from '@/helpers/pack.js'
|
||||||
import { useTheming } from '@/store/state.js'
|
import { useTheming } from '@/store/state.js'
|
||||||
@ -155,7 +155,7 @@ const handleOptionsClick = async (args) => {
|
|||||||
deleteConfirmModal.value.show()
|
deleteConfirmModal.value.show()
|
||||||
break
|
break
|
||||||
case 'open_folder':
|
case 'open_folder':
|
||||||
await showInFolder(args.item.path)
|
await showProfileInFolder(args.item.path)
|
||||||
break
|
break
|
||||||
case 'copy_path':
|
case 'copy_path':
|
||||||
await navigator.clipboard.writeText(args.item.path)
|
await navigator.clipboard.writeText(args.item.path)
|
||||||
|
@ -5,6 +5,7 @@ import { ref } from 'vue'
|
|||||||
import { export_profile_mrpack, get_potential_override_folders } from '@/helpers/profile.js'
|
import { export_profile_mrpack, get_potential_override_folders } from '@/helpers/profile.js'
|
||||||
import { open } from '@tauri-apps/api/dialog'
|
import { open } from '@tauri-apps/api/dialog'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import { sep } from '@tauri-apps/api/path'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
instance: {
|
instance: {
|
||||||
@ -33,11 +34,11 @@ const initFiles = async () => {
|
|||||||
filePaths
|
filePaths
|
||||||
.map((folder) => ({
|
.map((folder) => ({
|
||||||
path: folder,
|
path: folder,
|
||||||
name: folder.split('/').pop(),
|
name: folder.split(sep).pop(),
|
||||||
selected: false,
|
selected: false,
|
||||||
}))
|
}))
|
||||||
.forEach((pathData) => {
|
.forEach((pathData) => {
|
||||||
const parent = pathData.path.split('/').slice(0, -1).join('/')
|
const parent = pathData.path.split(sep).slice(0, -1).join(sep)
|
||||||
if (parent !== '') {
|
if (parent !== '') {
|
||||||
if (newFolders.has(parent)) {
|
if (newFolders.has(parent)) {
|
||||||
newFolders.get(parent).push(pathData)
|
newFolders.get(parent).push(pathData)
|
||||||
|
@ -31,14 +31,13 @@ defineExpose({
|
|||||||
async function install() {
|
async function install() {
|
||||||
installing.value = true
|
installing.value = true
|
||||||
console.log(`Installing ${projectId.value} ${version.value} ${title.value} ${icon.value}`)
|
console.log(`Installing ${projectId.value} ${version.value} ${title.value} ${icon.value}`)
|
||||||
|
confirmModal.value.hide()
|
||||||
await pack_install(
|
await pack_install(
|
||||||
projectId.value,
|
projectId.value,
|
||||||
version.value,
|
version.value,
|
||||||
title.value,
|
title.value,
|
||||||
icon.value ? icon.value : null
|
icon.value ? icon.value : null
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
confirmModal.value.hide()
|
|
||||||
|
|
||||||
mixpanel.track('PackInstall', {
|
mixpanel.track('PackInstall', {
|
||||||
id: projectId.value,
|
id: projectId.value,
|
||||||
version_id: version.value,
|
version_id: version.value,
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
import { process_listener } from '@/helpers/events'
|
import { process_listener } from '@/helpers/events'
|
||||||
import { useFetch } from '@/helpers/fetch.js'
|
import { useFetch } from '@/helpers/fetch.js'
|
||||||
import { handleError } from '@/store/state.js'
|
import { handleError } from '@/store/state.js'
|
||||||
import { showInFolder } from '@/helpers/utils.js'
|
import { showProfileInFolder } from '@/helpers/utils.js'
|
||||||
import InstanceInstallModal from '@/components/ui/InstanceInstallModal.vue'
|
import InstanceInstallModal from '@/components/ui/InstanceInstallModal.vue'
|
||||||
import mixpanel from 'mixpanel-browser'
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ const stop = async (e, context) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const openFolder = async () => {
|
const openFolder = async () => {
|
||||||
await showInFolder(props.instance.path)
|
await showProfileInFolder(props.instance.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
const addContent = async () => {
|
const addContent = async () => {
|
||||||
|
@ -37,6 +37,12 @@ export async function get(path, clearProjects) {
|
|||||||
return await invoke('plugin:profile|profile_get', { path, clearProjects })
|
return await invoke('plugin:profile|profile_get', { path, clearProjects })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 optimal java version from profile
|
// Get optimal java version from profile
|
||||||
// Returns a java version
|
// Returns a java version
|
||||||
export async function get_optimal_jre_key(path) {
|
export async function get_optimal_jre_key(path) {
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
import { add_project_from_version as installMod, check_installed } from '@/helpers/profile'
|
import {
|
||||||
|
add_project_from_version as installMod,
|
||||||
|
check_installed,
|
||||||
|
get_full_path,
|
||||||
|
} from '@/helpers/profile'
|
||||||
import { useFetch } from '@/helpers/fetch.js'
|
import { useFetch } from '@/helpers/fetch.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { invoke } from '@tauri-apps/api/tauri'
|
import { invoke } from '@tauri-apps/api/tauri'
|
||||||
@ -11,6 +15,12 @@ export async function showInFolder(path) {
|
|||||||
return await invoke('plugin:utils|show_in_folder', { path })
|
return await invoke('plugin:utils|show_in_folder', { path })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Opens a profile's folder in the OS file explorer
|
||||||
|
export async function showProfileInFolder(path) {
|
||||||
|
const fullPath = await get_full_path(path)
|
||||||
|
return await showInFolder(fullPath)
|
||||||
|
}
|
||||||
|
|
||||||
export const releaseColor = (releaseType) => {
|
export const releaseColor = (releaseType) => {
|
||||||
switch (releaseType) {
|
switch (releaseType) {
|
||||||
case 'release':
|
case 'release':
|
||||||
|
@ -23,8 +23,12 @@ app.mixin(loadCssMixin)
|
|||||||
const mountedApp = app.mount('#app')
|
const mountedApp = app.mount('#app')
|
||||||
|
|
||||||
const raw_invoke = async (plugin, fn, args) => {
|
const raw_invoke = async (plugin, fn, args) => {
|
||||||
|
if (plugin == '') {
|
||||||
|
return await invoke(fn, args)
|
||||||
|
} else {
|
||||||
return await invoke('plugin:' + plugin + '|' + fn, args)
|
return await invoke('plugin:' + plugin + '|' + fn, args)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
isDev()
|
isDev()
|
||||||
.then((dev) => {
|
.then((dev) => {
|
||||||
if (dev) {
|
if (dev) {
|
||||||
|
@ -654,7 +654,7 @@ const showLoaders = computed(
|
|||||||
</Card>
|
</Card>
|
||||||
</aside>
|
</aside>
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<Promotion class="promotion" />
|
<Promotion class="promotion" :external="false" />
|
||||||
<Card class="project-type-container">
|
<Card class="project-type-container">
|
||||||
<NavRow :links="selectableProjectTypes" />
|
<NavRow :links="selectableProjectTypes" />
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
<Button
|
<Button
|
||||||
v-tooltip="'Open instance folder'"
|
v-tooltip="'Open instance folder'"
|
||||||
class="instance-button"
|
class="instance-button"
|
||||||
@click="showInFolder(instance.path)"
|
@click="showProfileInFolder(instance.path)"
|
||||||
>
|
>
|
||||||
<FolderOpenIcon />
|
<FolderOpenIcon />
|
||||||
Folder
|
Folder
|
||||||
@ -148,7 +148,7 @@ import { process_listener, profile_listener } from '@/helpers/events'
|
|||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { ref, onUnmounted } from 'vue'
|
import { ref, onUnmounted } from 'vue'
|
||||||
import { handleError, useBreadcrumbs, useLoading } from '@/store/state'
|
import { handleError, useBreadcrumbs, useLoading } from '@/store/state'
|
||||||
import { showInFolder } from '@/helpers/utils.js'
|
import { showProfileInFolder } from '@/helpers/utils.js'
|
||||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||||
import mixpanel from 'mixpanel-browser'
|
import mixpanel from 'mixpanel-browser'
|
||||||
import { PackageIcon } from '@/assets/icons/index.js'
|
import { PackageIcon } from '@/assets/icons/index.js'
|
||||||
@ -268,7 +268,7 @@ const handleOptionsClick = async (args) => {
|
|||||||
})
|
})
|
||||||
break
|
break
|
||||||
case 'open_folder':
|
case 'open_folder':
|
||||||
await showInFolder(instance.value.path)
|
await showProfileInFolder(instance.value.path)
|
||||||
break
|
break
|
||||||
case 'copy_path':
|
case 'copy_path':
|
||||||
await navigator.clipboard.writeText(instance.value.path)
|
await navigator.clipboard.writeText(instance.value.path)
|
||||||
|
@ -223,7 +223,11 @@
|
|||||||
:checked="!mod.disabled"
|
:checked="!mod.disabled"
|
||||||
@change="toggleDisableMod(mod)"
|
@change="toggleDisableMod(mod)"
|
||||||
/>
|
/>
|
||||||
<Button v-tooltip="`Show ${mod.file_name}`" icon-only @click="showInFolder(mod.path)">
|
<Button
|
||||||
|
v-tooltip="`Show ${mod.file_name}`"
|
||||||
|
icon-only
|
||||||
|
@click="showProfileInFolder(mod.path)"
|
||||||
|
>
|
||||||
<FolderOpenIcon />
|
<FolderOpenIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@ -345,7 +349,7 @@ import mixpanel from 'mixpanel-browser'
|
|||||||
import { open } from '@tauri-apps/api/dialog'
|
import { open } from '@tauri-apps/api/dialog'
|
||||||
import { listen } from '@tauri-apps/api/event'
|
import { listen } from '@tauri-apps/api/event'
|
||||||
import { convertFileSrc } from '@tauri-apps/api/tauri'
|
import { convertFileSrc } from '@tauri-apps/api/tauri'
|
||||||
import { showInFolder } from '@/helpers/utils.js'
|
import { showProfileInFolder } from '@/helpers/utils.js'
|
||||||
import { MenuIcon, ToggleIcon, TextInputIcon, AddProjectImage } from '@/assets/icons'
|
import { MenuIcon, ToggleIcon, TextInputIcon, AddProjectImage } from '@/assets/icons'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -605,8 +609,23 @@ const updateProject = async (mod) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let locks = {}
|
||||||
|
|
||||||
const toggleDisableMod = async (mod) => {
|
const toggleDisableMod = async (mod) => {
|
||||||
mod.path = await toggle_disable_project(props.instance.path, mod.path).catch(handleError)
|
// Use mod's id as the key for the lock. If mod doesn't have a unique id, replace `mod.id` with some unique property.
|
||||||
|
if (!locks[mod.id]) {
|
||||||
|
locks[mod.id] = ref(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
let lock = locks[mod.id]
|
||||||
|
|
||||||
|
while (lock.value) {
|
||||||
|
await lock.value
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.value = toggle_disable_project(props.instance.path, mod.path)
|
||||||
|
.then((newPath) => {
|
||||||
|
mod.path = newPath
|
||||||
mod.disabled = !mod.disabled
|
mod.disabled = !mod.disabled
|
||||||
mixpanel.track('InstanceProjectDisable', {
|
mixpanel.track('InstanceProjectDisable', {
|
||||||
loader: props.instance.metadata.loader,
|
loader: props.instance.metadata.loader,
|
||||||
@ -616,6 +635,13 @@ const toggleDisableMod = async (mod) => {
|
|||||||
project_type: mod.project_type,
|
project_type: mod.project_type,
|
||||||
disabled: mod.disabled,
|
disabled: mod.disabled,
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
.catch(handleError)
|
||||||
|
.finally(() => {
|
||||||
|
lock.value = null
|
||||||
|
})
|
||||||
|
|
||||||
|
await lock.value
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeMod = async (mod) => {
|
const removeMod = async (mod) => {
|
||||||
|
@ -350,15 +350,19 @@ async function install(version) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (installed.value) {
|
if (installed.value) {
|
||||||
await remove_project(
|
const old_project = Object.entries(instance.value.projects)
|
||||||
instance.value.path,
|
|
||||||
Object.entries(instance.value.projects)
|
|
||||||
.map(([key, value]) => ({
|
.map(([key, value]) => ({
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
}))
|
}))
|
||||||
.find((p) => p.value.metadata?.version?.project_id === data.value.id).key
|
.find((p) => p.value.metadata?.version?.project_id === data.value.id)
|
||||||
)
|
if (!old_project) {
|
||||||
|
// Switching too fast, old project is not recognized as a Modrinth project yet
|
||||||
|
installing.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await remove_project(instance.value.path, old_project.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version) {
|
if (version) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user