Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
17 changes: 15 additions & 2 deletions .github/workflows/theseus-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ on:
- 'packages/utils/**'
workflow_dispatch:
inputs:
sign-macos-binaries:
description: Sign macOS binaries
type: boolean
default: true
required: false
sign-windows-binaries:
description: Sign Windows binaries
type: boolean
Expand Down Expand Up @@ -170,9 +175,9 @@ jobs:
dasel delete -f apps/app/tauri-release.conf.json 'bundle.windows.signCommand'
fi

- name: Build macOS app
- name: Build signed macOS app
run: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || inputs.app-version-override != '') && 'pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-release.conf.json' || 'pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-dev.conf.json' }}
if: contains(matrix.artifact-target-name, 'darwin')
if: contains(matrix.artifact-target-name, 'darwin') && (github.event_name != 'workflow_dispatch' || inputs.sign-macos-binaries)
env:
TAURI_BUNDLER_DMG_IGNORE_CI: 'true'
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
Expand All @@ -185,6 +190,14 @@ jobs:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}

- name: Build unsigned macOS app
run: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || inputs.app-version-override != '') && 'pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-release.conf.json' || 'pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-dev.conf.json' }}
if: contains(matrix.artifact-target-name, 'darwin') && github.event_name == 'workflow_dispatch' && !inputs.sign-macos-binaries
env:
TAURI_BUNDLER_DMG_IGNORE_CI: 'true'
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}

