Skip to content
Draft
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions SERVER_PLAY_NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Flow:
1. Shared instance wont exist until they:
- Click "Play server"
- Need special handling in-app
- Click "Invite players"
- Click "Download mrpack"
- disable btns until share response is done, then continue
2. When content changes, watch shared_instance_needs_update: boolean on WorldsFull, show "Push update" admonition like app instances
1. Push update flow like usual, show content changes diff]
2. tbd
16 changes: 6 additions & 10 deletions apps/app-frontend/src/pages/Browse.vue
Original file line number Diff line number Diff line change
Expand Up @@ -909,17 +909,18 @@ function getCardActions(
const isQueued = queuedServerInstallProjectIds.value.has(projectResult.project_id)
const isQueuedRoot = queuedServerInstallRootProjectIds.value.has(projectResult.project_id)
const isInstallingSelection = isInstallingQueuedServerInstalls.value
const showAsInstalling = isInstalling || (isInstallingSelection && isQueuedRoot)
const validatingInstall =
isInstalling && currentProjectType !== 'modpack' && !isInstallingSelection
const installLabel = showAsInstalled
? commonMessages.installedLabel
: isQueued
? isInstalling || isInstallingSelection
? showAsInstalling
? validatingInstall
? commonMessages.validatingLabel
: messages.installingToServer
: commonMessages.selectedLabel
: isInstalling || isInstallingSelection
: showAsInstalling
? validatingInstall
? commonMessages.validatingLabel
: messages.installingToServer
Expand All @@ -928,16 +929,11 @@ function getCardActions(
{
key: 'install',
label: formatMessage(installLabel),
icon:
isInstalling || isInstallingSelection
? SpinnerIcon
: isQueued || showAsInstalled
? CheckIcon
: PlusIcon,
iconClass: isInstalling || isInstallingSelection ? 'animate-spin' : undefined,
icon: showAsInstalling ? SpinnerIcon : isQueued || showAsInstalled ? CheckIcon : PlusIcon,
iconClass: showAsInstalling ? 'animate-spin' : undefined,
disabled:
showAsInstalled || isInstalling || isInstallingSelection || (isQueued && !isQueuedRoot),
color: isQueued && !isInstalling && !isInstallingSelection ? 'green' : 'brand',
color: isQueued && !showAsInstalling ? 'green' : 'brand',
type: 'outlined',
onClick: async () => {
if (isQueuedRoot) {
Expand Down
7 changes: 7 additions & 0 deletions apps/app-frontend/src/pages/hosting/manage/Play.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script setup lang="ts">
import { ServersManagePlayPage } from '@modrinth/ui'
</script>

<template>
<ServersManagePlayPage />
</template>
3 changes: 2 additions & 1 deletion apps/app-frontend/src/pages/hosting/manage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ import Content from './Content.vue'
import Files from './Files.vue'
import Index from './Index.vue'
import Overview from './Overview.vue'
import Play from './Play.vue'

export { Access, Backups, Content, Files, Index, Overview }
export { Access, Backups, Content, Files, Index, Overview, Play }
5 changes: 5 additions & 0 deletions apps/app-frontend/src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ export default new createRouter({
name: 'ServerManage',
component: Hosting.Index,
children: [
{
path: 'play',
name: 'ServerManagePlay',
component: Hosting.Play,
},
{
path: '',
name: 'ServerManageOverview',
Expand Down
16 changes: 6 additions & 10 deletions apps/frontend/src/pages/discover/[type]/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -361,17 +361,18 @@ function getCardActions(
serverData.value.upstream?.project_id === result.project_id
const isInstalling = installingProjectIds.value.has(result.project_id)
const isInstallingSelection = isInstallingQueuedServerInstalls.value
const showAsInstalling = isInstalling || (isInstallingSelection && isQueuedRoot)
const validatingInstall =
isInstalling && currentProjectType !== 'modpack' && !isInstallingSelection
const installLabel = isInstalled
? formatMessage(commonMessages.installedLabel)
: isQueued
? isInstalling || isInstallingSelection
? showAsInstalling
? validatingInstall
? formatMessage(commonMessages.validatingLabel)
: formatMessage(commonMessages.installingLabel)
: formatMessage(commonMessages.selectedLabel)
: isInstalling || isInstallingSelection
: showAsInstalling
? validatingInstall
? formatMessage(commonMessages.validatingLabel)
: formatMessage(commonMessages.installingLabel)
Expand All @@ -381,16 +382,11 @@ function getCardActions(
{
key: 'install',
label: installLabel,
icon:
isInstalling || isInstallingSelection
? SpinnerIcon
: isQueued || isInstalled
? CheckIcon
: DownloadIcon,
iconClass: isInstalling || isInstallingSelection ? 'animate-spin' : undefined,
icon: showAsInstalling ? SpinnerIcon : isQueued || isInstalled ? CheckIcon : DownloadIcon,
iconClass: showAsInstalling ? 'animate-spin' : undefined,
disabled:
!!isInstalled || isInstalling || isInstallingSelection || (isQueued && !isQueuedRoot),
color: isQueued && !isInstalling && !isInstallingSelection ? 'green' : 'brand',
color: isQueued && !showAsInstalling ? 'green' : 'brand',
type: 'outlined',
onClick: () => serverInstall(projectResult),
},
Expand Down
13 changes: 13 additions & 0 deletions apps/frontend/src/pages/hosting/manage/[id]/play.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script setup lang="ts">
import { injectModrinthServerContext, ServersManagePlayPage } from '@modrinth/ui'

const { server } = injectModrinthServerContext()

useHead({
title: computed(() => `Play - ${server.value?.name ?? 'Server'} - Modrinth`),
})
</script>

<template>
<ServersManagePlayPage />
</template>
51 changes: 51 additions & 0 deletions packages/api-client/src/modules/archon/content/v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,57 @@ export class ArchonContentV1Module extends AbstractModule {
})
}

/** POST /v1/:server_id/worlds/:world_id/addons/set-enabled-server */
public async setAddonEnabledServer(
serverId: string,
worldId: string,
request: Archon.Content.v1.SetAddonEnabledRequest,
): Promise<void> {
await this.client.request<void>(
`/servers/${serverId}/worlds/${worldId}/addons/set-enabled-server`,
{
api: 'archon',
version: 1,
method: 'POST',
body: request,
},
)
}

/** POST /v1/:server_id/worlds/:world_id/addons/set-enabled-player */
public async setAddonEnabledPlayer(
serverId: string,
worldId: string,
request: Archon.Content.v1.SetAddonEnabledRequest,
): Promise<void> {
await this.client.request<void>(
`/servers/${serverId}/worlds/${worldId}/addons/set-enabled-player`,
{
api: 'archon',
version: 1,
method: 'POST',
body: request,
},
)
}

/** POST /v1/:server_id/worlds/:world_id/addons/set-locked-side-toggle */
public async setAddonSideToggleLocked(
serverId: string,
worldId: string,
request: Archon.Content.v1.SetAddonSideToggleLockedRequest,
): Promise<void> {
await this.client.request<void>(
`/servers/${serverId}/worlds/${worldId}/addons/set-locked-side-toggle`,
{
api: 'archon',
version: 1,
method: 'POST',
body: request,
},
)
}

/** POST /v1/:server_id/worlds/:world_id/addons/delete-many */
public async deleteAddons(
serverId: string,
Expand Down
32 changes: 32 additions & 0 deletions packages/api-client/src/modules/archon/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,25 @@ export namespace Archon {
environment?: Labrinth.Projects.v3.Environment | null
}

export type AddonManifestEnvironment =
| 'client_and_server'
| 'client_only'
| 'dedicated_server_only'

export type AddonManifestWarnings = {
multiple_mod_entries: number | null
malformed: boolean
}

export type AddonManifest = {
platform: Modloader
name: string | null
version: string | null
environment: AddonManifestEnvironment | null
icon_embedded: boolean
warnings: AddonManifestWarnings
}

export type AddonStatus =
| 'pending'
| 'installed'
Expand All @@ -316,6 +335,10 @@ export namespace Archon {
filesize: number
btime?: string
disabled: boolean
disabled_server: boolean
disabled_player: boolean
side_toggle_unlocked: boolean
manifest: AddonManifest | null
kind: AddonKind
from_modpack: boolean
status: AddonStatus
Expand Down Expand Up @@ -354,6 +377,14 @@ export namespace Archon {
filename: string
}

export type SetAddonEnabledRequest = RemoveAddonRequest & {
enabled: boolean
}

export type SetAddonSideToggleLockedRequest = RemoveAddonRequest & {
locked: boolean
}

export type UpdateAddonRequest = {
filename: string
version_id?: string | null
Expand Down Expand Up @@ -1073,6 +1104,7 @@ export namespace Archon {
project_id: string | null
pack_client_retained: boolean
pack_client_depends: boolean
manifest?: Archon.Content.v1.AddonManifest | null
status: Archon.Content.v1.AddonStatus
filesize: number | null
name: string | null
Expand Down
18 changes: 18 additions & 0 deletions packages/api-client/src/modules/kyros/content/v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@ export class KyrosContentV1Module extends AbstractModule {
return 'kyros_content_v1'
}

/** GET /v1/worlds/:world_id/content/embedded-icon */
public async getEmbeddedAddonIcon(
worldId: string,
parentDirectory: 'mods' | 'plugins',
filename: string,
): Promise<Blob> {
return this.client.request<Blob>(`/worlds/${worldId}/content/embedded-icon`, {
api: '',
version: 'v1',
method: 'GET',
params: {
parent_directory: parentDirectory,
filename,
},
useNodeAuth: true,
})
}

/**
* Upload addon files to a world via multipart form data
*
Expand Down
28 changes: 18 additions & 10 deletions packages/ui/src/components/base/Toggle.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,37 @@
:id="id"
type="button"
role="switch"
:aria-checked="modelValue"
:aria-checked="indeterminate ? 'mixed' : modelValue"
:disabled="disabled"
class="group inline-flex shrink-0 touch-manipulation items-center rounded-full m-0 p-1 transition-all duration-200 cursor-pointer border border-solid border-surface-5"
:class="[
small ? 'h-5 !w-[40px]' : 'h-6 !w-[48px]',
modelValue ? 'bg-brand' : 'bg-button-bg',
indeterminate || modelValue ? 'bg-brand' : 'bg-button-bg',
disabled ? 'opacity-50 cursor-not-allowed' : '',
]"
@click="toggle"
>
<span
class="rounded-full transition-all duration-200"
:class="[
small ? 'w-3 h-3' : 'w-4 h-4',
modelValue
indeterminate
? small
? 'translate-x-[20px] bg-black/90'
: 'translate-x-[24px] bg-black/90'
: 'bg-secondary',
? 'h-0.5 w-2.5 translate-x-[11px] bg-black/90'
: 'h-0.5 w-3 translate-x-[14px] bg-black/90'
: modelValue
? small
? 'h-3 w-3 translate-x-[20px] bg-black/90'
: 'h-4 w-4 translate-x-[24px] bg-black/90'
: small
? 'h-3 w-3 bg-gray'
: 'h-4 w-4 bg-gray',
disabled
? ''
: small
? 'group-hover:w-[14px] group-hover:h-[14px] group-hover:m-[-1px] group-active:w-[10px] group-active:h-[10px] group-active:m-[1px]'
: 'group-hover:w-[18px] group-hover:h-[18px] group-hover:m-[-1px] group-active:w-[14px] group-active:h-[14px] group-active:m-[1px]',
: indeterminate
? 'group-hover:scale-x-110 group-active:scale-x-75'
: small
? 'group-hover:w-[14px] group-hover:h-[14px] group-hover:m-[-1px] group-active:w-[10px] group-active:h-[10px] group-active:m-[1px]'
: 'group-hover:w-[18px] group-hover:h-[18px] group-hover:m-[-1px] group-active:w-[14px] group-active:h-[14px] group-active:m-[1px]',
]"
/>
</button>
Expand All @@ -37,6 +44,7 @@ const props = defineProps<{
id?: string
disabled?: boolean
small?: boolean
indeterminate?: boolean
}>()

const modelValue = defineModel<boolean>()
Expand Down
Loading
Loading