Skip to content

Commit

Permalink
Merge branch 'pyro' of github.com:/modrinth/code into pyro
Browse files Browse the repository at this point in the history
  • Loading branch information
not-nullptr committed Oct 18, 2024
2 parents 0b62856 + 415c43e commit 97c7407
Show file tree
Hide file tree
Showing 25 changed files with 493 additions and 183 deletions.
69 changes: 37 additions & 32 deletions apps/frontend/src/components/ui/servers/FileItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,38 +23,43 @@
</span>
</div>
</div>
<ButtonStyled type="transparent">
<OverflowMenu
class="btn-dropdown-animation flex items-center gap-1 rounded-xl bg-transparent px-2 py-1"
:options="[
{
id: 'rename',
action: () => $emit('rename', { name, type, path }),
},
{
id: 'move',
action: () => $emit('move', { name, type, path }),
},
{
id: 'download',
action: () => $emit('download', { name, type, path }),
shown: type !== 'directory',
},
{
id: 'delete',
action: () => $emit('delete', { name, type, path }),
color: 'red',
},
]"
direction="left"
>
<MoreHorizontalIcon class="h-5 w-5 bg-transparent" />
<template #rename> <EditIcon /> Rename </template>
<template #move> <ArrowBigUpDashIcon /> Move </template>
<template #download> <DownloadIcon /> Download </template>
<template #delete> <TrashIcon /> Delete </template>
</OverflowMenu>
</ButtonStyled>
<div class="flex w-fit items-center gap-4">
<span class="w-full text-nowrap text-sm text-secondary">
{{ new Date(modified * 1000).toLocaleString() }}
</span>
<ButtonStyled type="transparent">
<OverflowMenu
class="btn-dropdown-animation flex items-center gap-1 rounded-xl bg-transparent px-2 py-1"
:options="[
{
id: 'rename',
action: () => $emit('rename', { name, type, path }),
},
{
id: 'move',
action: () => $emit('move', { name, type, path }),
},
{
id: 'download',
action: () => $emit('download', { name, type, path }),
shown: type !== 'directory',
},
{
id: 'delete',
action: () => $emit('delete', { name, type, path }),
color: 'red',
},
]"
direction="left"
>
<MoreHorizontalIcon class="h-5 w-5 bg-transparent" />
<template #rename> <EditIcon /> Rename </template>
<template #move> <ArrowBigUpDashIcon /> Move </template>
<template #download> <DownloadIcon /> Download </template>
<template #delete> <TrashIcon /> Delete </template>
</OverflowMenu>
</ButtonStyled>
</div>
</div>
</template>

