You've already forked AstralRinth
forked from didirus/AstralRinth
feat: frontend explicit imports + error page fix (#4184)
* feat: frontend explicit imports * fix: error handling * fix: dashboard missing import * fix: error page issues * fix: exclude RouterView * feat: fix lint issues * fix: lint issues * fix: import issues * add getVersionLink * make articles.json use tabs on generation so it doesn't have to be reformatted * fix: lint issues --------- Signed-off-by: Cal H. <hendersoncal117@gmail.com> Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
This commit is contained in:
@@ -331,7 +331,19 @@ import {
|
||||
VersionIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { injectNotificationManager, useRelativeTime } from '@modrinth/ui'
|
||||
import {
|
||||
Avatar,
|
||||
Categories,
|
||||
CopyCode,
|
||||
DoubleIcon,
|
||||
injectNotificationManager,
|
||||
ProjectStatusBadge,
|
||||
useRelativeTime,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import { getProjectLink, getVersionLink } from '~/helpers/projects'
|
||||
|
||||
import ThreadSummary from './thread/ThreadSummary.vue'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
const emit = defineEmits(['update:notifications'])
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="flex gap-2">
|
||||
<ButtonStyled>
|
||||
<button size="sm" @click="$emit('refetch')">
|
||||
<UiServersIconsLoadingIcon class="h-5 w-5" />
|
||||
<LoadingIcon class="h-5 w-5" />
|
||||
Try again
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
@@ -28,6 +28,8 @@
|
||||
import { FileIcon, HomeIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled } from '@modrinth/ui'
|
||||
|
||||
import LoadingIcon from './icons/LoadingIcon.vue'
|
||||
|
||||
defineProps<{
|
||||
title: string
|
||||
message: string
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
}"
|
||||
data-pyro-files-virtual-list
|
||||
>
|
||||
<UiServersFileItem
|
||||
<FileItem
|
||||
v-for="item in visibleItems"
|
||||
:key="item.path"
|
||||
:count="item.count"
|
||||
@@ -45,6 +45,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
import FileItem from './FileItem.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
items: any[]
|
||||
}>()
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
v-if="state.hasError"
|
||||
class="flex h-full w-full flex-col items-center justify-center gap-8"
|
||||
>
|
||||
<UiServersIconsPanelErrorIcon />
|
||||
<PanelErrorIcon />
|
||||
<p class="m-0">{{ state.errorMessage || 'Invalid or empty image file.' }}</p>
|
||||
</div>
|
||||
<img
|
||||
@@ -57,6 +57,8 @@ import { ZoomInIcon, ZoomOutIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled } from '@modrinth/ui'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
|
||||
import PanelErrorIcon from './icons/PanelErrorIcon.vue'
|
||||
|
||||
const ZOOM_MIN = 0.1
|
||||
const ZOOM_MAX = 5
|
||||
const ZOOM_IN_FACTOR = 1.2
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
>
|
||||
<div class="flex flex-1 items-center gap-2 truncate">
|
||||
<transition-group name="status-icon" mode="out-in">
|
||||
<UiServersPanelSpinner
|
||||
<PanelSpinner
|
||||
v-show="item.status === 'uploading'"
|
||||
key="spinner"
|
||||
class="absolute !size-4"
|
||||
@@ -107,6 +107,8 @@ import { computed, nextTick, ref, watch } from 'vue'
|
||||
|
||||
import type { FSModule } from '~/composables/servers/modules/fs.ts'
|
||||
|
||||
import PanelSpinner from './PanelSpinner.vue'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
|
||||
interface UploadItem {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
:key="loader.name"
|
||||
class="group relative flex items-center justify-between rounded-2xl p-2 pr-2.5 hover:bg-bg"
|
||||
>
|
||||
<UiServersLoaderSelectorCard
|
||||
<LoaderSelectorCard
|
||||
:loader="loader"
|
||||
:is-current="isCurrentLoader(loader.name)"
|
||||
:loader-version="data.loader_version"
|
||||
@@ -24,7 +24,7 @@
|
||||
:key="loader.name"
|
||||
class="group relative flex items-center justify-between rounded-2xl p-2 pr-2.5 hover:bg-bg"
|
||||
>
|
||||
<UiServersLoaderSelectorCard
|
||||
<LoaderSelectorCard
|
||||
:loader="loader"
|
||||
:is-current="isCurrentLoader(loader.name)"
|
||||
:loader-version="data.loader_version"
|
||||
@@ -44,7 +44,7 @@
|
||||
:key="loader.name"
|
||||
class="group relative flex items-center justify-between rounded-2xl p-2 pr-2.5 hover:bg-bg"
|
||||
>
|
||||
<UiServersLoaderSelectorCard
|
||||
<LoaderSelectorCard
|
||||
:loader="loader"
|
||||
:is-current="isCurrentLoader(loader.name)"
|
||||
:loader-version="data.loader_version"
|
||||
@@ -58,6 +58,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import LoaderSelectorCard from './LoaderSelectorCard.vue'
|
||||
const props = defineProps<{
|
||||
data: {
|
||||
loader: string | null
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
class="grid size-10 place-content-center rounded-xl border-[1px] border-solid border-button-border bg-button-bg shadow-sm"
|
||||
:class="isCurrentLoader ? '[&&]:bg-bg-green' : ''"
|
||||
>
|
||||
<UiServersIconsLoaderIcon
|
||||
<LoaderIcon
|
||||
:loader="loader.name"
|
||||
class="[&&]:size-6"
|
||||
:class="isCurrentLoader ? 'text-brand' : ''"
|
||||
@@ -43,6 +43,8 @@
|
||||
import { CheckIcon, DownloadIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled } from '@modrinth/ui'
|
||||
|
||||
import LoaderIcon from './icons/LoaderIcon.vue'
|
||||
|
||||
interface LoaderInfo {
|
||||
name: 'Vanilla' | 'Fabric' | 'Forge' | 'Quilt' | 'Paper' | 'NeoForge' | 'Purpur'
|
||||
displayName: string
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Are you sure you want to
|
||||
<span class="lowercase">{{ confirmActionText }}</span> the server?
|
||||
</p>
|
||||
<UiCheckbox
|
||||
<Checkbox
|
||||
v-model="dontAskAgain"
|
||||
label="Don't ask me again"
|
||||
class="text-sm"
|
||||
@@ -34,7 +34,7 @@
|
||||
:header="`All of ${serverName || 'Server'} info`"
|
||||
@close="closeDetailsModal"
|
||||
>
|
||||
<UiServersServerInfoLabels
|
||||
<ServerInfoLabels
|
||||
:server-data="serverData"
|
||||
:show-game-label="true"
|
||||
:show-loader-label="true"
|
||||
@@ -53,7 +53,7 @@
|
||||
<div class="flex flex-row items-center gap-2 rounded-lg">
|
||||
<ButtonStyled v-if="isInstalling" type="standard" color="brand">
|
||||
<button disabled class="flex-shrink-0">
|
||||
<UiServersPanelSpinner class="size-5" /> Installing...
|
||||
<PanelSpinner class="size-5" /> Installing...
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<ButtonStyled type="standard" color="brand">
|
||||
<button :disabled="!canTakeAction" @click="handlePrimaryAction">
|
||||
<div v-if="isTransitionState" class="grid place-content-center">
|
||||
<UiServersIconsLoadingIcon />
|
||||
<LoadingIcon />
|
||||
</div>
|
||||
<component :is="isRunning ? UpdatedIcon : PlayIcon" v-else />
|
||||
<span>{{ primaryActionText }}</span>
|
||||
@@ -116,12 +116,16 @@ import {
|
||||
UpdatedIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { ButtonStyled, NewModal } from '@modrinth/ui'
|
||||
import { ButtonStyled, Checkbox, NewModal } from '@modrinth/ui'
|
||||
import type { PowerAction as ServerPowerAction, ServerState } from '@modrinth/utils'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import LoadingIcon from './icons/LoadingIcon.vue'
|
||||
import PanelSpinner from './PanelSpinner.vue'
|
||||
import ServerInfoLabels from './ServerInfoLabels.vue'
|
||||
|
||||
const flags = useFeatureFlags()
|
||||
|
||||
interface PowerAction {
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
class="group"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<UiServersLogLine :log="item" @show-full-log="showFullLogMessage" />
|
||||
<LogLine :log="item" @show-full-log="showFullLogMessage" />
|
||||
<div @mousedown.stop @click.stop>
|
||||
<button
|
||||
v-if="searchInput"
|
||||
@@ -223,8 +223,8 @@
|
||||
:class="{ hidden: searchInput || hasSelection || isSingleLineSelected }"
|
||||
@click="toggleFullscreen"
|
||||
>
|
||||
<LazyUiServersIconsMinimizeIconVue v-if="isFullScreen" />
|
||||
<LazyUiServersIconsFullscreenIcon v-else />
|
||||
<MinimizeIconVue v-if="isFullScreen" />
|
||||
<FullscreenIcon v-else />
|
||||
</button>
|
||||
|
||||
<Transition name="fade">
|
||||
@@ -306,6 +306,10 @@ import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
|
||||
import { useModrinthServersConsole } from '~/store/console.ts'
|
||||
|
||||
import FullscreenIcon from './icons/FullscreenIcon.vue'
|
||||
import MinimizeIconVue from './icons/MinimizeIcon.vue.vue'
|
||||
import LogLine from './LogLine.vue'
|
||||
|
||||
const { $cosmetics } = useNuxtApp()
|
||||
const cosmetics = $cosmetics
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<div
|
||||
class="grid size-16 place-content-center rounded-2xl border-[2px] border-solid border-button-border bg-button-bg shadow-sm"
|
||||
>
|
||||
<UiServersIconsLoaderIcon class="size-10" :loader="selectedLoader" />
|
||||
<LoaderIcon class="size-10" :loader="selectedLoader" />
|
||||
</div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
<div class="flex w-full flex-col gap-2 rounded-2xl bg-table-alternateRow p-4">
|
||||
<div class="text-lg font-bold text-contrast">Minecraft version</div>
|
||||
<UiServersTeleportDropdownMenu
|
||||
<TeleportDropdownMenu
|
||||
v-model="selectedMCVersion"
|
||||
name="mcVersion"
|
||||
:options="mcVersions"
|
||||
@@ -102,13 +102,13 @@
|
||||
<div
|
||||
class="relative flex h-9 w-full items-center rounded-xl bg-button-bg px-4 opacity-50"
|
||||
>
|
||||
<UiServersIconsLoadingIcon class="mr-2 animate-spin" />
|
||||
<LoadingIcon class="mr-2 animate-spin" />
|
||||
Loading versions...
|
||||
<DropdownIcon class="absolute right-4" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="selectedLoaderVersions.length > 0">
|
||||
<UiServersTeleportDropdownMenu
|
||||
<TeleportDropdownMenu
|
||||
v-model="selectedLoaderVersion"
|
||||
name="loaderVersion"
|
||||
:options="selectedLoaderVersions"
|
||||
@@ -211,6 +211,9 @@ import { $fetch } from 'ofetch'
|
||||
import type { ModrinthServer } from '~/composables/servers/modrinth-servers.ts'
|
||||
import type { BackupInProgressReason } from '~/pages/servers/manage/[id].vue'
|
||||
|
||||
import LoaderIcon from './icons/LoaderIcon.vue'
|
||||
import LoadingIcon from './icons/LoadingIcon.vue'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<div>
|
||||
<UiServersServerGameLabel
|
||||
<ServerGameLabel
|
||||
v-if="showGameLabel"
|
||||
:game="serverData.game"
|
||||
:mc-version="serverData.mc_version ?? ''"
|
||||
:is-link="linked"
|
||||
/>
|
||||
<UiServersServerLoaderLabel
|
||||
<ServerLoaderLabel
|
||||
:loader="serverData.loader"
|
||||
:loader-version="serverData.loader_version ?? ''"
|
||||
:no-separator="column"
|
||||
:is-link="linked"
|
||||
/>
|
||||
<UiServersServerSubdomainLabel
|
||||
<ServerSubdomainLabel
|
||||
v-if="serverData.net?.domain"
|
||||
:subdomain="serverData.net.domain"
|
||||
:no-separator="column"
|
||||
:is-link="linked"
|
||||
/>
|
||||
<UiServersServerUptimeLabel
|
||||
<ServerUptimeLabel
|
||||
v-if="uptimeSeconds"
|
||||
:uptime-seconds="uptimeSeconds"
|
||||
:no-separator="column"
|
||||
@@ -27,6 +27,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ServerGameLabel from './ServerGameLabel.vue'
|
||||
import ServerLoaderLabel from './ServerLoaderLabel.vue'
|
||||
import ServerSubdomainLabel from './ServerSubdomainLabel.vue'
|
||||
import ServerUptimeLabel from './ServerUptimeLabel.vue'
|
||||
|
||||
interface ServerInfoLabelsProps {
|
||||
serverData: Record<string, any>
|
||||
showGameLabel: boolean
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<LazyUiServersPlatformVersionSelectModal
|
||||
<PlatformVersionSelectModal
|
||||
ref="versionSelectModal"
|
||||
:server="props.server"
|
||||
:current-loader="ignoreCurrentInstallation ? undefined : (data?.loader as Loaders)"
|
||||
@@ -8,13 +8,13 @@
|
||||
@reinstall="emit('reinstall', $event)"
|
||||
/>
|
||||
|
||||
<LazyUiServersPlatformMrpackModal
|
||||
<PlatformMrpackModal
|
||||
ref="mrpackModal"
|
||||
:server="props.server"
|
||||
@reinstall="emit('reinstall', $event)"
|
||||
/>
|
||||
|
||||
<LazyUiServersPlatformChangeModpackVersionModal
|
||||
<PlatformChangeModpackVersionModal
|
||||
ref="modpackVersionModal"
|
||||
:server="props.server"
|
||||
:project="data?.project"
|
||||
@@ -137,7 +137,7 @@
|
||||
}"
|
||||
:tabindex="props.server.general?.status === 'installing' ? -1 : 0"
|
||||
>
|
||||
<UiServersLoaderSelector
|
||||
<LoaderSelector
|
||||
:data="
|
||||
ignoreCurrentInstallation
|
||||
? {
|
||||
@@ -165,6 +165,11 @@ import type { Loaders } from '@modrinth/utils'
|
||||
import type { ModrinthServer } from '~/composables/servers/modrinth-servers.ts'
|
||||
import type { BackupInProgressReason } from '~/pages/servers/manage/[id].vue'
|
||||
|
||||
import LoaderSelector from './LoaderSelector.vue'
|
||||
import PlatformChangeModpackVersionModal from './PlatformChangeModpackVersionModal.vue'
|
||||
import PlatformMrpackModal from './PlatformMrpackModal.vue'
|
||||
import PlatformVersionSelectModal from './PlatformVersionSelectModal.vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
data-pyro-server-listing
|
||||
:data-pyro-server-listing-id="server_id"
|
||||
>
|
||||
<UiServersServerIcon v-if="status !== 'suspended'" :image="image" />
|
||||
<ServerIcon v-if="status !== 'suspended'" :image="image" />
|
||||
<div
|
||||
v-else
|
||||
class="bg-bg-secondary flex size-24 items-center justify-center rounded-xl border-[1px] border-solid border-button-border bg-button-bg shadow-sm"
|
||||
@@ -49,7 +49,7 @@
|
||||
>
|
||||
<SparklesIcon class="size-5 shrink-0" /> New server
|
||||
</div>
|
||||
<UiServersServerInfoLabels
|
||||
<ServerInfoLabels
|
||||
v-else
|
||||
:server-data="{ game, mc_version, loader, loader_version, net }"
|
||||
:show-game-label="showGameLabel"
|
||||
@@ -63,7 +63,7 @@
|
||||
v-if="status === 'suspended' && suspension_reason === 'upgrading'"
|
||||
class="relative -mt-4 flex w-full flex-row items-center gap-2 rounded-b-3xl bg-bg-blue p-4 text-sm font-bold text-contrast"
|
||||
>
|
||||
<UiServersPanelSpinner />
|
||||
<PanelSpinner />
|
||||
Your server's hardware is currently being upgraded and will be back online shortly.
|
||||
</div>
|
||||
<div
|
||||
@@ -71,8 +71,8 @@
|
||||
class="relative -mt-4 flex w-full flex-col gap-2 rounded-b-3xl bg-bg-red p-4 text-sm font-bold text-contrast"
|
||||
>
|
||||
<div class="flex flex-row gap-2">
|
||||
<UiServersIconsPanelErrorIcon class="!size-5" /> Your server has been cancelled. Please
|
||||
update your billing information or contact Modrinth Support for more information.
|
||||
<PanelErrorIcon class="!size-5" /> Your server has been cancelled. Please update your
|
||||
billing information or contact Modrinth Support for more information.
|
||||
</div>
|
||||
<CopyCode :text="`${props.server_id}`" class="ml-auto" />
|
||||
</div>
|
||||
@@ -81,9 +81,8 @@
|
||||
class="relative -mt-4 flex w-full flex-col gap-2 rounded-b-3xl bg-bg-red p-4 text-sm font-bold text-contrast"
|
||||
>
|
||||
<div class="flex flex-row gap-2">
|
||||
<UiServersIconsPanelErrorIcon class="!size-5" /> Your server has been suspended:
|
||||
{{ suspension_reason }}. Please update your billing information or contact Modrinth Support
|
||||
for more information.
|
||||
<PanelErrorIcon class="!size-5" /> Your server has been suspended: {{ suspension_reason }}.
|
||||
Please update your billing information or contact Modrinth Support for more information.
|
||||
</div>
|
||||
<CopyCode :text="`${props.server_id}`" class="ml-auto" />
|
||||
</div>
|
||||
@@ -92,8 +91,8 @@
|
||||
class="relative -mt-4 flex w-full flex-col gap-2 rounded-b-3xl bg-bg-red p-4 text-sm font-bold text-contrast"
|
||||
>
|
||||
<div class="flex flex-row gap-2">
|
||||
<UiServersIconsPanelErrorIcon class="!size-5" /> Your server has been suspended. Please
|
||||
update your billing information or contact Modrinth Support for more information.
|
||||
<PanelErrorIcon class="!size-5" /> Your server has been suspended. Please update your
|
||||
billing information or contact Modrinth Support for more information.
|
||||
</div>
|
||||
<CopyCode :text="`${props.server_id}`" class="ml-auto" />
|
||||
</div>
|
||||
@@ -107,6 +106,11 @@ import type { Project, Server } from '@modrinth/utils'
|
||||
|
||||
import { useModrinthServers } from '~/composables/servers/modrinth-servers.ts'
|
||||
|
||||
import PanelErrorIcon from './icons/PanelErrorIcon.vue'
|
||||
import PanelSpinner from './PanelSpinner.vue'
|
||||
import ServerIcon from './ServerIcon.vue'
|
||||
import ServerInfoLabels from './ServerInfoLabels.vue'
|
||||
|
||||
const props = defineProps<Partial<Server>>()
|
||||
|
||||
if (props.server_id && props.status === 'available') {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
src="~/assets/images/servers/minecraft_server_icon.png"
|
||||
/>
|
||||
<div class="absolute inset-0 grid place-content-center">
|
||||
<UiServersIconsLoadingIcon class="size-8 animate-spin text-contrast" />
|
||||
<LoadingIcon class="size-8 animate-spin text-contrast" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
@@ -18,3 +18,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import LoadingIcon from './icons/LoadingIcon.vue'
|
||||
</script>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div v-tooltip="'Change server loader'" class="flex min-w-0 flex-row items-center gap-4 truncate">
|
||||
<div v-if="!noSeparator" class="experimental-styles-within h-6 w-0.5 bg-button-border"></div>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<UiServersIconsLoaderIcon v-if="loader" :loader="loader" class="flex shrink-0 [&&]:size-5" />
|
||||
<LoaderIcon v-if="loader" :loader="loader" class="flex shrink-0 [&&]:size-5" />
|
||||
<div v-else class="size-5 shrink-0 animate-pulse rounded-full bg-button-border"></div>
|
||||
<NuxtLink
|
||||
v-if="isLink"
|
||||
@@ -34,6 +34,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import LoaderIcon from './icons/LoaderIcon.vue'
|
||||
defineProps<{
|
||||
noSeparator?: boolean
|
||||
loader?: 'Fabric' | 'Quilt' | 'Forge' | 'NeoForge' | 'Paper' | 'Spigot' | 'Bukkit' | 'Vanilla'
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<div v-if="!noSeparator" class="experimental-styles-within h-6 w-0.5 bg-button-border"></div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<UiServersIconsTimer class="flex size-5 shrink-0" />
|
||||
<Timer class="flex size-5 shrink-0" />
|
||||
<time class="truncate text-sm font-semibold" :aria-label="verboseUptime">
|
||||
{{ formattedUptime }}
|
||||
</time>
|
||||
@@ -19,6 +19,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
import Timer from './icons/Timer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
uptimeSeconds: number
|
||||
noSeparator?: boolean
|
||||
|
||||
Reference in New Issue
Block a user