diff --git a/.github/workflows/axolotl-release.yml b/.github/workflows/axolotl-release.yml
index 3709c38..bae9f35 100644
--- a/.github/workflows/axolotl-release.yml
+++ b/.github/workflows/axolotl-release.yml
@@ -1,4 +1,4 @@
-name: Axolotl release
+name: Starlight release
on:
push:
@@ -53,6 +53,15 @@ jobs:
node scripts/axolotl/i18n-check.mjs
cargo fmt --all --check
+ - name: Check updater signing configuration
+ env:
+ TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
+ run: |
+ if [[ -z "${TAURI_SIGNING_PRIVATE_KEY:-}" ]]; then
+ echo '::error::Configure TAURI_SIGNING_PRIVATE_KEY with the private key matching apps/app/tauri-release.conf.json before publishing updates.'
+ exit 1
+ fi
+
- name: Prepare draft release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -72,7 +81,7 @@ jobs:
release_args=(
--draft
--notes-file "$release_notes"
- --title "Axolotl Launcher ${GITHUB_REF_NAME}"
+ --title "Starlight Launcher ${GITHUB_REF_NAME}"
)
if [[ "${GITHUB_REF_NAME}" == *-* ]]; then
release_args+=(--prerelease)
@@ -175,7 +184,7 @@ jobs:
tauriScript: pnpm tauri
args: ${{ matrix.args }}
tagName: ${{ github.ref_name }}
- releaseName: Axolotl Launcher ${{ github.ref_name }}
+ releaseName: Starlight Launcher ${{ github.ref_name }}
releaseDraft: true
prerelease: ${{ contains(github.ref_name, '-') }}
generateReleaseNotes: false
@@ -277,12 +286,17 @@ jobs:
name: Verify and publish
needs: build
runs-on: ubuntu-24.04
+ env:
+ UPDATE_SERVER_URL: ${{ secrets.UPDATE_SERVER_URL }}
+ UPDATE_SERVER_WEBHOOK_SECRET: ${{ secrets.UPDATE_SERVER_WEBHOOK_SECRET }}
+ CNB_TOKEN: ${{ secrets.CNB_TOKEN }}
+ CNB_REPO_URL_HTTPS: ${{ secrets.CNB_REPO_URL_HTTPS }}
steps:
- name: Check out source
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- ref: main
+ ref: ${{ github.ref }}
- name: Download updater signatures
env:
@@ -349,6 +363,7 @@ jobs:
node scripts/axolotl/create-update-server-catalog.test.mjs
- name: Notify Update Server to publish release assets
+ if: ${{ env.UPDATE_SERVER_URL != '' && env.UPDATE_SERVER_WEBHOOK_SECRET != '' }}
env:
UPDATE_SERVER_URL: ${{ secrets.UPDATE_SERVER_URL }}
UPDATE_SERVER_WEBHOOK_SECRET: ${{ secrets.UPDATE_SERVER_WEBHOOK_SECRET }}
@@ -359,6 +374,13 @@ jobs:
release-check/release.json \
"${GITHUB_REF_NAME}"
+ - name: Check out website branch
+ if: ${{ !contains(github.ref_name, '-') }}
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
+ with:
+ ref: main
+ clean: false
+
- name: Publish website download metadata
if: ${{ !contains(github.ref_name, '-') }}
env:
@@ -381,11 +403,14 @@ jobs:
fi
- name: Mirror published release to CNB
+ if: ${{ env.CNB_TOKEN != '' && env.CNB_REPO_URL_HTTPS != '' }}
env:
CNB_REPO_URL_HTTPS: ${{ secrets.CNB_REPO_URL_HTTPS }}
CNB_TOKEN: ${{ secrets.CNB_TOKEN }}
CNB_TOKEN_USER_NAME: ${{ secrets.CNB_TOKEN_USER_NAME }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITHUB_API_BASE_URL: https://api.github.com/repos/${{ github.repository }}
+ GITHUB_RELEASE_BASE_URL: https://github.com/${{ github.repository }}/releases/download
run: |
set -euo pipefail
if [[ -z "${CNB_TOKEN:-}" ]]; then
diff --git a/.github/workflows/sync-cnb-source.yml b/.github/workflows/sync-cnb-source.yml
index 96f5fa6..71cf563 100644
--- a/.github/workflows/sync-cnb-source.yml
+++ b/.github/workflows/sync-cnb-source.yml
@@ -19,6 +19,7 @@ concurrency:
jobs:
sync:
name: Sync Git ref
+ if: ${{ vars.ENABLE_CNB_SYNC == 'true' }}
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
@@ -38,8 +39,8 @@ jobs:
DELETED_REF_TYPE: ${{ github.event.ref_type }}
run: |
set -euo pipefail
- if [[ -z "${CNB_TOKEN:-}" ]]; then
- echo "CNB_TOKEN is not configured"
+ if [[ -z "${CNB_TOKEN:-}" || -z "${CNB_REPO_URL_HTTPS:-}" ]]; then
+ echo "CNB_TOKEN and CNB_REPO_URL_HTTPS must be configured"
exit 1
fi
diff --git a/apps/app-frontend/package.json b/apps/app-frontend/package.json
index ce8bc27..d0a30b2 100644
--- a/apps/app-frontend/package.json
+++ b/apps/app-frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "@modrinth/app-frontend",
"private": true,
- "version": "1.0.0-beta1",
+ "version": "1.0.0-beta12",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/apps/app-frontend/src/components/RowDisplay.vue b/apps/app-frontend/src/components/RowDisplay.vue
index b55fb5c..723204d 100644
--- a/apps/app-frontend/src/components/RowDisplay.vue
+++ b/apps/app-frontend/src/components/RowDisplay.vue
@@ -42,6 +42,7 @@ const { offline } = useNetworkStatus()
const handleMinecraftLaunchError = useMinecraftLaunchError()
const messages = defineMessages({
+ stopAll: { id: 'app.instance.stop-all', defaultMessage: 'Stop all windows of this instance' },
addContent: { id: 'app.instances.add-content', defaultMessage: 'Add content' },
viewInstance: { id: 'app.instances.view-instance', defaultMessage: 'View instance' },
duplicateInstance: {
@@ -265,7 +266,12 @@ onUnmounted(() => {
@delete="deleteInstance"
/>
-
+
{{ row.label }}
@@ -307,7 +313,7 @@ onUnmounted(() => {
{{ formatMessage(commonMessages.playButton) }}
- {{ formatMessage(commonMessages.stopButton) }}
+ {{ formatMessage(messages.stopAll) }}
{{ formatMessage(messages.addContent) }}
{{ formatMessage(messages.viewInstance) }}
{{ formatMessage(commonMessages.deleteLabel) }}
diff --git a/apps/app-frontend/src/components/home/HomeMinimal.vue b/apps/app-frontend/src/components/home/HomeMinimal.vue
index 865498f..b913783 100644
--- a/apps/app-frontend/src/components/home/HomeMinimal.vue
+++ b/apps/app-frontend/src/components/home/HomeMinimal.vue
@@ -29,6 +29,7 @@ import { process_listener } from '@/helpers/events'
import { install_existing_instance, install_pack_to_existing_instance } from '@/helpers/install'
import { kill, run } from '@/helpers/instance'
import { get_by_instance_id } from '@/helpers/process'
+import { isInstanceLaunching } from '@/helpers/instance-launch-state'
import type { GameInstance } from '@/helpers/types'
import { handleSevereError } from '@/store/error'
@@ -50,6 +51,8 @@ const handleMinecraftLaunchError = useMinecraftLaunchError()
const { offline } = useNetworkStatus()
const messages = defineMessages({
+ launchAnother: { id: 'app.instance.launch-another', defaultMessage: 'Launch another window' },
+ stopAll: { id: 'app.instance.stop-all', defaultMessage: 'Stop all windows of this instance' },
chooseInstance: {
id: 'app.home.minimal.choose-instance',
defaultMessage: 'Choose instance',
@@ -88,14 +91,17 @@ const selectedInstance = computed(() =>
props.instances.find((instance) => instance.id === props.selectedInstanceId),
)
const running = ref(false)
-const loading = ref(false)
-const currentEvent = ref(null)
+const installingId = ref()
const installed = computed(() => selectedInstance.value?.install_stage === 'installed')
const installing = computed(
() => selectedInstance.value?.install_stage.includes('installing') ?? false,
)
const busy = computed(
- () => loading.value || installing.value || (currentEvent.value === 'launched' && !running.value),
+ () =>
+ !!selectedInstance.value &&
+ (isInstanceLaunching(selectedInstance.value.id) ||
+ installingId.value === selectedInstance.value.id ||
+ installing.value),
)
const lastPlayed = computed(() => {
@@ -111,18 +117,17 @@ async function refreshProcessState() {
return
}
- const processes = await get_by_instance_id(selectedInstance.value.id).catch((error) => {
+ const id = selectedInstance.value.id
+ const processes = await get_by_instance_id(id).catch((error) => {
handleError(error)
return []
})
- running.value = processes.length > 0
+ if (selectedInstance.value?.id === id) running.value = processes.length > 0
}
async function playInstance() {
const instance = selectedInstance.value
- if (!instance) return
-
- loading.value = true
+ if (!instance || busy.value) return
try {
await run(instance.id)
} catch (error) {
@@ -132,7 +137,6 @@ async function playInstance() {
})
if (!handled) handleSevereError(error, { instanceId: instance.id })
} finally {
- loading.value = false
await refreshProcessState()
}
}
@@ -142,14 +146,14 @@ async function stopInstance() {
if (!instance) return
await kill(instance.id).catch(handleError)
- running.value = false
+ await refreshProcessState()
}
async function installInstance() {
const instance = selectedInstance.value
if (!instance) return
- loading.value = true
+ installingId.value = instance.id
try {
if (
instance.install_stage !== 'pack_installed' &&
@@ -168,14 +172,14 @@ async function installInstance() {
} catch (error) {
handleError(error)
} finally {
- loading.value = false
+ if (installingId.value === instance.id) installingId.value = undefined
}
}
watch(
() => props.selectedInstanceId,
() => {
- currentEvent.value = null
+ running.value = false
void refreshProcessState()
},
)
@@ -184,9 +188,7 @@ await refreshProcessState()
const unlistenProcess = await process_listener((event: { instance_id: string; event: string }) => {
if (event.instance_id !== selectedInstance.value?.id) return
- currentEvent.value = event.event
- if (event.event === 'finished') running.value = false
- else void refreshProcessState()
+ void refreshProcessState()
})
onUnmounted(() => {
@@ -237,13 +239,17 @@ onUnmounted(() => {
-
-