Expand Down
37 changes: 26 additions & 11 deletions apps/frontend/src/components/ui/servers/LogParser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,34 @@ const convert = new Convert({
fg: "#FFF",
bg: "#000",
newline: false,
escapeXML: false,
escapeXML: true,
stream: false,
colors,
});
const parsedLog = computed(() => {
return convert.toHtml(props.log);
});
const urlRegex = /https?:\/\/[^\s]+/g;
const usernameRegex = /&lt;([^&]+)&gt;/g;
const sanitizedLog = computed(() => {
return DOMPurify.sanitize(parsedLog.value, {
ALLOWED_TAGS: ["span"],
ALLOWED_ATTR: ["style"],
ALLOWED_CSS_STYLES: {
color: true,
"background-color": true,
},
let html = convert.toHtml(props.log);
html = html.replace(
urlRegex,
(url) =>
`<a style="color:var(--color-link);text-decoration:underline;" href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`,
);
html = html.replace(
usernameRegex,
(_, username) => `<span class="minecraft-username">&lt;${username}&gt;</span>`,
);
return DOMPurify.sanitize(html, {
ALLOWED_TAGS: ["span", "a"],
ALLOWED_ATTR: ["style", "href", "target", "rel", "class"],
ADD_ATTR: ["target"],
RETURN_TRUSTED_TYPE: true,
USE_PROFILES: { html: true },
});
});
</script>
Expand All @@ -70,4 +81,8 @@ html.dark-mode .parsed-log:hover {
html.oled-mode .parsed-log:hover {
background-color: #333;
}
.minecraft-username {
font-weight: bold;
}
</style>
81 changes: 29 additions & 52 deletions apps/frontend/src/components/ui/servers/PanelServerActionButton.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
<template>
<div class="flex flex-row items-center gap-2 rounded-lg">
<ButtonStyled v-if="showStopButton" type="standard" color="red">
<button :disabled="!canTakeAction || isStartingDelay || disabled" @click="killServer">
<ButtonStyled v-if="showKillButton" type="standard" color="red">
<button @click="killServer">
<div class="flex gap-1">
<SlashIcon class="h-5 w-5" />
<span>{{ killButtonText }}</span>
</div>
</button>
</ButtonStyled>
<ButtonStyled v-if="showStopButton" type="standard" color="red">
<button :disabled="!canTakeAction || isStartingDelay || disabled" @click="stopServer">
<button :disabled="!canTakeAction || disabled" @click="stopServer">
<div class="flex gap-1">
<StopCircleIcon class="h-5 w-5" />
<span>{{ stopButtonText }}</span>
</div>
</button>
</ButtonStyled>

<ButtonStyled type="standard" color="brand">
<button :disabled="!canTakeAction || isStartingDelay || disabled" @click="handleAction">
<button :disabled="!canTakeAction || disabled" @click="handleAction">
<div v-if="isStartingOrRestarting" class="grid place-content-center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path
Expand All @@ -28,11 +27,9 @@
/>
</svg>
</div>

<div v-else class="contents">
<component :is="showRestartIcon ? UpdatedIcon : PlayIcon" />
</div>

<span>
{{ actionButtonText }}
</span>
Expand All @@ -49,7 +46,7 @@ import { ButtonStyled } from "@modrinth/ui";
const props = defineProps<{
isOnline: boolean;
isActioning: boolean;
disabled: any;
disabled: boolean;
}>();
const emit = defineEmits<{
Expand All @@ -70,60 +67,50 @@ const currentState = ref<ServerStateType>(
props.isOnline ? ServerState.Running : ServerState.Stopped,
);
const showStopButton = computed(
() => currentState.value === ServerState.Running || currentState.value === ServerState.Stopping,
);
const isStartingDelay = ref(false);
const showKillButton = computed(() => currentState.value === ServerState.Running);
const showStopButton = computed(() => currentState.value === ServerState.Running);
const showRestartIcon = computed(() => currentState.value === ServerState.Running);
const canTakeAction = computed(
() =>
!props.isActioning &&
!isStartingDelay.value &&
currentState.value !== ServerState.Starting &&
currentState.value !== ServerState.Stopping &&
currentState.value !== ServerState.Restarting,
currentState.value !== ServerState.Stopping,
);
const isStartingOrRestarting = computed(
() =>
currentState.value === ServerState.Starting || currentState.value === ServerState.Restarting,
);
const actionButtonText = computed(() => {
switch (currentState.value) {
case ServerState.Stopped:
return "Start";
case ServerState.Starting:
return "Starting...";
case ServerState.Running:
return "Restart";
case ServerState.Restarting:
return "Restarting...";
case ServerState.Stopping:
case ServerState.Running:
return "Restart";
default:
return "Unknown";
return "Start";
}
});
const stopButtonText = computed(() => {
return currentState.value === ServerState.Stopping ? "Stopping..." : "Stop";
});
const killButtonText = computed(() => {
return "Kill";
});
const isStartingDelay = ref(false);
const stopButtonText = computed(() =>
currentState.value === ServerState.Stopping ? "Stopping..." : "Stop",
);
const updateState = (newState: ServerStateType) => {
currentState.value = newState;
};
const killButtonText = computed(() => "Kill");
const handleAction = () => {
if (!canTakeAction.value) return;
if (currentState.value === ServerState.Running) {
updateState(ServerState.Restarting);
currentState.value = ServerState.Restarting;
emit("action", "restart");
} else {
updateState(ServerState.Starting);
currentState.value = ServerState.Starting;
emit("action", "start");
isStartingDelay.value = true;
setTimeout(() => {
Expand All @@ -134,43 +121,33 @@ const handleAction = () => {
const stopServer = () => {
if (!canTakeAction.value) return;
updateState(ServerState.Stopping);
currentState.value = ServerState.Stopping;
emit("action", "stop");
};
const killServer = () => {
if (!canTakeAction.value) return;
emit("action", "kill");
};
watch(
() => props.isOnline,
(newValue) => {
if (newValue) {
updateState(ServerState.Running);
} else {
updateState(ServerState.Stopped);
currentState.value = ServerState.Running;
} else if (
currentState.value !== ServerState.Starting &&
currentState.value !== ServerState.Restarting
) {
currentState.value = ServerState.Stopped;
}
},
);
// debounce to prevent flickering
watch(
() => props.isActioning,
(newValue) => {
if (!newValue) {
setTimeout(() => {
if (
currentState.value === ServerState.Starting ||
currentState.value === ServerState.Restarting
) {
updateState(ServerState.Running);
} else if (currentState.value === ServerState.Stopping) {
updateState(ServerState.Stopped);
}
}, 500);
currentState.value = props.isOnline ? ServerState.Running : ServerState.Stopped;
}
},
);
Expand Down
22 changes: 22 additions & 0 deletions apps/frontend/src/components/ui/servers/PanelSpinner.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<template>
<svg
class="h-5 w-5 animate-spin"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
class="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
stroke-width="4"
></circle>
<path
class="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
</template>
2 changes: 1 addition & 1 deletion apps/frontend/src/components/ui/servers/PanelTerminal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
tabindex="-1"
>
<div
class="progressive-gradient pointer-events-none absolute -bottom-6 left-0 z-[9999] h-2/5 w-full overflow-hidden rounded-xl"
class="progressive-gradient pointer-events-none absolute -bottom-6 left-0 z-[9999] h-[10rem] w-full overflow-hidden rounded-xl"
:style="`--transparency: ${Math.max(0, lerp(100, 0, bottomThreshold * 8))}%`"
>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M4.5 9V4.5H9M4.5 9L9 4.5M15 4.5h4.5V9M15 4.5l4.5 4.5M4.5 15v4.5H9M4.5 15L9 19.5M15 19.5h4.5V15M15 19.5l4.5-4.5"
d="M9 9V4.5M9 9H4.5M9 9 3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5 5.25 5.25"
/>
</svg>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 9V4.5M9 9H4.5M9 9 3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5 5.25 5.25"
d="M4.5 9V4.5H9M4.5 9L9 4.5M15 4.5h4.5V9M15 4.5l4.5 4.5M4.5 15v4.5H9M4.5 15L9 19.5M15 19.5h4.5V15M15 19.5l4.5-4.5"
/>
</svg>
</template>
10 changes: 7 additions & 3 deletions apps/frontend/src/components/ui/servers/ServerGameLabel.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<template>
<div v-if="game" v-tooltip="'Change server version'" class="flex flex-row items-center gap-2">
<GameIcon aria-hidden="true" class="size-5 text-secondary" />
<div
v-if="game"
v-tooltip="'Change server version'"
class="flex min-w-0 flex-row items-center gap-2"
>
<GameIcon aria-hidden="true" class="size-5 shrink-0 text-secondary" />
<NuxtLink
:to="serverId ? `/servers/manage/${serverId}/options/loader` : ''"
class="text-sm font-semibold"
class="min-w-0 truncate text-sm font-semibold"
:class="serverId ? 'hover:underline' : ''"
>
{{ game[0].toUpperCase() + game.slice(1) }} {{ mcVersion }}
Expand Down
6 changes: 5 additions & 1 deletion apps/frontend/src/components/ui/servers/ServerListing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,11 @@ onMounted(async () => {
});
}
} catch (error) {
console.error("Error processing server image:", error);
if (error instanceof PyroFetchError && error.statusCode === 404) {
image.value = undefined;
} else {
console.error(error);
}
}
});
Expand Down
Loading

0 comments on commit 97c7407

Please sign in to comment.