- name: Build Linux app
run: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || inputs.app-version-override != '') && 'pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json' || 'pnpm --filter=@modrinth/app run tauri build --config tauri-dev.conf.json' }}
if: contains(matrix.artifact-target-name, 'linux')
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ rust-s3 = { version = "0.38.0", default-features = false, features = [
"tags",
"tokio-rustls-tls",
] }
rustls = "0.23.46"
rustls = { version = "0.23.46", default-features = false }
rustrict = { version = "0.7.39", default-features = false, features = ["censor"] }
rusty-money = "0.5.1"
same-file = "1.0.6"
Expand Down
95 changes: 57 additions & 38 deletions apps/app-frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
commonSettingsMessages,
ContentInstallModal,
ContentUpdaterModal,
createServerInviteHandoff,
createServerOnboardingFlow,
CreationFlowModal,
defineMessages,
I18nDebugPanel,
Expand All @@ -35,12 +37,17 @@ import {
NotificationPanel,
PopupNotificationPanel,
provideFileDownload,
provideIconCache,
provideLoadingState,
provideModalBehavior,
provideModrinthClient,
provideNotificationManager,
providePageContext,
providePopupNotificationManager,
provideServerInviteHandoff,
provideServerOnboardingFlow,
provideServerPlay,
ServerOnboardingModal,
TeleportOverflowMenu,
TooltipDirective,
useDebugLogger,
Expand Down Expand Up @@ -90,6 +97,12 @@ import { useInstanceMetadataRefresh } from '@/composables/use-instance-metadata-
import { useQuickInstanceLimit } from '@/composables/use-quick-instance-limit.ts'
import { isDarkTheme, useTheme } from '@/composables/use-theme.ts'
import { config } from '@/config'
import ServerPlayHandler from '@/features/hosting/play-handler.vue'
import { prefetchHostingData } from '@/features/hosting/prefetch'
import {
createInstanceLaunchState,
provideInstanceLaunchState,
} from '@/features/instances/launch-state'
import { provideMinecraftAccounts } from '@/features/minecraft-accounts/context'
import AppSettingsModal from '@/features/settings/app-settings-modal/index.vue'
import { provideSettingsActions } from '@/features/settings/settings-actions'
Expand Down Expand Up @@ -160,6 +173,7 @@ import {
screenshotKeys,
} from '@/pages/instance/query-options'
import { createFileDownload } from '@/platform/adapters/file-download'
import { createIconCache } from '@/platform/adapters/icon-cache'
import { createAppClient } from '@/platform/modrinth-client'
import {
appUpdateState,
Expand Down Expand Up @@ -286,7 +300,20 @@ useAppEvent('ads_consent_required', handleAdsConsentRequired, appEvents)

const tauriApiClient = createAppClient()
provideModrinthClient(tauriApiClient)
provideServerOnboardingFlow(createServerOnboardingFlow())
provideServerInviteHandoff(createServerInviteHandoff())
provideFileDownload(createFileDownload(tauriApiClient, trackExternalFileDownload))
const iconCache = createIconCache()
provideIconCache(iconCache)
provideInstanceLaunchState(createInstanceLaunchState())
const serverPlayHandler = ref()
const serverPlay = {
async play(target) {
if (!serverPlayHandler.value) throw new Error('Server play handler is not ready.')
await serverPlayHandler.value.play(target)
},
}
provideServerPlay(serverPlay)
const { data: authenticatedModrinthUser } = useQuery({
queryKey: computed(() => ['authenticated-user', 'campaigns', credentials.value?.user?.id]),
queryFn: () => tauriApiClient.labrinth.users_v3.getAuthenticated(),
Expand Down Expand Up @@ -808,8 +835,14 @@ async function setupApp() {
}

const stateFailed = ref(false)
const { loading, canNavigateBack, canNavigateForward, onSuspensePending, onSuspenseResolve } =
useRouteLoading({ stateInitialized, stateFailed })
const {
loading,
canNavigateBack,
canNavigateForward,
onboardingPageReady,
onSuspensePending,
onSuspenseResolve,
} = useRouteLoading({ stateInitialized, stateFailed })
provideLoadingState(loading)

traceStartupStep('Initialize backend state', () => initialize_state(appEventChannel))
Expand All @@ -833,42 +866,19 @@ const handleClose = async () => {

const queryClient = useQueryClient()

watch(stateInitialized, (ready) => {
if (ready) {
queryClient.prefetchQuery({
queryKey: ['servers'],
queryFn: async () => {
const response = await tauriApiClient.archon.servers_v0.list({ limit: 100 })
const hasMedalServers = response.servers.some((s) => s.is_medal)
if (hasMedalServers) {
const subscriptions = await tauriApiClient.labrinth.billing_internal.getSubscriptions()
for (const server of response.servers) {
if (server.is_medal) {
const sub = subscriptions.find((s) => s.metadata?.id === server.server_id)
if (sub) {
server.medal_expires = new Date(
new Date(sub.created).getTime() + 5 * 86400000,
).toISOString()
}
}
}
}
return response
},
staleTime: 30_000,
})
queryClient.prefetchQuery({
queryKey: ['billing', 'subscriptions'],
queryFn: () => tauriApiClient.labrinth.billing_internal.getSubscriptions(),
staleTime: 30_000,
})
queryClient.prefetchQuery({
queryKey: ['billing', 'payments'],
queryFn: () => tauriApiClient.labrinth.billing_internal.getPayments(),
staleTime: 30_000,
})
}
})
watch(
() => stateInitialized.value && credentials.value?.session,
(session) => {
if (!session) return

void prefetchHostingData(
queryClient,
tauriApiClient,
iconCache,
() => credentials.value?.session === session,
)
},
)

const error = useError()
const errorModal = ref()
Expand Down Expand Up @@ -1539,6 +1549,8 @@ async function handleCommand(e) {
} else {
await run(e.id).catch(handleError)
}
} else if (e.event === 'PlayHostingServer') {
await serverPlay.play({ serverId: e.server_id, worldId: e.world_id }).catch(handleError)
} else if (e.event === 'InstallSharedInstanceInvite') {
await sharedInstanceInviteHandler.value?.installFromInviteId(e.invite_id)
} else if (e.event === 'InstallServer') {
Expand Down Expand Up @@ -2005,6 +2017,12 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
@create="handleCreate"
@browse-modpacks="handleBrowseModpacks"
/>
<ServerOnboardingModal
browse-path="/browse/modpack"
:get-loader-manifest="getLoaderManifest"
:navigate="(to) => router.push(to)"
:page-ready="onboardingPageReady"
/>
<IconEditorModal
ref="creationIconEditorModal"
:config="creationGeneratedIcon?.config"
Expand Down Expand Up @@ -2274,6 +2292,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
@create-anyway="handleContentInstallModpackDuplicateCreateAnyway"
@go-to-instance="handleContentInstallModpackDuplicateGoToInstance"
/>
<ServerPlayHandler ref="serverPlayHandler" />
<SharedInstanceInviteHandler ref="sharedInstanceInviteHandler" />
<InstallToPlayModal ref="installToPlayModal" :show-external-warnings="false" />
<UpdateToPlayModal ref="updateToPlayModal" :show-external-warnings="false" />
Expand Down
12 changes: 11 additions & 1 deletion apps/app-frontend/src/app/runtime/use-route-loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export function useRouteLoading({ stateInitialized, stateFailed }: RouteLoadingO
const route = useRoute()
const canNavigateBack = ref(false)
const canNavigateForward = ref(false)
const onboardingPageReady = ref(true)
let initialLoadToken: symbol | null = null
let routerToken: symbol | null = null
let suspenseToken: symbol | null = null
Expand Down Expand Up @@ -83,6 +84,7 @@ export function useRouteLoading({ stateInitialized, stateFailed }: RouteLoadingO
})

function onSuspensePending() {
onboardingPageReady.value = false
debugStartup('Route Suspense pending', { route: route.path })
suspensePending = true
viewportScroll.onRoutePending()
Expand All @@ -91,6 +93,7 @@ export function useRouteLoading({ stateInitialized, stateFailed }: RouteLoadingO
}

function onSuspenseResolve() {
onboardingPageReady.value = true
debugStartup('Route Suspense resolved', { route: route.path })
viewportScroll.onRouteResolved()
if (suspenseToken) {
Expand Down Expand Up @@ -120,5 +123,12 @@ export function useRouteLoading({ stateInitialized, stateFailed }: RouteLoadingO
}
})

return { loading, canNavigateBack, canNavigateForward, onSuspensePending, onSuspenseResolve }
return {
loading,
canNavigateBack,
canNavigateForward,
onboardingPageReady,
onSuspensePending,
onSuspenseResolve,
}
}
4 changes: 2 additions & 2 deletions apps/app-frontend/src/components/ui/HostingUpdateRequired.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { DownloadIcon, ExcitedRinthbot, RefreshCwIcon, ServerStackIcon } from '@modrinth/assets'
import { Button, commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
import { Button, defineMessages, useVIntl } from '@modrinth/ui'
import { computed } from 'vue'

import {
Expand Down Expand Up @@ -42,7 +42,7 @@ const messages = defineMessages({
useRootBreadcrumb({
slot: 'root',
id: 'servers',
label: () => formatMessage(commonMessages.serversLabel),
label: 'Hosting',
to: '/hosting/manage/',
visual: { type: 'icon', component: ServerStackIcon },
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ defineEmits<{ close: [] }>()

const messages = defineMessages({
title: { id: 'app.download-manager.title', defaultMessage: 'Download manager' },
show: { id: 'app.download-manager.show', defaultMessage: 'Show installation tasks' },
hide: { id: 'app.download-manager.hide', defaultMessage: 'Hide installation tasks' },
show: { id: 'app.download-manager.show-tasks', defaultMessage: 'Show tasks' },
hide: { id: 'app.download-manager.hide-tasks', defaultMessage: 'Hide tasks' },
attention: { id: 'app.download-manager.attention', defaultMessage: 'Needs attention' },
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
CheckIcon,
CopyIcon,
DownloadIcon,
MinecraftServerIcon,
PauseIcon,
PlayIcon,
TrashIcon,
Expand All @@ -21,6 +22,7 @@ import {
ProgressBar,
truncatedTooltip,
useRelativeTime,
useServerIcon,
useVIntl,
} from '@modrinth/ui'
import { computed, useTemplateRef } from 'vue'
Expand All @@ -29,6 +31,10 @@ import { RouterLink } from 'vue-router'
import type { DownloadManagerJob } from './use-download-manager'

const props = defineProps<{ job: DownloadManagerJob }>()
const { icon: serverIcon } = useServerIcon(() => props.job.serverId ?? '')
const displayIcon = computed(() =>
props.job.serverId ? (serverIcon.value ?? MinecraftServerIcon) : props.job.iconUrl,
)
defineEmits<{
retry: [id: string]
cancel: [id: string]
Expand Down Expand Up @@ -95,8 +101,8 @@ const instanceLink = computed(() =>
@click="instanceLink && $emit('open')"
>
<Avatar
v-if="job.iconUrl"
:src="job.iconUrl"
v-if="displayIcon"
:src="displayIcon"
size="36px"
no-shadow
class="!rounded-xl border border-solid border-surface-5"
Expand Down Expand Up @@ -126,7 +132,7 @@ const instanceLink = computed(() =>
{{ job.title }}
</span>
<span
v-if="job.taskType && job.taskType !== job.text"
v-if="job.kind !== 'external-file' && job.taskType && job.taskType !== job.text"
class="truncate text-xs font-medium leading-4 text-primary"
>
{{ job.taskType }}
Expand All @@ -141,6 +147,12 @@ const instanceLink = computed(() =>
: 'text-primary'
"
>
<template
v-if="job.kind === 'external-file' && job.taskType && job.taskType !== job.text"
>
<span class="min-w-0 truncate text-primary">{{ job.taskType }}</span>
<BulletDivider class="shrink-0 text-primary" />
</template>
<template v-if="complete && job.finishedAt">
<time :datetime="job.finishedAt" class="shrink-0">
{{ formatRelativeTime(job.finishedAt) }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const messages = defineMessages({
defaultMessage: 'Clear all completed tasks',
},
complete: { id: 'app.download-manager.complete', defaultMessage: 'Complete' },
empty: { id: 'app.download-manager.empty', defaultMessage: 'No installation tasks' },
empty: { id: 'app.download-manager.no-tasks', defaultMessage: 'No tasks' },
rate: { id: 'app.download-manager.estimated-rate', defaultMessage: 'Estimated download speed' },
})
const panel = useTemplateRef('panel')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
width="544px"
>
<div v-if="requiredContentProject" class="flex w-full flex-col gap-6">
<p class="m-0 text-primary">
{{ formatMessage(messages.inviteWarning) }}
</p>

<div class="flex flex-col gap-2.5">
<div class="flex items-center justify-between">
<span class="font-semibold text-contrast">
Expand Down Expand Up @@ -401,11 +397,6 @@ const messages = defineMessages({
id: 'app.modal.install-to-play.header',
defaultMessage: 'Install to play',
},
inviteWarning: {
id: 'app.modal.install-to-play.invite-warning',
defaultMessage:
'This invite was created by another Modrinth user, not Modrinth. Only accept invites from people you trust.',
},
sharedInstance: {
id: 'app.modal.install-to-play.shared-instance',
defaultMessage: 'Shared instance',
Expand Down
Loading
Loading