first draft
This commit is contained in:
parent
0d3f007dd4
commit
bdde054036
@ -15,6 +15,7 @@ pub mod profile_create;
|
||||
pub mod settings;
|
||||
pub mod tags;
|
||||
pub mod utils;
|
||||
pub mod profile_share;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, TheseusSerializableError>;
|
||||
|
||||
|
||||
76
theseus_gui/src-tauri/src/api/profile_share.rs
Normal file
76
theseus_gui/src-tauri/src/api/profile_share.rs
Normal file
@ -0,0 +1,76 @@
|
||||
use crate::api::Result;
|
||||
use theseus::{prelude::*, shared_profile::SharedProfile};
|
||||
|
||||
pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
||||
tauri::plugin::Builder::new("profile_share")
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
profile_share_get_all,
|
||||
profile_share_install,
|
||||
profile_share_create,
|
||||
profile_share_inbound_sync,
|
||||
profile_share_outbound_sync,
|
||||
profile_share_generate_share_link,
|
||||
profile_share_accept_share_link
|
||||
])
|
||||
.build()
|
||||
}
|
||||
|
||||
// invoke('plugin:profile_share|profile_share_get_all',profile)
|
||||
#[tauri::command]
|
||||
pub async fn profile_share_get_all(
|
||||
) -> Result<Vec<SharedProfile>> {
|
||||
let res = shared_profile::get_all()
|
||||
.await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn profile_share_install(
|
||||
profile: SharedProfile,
|
||||
) -> Result<ProfilePathId> {
|
||||
let res = shared_profile::install(profile)
|
||||
.await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn profile_share_create(
|
||||
path: ProfilePathId
|
||||
) -> Result<()> {
|
||||
shared_profile::create(path)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn profile_share_inbound_sync(
|
||||
path: ProfilePathId
|
||||
) -> Result<()> {
|
||||
shared_profile::inbound_sync(path)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn profile_share_outbound_sync(
|
||||
path : ProfilePathId
|
||||
) -> Result<()> {
|
||||
shared_profile::outbound_sync(path).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn profile_share_generate_share_link(
|
||||
path : ProfilePathId
|
||||
) -> Result<String> {
|
||||
let res = shared_profile::generate_share_link(path).await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn profile_share_accept_share_link(
|
||||
link : String
|
||||
) -> Result<()> {
|
||||
shared_profile::accept_share_link(link).await?;
|
||||
Ok(())
|
||||
}
|
||||
@ -139,6 +139,7 @@ fn main() {
|
||||
.plugin(api::process::init())
|
||||
.plugin(api::profile::init())
|
||||
.plugin(api::profile_create::init())
|
||||
.plugin(api::profile_share::init())
|
||||
.plugin(api::settings::init())
|
||||
.plugin(api::tags::init())
|
||||
.plugin(api::utils::init())
|
||||
|
||||
@ -40,12 +40,14 @@ import { TauriEvent } from '@tauri-apps/api/event'
|
||||
import { await_sync, check_safe_loading_bars_complete } from './helpers/state'
|
||||
import { confirm } from '@tauri-apps/api/dialog'
|
||||
import URLConfirmModal from '@/components/ui/URLConfirmModal.vue'
|
||||
import AcceptSharedProfileModal from '@/components/ui/AcceptSharedProfileModal.vue'
|
||||
import StickyTitleBar from '@/components/ui/tutorial/StickyTitleBar.vue'
|
||||
import OnboardingScreen from '@/components/ui/tutorial/OnboardingScreen.vue'
|
||||
import { install_from_file } from './helpers/pack'
|
||||
|
||||
const themeStore = useTheming()
|
||||
const urlModal = ref(null)
|
||||
const sharedProfileConfirmModal = ref(null)
|
||||
const isLoading = ref(true)
|
||||
|
||||
const videoPlaying = ref(false)
|
||||
@ -237,6 +239,9 @@ command_listener(async (e) => {
|
||||
source: 'CreationModalFileDrop',
|
||||
})
|
||||
}
|
||||
} else if (e.event === 'OpenSharedProfile') {
|
||||
// Install a shared profile
|
||||
sharedProfileConfirmModal.value.show(e)
|
||||
} else {
|
||||
// Other commands are URL-based (deep linking)
|
||||
urlModal.value.show(e)
|
||||
@ -388,6 +393,7 @@ command_listener(async (e) => {
|
||||
</div>
|
||||
</div>
|
||||
<URLConfirmModal ref="urlModal" />
|
||||
<AcceptSharedProfileModal ref="sharedProfileConfirmModal" />
|
||||
<Notifications ref="notificationsWrapper" />
|
||||
</template>
|
||||
|
||||
|
||||
@ -169,7 +169,7 @@ const filteredResults = computed(() => {
|
||||
})
|
||||
} else if (filters.value === 'Downloaded modpacks') {
|
||||
instances = instances.filter((instance) => {
|
||||
return instance.metadata?.linked_data
|
||||
return instance.metadata?.linked_data?.modrinth_modpack
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -170,7 +170,7 @@ const handleOptionsClick = async (args) => {
|
||||
break
|
||||
case 'install': {
|
||||
const versions = await useFetch(
|
||||
`https://api.modrinth.com/v2/project/${args.item.project_id}/version`,
|
||||
`https://staging-api.modrinth.com/v2/project/${args.item.project_id}/version`,
|
||||
'project versions'
|
||||
)
|
||||
|
||||
|
||||
89
theseus_gui/src/components/ui/AcceptSharedProfileModal.vue
Normal file
89
theseus_gui/src/components/ui/AcceptSharedProfileModal.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<script setup>
|
||||
import { Modal, Button } from 'omorphia'
|
||||
import { ref } from 'vue'
|
||||
import { useFetch } from '@/helpers/fetch.js'
|
||||
import SearchCard from '@/components/ui/SearchCard.vue'
|
||||
import { handleError } from '@/store/notifications.js'
|
||||
import { share_accept, share_install } from '@/helpers/shared_profiles.js'
|
||||
|
||||
const confirmModal = ref(null)
|
||||
const linkId = ref(null)
|
||||
const sharedProfile = ref(null)
|
||||
|
||||
defineExpose({
|
||||
async show(event) {
|
||||
linkId.value = event.id
|
||||
sharedProfile.value = await useFetch(
|
||||
`https://staging-api.modrinth.com/_internal/share/${encodeURIComponent(event.id)}`,
|
||||
'shared profile'
|
||||
)
|
||||
|
||||
confirmModal.value.show()
|
||||
},
|
||||
})
|
||||
|
||||
async function install() {
|
||||
confirmModal.value.hide()
|
||||
await share_accept(linkId.value).catch(handleError)
|
||||
await share_install(sharedProfile.value.id).catch(handleError)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal ref="confirmModal" :header="`Install ${project?.title}`">
|
||||
<div class="modal-body">
|
||||
<SearchCard
|
||||
:project="project"
|
||||
class="project-card"
|
||||
:categories="categories"
|
||||
@open="confirmModal.hide()"
|
||||
/>
|
||||
<div class="button-row">
|
||||
<div class="markdown-body">
|
||||
<p>
|
||||
Installing <code>{{ sharedProfile.id }}</code> from user {{ sharedProfile.owner_id }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="button-group">
|
||||
<Button color="primary" @click="install">Install</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.modal-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--gap-md);
|
||||
padding: var(--gap-lg);
|
||||
}
|
||||
|
||||
.button-row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--gap-md);
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: var(--gap-sm);
|
||||
}
|
||||
|
||||
.project-card {
|
||||
background-color: var(--color-bg);
|
||||
width: 100%;
|
||||
|
||||
:deep(.badge) {
|
||||
border: 1px solid var(--color-raised-bg);
|
||||
background-color: var(--color-accent-contrast);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -71,7 +71,7 @@ const install = async (e) => {
|
||||
e?.stopPropagation()
|
||||
modLoading.value = true
|
||||
const versions = await useFetch(
|
||||
`https://api.modrinth.com/v2/project/${props.instance.project_id}/version`,
|
||||
`https://staging-api.modrinth.com/v2/project/${props.instance.project_id}/version`,
|
||||
'project versions'
|
||||
)
|
||||
|
||||
@ -82,7 +82,7 @@ const install = async (e) => {
|
||||
packs.length === 0 ||
|
||||
!packs
|
||||
.map((value) => value.metadata)
|
||||
.find((pack) => pack.linked_data?.project_id === props.instance.project_id)
|
||||
.find((pack) => pack.linked_data?.modrinth_modpack?.project_id === props.instance.project_id)
|
||||
) {
|
||||
modLoading.value = true
|
||||
await pack_install(
|
||||
|
||||
@ -247,7 +247,9 @@ const check_valid = computed(() => {
|
||||
</Button>
|
||||
<div
|
||||
v-tooltip="
|
||||
profile.metadata.linked_data?.locked && !profile.installedMod
|
||||
(profile.metadata.linked_data?.modrinth_modpack.locked
|
||||
|| profile.metadata.linked_data?.shared_profile
|
||||
) && !profile.installedMod
|
||||
? 'Unpair or unlock an instance to add mods.'
|
||||
: ''
|
||||
"
|
||||
@ -265,7 +267,7 @@ const check_valid = computed(() => {
|
||||
? 'Installing...'
|
||||
: profile.installedMod
|
||||
? 'Installed'
|
||||
: profile.metadata.linked_data && profile.metadata.linked_data.locked
|
||||
: profile.metadata.linked_data?.modrinth_modpack.locked || profile.metadata.linked_data?.shared_profile
|
||||
? 'Paired'
|
||||
: 'Install'
|
||||
}}
|
||||
|
||||
@ -28,7 +28,7 @@ const filteredVersions = computed(() => {
|
||||
})
|
||||
|
||||
const modpackVersionModal = ref(null)
|
||||
const installedVersion = computed(() => props.instance?.metadata?.linked_data?.version_id)
|
||||
const installedVersion = computed(() => props.instance?.metadata?.linked_data?.modrinth_modpack?.version_id)
|
||||
const installing = computed(() => props.instance.install_stage !== 'installed')
|
||||
const inProgress = ref(false)
|
||||
|
||||
@ -49,7 +49,7 @@ const switchVersion = async (versionId) => {
|
||||
:noblur="!themeStore.advancedRendering"
|
||||
>
|
||||
<div class="modal-body">
|
||||
<Card v-if="instance.metadata.linked_data" class="mod-card">
|
||||
<Card v-if="instance.metadata.linked_data?.modrinth_modpack" class="mod-card">
|
||||
<div class="table">
|
||||
<div class="table-row with-columns table-head">
|
||||
<div class="table-cell table-text download-cell" />
|
||||
|
||||
@ -73,7 +73,7 @@ const install = async (e) => {
|
||||
e?.stopPropagation()
|
||||
installing.value = true
|
||||
const versions = await useFetch(
|
||||
`https://api.modrinth.com/v2/project/${props.project.project_id}/version`,
|
||||
`https://staging-api.modrinth.com/v2/project/${props.project.project_id}/version`,
|
||||
'project versions'
|
||||
)
|
||||
|
||||
@ -84,7 +84,7 @@ const install = async (e) => {
|
||||
packs.length === 0 ||
|
||||
!packs
|
||||
.map((value) => value.metadata)
|
||||
.find((pack) => pack.linked_data?.project_id === props.project.project_id)
|
||||
.find((pack) => pack.linked_data?.modrinth_modpack?.project_id === props.project.project_id)
|
||||
) {
|
||||
installing.value = true
|
||||
await pack_install(
|
||||
|
||||
@ -135,7 +135,7 @@ const installed = ref(props.installed)
|
||||
async function install() {
|
||||
installing.value = true
|
||||
const versions = await useFetch(
|
||||
`https://api.modrinth.com/v2/project/${props.project.project_id}/version`,
|
||||
`https://staging-api.modrinth.com/v2/project/${props.project.project_id}/version`,
|
||||
'project versions'
|
||||
)
|
||||
let queuedVersionData
|
||||
@ -156,7 +156,7 @@ async function install() {
|
||||
packs.length === 0 ||
|
||||
!packs
|
||||
.map((value) => value.metadata)
|
||||
.find((pack) => pack.linked_data?.project_id === props.project.project_id)
|
||||
.find((pack) => pack.linked_data?.modrinth_modpack?.project_id === props.project.project_id)
|
||||
) {
|
||||
await packInstall(
|
||||
props.project.project_id,
|
||||
|
||||
@ -20,20 +20,20 @@ defineExpose({
|
||||
async show(event) {
|
||||
if (event.event === 'InstallVersion') {
|
||||
version.value = await useFetch(
|
||||
`https://api.modrinth.com/v2/version/${encodeURIComponent(event.id)}`,
|
||||
`https://staging-api.modrinth.com/v2/version/${encodeURIComponent(event.id)}`,
|
||||
'version'
|
||||
)
|
||||
project.value = await useFetch(
|
||||
`https://api.modrinth.com/v2/project/${encodeURIComponent(version.value.project_id)}`,
|
||||
`https://staging-api.modrinth.com/v2/project/${encodeURIComponent(version.value.project_id)}`,
|
||||
'project'
|
||||
)
|
||||
} else {
|
||||
project.value = await useFetch(
|
||||
`https://api.modrinth.com/v2/project/${encodeURIComponent(event.id)}`,
|
||||
`https://staging-api.modrinth.com/v2/project/${encodeURIComponent(event.id)}`,
|
||||
'project'
|
||||
)
|
||||
version.value = await useFetch(
|
||||
`https://api.modrinth.com/v2/version/${encodeURIComponent(project.value.versions[0])}`,
|
||||
`https://staging-api.modrinth.com/v2/version/${encodeURIComponent(project.value.versions[0])}`,
|
||||
'version'
|
||||
)
|
||||
}
|
||||
|
||||
42
theseus_gui/src/helpers/shared_profiles.js
Normal file
42
theseus_gui/src/helpers/shared_profiles.js
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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/tauri'
|
||||
|
||||
/// Created shared modpack from profile
|
||||
export async function share_create(path) {
|
||||
return await invoke('plugin:profile_share|profile_share_create', { path })
|
||||
}
|
||||
|
||||
/// Generates a shared profile link
|
||||
export async function share_generate(path) {
|
||||
return await invoke('plugin:profile_share|profile_share_generate_share_link', { path })
|
||||
}
|
||||
|
||||
/// Accepts a shared profile link
|
||||
export async function share_accept(link) {
|
||||
return await invoke('plugin:profile_share|profile_share_accept', { link })
|
||||
}
|
||||
|
||||
/// Install a pack from a shared profile id
|
||||
export async function share_install(id) {
|
||||
return await invoke('plugin:profile_share|profile_share_install', { id })
|
||||
}
|
||||
|
||||
// get all user profiles that are available to the currentt user
|
||||
export async function get_all(path) {
|
||||
return await invoke('plugin:profile_share|profile_share_get_all', { path })
|
||||
}
|
||||
|
||||
// syncs profile to match that on server
|
||||
export async function inbound_sync(path) {
|
||||
return await invoke('plugin:profile_share|profile_share_inbound_sync', { path })
|
||||
}
|
||||
|
||||
// syncs profile to update server
|
||||
// only allowed if profile is owned by user
|
||||
export async function outbound_sync(path) {
|
||||
return await invoke('plugin:profile_share|profile_share_outbound_sync', { path })
|
||||
}
|
||||
@ -68,7 +68,7 @@ export const installVersionDependencies = async (profile, version) => {
|
||||
)
|
||||
continue
|
||||
const depVersions = await useFetch(
|
||||
`https://api.modrinth.com/v2/project/${dep.project_id}/version`,
|
||||
`https://staging-api.modrinth.com/v2/project/${dep.project_id}/version`,
|
||||
'dependency versions'
|
||||
)
|
||||
const latest = depVersions.find(
|
||||
|
||||
@ -149,7 +149,7 @@ if (route.query.ai) {
|
||||
}
|
||||
|
||||
async function refreshSearch() {
|
||||
const base = 'https://api.modrinth.com/v2/'
|
||||
const base = 'https://staging-api.modrinth.com/v2/'
|
||||
|
||||
const params = [`limit=${maxResults.value}`, `index=${sortType.value.name}`]
|
||||
if (query.value.length > 0) {
|
||||
|
||||
@ -31,8 +31,8 @@ const getInstances = async () => {
|
||||
|
||||
let filters = []
|
||||
for (const instance of recentInstances.value) {
|
||||
if (instance.metadata.linked_data && instance.metadata.linked_data.project_id) {
|
||||
filters.push(`NOT"project_id"="${instance.metadata.linked_data.project_id}"`)
|
||||
if (instance.metadata.linked_data?.modrinth_modpack?.project_id) {
|
||||
filters.push(`NOT"project_id"="${instance.metadata.linked_data?.modrinth_modpack?.project_id}"`)
|
||||
}
|
||||
}
|
||||
filter.value = filters.join(' AND ')
|
||||
@ -40,7 +40,7 @@ const getInstances = async () => {
|
||||
|
||||
const getFeaturedModpacks = async () => {
|
||||
const response = await useFetch(
|
||||
`https://api.modrinth.com/v2/search?facets=[["project_type:modpack"]]&limit=10&index=follows&filters=${filter.value}`,
|
||||
`https://staging-api.modrinth.com/v2/search?facets=[["project_type:modpack"]]&limit=10&index=follows&filters=${filter.value}`,
|
||||
'featured modpacks',
|
||||
offline.value
|
||||
)
|
||||
@ -52,7 +52,7 @@ const getFeaturedModpacks = async () => {
|
||||
}
|
||||
const getFeaturedMods = async () => {
|
||||
const response = await useFetch(
|
||||
'https://api.modrinth.com/v2/search?facets=[["project_type:mod"]]&limit=10&index=follows',
|
||||
'https://staging-api.modrinth.com/v2/search?facets=[["project_type:mod"]]&limit=10&index=follows',
|
||||
'featured mods',
|
||||
offline.value
|
||||
)
|
||||
|
||||
@ -209,9 +209,9 @@ const checkProcess = async () => {
|
||||
|
||||
// Get information on associated modrinth versions, if any
|
||||
const modrinthVersions = ref([])
|
||||
if (!(await isOffline()) && instance.value.metadata.linked_data?.project_id) {
|
||||
if (!(await isOffline()) && instance.value.metadata.linked_data?.modrinth_modpack?.project_id) {
|
||||
modrinthVersions.value = await useFetch(
|
||||
`https://api.modrinth.com/v2/project/${instance.value.metadata.linked_data.project_id}/version`,
|
||||
`https://staging-api.modrinth.com/v2/project/${instance.value.metadata.linked_data?.modrinth_modpack?.project_id}/version`,
|
||||
'project'
|
||||
)
|
||||
}
|
||||
|
||||
@ -359,7 +359,7 @@
|
||||
/>
|
||||
<ExportModal v-if="projects.length > 0" ref="exportModal" :instance="instance" />
|
||||
<ModpackVersionModal
|
||||
v-if="instance.metadata.linked_data"
|
||||
v-if="instance.metadata.linked_data?.modrinth_modpack"
|
||||
ref="modpackVersionModal"
|
||||
:instance="instance"
|
||||
:versions="props.versions"
|
||||
@ -443,11 +443,18 @@ const projects = ref([])
|
||||
const selectionMap = ref(new Map())
|
||||
const showingOptions = ref(false)
|
||||
const isPackLocked = computed(() => {
|
||||
return props.instance.metadata.linked_data && props.instance.metadata.linked_data.locked
|
||||
if (props.instance.metadata.linked_data?.shared_profile) {
|
||||
return !props.instance.metadata.linked_data.shared_profile.is_owner
|
||||
}
|
||||
return props.instance.metadata.linked_data?.modrinth_modpack?.locked
|
||||
})
|
||||
const canUpdatePack = computed(() => {
|
||||
if (!props.instance.metadata.linked_data) return false
|
||||
return props.instance.metadata.linked_data.version_id !== props.instance.modrinth_update_version
|
||||
let linked_data = props.instance.metadata.linked_data
|
||||
if (linked_data.modrinth_modpack) {
|
||||
return linked_data.modrinth_modpack.version_id !== props.instance.sync_update_version
|
||||
}
|
||||
return false
|
||||
})
|
||||
const exportModal = ref(null)
|
||||
|
||||
|
||||
@ -358,7 +358,7 @@
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
<Card v-if="instance.metadata.linked_data">
|
||||
<Card v-if="instance.metadata.linked_data?.modrinth_modpack">
|
||||
<div class="label">
|
||||
<h3>
|
||||
<span class="label__title size-card-header">Modpack</span>
|
||||
@ -413,8 +413,7 @@
|
||||
<XIcon /> Unpair
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div v-if="props.instance.metadata.linked_data.project_id" class="adjacent-input">
|
||||
<div v-if="props.instance.metadata.linked_data?.modrinth_modpack?.project_id" class="adjacent-input">
|
||||
<label for="change-modpack-version">
|
||||
<span class="label__title">Change modpack version</span>
|
||||
<span class="label__description">
|
||||
@ -445,6 +444,90 @@
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<Card v-if="installedSharedProfileData">
|
||||
<div class="label">
|
||||
<h3>
|
||||
<span class="label__title size-card-header">Shared profile management</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div v-if="installedSharedProfileData.is_owned" class="adjacent-input">
|
||||
<label for="share-links">
|
||||
<span class="label__title">Generate share link</span>
|
||||
<span class="label__description">
|
||||
Creates a share link to share this modpack with others. This allows them to install your instance, as well as stay up to date with any changes you make.
|
||||
</span>
|
||||
</label>
|
||||
<Button id="share-links" @click="generateShareLink">
|
||||
<GlobeIcon /> Share
|
||||
</Button>
|
||||
</div>
|
||||
<div v-if="shareLink" class="adjacent-input">
|
||||
Generated link: <code>{{ shareLink }}</code>
|
||||
</div>
|
||||
<div v-if="installedSharedProfileData.is_owned" class="table">
|
||||
<div class="table-row table-head">
|
||||
<div class="table-cell table-text name-cell actions-cell">
|
||||
<Button class="transparent">
|
||||
Name
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="user in installedSharedProfileData.users"
|
||||
:key="user"
|
||||
class="table-row"
|
||||
>
|
||||
<div class="table-cell table-text name-cell">
|
||||
<div class="user-content">
|
||||
<span v-tooltip="`${user}`" class="title">{{ user }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-cell table-text manage">
|
||||
<div v-tooltip="'Remove project'">
|
||||
<Button icon-only @click="removeSharedPackUser(user)">
|
||||
<TrashIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="installedSharedProfileData.is_owned" class="adjacent-input">
|
||||
your project
|
||||
{{ props.instance.sync_update_version }}
|
||||
:)
|
||||
<label for="share-sync">
|
||||
<span class="label__title">Sync shared profile</span>
|
||||
<span class="label__description" v-if="props.instance.sync_update_version?.is_synced">
|
||||
You are up to date with the shared profile.
|
||||
</span>
|
||||
<span class="label__description" v-else>
|
||||
You have changes that have not been synced to the shared profile. Click the button to upload your changes.
|
||||
</span>
|
||||
</label>
|
||||
<Button id="share-sync-sync" @click="outboundSyncSharedProfile" :disabled="props.instance.sync_update_version?.is_synced">
|
||||
<GlobeIcon /> Sync
|
||||
</Button>
|
||||
<Button id="share-sync-revert" @click="inboundSyncSharedProfile" :disabled="props.instance.sync_update_version?.is_synced">
|
||||
<GlobeIcon /> Revert
|
||||
</Button>
|
||||
</div>
|
||||
<div v-else>
|
||||
not yours
|
||||
{{ props.instance.sync_update_version }}
|
||||
<label for="share-sync">
|
||||
<span class="label__title">Sync shared profile</span>
|
||||
<span class="label__description" v-if="props.instance.sync_update_version?.is_synced">
|
||||
You are up to date with the shared profile.
|
||||
</span>
|
||||
<span class="label__description" v-else>
|
||||
You are not up to date with the shared profile. Click the button to update your instance.
|
||||
</span>
|
||||
</label>
|
||||
<Button id="share-sync-sync" @click="inboundSyncSharedProfile">
|
||||
<GlobeIcon /> Sync
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<div class="label">
|
||||
<h3>
|
||||
@ -502,7 +585,7 @@
|
||||
</div>
|
||||
</Card>
|
||||
<ModpackVersionModal
|
||||
v-if="instance.metadata.linked_data"
|
||||
v-if="instance.metadata.linked_data?.modrinth_modpack"
|
||||
ref="modpackVersionModal"
|
||||
:instance="instance"
|
||||
:versions="props.versions"
|
||||
@ -527,6 +610,7 @@ import {
|
||||
HammerIcon,
|
||||
ModalConfirm,
|
||||
DownloadIcon,
|
||||
GlobeIcon,
|
||||
ClipboardCopyIcon,
|
||||
Button,
|
||||
Toggle,
|
||||
@ -545,6 +629,12 @@ import {
|
||||
remove,
|
||||
update_repair_modrinth,
|
||||
} from '@/helpers/profile.js'
|
||||
import {
|
||||
get_all,
|
||||
outbound_sync,
|
||||
inbound_sync,
|
||||
share_generate
|
||||
} from '@/helpers/shared_profiles.js'
|
||||
import { computed, readonly, ref, shallowRef, watch } from 'vue'
|
||||
import { get_max_memory } from '@/helpers/jre.js'
|
||||
import { get } from '@/helpers/settings.js'
|
||||
@ -659,12 +749,18 @@ const unlinkModpack = ref(false)
|
||||
|
||||
const inProgress = ref(false)
|
||||
const installing = computed(() => props.instance.install_stage !== 'installed')
|
||||
const installedVersion = computed(() => props.instance?.metadata?.linked_data?.version_id)
|
||||
const installedVersion = computed(() => props.instance?.metadata?.linked_data?.modrinth_modpack?.version_id)
|
||||
const installedVersionData = computed(() => {
|
||||
if (!installedVersion.value) return null
|
||||
return props.versions.find((version) => version.id === installedVersion.value)
|
||||
})
|
||||
|
||||
const sharedProfiles = await get_all();
|
||||
const installedSharedProfileData = computed(() => {
|
||||
if (!props.instance.metadata.linked_data?.shared_profile) return null
|
||||
return sharedProfiles.find((profile) => profile.id === props.instance.metadata.linked_data?.shared_profile?.profile_id)
|
||||
})
|
||||
|
||||
watch(
|
||||
[
|
||||
title,
|
||||
@ -794,13 +890,13 @@ async function unpairProfile() {
|
||||
|
||||
async function unlockProfile() {
|
||||
const editProfile = props.instance
|
||||
editProfile.metadata.linked_data.locked = false
|
||||
editProfile.metadata.linked_data.modrinth_modpack.locked = false
|
||||
await edit(props.instance.path, editProfile)
|
||||
modalConfirmUnlock.value.hide()
|
||||
}
|
||||
|
||||
const isPackLocked = computed(() => {
|
||||
return props.instance.metadata.linked_data && props.instance.metadata.linked_data.locked
|
||||
return props.instance.metadata.linked_data?.modrinth_modpack.locked
|
||||
})
|
||||
|
||||
async function repairModpack() {
|
||||
@ -932,6 +1028,20 @@ async function saveGvLoaderEdits() {
|
||||
editing.value = false
|
||||
changeVersionsModal.value.hide()
|
||||
}
|
||||
|
||||
async function outboundSyncSharedProfile() {
|
||||
await outbound_sync(props.instance.path).catch(handleError)
|
||||
}
|
||||
|
||||
async function inboundSyncSharedProfile() {
|
||||
await inbound_sync(props.instance.path).catch(handleError)
|
||||
}
|
||||
|
||||
const shareLink = ref(null)
|
||||
async function generateShareLink() {
|
||||
shareLink.value = await share_generate(props.instance.path).catch(handleError)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@ -1012,4 +1122,32 @@ async function saveGvLoaderEdits() {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
}
|
||||
.table {
|
||||
margin-block-start: 0;
|
||||
border-radius: var(--radius-lg);
|
||||
border: 2px solid var(--color-bg);
|
||||
}
|
||||
|
||||
.table-row {
|
||||
grid-template-columns: 7fr 1fr;
|
||||
}
|
||||
|
||||
.table-cell {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.user-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
|
||||
|
||||
.title {
|
||||
color: var(--color-contrast);
|
||||
font-weight: bolder;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
@ -314,10 +314,10 @@ async function fetchProjectData() {
|
||||
categories.value,
|
||||
instance.value,
|
||||
] = await Promise.all([
|
||||
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}`, 'project'),
|
||||
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}/version`, 'project'),
|
||||
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}/members`, 'project'),
|
||||
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}/dependencies`, 'project'),
|
||||
useFetch(`https://staging-api.modrinth.com/v2/project/${route.params.id}`, 'project'),
|
||||
useFetch(`https://staging-api.modrinth.com/v2/project/${route.params.id}/version`, 'project'),
|
||||
useFetch(`https://staging-api.modrinth.com/v2/project/${route.params.id}/members`, 'project'),
|
||||
useFetch(`https://staging-api.modrinth.com/v2/project/${route.params.id}/dependencies`, 'project'),
|
||||
get_categories().catch(handleError),
|
||||
route.query.i ? getInstance(route.query.i, false).catch(handleError) : Promise.resolve(),
|
||||
])
|
||||
@ -391,7 +391,7 @@ async function install(version) {
|
||||
packs.length === 0 ||
|
||||
!packs
|
||||
.map((value) => value.metadata)
|
||||
.find((pack) => pack.linked_data?.project_id === data.value.id)
|
||||
.find((pack) => pack.linked_data?.modrinth_modpack?.project_id === data.value.id)
|
||||
) {
|
||||
await packInstall(
|
||||
data.value.id,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user