You've already forked AstralRinth
forked from didirus/AstralRinth
feat: introduce dependency injection framework (#4091)
* feat: migrate frontend notifications to dependency injection based notificaton manager * fix: lint * fix: issues * fix: compile error + notif binding issue * refactor: move org context to new DI setup * feat: migrate app notifications to DI + frontend styling * fix: sidebar issues * fix: dont use delete in computed * fix: import and prop issue * refactor: move handleError to main notification manager class * fix: lint & build * fix: merge issues * fix: lint issues * fix: lint issues --------- Signed-off-by: IMB11 <hendersoncal117@gmail.com> Signed-off-by: Cal H. <hendersoncal117@gmail.com>
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
<template>
|
||||
<NuxtLayout>
|
||||
<ModrinthLoadingIndicator />
|
||||
<Notifications />
|
||||
<NotificationPanel />
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { NotificationPanel, provideNotificationManager } from "@modrinth/ui";
|
||||
import { FrontendNotificationManager } from "./providers/frontend-notifications.ts";
|
||||
import ModrinthLoadingIndicator from "~/components/ui/modrinth-loading-indicator.ts";
|
||||
import Notifications from "~/components/ui/Notifications.vue";
|
||||
|
||||
provideNotificationManager(new FrontendNotificationManager());
|
||||
</script>
|
||||
|
||||
@@ -51,7 +51,9 @@
|
||||
<script setup>
|
||||
import { PlusIcon, XIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, NewModal } from "@modrinth/ui";
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const router = useNativeRouter();
|
||||
|
||||
const name = ref("");
|
||||
@@ -87,7 +89,6 @@ async function create() {
|
||||
await router.push(`/collection/${result.id}`);
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err?.data?.description || err?.message || err,
|
||||
type: "error",
|
||||
|
||||
@@ -84,8 +84,11 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { NewModal, ButtonStyled, DropdownSelect } from "@modrinth/ui";
|
||||
import { XIcon, PlusIcon } from "@modrinth/assets";
|
||||
import { PlusIcon, XIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, DropdownSelect, NewModal } from "@modrinth/ui";
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const router = useRouter();
|
||||
const app = useNuxtApp();
|
||||
@@ -180,8 +183,7 @@ async function createProject() {
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -319,30 +319,21 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { renderString } from "@modrinth/utils";
|
||||
import {
|
||||
UserPlusIcon,
|
||||
ScaleIcon,
|
||||
BellIcon,
|
||||
CheckCircleIcon,
|
||||
CalendarIcon,
|
||||
VersionIcon,
|
||||
CheckCircleIcon,
|
||||
CheckIcon,
|
||||
XIcon,
|
||||
ExternalIcon,
|
||||
ScaleIcon,
|
||||
UserPlusIcon,
|
||||
VersionIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { Avatar, ProjectStatusBadge, CopyCode, useRelativeTime } from "@modrinth/ui";
|
||||
import ThreadSummary from "~/components/ui/thread/ThreadSummary.vue";
|
||||
import { getProjectLink, getVersionLink } from "~/helpers/projects.js";
|
||||
import { getUserLink } from "~/helpers/users.js";
|
||||
import { acceptTeamInvite, removeSelfFromTeam } from "~/helpers/teams.js";
|
||||
import { markAsRead } from "~/helpers/notifications.ts";
|
||||
import DoubleIcon from "~/components/ui/DoubleIcon.vue";
|
||||
import Categories from "~/components/ui/search/Categories.vue";
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
|
||||
const app = useNuxtApp();
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const emit = defineEmits(["update:notifications"]);
|
||||
|
||||
const formatRelativeTime = useRelativeTime();
|
||||
|
||||
const props = defineProps({
|
||||
@@ -407,8 +398,7 @@ async function read() {
|
||||
const newNotifs = updateNotifs(props.notifications);
|
||||
emit("update:notifications", newNotifs);
|
||||
} catch (err) {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error marking notification as read",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -427,8 +417,7 @@ async function performAction(notification, actionIndex) {
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="vue-notification-group experimental-styles-within"
|
||||
:class="{
|
||||
'intercom-present': isIntercomPresent,
|
||||
rightwards: moveNotificationsRight,
|
||||
}"
|
||||
>
|
||||
<transition-group name="notifs">
|
||||
<div
|
||||
v-for="(item, index) in notifications"
|
||||
:key="item.id"
|
||||
class="vue-notification-wrapper"
|
||||
@mouseenter="stopTimer(item)"
|
||||
@mouseleave="setNotificationTimer(item)"
|
||||
>
|
||||
<div class="flex w-full gap-2 overflow-hidden rounded-lg bg-bg-raised shadow-xl">
|
||||
<div
|
||||
class="w-2"
|
||||
:class="{
|
||||
'bg-red': item.type === 'error',
|
||||
'bg-orange': item.type === 'warning',
|
||||
'bg-green': item.type === 'success',
|
||||
'bg-blue': !item.type || !['error', 'warning', 'success'].includes(item.type),
|
||||
}"
|
||||
></div>
|
||||
<div
|
||||
class="grid w-full grid-cols-[auto_1fr_auto] items-center gap-x-2 gap-y-1 py-2 pl-1 pr-3"
|
||||
>
|
||||
<div
|
||||
class="flex items-center"
|
||||
:class="{
|
||||
'text-red': item.type === 'error',
|
||||
'text-orange': item.type === 'warning',
|
||||
'text-green': item.type === 'success',
|
||||
'text-blue': !item.type || !['error', 'warning', 'success'].includes(item.type),
|
||||
}"
|
||||
>
|
||||
<IssuesIcon v-if="item.type === 'warning'" class="h-6 w-6" />
|
||||
<CheckCircleIcon v-else-if="item.type === 'success'" class="h-6 w-6" />
|
||||
<XCircleIcon v-else-if="item.type === 'error'" class="h-6 w-6" />
|
||||
<InfoIcon v-else class="h-6 w-6" />
|
||||
</div>
|
||||
<div class="m-0 text-wrap font-bold text-contrast" v-html="item.title"></div>
|
||||
<div class="flex items-center gap-1">
|
||||
<div v-if="item.count && item.count > 1" class="text-xs font-bold text-contrast">
|
||||
x{{ item.count }}
|
||||
</div>
|
||||
<ButtonStyled circular size="small">
|
||||
<button v-tooltip="'Copy to clipboard'" @click="copyToClipboard(item)">
|
||||
<CheckIcon v-if="copied[createNotifText(item)]" />
|
||||
<CopyIcon v-else />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled circular size="small">
|
||||
<button v-tooltip="`Dismiss`" @click="notifications.splice(index, 1)">
|
||||
<XIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<div></div>
|
||||
<div class="col-span-2 text-sm text-primary" v-html="item.text"></div>
|
||||
<template v-if="item.errorCode">
|
||||
<div></div>
|
||||
<div
|
||||
class="m-0 text-wrap text-xs font-medium text-secondary"
|
||||
v-html="item.errorCode"
|
||||
></div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ButtonStyled } from "@modrinth/ui";
|
||||
import {
|
||||
XCircleIcon,
|
||||
CheckCircleIcon,
|
||||
CheckIcon,
|
||||
InfoIcon,
|
||||
IssuesIcon,
|
||||
XIcon,
|
||||
CopyIcon,
|
||||
} from "@modrinth/assets";
|
||||
const notifications = useNotifications();
|
||||
const { isVisible: moveNotificationsRight } = useNotificationRightwards();
|
||||
|
||||
const isIntercomPresent = ref(false);
|
||||
|
||||
function stopTimer(notif) {
|
||||
clearTimeout(notif.timer);
|
||||
}
|
||||
|
||||
const copied = ref({});
|
||||
|
||||
const createNotifText = (notif) => {
|
||||
let text = "";
|
||||
if (notif.title) {
|
||||
text += notif.title;
|
||||
}
|
||||
if (notif.text) {
|
||||
if (text.length > 0) {
|
||||
text += "\n";
|
||||
}
|
||||
text += notif.text;
|
||||
}
|
||||
if (notif.errorCode) {
|
||||
if (text.length > 0) {
|
||||
text += "\n";
|
||||
}
|
||||
text += notif.errorCode;
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
function checkIntercomPresence() {
|
||||
isIntercomPresent.value = !!document.querySelector(".intercom-lightweight-app");
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkIntercomPresence();
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
checkIntercomPresence();
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
observer.disconnect();
|
||||
});
|
||||
});
|
||||
|
||||
function copyToClipboard(notif) {
|
||||
const text = createNotifText(notif);
|
||||
|
||||
copied.value[text] = true;
|
||||
navigator.clipboard.writeText(text);
|
||||
setTimeout(() => {
|
||||
delete copied.value[text];
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.vue-notification-group {
|
||||
position: fixed;
|
||||
right: 1.5rem;
|
||||
bottom: 1.5rem;
|
||||
z-index: 200;
|
||||
width: 450px;
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
width: calc(100% - 0.75rem * 2);
|
||||
right: 0.75rem;
|
||||
bottom: 0.75rem;
|
||||
}
|
||||
|
||||
&.intercom-present {
|
||||
bottom: 5rem;
|
||||
}
|
||||
|
||||
&.rightwards {
|
||||
right: unset !important;
|
||||
left: 1.5rem;
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
left: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.vue-notification-wrapper {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&:last-child {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 750px) {
|
||||
transition: bottom 0.25s ease-in-out;
|
||||
bottom: calc(var(--size-mobile-navbar-height) + 10px) !important;
|
||||
|
||||
&.browse-menu-open {
|
||||
bottom: calc(var(--size-mobile-navbar-height-expanded) + 10px) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notifs-enter-active,
|
||||
.notifs-leave-active,
|
||||
.notifs-move {
|
||||
transition: all 0.25s ease-in-out;
|
||||
}
|
||||
.notifs-enter-from,
|
||||
.notifs-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.notifs-enter-from {
|
||||
transform: translateY(100%) scale(0.8);
|
||||
}
|
||||
|
||||
.notifs-leave-to {
|
||||
transform: translateX(100%) scale(0.8);
|
||||
}
|
||||
</style>
|
||||
@@ -15,7 +15,7 @@
|
||||
maxlength="64"
|
||||
:placeholder="`Enter organization name...`"
|
||||
autocomplete="off"
|
||||
@input="updateSlug()"
|
||||
@input="updateSlug"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
@@ -33,7 +33,7 @@
|
||||
type="text"
|
||||
maxlength="64"
|
||||
autocomplete="off"
|
||||
@input="manualSlug = true"
|
||||
@input="setManualSlug"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -61,7 +61,7 @@
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button @click="modal.hide()">
|
||||
<button @click="hide">
|
||||
<XIcon aria-hidden="true" />
|
||||
Cancel
|
||||
</button>
|
||||
@@ -70,20 +70,22 @@
|
||||
</div>
|
||||
</NewModal>
|
||||
</template>
|
||||
<script setup>
|
||||
import { XIcon, PlusIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, NewModal } from "@modrinth/ui";
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PlusIcon, XIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, NewModal, injectNotificationManager } from "@modrinth/ui";
|
||||
import { ref } from "vue";
|
||||
|
||||
const router = useNativeRouter();
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const name = ref("");
|
||||
const slug = ref("");
|
||||
const description = ref("");
|
||||
const manualSlug = ref(false);
|
||||
const name = ref<string>("");
|
||||
const slug = ref<string>("");
|
||||
const description = ref<string>("");
|
||||
const manualSlug = ref<boolean>(false);
|
||||
const modal = ref<InstanceType<typeof NewModal>>();
|
||||
|
||||
const modal = ref();
|
||||
|
||||
async function createOrganization() {
|
||||
async function createOrganization(): Promise<void> {
|
||||
startLoading();
|
||||
try {
|
||||
const value = {
|
||||
@@ -92,19 +94,18 @@ async function createOrganization() {
|
||||
slug: slug.value.trim().replace(/ +/g, ""),
|
||||
};
|
||||
|
||||
const result = await useBaseFetch("organization", {
|
||||
const result: any = await useBaseFetch("organization", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(value),
|
||||
apiVersion: 3,
|
||||
});
|
||||
|
||||
modal.value.hide();
|
||||
modal.value?.hide();
|
||||
|
||||
await router.push(`/organization/${result.slug}`);
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -112,13 +113,18 @@ async function createOrganization() {
|
||||
}
|
||||
stopLoading();
|
||||
}
|
||||
function show(event) {
|
||||
|
||||
function show(event?: MouseEvent): void {
|
||||
name.value = "";
|
||||
description.value = "";
|
||||
modal.value.show(event);
|
||||
modal.value?.show(event);
|
||||
}
|
||||
|
||||
function updateSlug() {
|
||||
function hide(): void {
|
||||
modal.value?.hide();
|
||||
}
|
||||
|
||||
function updateSlug(): void {
|
||||
if (!manualSlug.value) {
|
||||
slug.value = name.value
|
||||
.trim()
|
||||
@@ -129,6 +135,10 @@ function updateSlug() {
|
||||
}
|
||||
}
|
||||
|
||||
function setManualSlug(): void {
|
||||
manualSlug.value = true;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
});
|
||||
|
||||
@@ -105,24 +105,25 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
ChevronRightIcon,
|
||||
CheckIcon,
|
||||
XIcon,
|
||||
AsteriskIcon,
|
||||
LightBulbIcon,
|
||||
TriangleAlertIcon,
|
||||
CheckIcon,
|
||||
ChevronRightIcon,
|
||||
DropdownIcon,
|
||||
SendIcon,
|
||||
LightBulbIcon,
|
||||
ScaleIcon,
|
||||
InfoIcon,
|
||||
SendIcon,
|
||||
TriangleAlertIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { acceptTeamInvite, removeTeamMember } from "~/helpers/teams.js";
|
||||
import { nags } from "@modrinth/moderation";
|
||||
import { ButtonStyled } from "@modrinth/ui";
|
||||
import { useVIntl, defineMessages, type MessageDescriptor } from "@vintl/vintl";
|
||||
import type { Nag, NagContext, NagStatus } from "@modrinth/moderation";
|
||||
import { nags } from "@modrinth/moderation";
|
||||
import { ButtonStyled, injectNotificationManager } from "@modrinth/ui";
|
||||
import type { Project, User, Version } from "@modrinth/utils";
|
||||
import { defineMessages, useVIntl, type MessageDescriptor } from "@vintl/vintl";
|
||||
import type { Component } from "vue";
|
||||
import { acceptTeamInvite, removeTeamMember } from "~/helpers/teams.js";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
interface Tags {
|
||||
rejectedStatuses: string[];
|
||||
@@ -433,14 +434,12 @@ async function acceptInvite(): Promise<void> {
|
||||
await acceptTeamInvite(props.project.team);
|
||||
await updateMembers();
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(messages.success),
|
||||
text: formatMessage(messages.successJoin),
|
||||
type: "success",
|
||||
});
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(messages.error),
|
||||
text: formatMessage(messages.errorJoin),
|
||||
type: "error",
|
||||
@@ -456,14 +455,12 @@ async function declineInvite(): Promise<void> {
|
||||
await removeTeamMember(props.project.team, props.auth.user.id);
|
||||
await updateMembers();
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(messages.success),
|
||||
text: formatMessage(messages.successDecline),
|
||||
type: "success",
|
||||
});
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(messages.error),
|
||||
text: formatMessage(messages.errorDecline),
|
||||
type: "error",
|
||||
|
||||
@@ -118,22 +118,25 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import dayjs from "dayjs";
|
||||
import {
|
||||
Avatar,
|
||||
useRelativeTime,
|
||||
OverflowMenu,
|
||||
type OverflowMenuOption,
|
||||
ButtonStyled,
|
||||
} from "@modrinth/ui";
|
||||
import {
|
||||
EllipsisVerticalIcon,
|
||||
OrganizationIcon,
|
||||
EyeIcon,
|
||||
ClipboardCopyIcon,
|
||||
EllipsisVerticalIcon,
|
||||
EyeIcon,
|
||||
LinkIcon,
|
||||
OrganizationIcon,
|
||||
} from "@modrinth/assets";
|
||||
import type { ExtendedDelphiReport } from "@modrinth/moderation";
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
useRelativeTime,
|
||||
type OverflowMenuOption,
|
||||
} from "@modrinth/ui";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps<{
|
||||
report: ExtendedDelphiReport;
|
||||
|
||||
@@ -135,28 +135,31 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Avatar,
|
||||
useRelativeTime,
|
||||
OverflowMenu,
|
||||
type OverflowMenuOption,
|
||||
CollapsibleRegion,
|
||||
ButtonStyled,
|
||||
} from "@modrinth/ui";
|
||||
import {
|
||||
EllipsisVerticalIcon,
|
||||
OrganizationIcon,
|
||||
EyeIcon,
|
||||
ClipboardCopyIcon,
|
||||
EllipsisVerticalIcon,
|
||||
EyeIcon,
|
||||
LinkIcon,
|
||||
OrganizationIcon,
|
||||
} from "@modrinth/assets";
|
||||
import {
|
||||
type ExtendedReport,
|
||||
reportQuickReplies,
|
||||
type ReportQuickReply,
|
||||
} from "@modrinth/moderation";
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
CollapsibleRegion,
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
type OverflowMenuOption,
|
||||
useRelativeTime,
|
||||
} from "@modrinth/ui";
|
||||
import ChevronDownIcon from "../servers/icons/ChevronDownIcon.vue";
|
||||
import ReportThread from "../thread/ReportThread.vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps<{
|
||||
report: ExtendedReport;
|
||||
}>();
|
||||
|
||||
@@ -335,66 +335,67 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
LeftArrowIcon,
|
||||
RightArrowIcon,
|
||||
DropdownIcon,
|
||||
XIcon,
|
||||
ScaleIcon,
|
||||
ListBulletedIcon,
|
||||
FileTextIcon,
|
||||
BrushCleaningIcon,
|
||||
CheckIcon,
|
||||
KeyboardIcon,
|
||||
DropdownIcon,
|
||||
EyeOffIcon,
|
||||
FileTextIcon,
|
||||
KeyboardIcon,
|
||||
LeftArrowIcon,
|
||||
ListBulletedIcon,
|
||||
RightArrowIcon,
|
||||
ScaleIcon,
|
||||
ToggleLeftIcon,
|
||||
ToggleRightIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import {
|
||||
type Action,
|
||||
type ButtonAction,
|
||||
type ConditionalButtonAction,
|
||||
type DropdownAction,
|
||||
type MultiSelectChipsAction,
|
||||
type Stage,
|
||||
type ToggleAction,
|
||||
checklist,
|
||||
getActionIdForStage,
|
||||
initializeActionState,
|
||||
getActionMessage,
|
||||
findMatchingVariant,
|
||||
processMessage,
|
||||
getVisibleInputs,
|
||||
serializeActionStates,
|
||||
deserializeActionStates,
|
||||
kebabToTitleCase,
|
||||
flattenProjectVariables,
|
||||
expandVariables,
|
||||
finalPermissionMessages,
|
||||
findMatchingVariant,
|
||||
flattenProjectVariables,
|
||||
getActionIdForStage,
|
||||
getActionMessage,
|
||||
getVisibleInputs,
|
||||
handleKeybind,
|
||||
initializeActionState,
|
||||
kebabToTitleCase,
|
||||
keybinds,
|
||||
processMessage,
|
||||
serializeActionStates,
|
||||
} from "@modrinth/moderation";
|
||||
import {
|
||||
ButtonStyled,
|
||||
Collapsible,
|
||||
OverflowMenu,
|
||||
type OverflowMenuOption,
|
||||
Checkbox,
|
||||
Collapsible,
|
||||
DropdownSelect,
|
||||
MarkdownEditor,
|
||||
OverflowMenu,
|
||||
type OverflowMenuOption,
|
||||
injectNotificationManager,
|
||||
} from "@modrinth/ui";
|
||||
import {
|
||||
type Project,
|
||||
renderHighlightedString,
|
||||
type ModerationJudgements,
|
||||
type ModerationModpackItem,
|
||||
type Project,
|
||||
type ProjectStatus,
|
||||
renderHighlightedString,
|
||||
} from "@modrinth/utils";
|
||||
import { computedAsync, useLocalStorage } from "@vueuse/core";
|
||||
import {
|
||||
type Action,
|
||||
type MultiSelectChipsAction,
|
||||
type DropdownAction,
|
||||
type ButtonAction,
|
||||
type ToggleAction,
|
||||
type ConditionalButtonAction,
|
||||
type Stage,
|
||||
finalPermissionMessages,
|
||||
} from "@modrinth/moderation";
|
||||
import ModpackPermissionsFlow from "./ModpackPermissionsFlow.vue";
|
||||
import KeybindsModal from "./ChecklistKeybindsModal.vue";
|
||||
import { useModerationStore } from "~/store/moderation.ts";
|
||||
import KeybindsModal from "./ChecklistKeybindsModal.vue";
|
||||
import ModpackPermissionsFlow from "./ModpackPermissionsFlow.vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const keybindsModal = ref<InstanceType<typeof KeybindsModal>>();
|
||||
|
||||
|
||||
@@ -42,12 +42,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, nextTick, computed } from "vue";
|
||||
import { ButtonStyled, NewModal } from "@modrinth/ui";
|
||||
import { IssuesIcon, PlusIcon, XIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, injectNotificationManager, NewModal } from "@modrinth/ui";
|
||||
import { ModrinthServersFetchError, type ServerBackup } from "@modrinth/utils";
|
||||
import { computed, nextTick, ref } from "vue";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
}>();
|
||||
|
||||
@@ -45,12 +45,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, nextTick, computed } from "vue";
|
||||
import { ButtonStyled, NewModal } from "@modrinth/ui";
|
||||
import { SpinnerIcon, SaveIcon, XIcon, IssuesIcon } from "@modrinth/assets";
|
||||
import { IssuesIcon, SaveIcon, SpinnerIcon, XIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, injectNotificationManager, NewModal } from "@modrinth/ui";
|
||||
import type { Backup } from "@modrinth/utils";
|
||||
import { computed, nextTick, ref } from "vue";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
}>();
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { ConfirmModal, NewModal } from "@modrinth/ui";
|
||||
import { ConfirmModal, injectNotificationManager, NewModal } from "@modrinth/ui";
|
||||
import type { Backup } from "@modrinth/utils";
|
||||
import { ref } from "vue";
|
||||
import BackupItem from "~/components/ui/servers/BackupItem.vue";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
}>();
|
||||
|
||||
@@ -56,11 +56,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ButtonStyled, NewModal } from "@modrinth/ui";
|
||||
import { XIcon, SaveIcon } from "@modrinth/assets";
|
||||
import { ref, computed } from "vue";
|
||||
import { SaveIcon, XIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, injectNotificationManager, NewModal } from "@modrinth/ui";
|
||||
import { computed, ref } from "vue";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
}>();
|
||||
@@ -110,7 +112,6 @@ const fetchSettings = async () => {
|
||||
} catch (error) {
|
||||
console.error("Error fetching backup settings:", error);
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Error",
|
||||
text: "Failed to load backup settings",
|
||||
type: "error",
|
||||
@@ -135,7 +136,6 @@ const saveSettings = async () => {
|
||||
};
|
||||
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Success",
|
||||
text: "Backup settings updated successfully",
|
||||
type: "success",
|
||||
@@ -145,7 +145,6 @@ const saveSettings = async () => {
|
||||
} catch (error) {
|
||||
console.error("Error saving backup settings:", error);
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Error",
|
||||
text: "Failed to save backup settings",
|
||||
type: "error",
|
||||
|
||||
@@ -101,11 +101,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { FolderOpenIcon, CheckCircleIcon, XCircleIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled } from "@modrinth/ui";
|
||||
import { ref, computed, watch, nextTick } from "vue";
|
||||
import { CheckCircleIcon, FolderOpenIcon, XCircleIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, injectNotificationManager } from "@modrinth/ui";
|
||||
import { computed, nextTick, ref, watch } from "vue";
|
||||
import { FSModule } from "~/composables/servers/modules/fs.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
interface UploadItem {
|
||||
file: File;
|
||||
progress: number;
|
||||
@@ -282,7 +284,6 @@ const uploadFile = async (file: File) => {
|
||||
|
||||
if (error instanceof Error && error.message !== "Upload cancelled") {
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "Upload failed",
|
||||
text: `Failed to upload ${file.name}`,
|
||||
type: "error",
|
||||
|
||||
@@ -67,11 +67,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ButtonStyled, NewModal } from "@modrinth/ui";
|
||||
import { DownloadIcon, XIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, injectNotificationManager, NewModal } from "@modrinth/ui";
|
||||
import { ModrinthServersFetchError } from "@modrinth/utils";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
project: any;
|
||||
@@ -112,14 +114,12 @@ const handleReinstall = async () => {
|
||||
} catch (error) {
|
||||
if (error instanceof ModrinthServersFetchError && error.statusCode === 429) {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Cannot reinstall server",
|
||||
text: "You are being rate limited. Please try again later.",
|
||||
type: "error",
|
||||
});
|
||||
} else {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Reinstall Failed",
|
||||
text: "An unexpected error occurred while reinstalling. Please try again later.",
|
||||
type: "error",
|
||||
|
||||
@@ -144,18 +144,20 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { BackupWarning, ButtonStyled, NewModal } from "@modrinth/ui";
|
||||
import {
|
||||
UploadIcon,
|
||||
RightArrowIcon,
|
||||
XIcon,
|
||||
ServerIcon,
|
||||
ArrowBigRightDashIcon,
|
||||
RightArrowIcon,
|
||||
ServerIcon,
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { BackupWarning, ButtonStyled, injectNotificationManager, NewModal } from "@modrinth/ui";
|
||||
import { formatBytes, ModrinthServersFetchError } from "@modrinth/utils";
|
||||
import { onMounted, onUnmounted } from "vue";
|
||||
import type { BackupInProgressReason } from "~/pages/servers/manage/[id].vue";
|
||||
import type { ModrinthServer } from "~/composables/servers/modrinth-servers";
|
||||
import type { BackupInProgressReason } from "~/pages/servers/manage/[id].vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
|
||||
if (isLoading.value) {
|
||||
@@ -250,7 +252,6 @@ const handleReinstall = async () => {
|
||||
|
||||
if (!mrpackFile.value) {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "No file selected",
|
||||
text: "Choose a .mrpack file before installing.",
|
||||
type: "error",
|
||||
@@ -301,14 +302,12 @@ const handleReinstall = async () => {
|
||||
} catch (error) {
|
||||
if (error instanceof ModrinthServersFetchError && error.statusCode === 429) {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Cannot upload and install modpack to server",
|
||||
text: "You are being rate limited. Please try again later.",
|
||||
type: "error",
|
||||
});
|
||||
} else {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Modpack upload and install failed",
|
||||
text: "An unexpected error occurred while uploading/installing. Please try again later.",
|
||||
type: "error",
|
||||
|
||||
@@ -197,13 +197,20 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { BackupWarning, ButtonStyled, NewModal, Toggle } from "@modrinth/ui";
|
||||
import { DropdownIcon, RightArrowIcon, ServerIcon, XIcon } from "@modrinth/assets";
|
||||
import { $fetch } from "ofetch";
|
||||
import {
|
||||
BackupWarning,
|
||||
ButtonStyled,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
Toggle,
|
||||
} from "@modrinth/ui";
|
||||
import { type Loaders, ModrinthServersFetchError } from "@modrinth/utils";
|
||||
import type { BackupInProgressReason } from "~/pages/servers/manage/[id].vue";
|
||||
import { $fetch } from "ofetch";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
import type { BackupInProgressReason } from "~/pages/servers/manage/[id].vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
interface LoaderVersion {
|
||||
@@ -475,14 +482,12 @@ const handleReinstall = async () => {
|
||||
} catch (error) {
|
||||
if (error instanceof ModrinthServersFetchError && (error as any)?.statusCode === 429) {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Cannot reinstall server",
|
||||
text: "You are being rate limited. Please try again later.",
|
||||
type: "error",
|
||||
});
|
||||
} else {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Reinstall Failed",
|
||||
text: "An unexpected error occurred while reinstalling. Please try again later.",
|
||||
type: "error",
|
||||
|
||||
@@ -20,8 +20,11 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { LinkIcon } from "@modrinth/assets";
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
import { useStorage } from "@vueuse/core";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps<{
|
||||
subdomain: string;
|
||||
noSeparator?: boolean;
|
||||
@@ -30,7 +33,6 @@ const props = defineProps<{
|
||||
const copySubdomain = () => {
|
||||
navigator.clipboard.writeText(props.subdomain + ".modrinth.gg");
|
||||
addNotification({
|
||||
group: "servers",
|
||||
title: "Custom URL copied",
|
||||
text: "Your server's URL has been copied to your clipboard.",
|
||||
type: "success",
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { Accordion, ButtonStyled, NewModal, ServerNotice, TagItem } from "@modrinth/ui";
|
||||
import { PlusIcon, XIcon } from "@modrinth/assets";
|
||||
import type { ServerNotice as ServerNoticeType } from "@modrinth/utils";
|
||||
import {
|
||||
Accordion,
|
||||
ButtonStyled,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
ServerNotice,
|
||||
TagItem,
|
||||
} from "@modrinth/ui";
|
||||
import { type ServerNotice as ServerNoticeType } from "@modrinth/utils";
|
||||
import { ref } from "vue";
|
||||
import { useServersFetch } from "~/composables/servers/servers-fetch.ts";
|
||||
|
||||
const app = useNuxtApp() as unknown as { $notify: any };
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>();
|
||||
|
||||
@@ -39,16 +46,14 @@ async function assign(server: boolean = true) {
|
||||
method: "PUT",
|
||||
},
|
||||
).catch((err) => {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error assigning notice",
|
||||
text: err,
|
||||
type: "error",
|
||||
});
|
||||
});
|
||||
} else {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error assigning notice",
|
||||
text: "No server or node specified",
|
||||
type: "error",
|
||||
@@ -64,8 +69,7 @@ async function unassignDetect() {
|
||||
const node = assignedNodes.value.some((assigned) => assigned.id === input);
|
||||
|
||||
if (!server && !node) {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error unassigning notice",
|
||||
text: "ID is not an assigned server or node",
|
||||
type: "error",
|
||||
@@ -84,8 +88,7 @@ async function unassign(id: string, server: boolean = true) {
|
||||
method: "PUT",
|
||||
},
|
||||
).catch((err) => {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error unassigning notice",
|
||||
text: err,
|
||||
type: "error",
|
||||
|
||||
@@ -251,23 +251,25 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { CopyCode, OverflowMenu, MarkdownEditor } from "@modrinth/ui";
|
||||
import {
|
||||
DropdownIcon,
|
||||
ReplyIcon,
|
||||
SendIcon,
|
||||
CheckCircleIcon,
|
||||
XIcon,
|
||||
EyeOffIcon,
|
||||
CheckIcon,
|
||||
DropdownIcon,
|
||||
EyeOffIcon,
|
||||
ReplyIcon,
|
||||
ScaleIcon,
|
||||
SendIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { useImageUpload } from "~/composables/image-upload.ts";
|
||||
import ThreadMessage from "~/components/ui/thread/ThreadMessage.vue";
|
||||
import { isStaff } from "~/helpers/users.js";
|
||||
import { isApproved, isRejected } from "~/helpers/projects.js";
|
||||
import Modal from "~/components/ui/Modal.vue";
|
||||
import { CopyCode, MarkdownEditor, OverflowMenu, injectNotificationManager } from "@modrinth/ui";
|
||||
import Checkbox from "~/components/ui/Checkbox.vue";
|
||||
import Modal from "~/components/ui/Modal.vue";
|
||||
import ThreadMessage from "~/components/ui/thread/ThreadMessage.vue";
|
||||
import { useImageUpload } from "~/composables/image-upload.ts";
|
||||
import { isApproved, isRejected } from "~/helpers/projects.js";
|
||||
import { isStaff } from "~/helpers/users.js";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps({
|
||||
thread: {
|
||||
@@ -388,8 +390,7 @@ async function sendReply(status = null, privateMessage = false) {
|
||||
props.setStatus(status);
|
||||
}
|
||||
} catch (err) {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error sending message",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -411,8 +412,7 @@ async function closeReport(reply) {
|
||||
});
|
||||
await updateThreadLocal();
|
||||
} catch (err) {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error closing report",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -430,8 +430,7 @@ async function reopenReport() {
|
||||
});
|
||||
await updateThreadLocal();
|
||||
} catch (err) {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error reopening report",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -110,13 +110,15 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CopyCode, MarkdownEditor, ButtonStyled } from "@modrinth/ui";
|
||||
import { ReplyIcon, SendIcon, CheckCircleIcon, ScaleIcon } from "@modrinth/assets";
|
||||
import type { Thread, Report, User, ThreadMessage as TypeThreadMessage } from "@modrinth/utils";
|
||||
import { CheckCircleIcon, ReplyIcon, ScaleIcon, SendIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, CopyCode, injectNotificationManager, MarkdownEditor } from "@modrinth/ui";
|
||||
import type { Report, Thread, ThreadMessage as TypeThreadMessage, User } from "@modrinth/utils";
|
||||
import dayjs from "dayjs";
|
||||
import ThreadMessage from "./ThreadMessage.vue";
|
||||
import { useImageUpload } from "~/composables/image-upload.ts";
|
||||
import { isStaff } from "~/helpers/users.js";
|
||||
import ThreadMessage from "./ThreadMessage.vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps<{
|
||||
thread: Thread;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
|
||||
export const useAuth = async (oldToken = null) => {
|
||||
const auth = useState("auth", () => ({
|
||||
user: null,
|
||||
@@ -128,9 +130,8 @@ export const removeAuthProvider = async (provider) => {
|
||||
});
|
||||
await useAuth(auth.value.token);
|
||||
} catch (err) {
|
||||
const data = useNuxtApp();
|
||||
data.$notify({
|
||||
group: "main",
|
||||
const { addNotification } = injectNotificationManager();
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data.description,
|
||||
type: "error",
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
export const useNotifications = () => useState("notifications", () => []);
|
||||
|
||||
export const addNotification = (notification) => {
|
||||
const notifications = useNotifications();
|
||||
|
||||
const existingNotif = notifications.value.find(
|
||||
(x) =>
|
||||
x.text === notification.text &&
|
||||
x.title === notification.title &&
|
||||
x.type === notification.type,
|
||||
);
|
||||
if (existingNotif) {
|
||||
setNotificationTimer(existingNotif);
|
||||
existingNotif.count++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
notification.id = new Date();
|
||||
notification.count = 1;
|
||||
|
||||
setNotificationTimer(notification);
|
||||
notifications.value.push(notification);
|
||||
};
|
||||
|
||||
export const setNotificationTimer = (notification) => {
|
||||
if (!notification) return;
|
||||
|
||||
const notifications = useNotifications();
|
||||
|
||||
if (notification.timer) {
|
||||
clearTimeout(notification.timer);
|
||||
}
|
||||
|
||||
notification.timer = setTimeout(() => {
|
||||
notifications.value.splice(notifications.value.indexOf(notification), 1);
|
||||
}, 30000);
|
||||
};
|
||||
@@ -1,18 +1,20 @@
|
||||
import { ModrinthServerError } from "@modrinth/utils";
|
||||
import type { JWTAuth, ModuleError, ModuleName } from "@modrinth/utils";
|
||||
import { ModrinthServerError } from "@modrinth/utils";
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
import { useServersFetch } from "./servers-fetch.ts";
|
||||
|
||||
import {
|
||||
GeneralModule,
|
||||
ContentModule,
|
||||
BackupsModule,
|
||||
ContentModule,
|
||||
FSModule,
|
||||
GeneralModule,
|
||||
NetworkModule,
|
||||
StartupModule,
|
||||
WSModule,
|
||||
FSModule,
|
||||
} from "./modules/index.ts";
|
||||
|
||||
export function handleError(err: any) {
|
||||
const { addNotification } = injectNotificationManager();
|
||||
if (err instanceof ModrinthServerError && err.v1Error) {
|
||||
addNotification({
|
||||
title: err.v1Error?.context ?? `An error occurred`,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
|
||||
type AsyncFunction<TArgs extends any[], TResult> = (...args: TArgs) => Promise<TResult>;
|
||||
type ErrorFunction = (err: any) => void | Promise<void>;
|
||||
type VoidFunction = () => void | Promise<void>;
|
||||
@@ -9,8 +11,8 @@ type useClientTry = <TArgs extends any[], TResult>(
|
||||
) => (...args: TArgs) => Promise<TResult | undefined>;
|
||||
|
||||
const defaultOnError: ErrorFunction = (error) => {
|
||||
const { addNotification } = injectNotificationManager();
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: error?.data?.description || error.message || error || "Unknown error",
|
||||
type: "error",
|
||||
|
||||
@@ -135,7 +135,8 @@ export const userFollowProject = async (project) => {
|
||||
}
|
||||
};
|
||||
export const resendVerifyEmail = async () => {
|
||||
const app = useNuxtApp();
|
||||
// const { injectNotificationManager } = await import("@modrinth/ui");
|
||||
// const { addNotification } = injectNotificationManager();
|
||||
|
||||
startLoading();
|
||||
try {
|
||||
@@ -144,15 +145,13 @@ export const resendVerifyEmail = async () => {
|
||||
});
|
||||
|
||||
const auth = await useAuth();
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Email sent",
|
||||
text: `An email with a link to verify your account has been sent to ${auth.value.user.email}.`,
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data.description,
|
||||
type: "error",
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
import { useNuxtApp } from "#imports";
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
import type { Organization, Project, Report, User, Version } from "@modrinth/utils";
|
||||
|
||||
// TODO: There needs to be a standardized way to get these types, eg; @modrinth/types generated from api schema. Later problem.
|
||||
type Project = { id: string };
|
||||
type Version = { id: string; project_id: string };
|
||||
type Report = { id: string; item_type: "project" | "user" | "version"; item_id: string };
|
||||
type Thread = { id: string };
|
||||
type User = { id: string };
|
||||
type Organization = { id: string };
|
||||
|
||||
export type NotificationAction = {
|
||||
export type PlatformNotificationAction = {
|
||||
title: string;
|
||||
action_route: [string, string];
|
||||
};
|
||||
|
||||
export type NotificationBody = {
|
||||
export type PlatformNotificationBody = {
|
||||
project_id?: string;
|
||||
version_id?: string;
|
||||
report_id?: string;
|
||||
@@ -22,7 +17,7 @@ export type NotificationBody = {
|
||||
organization_id?: string;
|
||||
};
|
||||
|
||||
export type Notification = {
|
||||
export type PlatformNotification = {
|
||||
id: string;
|
||||
user_id: string;
|
||||
type: "project_update" | "team_invite" | "status_change" | "moderator_message";
|
||||
@@ -31,10 +26,10 @@ export type Notification = {
|
||||
link: string;
|
||||
read: boolean;
|
||||
created: string;
|
||||
actions: NotificationAction[];
|
||||
body?: NotificationBody;
|
||||
actions: PlatformNotificationAction[];
|
||||
body?: PlatformNotificationBody;
|
||||
extra_data?: Record<string, unknown>;
|
||||
grouped_notifs?: Notification[];
|
||||
grouped_notifs?: PlatformNotification[];
|
||||
};
|
||||
|
||||
async function getBulk<T extends { id: string }>(
|
||||
@@ -55,8 +50,8 @@ async function getBulk<T extends { id: string }>(
|
||||
}
|
||||
|
||||
export async function fetchExtraNotificationData(
|
||||
notifications: Notification[],
|
||||
): Promise<Notification[]> {
|
||||
notifications: PlatformNotification[],
|
||||
): Promise<PlatformNotification[]> {
|
||||
const bulk = {
|
||||
projects: [] as string[],
|
||||
reports: [] as string[],
|
||||
@@ -133,8 +128,8 @@ export async function fetchExtraNotificationData(
|
||||
return notifications;
|
||||
}
|
||||
|
||||
export function groupNotifications(notifications: Notification[]): Notification[] {
|
||||
const grouped: Notification[] = [];
|
||||
export function groupNotifications(notifications: PlatformNotification[]): PlatformNotification[] {
|
||||
const grouped: PlatformNotification[] = [];
|
||||
for (let i = 0; i < notifications.length; i++) {
|
||||
const current = notifications[i];
|
||||
const next = notifications[i + 1];
|
||||
@@ -154,18 +149,18 @@ export function groupNotifications(notifications: Notification[]): Notification[
|
||||
return grouped;
|
||||
}
|
||||
|
||||
function isSimilar(a: Notification, b: Notification | undefined): boolean {
|
||||
function isSimilar(a: PlatformNotification, b: PlatformNotification | undefined): boolean {
|
||||
return !!a?.body?.project_id && a.body!.project_id === b?.body?.project_id;
|
||||
}
|
||||
|
||||
export async function markAsRead(
|
||||
ids: string[],
|
||||
): Promise<(notifications: Notification[]) => Notification[]> {
|
||||
): Promise<(notifications: PlatformNotification[]) => PlatformNotification[]> {
|
||||
try {
|
||||
await useBaseFetch(`notifications?ids=${JSON.stringify([...new Set(ids)])}`, {
|
||||
method: "PATCH",
|
||||
});
|
||||
return (notifications: Notification[]) => {
|
||||
return (notifications: PlatformNotification[]) => {
|
||||
const newNotifs = notifications ?? [];
|
||||
newNotifs.forEach((n) => {
|
||||
if (ids.includes(n.id)) n.read = true;
|
||||
@@ -173,9 +168,8 @@ export async function markAsRead(
|
||||
return newNotifs;
|
||||
};
|
||||
} catch (err: any) {
|
||||
const app: any = useNuxtApp();
|
||||
app.$notify({
|
||||
group: "main",
|
||||
const { addNotification } = injectNotificationManager();
|
||||
addNotification({
|
||||
title: "Error marking notification as read",
|
||||
text: err?.data?.description ?? err,
|
||||
type: "error",
|
||||
@@ -666,65 +666,65 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import {
|
||||
ModrinthIcon,
|
||||
ArrowBigUpDashIcon,
|
||||
BookmarkIcon,
|
||||
ServerIcon,
|
||||
LogInIcon,
|
||||
DownloadIcon,
|
||||
LibraryIcon,
|
||||
XIcon,
|
||||
IssuesIcon,
|
||||
ReportIcon,
|
||||
CompassIcon,
|
||||
HamburgerIcon,
|
||||
SearchIcon,
|
||||
BellIcon,
|
||||
SettingsIcon,
|
||||
BlueskyIcon,
|
||||
BookmarkIcon,
|
||||
BoxIcon,
|
||||
BracesIcon,
|
||||
ChartIcon,
|
||||
CollectionIcon,
|
||||
CompassIcon,
|
||||
CurrencyIcon,
|
||||
DiscordIcon,
|
||||
DownloadIcon,
|
||||
DropdownIcon,
|
||||
GithubIcon,
|
||||
GlassesIcon,
|
||||
HamburgerIcon,
|
||||
HomeIcon,
|
||||
IssuesIcon,
|
||||
LibraryIcon,
|
||||
LogInIcon,
|
||||
LogOutIcon,
|
||||
MastodonIcon,
|
||||
ModrinthIcon,
|
||||
MoonIcon,
|
||||
SunIcon,
|
||||
OrganizationIcon,
|
||||
PackageOpenIcon,
|
||||
PaintbrushIcon,
|
||||
PlugIcon,
|
||||
PlusIcon,
|
||||
DropdownIcon,
|
||||
LogOutIcon,
|
||||
ChartIcon,
|
||||
BoxIcon,
|
||||
CollectionIcon,
|
||||
OrganizationIcon,
|
||||
UserIcon,
|
||||
CurrencyIcon,
|
||||
BracesIcon,
|
||||
GlassesIcon,
|
||||
PaintbrushIcon,
|
||||
PackageOpenIcon,
|
||||
DiscordIcon,
|
||||
BlueskyIcon,
|
||||
TwitterIcon,
|
||||
MastodonIcon,
|
||||
GithubIcon,
|
||||
ReportIcon,
|
||||
ScaleIcon,
|
||||
SearchIcon,
|
||||
ServerIcon,
|
||||
SettingsIcon,
|
||||
SunIcon,
|
||||
TwitterIcon,
|
||||
UserIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
PagewideBanner,
|
||||
Avatar,
|
||||
commonMessages,
|
||||
} from "@modrinth/ui";
|
||||
import { isAdmin, isStaff } from "@modrinth/utils";
|
||||
import { errors as generatedStateErrors } from "~/generated/state.json";
|
||||
|
||||
import ModalCreation from "~/components/ui/ModalCreation.vue";
|
||||
import { getProjectTypeMessage } from "~/utils/i18n-project-type.ts";
|
||||
import CollectionCreateModal from "~/components/ui/CollectionCreateModal.vue";
|
||||
import ModalCreation from "~/components/ui/ModalCreation.vue";
|
||||
import OrganizationCreateModal from "~/components/ui/OrganizationCreateModal.vue";
|
||||
import TeleportOverflowMenu from "~/components/ui/servers/TeleportOverflowMenu.vue";
|
||||
import { errors as generatedStateErrors } from "~/generated/state.json";
|
||||
import { getProjectTypeMessage } from "~/utils/i18n-project-type.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const app = useNuxtApp();
|
||||
const auth = await useAuth();
|
||||
const user = await useUser();
|
||||
|
||||
@@ -1079,15 +1079,13 @@ function developerModeIncrement() {
|
||||
developerModeCounter.value = 0;
|
||||
saveFeatureFlags();
|
||||
if (flags.value.developerMode) {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Developer mode activated",
|
||||
text: "Developer mode has been enabled",
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Developer mode deactivated",
|
||||
text: "Developer mode has been disabled",
|
||||
type: "success",
|
||||
|
||||
@@ -890,6 +890,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { navigateTo } from "#app";
|
||||
import {
|
||||
BookmarkIcon,
|
||||
BookTextIcon,
|
||||
@@ -906,6 +907,7 @@ import {
|
||||
HeartIcon,
|
||||
InfoIcon,
|
||||
LinkIcon as LinksIcon,
|
||||
ModrinthIcon,
|
||||
MoreVerticalIcon,
|
||||
PlusIcon,
|
||||
ReportIcon,
|
||||
@@ -917,13 +919,13 @@ import {
|
||||
UsersIcon,
|
||||
VersionIcon,
|
||||
WrenchIcon,
|
||||
ModrinthIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
Checkbox,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
OverflowMenu,
|
||||
PopoutMenu,
|
||||
@@ -935,36 +937,37 @@ import {
|
||||
ProjectSidebarLinks,
|
||||
ProjectStatusBadge,
|
||||
ScrollablePanel,
|
||||
TagItem,
|
||||
ServersPromo,
|
||||
TagItem,
|
||||
useRelativeTime,
|
||||
} from "@modrinth/ui";
|
||||
import VersionSummary from "@modrinth/ui/src/components/version/VersionSummary.vue";
|
||||
import { formatCategory, formatProjectType, renderString } from "@modrinth/utils";
|
||||
import { useLocalStorage } from "@vueuse/core";
|
||||
import dayjs from "dayjs";
|
||||
import { Tooltip } from "floating-vue";
|
||||
import { useLocalStorage } from "@vueuse/core";
|
||||
import { navigateTo } from "#app";
|
||||
import Accordion from "~/components/ui/Accordion.vue";
|
||||
import AdPlaceholder from "~/components/ui/AdPlaceholder.vue";
|
||||
import AutomaticAccordion from "~/components/ui/AutomaticAccordion.vue";
|
||||
import Breadcrumbs from "~/components/ui/Breadcrumbs.vue";
|
||||
import CollectionCreateModal from "~/components/ui/CollectionCreateModal.vue";
|
||||
import MessageBanner from "~/components/ui/MessageBanner.vue";
|
||||
import ModerationChecklist from "~/components/ui/moderation/checklist/ModerationChecklist.vue";
|
||||
import NavStack from "~/components/ui/NavStack.vue";
|
||||
import NavStackItem from "~/components/ui/NavStackItem.vue";
|
||||
import NavTabs from "~/components/ui/NavTabs.vue";
|
||||
import ProjectMemberHeader from "~/components/ui/ProjectMemberHeader.vue";
|
||||
import { userCollectProject } from "~/composables/user.js";
|
||||
import { reportProject } from "~/utils/report-helpers.ts";
|
||||
import { saveFeatureFlags } from "~/composables/featureFlags.ts";
|
||||
import ModerationChecklist from "~/components/ui/moderation/checklist/ModerationChecklist.vue";
|
||||
import { userCollectProject } from "~/composables/user.js";
|
||||
import { useModerationStore } from "~/store/moderation.ts";
|
||||
import { reportProject } from "~/utils/report-helpers.ts";
|
||||
|
||||
const data = useNuxtApp();
|
||||
const route = useNativeRoute();
|
||||
const config = useRuntimeConfig();
|
||||
const moderationStore = useModerationStore();
|
||||
const notifications = injectNotificationManager();
|
||||
const { addNotification } = notifications;
|
||||
|
||||
const auth = await useAuth();
|
||||
const user = await useUser();
|
||||
@@ -974,7 +977,6 @@ const flags = useFeatureFlags();
|
||||
const cosmetics = useCosmetics();
|
||||
|
||||
const { formatMessage } = useVIntl();
|
||||
const { setVisible } = useNotificationRightwards();
|
||||
|
||||
const settingsModal = ref();
|
||||
const downloadModal = ref();
|
||||
@@ -1425,8 +1427,7 @@ async function setProcessing() {
|
||||
|
||||
project.value.status = "processing";
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -1459,8 +1460,7 @@ async function patchProject(resData, quiet = false) {
|
||||
|
||||
result = true;
|
||||
if (!quiet) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Project updated",
|
||||
text: "Your project has been updated.",
|
||||
type: "success",
|
||||
@@ -1468,8 +1468,7 @@ async function patchProject(resData, quiet = false) {
|
||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||
}
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -1498,15 +1497,13 @@ async function patchIcon(icon) {
|
||||
);
|
||||
await resetProject();
|
||||
result = true;
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Project icon updated",
|
||||
text: "Your project's icon has been updated.",
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -1555,11 +1552,15 @@ const collapsedModerationChecklist = useLocalStorage("collapsed-moderation-check
|
||||
watch(
|
||||
showModerationChecklist,
|
||||
(newValue) => {
|
||||
setVisible(newValue);
|
||||
notifications.setNotificationLocation(newValue ? "left" : "right");
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
notifications.setNotificationLocation("right");
|
||||
});
|
||||
|
||||
if (import.meta.client && history && history.state && history.state.showChecklist) {
|
||||
showModerationChecklist.value = true;
|
||||
}
|
||||
|
||||
@@ -278,26 +278,26 @@
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
PlusIcon,
|
||||
CalendarIcon,
|
||||
ContractIcon,
|
||||
EditIcon,
|
||||
TrashIcon,
|
||||
ExpandIcon,
|
||||
ExternalIcon,
|
||||
ImageIcon,
|
||||
InfoIcon,
|
||||
LeftArrowIcon,
|
||||
PlusIcon,
|
||||
RightArrowIcon,
|
||||
SaveIcon,
|
||||
StarIcon,
|
||||
XIcon,
|
||||
RightArrowIcon,
|
||||
LeftArrowIcon,
|
||||
ExternalIcon,
|
||||
ExpandIcon,
|
||||
ContractIcon,
|
||||
UploadIcon,
|
||||
InfoIcon,
|
||||
ImageIcon,
|
||||
TransferIcon,
|
||||
TrashIcon,
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { ConfirmModal } from "@modrinth/ui";
|
||||
import FileInput from "~/components/ui/FileInput.vue";
|
||||
import { ConfirmModal, injectNotificationManager } from "@modrinth/ui";
|
||||
import DropArea from "~/components/ui/DropArea.vue";
|
||||
import FileInput from "~/components/ui/FileInput.vue";
|
||||
import Modal from "~/components/ui/Modal.vue";
|
||||
|
||||
import { isPermission } from "~/utils/permissions.ts";
|
||||
@@ -425,6 +425,8 @@ export default defineNuxtComponent({
|
||||
this.shouldPreventActions = true;
|
||||
startLoading();
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
try {
|
||||
let url = `project/${this.project.id}/gallery?ext=${
|
||||
this.editFile
|
||||
@@ -450,8 +452,7 @@ export default defineNuxtComponent({
|
||||
|
||||
this.$refs.modal_edit_item.hide();
|
||||
} catch (err) {
|
||||
this.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -465,6 +466,8 @@ export default defineNuxtComponent({
|
||||
this.shouldPreventActions = true;
|
||||
startLoading();
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
try {
|
||||
let url = `project/${this.project.id}/gallery?url=${encodeURIComponent(
|
||||
this.project.gallery[this.editIndex].url,
|
||||
@@ -487,8 +490,7 @@ export default defineNuxtComponent({
|
||||
await this.resetProject();
|
||||
this.$refs.modal_edit_item.hide();
|
||||
} catch (err) {
|
||||
this.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -501,6 +503,8 @@ export default defineNuxtComponent({
|
||||
async deleteGalleryImage() {
|
||||
startLoading();
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
try {
|
||||
await useBaseFetch(
|
||||
`project/${this.project.id}/gallery?url=${encodeURIComponent(
|
||||
@@ -513,8 +517,7 @@ export default defineNuxtComponent({
|
||||
|
||||
await this.resetProject();
|
||||
} catch (err) {
|
||||
this.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -99,8 +99,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { XIcon, CheckIcon, IssuesIcon } from "@modrinth/assets";
|
||||
import { Badge } from "@modrinth/ui";
|
||||
import { CheckIcon, IssuesIcon, XIcon } from "@modrinth/assets";
|
||||
import { Badge, injectNotificationManager } from "@modrinth/ui";
|
||||
import ConversationThread from "~/components/ui/thread/ConversationThread.vue";
|
||||
import {
|
||||
getProjectLink,
|
||||
@@ -111,6 +111,7 @@ import {
|
||||
isUnderReview,
|
||||
} from "~/helpers/projects.js";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const props = defineProps({
|
||||
project: {
|
||||
type: Object,
|
||||
@@ -131,7 +132,6 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const app = useNuxtApp();
|
||||
const auth = await useAuth();
|
||||
|
||||
const { data: thread } = await useAsyncData(`thread/${props.project.thread_id}`, () =>
|
||||
@@ -153,8 +153,7 @@ async function setStatus(status) {
|
||||
await props.resetProject();
|
||||
thread.value = await useBaseFetch(`thread/${thread.value.id}`);
|
||||
} catch (err) {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -243,21 +243,23 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { formatProjectStatus, formatProjectType } from "@modrinth/utils";
|
||||
import {
|
||||
UploadIcon,
|
||||
CheckIcon,
|
||||
IssuesIcon,
|
||||
SaveIcon,
|
||||
TrashIcon,
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
IssuesIcon,
|
||||
CheckIcon,
|
||||
TriangleAlertIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { Avatar, ConfirmModal, injectNotificationManager } from "@modrinth/ui";
|
||||
import { formatProjectStatus, formatProjectType } from "@modrinth/utils";
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import { ConfirmModal, Avatar } from "@modrinth/ui";
|
||||
import { MIN_SUMMARY_CHARS } from "@modrinth/moderation";
|
||||
import FileInput from "~/components/ui/FileInput.vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps({
|
||||
project: {
|
||||
type: Object,
|
||||
@@ -398,7 +400,6 @@ const deleteProject = async () => {
|
||||
await initUserProjects();
|
||||
await router.push("/dashboard/projects");
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Project deleted",
|
||||
text: "Your project has been deleted.",
|
||||
type: "success",
|
||||
@@ -417,7 +418,6 @@ const deleteIcon = async () => {
|
||||
});
|
||||
await props.resetProject();
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Project icon removed",
|
||||
text: "Your project's icon has been removed.",
|
||||
type: "success",
|
||||
|
||||
@@ -518,21 +518,30 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import {
|
||||
TransferIcon,
|
||||
CheckIcon,
|
||||
UsersIcon,
|
||||
DropdownIcon,
|
||||
SaveIcon,
|
||||
UserPlusIcon,
|
||||
UserXIcon,
|
||||
OrganizationIcon,
|
||||
CrownIcon,
|
||||
DropdownIcon,
|
||||
OrganizationIcon,
|
||||
SaveIcon,
|
||||
TransferIcon,
|
||||
UserPlusIcon,
|
||||
UsersIcon,
|
||||
UserXIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { Avatar, Badge, Card, Checkbox, ConfirmModal } from "@modrinth/ui";
|
||||
import {
|
||||
Avatar,
|
||||
Badge,
|
||||
Card,
|
||||
Checkbox,
|
||||
ConfirmModal,
|
||||
injectNotificationManager,
|
||||
} from "@modrinth/ui";
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import { removeSelfFromTeam } from "~/helpers/teams.js";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const props = defineProps({
|
||||
project: {
|
||||
type: Object,
|
||||
@@ -654,7 +663,6 @@ const onAddToOrg = useClientTry(async () => {
|
||||
await updateMembers();
|
||||
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Project transferred",
|
||||
text: "Your project has been transferred to the organization.",
|
||||
type: "success",
|
||||
@@ -675,7 +683,6 @@ const onRemoveFromOrg = useClientTry(async () => {
|
||||
await updateMembers();
|
||||
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Project removed",
|
||||
text: "Your project has been removed from the organization.",
|
||||
type: "success",
|
||||
@@ -703,7 +710,6 @@ const inviteTeamMember = async () => {
|
||||
await updateMembers();
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err?.data?.description || err?.message || err || "Unknown error",
|
||||
type: "error",
|
||||
@@ -726,7 +732,6 @@ const removeTeamMember = async (index) => {
|
||||
await updateMembers();
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err?.data?.description || err?.message || err || "Unknown error",
|
||||
type: "error",
|
||||
@@ -760,14 +765,12 @@ const updateTeamMember = async (index) => {
|
||||
);
|
||||
await updateMembers();
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Member(s) updated",
|
||||
text: "Your project's member(s) has been updated.",
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err?.data?.description || err?.message || err || "Unknown error",
|
||||
type: "error",
|
||||
@@ -790,7 +793,6 @@ const transferOwnership = async (index) => {
|
||||
await updateMembers();
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err?.data?.description || err?.message || err || "Unknown error",
|
||||
type: "error",
|
||||
@@ -837,7 +839,6 @@ async function updateOrgMember(index) {
|
||||
await updateMembers();
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err?.data?.description || err?.message || err || "Unknown error",
|
||||
type: "error",
|
||||
|
||||
@@ -631,45 +631,46 @@
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
Avatar,
|
||||
Badge,
|
||||
CopyCode,
|
||||
Checkbox,
|
||||
ButtonStyled,
|
||||
ConfirmModal,
|
||||
MarkdownEditor,
|
||||
} from "@modrinth/ui";
|
||||
import {
|
||||
FileIcon,
|
||||
TrashIcon,
|
||||
EditIcon,
|
||||
BoxIcon,
|
||||
ChevronRightIcon,
|
||||
DownloadIcon,
|
||||
StarIcon,
|
||||
ReportIcon,
|
||||
SaveIcon,
|
||||
XIcon,
|
||||
EditIcon,
|
||||
FileIcon,
|
||||
HashIcon,
|
||||
PlusIcon,
|
||||
TransferIcon,
|
||||
UploadIcon,
|
||||
BoxIcon,
|
||||
ReportIcon,
|
||||
RightArrowIcon,
|
||||
ChevronRightIcon,
|
||||
SaveIcon,
|
||||
StarIcon,
|
||||
TransferIcon,
|
||||
TrashIcon,
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import {
|
||||
Avatar,
|
||||
Badge,
|
||||
ButtonStyled,
|
||||
Checkbox,
|
||||
ConfirmModal,
|
||||
CopyCode,
|
||||
injectNotificationManager,
|
||||
MarkdownEditor,
|
||||
} from "@modrinth/ui";
|
||||
import { formatBytes, formatCategory } from "@modrinth/utils";
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import { useImageUpload } from "~/composables/image-upload.ts";
|
||||
import { acceptFileFromProjectType } from "~/helpers/fileUtils.js";
|
||||
import { renderHighlightedString } from "~/helpers/highlight.js";
|
||||
import { inferVersionInfo } from "~/helpers/infer.js";
|
||||
import { createDataPackVersion } from "~/helpers/package.js";
|
||||
import { renderHighlightedString } from "~/helpers/highlight.js";
|
||||
import { reportVersion } from "~/utils/report-helpers.ts";
|
||||
import { useImageUpload } from "~/composables/image-upload.ts";
|
||||
|
||||
import AdPlaceholder from "~/components/ui/AdPlaceholder.vue";
|
||||
import Breadcrumbs from "~/components/ui/Breadcrumbs.vue";
|
||||
import Categories from "~/components/ui/search/Categories.vue";
|
||||
import FileInput from "~/components/ui/FileInput.vue";
|
||||
import Modal from "~/components/ui/Modal.vue";
|
||||
import Categories from "~/components/ui/search/Categories.vue";
|
||||
|
||||
export default defineNuxtComponent({
|
||||
components: {
|
||||
@@ -997,8 +998,8 @@ export default defineNuxtComponent({
|
||||
const project = await useBaseFetch(`project/${newDependencyId}`);
|
||||
|
||||
if (this.version.dependencies.some((dep) => project.id === dep.project_id)) {
|
||||
this.$notify({
|
||||
group: "main",
|
||||
const { addNotification } = injectNotificationManager();
|
||||
addNotification({
|
||||
title: "Dependency already added",
|
||||
text: "You cannot add the same dependency twice.",
|
||||
type: "error",
|
||||
@@ -1022,8 +1023,8 @@ export default defineNuxtComponent({
|
||||
const project = await useBaseFetch(`project/${version.project_id}`);
|
||||
|
||||
if (this.version.dependencies.some((dep) => version.id === dep.version_id)) {
|
||||
this.$notify({
|
||||
group: "main",
|
||||
const { addNotification } = injectNotificationManager();
|
||||
addNotification({
|
||||
title: "Dependency already added",
|
||||
text: "You cannot add the same dependency twice.",
|
||||
type: "error",
|
||||
@@ -1050,8 +1051,8 @@ export default defineNuxtComponent({
|
||||
this.newDependencyId = "";
|
||||
} catch {
|
||||
if (!hideErrors) {
|
||||
this.$notify({
|
||||
group: "main",
|
||||
const { addNotification } = injectNotificationManager();
|
||||
addNotification({
|
||||
title: "Invalid Dependency",
|
||||
text: "The specified dependency could not be found",
|
||||
type: "error",
|
||||
@@ -1144,8 +1145,8 @@ export default defineNuxtComponent({
|
||||
)}`,
|
||||
);
|
||||
} catch (err) {
|
||||
this.$notify({
|
||||
group: "main",
|
||||
const { addNotification } = injectNotificationManager();
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -1169,8 +1170,8 @@ export default defineNuxtComponent({
|
||||
try {
|
||||
await this.createVersionRaw(this.version);
|
||||
} catch (err) {
|
||||
this.$notify({
|
||||
group: "main",
|
||||
const { addNotification } = injectNotificationManager();
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -1293,15 +1294,15 @@ export default defineNuxtComponent({
|
||||
|
||||
this.$refs.modal_package_mod.hide();
|
||||
|
||||
this.$notify({
|
||||
group: "main",
|
||||
const { addNotification } = injectNotificationManager();
|
||||
addNotification({
|
||||
title: "Packaging Success",
|
||||
text: "Your data pack was successfully packaged as a mod! Make sure to playtest to check for errors.",
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
this.$notify({
|
||||
group: "main",
|
||||
const { addNotification } = injectNotificationManager();
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -251,28 +251,31 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import {
|
||||
CheckIcon,
|
||||
CurrencyIcon,
|
||||
ExternalIcon,
|
||||
ModrinthPlusIcon,
|
||||
ServerIcon,
|
||||
UserIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
CopyCode,
|
||||
DropdownSelect,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
Toggle,
|
||||
useRelativeTime,
|
||||
} from "@modrinth/ui";
|
||||
import { formatCategory, formatPrice } from "@modrinth/utils";
|
||||
import {
|
||||
CheckIcon,
|
||||
XIcon,
|
||||
UserIcon,
|
||||
ModrinthPlusIcon,
|
||||
ServerIcon,
|
||||
ExternalIcon,
|
||||
CurrencyIcon,
|
||||
} from "@modrinth/assets";
|
||||
import dayjs from "dayjs";
|
||||
import { products } from "~/generated/state.json";
|
||||
import ModrinthServersIcon from "~/components/ui/servers/ModrinthServersIcon.vue";
|
||||
import { products } from "~/generated/state.json";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const route = useRoute();
|
||||
const vintl = useVIntl();
|
||||
|
||||
@@ -258,31 +258,31 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { EditIcon, PlusIcon, SaveIcon, SettingsIcon, TrashIcon, XIcon } from "@modrinth/assets";
|
||||
import {
|
||||
CopyCode,
|
||||
TagItem,
|
||||
ButtonStyled,
|
||||
ServerNotice,
|
||||
commonMessages,
|
||||
CopyCode,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
ServerNotice,
|
||||
TagItem,
|
||||
TeleportDropdownMenu,
|
||||
Toggle,
|
||||
useRelativeTime,
|
||||
} from "@modrinth/ui";
|
||||
import { SettingsIcon, PlusIcon, SaveIcon, TrashIcon, EditIcon, XIcon } from "@modrinth/assets";
|
||||
import dayjs from "dayjs";
|
||||
import { useVIntl } from "@vintl/vintl";
|
||||
import type { ServerNotice as ServerNoticeType } from "@modrinth/utils";
|
||||
import { computed } from "vue";
|
||||
import { NOTICE_LEVELS } from "@modrinth/ui/src/utils/notices.ts";
|
||||
import { useServersFetch } from "~/composables/servers/servers-fetch.ts";
|
||||
import type { ServerNotice as ServerNoticeType } from "@modrinth/utils";
|
||||
import { useVIntl } from "@vintl/vintl";
|
||||
import dayjs from "dayjs";
|
||||
import { computed } from "vue";
|
||||
import AssignNoticeModal from "~/components/ui/servers/notice/AssignNoticeModal.vue";
|
||||
import { useServersFetch } from "~/composables/servers/servers-fetch.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
const formatRelativeTime = useRelativeTime();
|
||||
|
||||
const app = useNuxtApp() as unknown as { $notify: any };
|
||||
|
||||
const notices = ref<ServerNoticeType[]>([]);
|
||||
const createNoticeModal = ref<InstanceType<typeof NewModal>>();
|
||||
const assignNoticeModal = ref<InstanceType<typeof AssignNoticeModal>>();
|
||||
@@ -351,15 +351,13 @@ async function deleteNotice(notice: ServerNoticeType) {
|
||||
method: "DELETE",
|
||||
})
|
||||
.then(() => {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: `Successfully deleted notice #${notice.id}`,
|
||||
type: "success",
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error deleting notice",
|
||||
text: err,
|
||||
type: "error",
|
||||
@@ -386,7 +384,6 @@ const noticeSubmitError = computed(() => {
|
||||
function validateSubmission(message: string) {
|
||||
if (noticeSubmitError.value) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: message,
|
||||
text: noticeSubmitError.value,
|
||||
type: "error",
|
||||
@@ -416,8 +413,7 @@ async function saveChanges() {
|
||||
: undefined,
|
||||
},
|
||||
}).catch((err) => {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error saving changes to notice",
|
||||
text: err,
|
||||
type: "error",
|
||||
@@ -447,8 +443,7 @@ async function createNotice() {
|
||||
: undefined,
|
||||
},
|
||||
}).catch((err) => {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error creating notice",
|
||||
text: err,
|
||||
type: "error",
|
||||
|
||||
@@ -32,8 +32,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ButtonStyled } from "@modrinth/ui";
|
||||
import { MailIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, injectNotificationManager } from "@modrinth/ui";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const userEmail = ref("");
|
||||
|
||||
@@ -50,7 +52,6 @@ async function getUserFromEmail() {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err.data.description,
|
||||
type: "error",
|
||||
|
||||
@@ -80,13 +80,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Button, Avatar, commonMessages } from "@modrinth/ui";
|
||||
import { XIcon, CheckIcon } from "@modrinth/assets";
|
||||
import { useBaseFetch } from "@/composables/fetch.js";
|
||||
import { CheckIcon, XIcon } from "@modrinth/assets";
|
||||
import { Avatar, Button, commonMessages, injectNotificationManager } from "@modrinth/ui";
|
||||
import { useAuth } from "@/composables/auth.js";
|
||||
import { useBaseFetch } from "@/composables/fetch.js";
|
||||
|
||||
import { useScopes } from "@/composables/auth/scopes.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -117,8 +118,6 @@ const messages = defineMessages({
|
||||
},
|
||||
});
|
||||
|
||||
const data = useNuxtApp();
|
||||
|
||||
const router = useNativeRoute();
|
||||
const auth = await useAuth();
|
||||
const { scopesToDefinitions } = useScopes();
|
||||
@@ -196,8 +195,7 @@ const onAuthorize = async () => {
|
||||
|
||||
throw new Error(formatMessage(messages.noRedirectUrlError));
|
||||
} catch {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -223,8 +221,7 @@ const onReject = async () => {
|
||||
|
||||
throw new Error(formatMessage(messages.noRedirectUrlError));
|
||||
} catch {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -67,10 +67,11 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { SendIcon, MailIcon, KeyIcon } from "@modrinth/assets";
|
||||
import { commonMessages } from "@modrinth/ui";
|
||||
import { KeyIcon, MailIcon, SendIcon } from "@modrinth/assets";
|
||||
import { commonMessages, injectNotificationManager } from "@modrinth/ui";
|
||||
import HCaptcha from "@/components/ui/HCaptcha.vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const methodChoiceMessages = defineMessages({
|
||||
@@ -179,14 +180,12 @@ async function recovery() {
|
||||
});
|
||||
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(emailSentNotificationMessages.title),
|
||||
text: formatMessage(emailSentNotificationMessages.text),
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -211,7 +210,6 @@ async function changePassword() {
|
||||
});
|
||||
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(passwordResetNotificationMessages.title),
|
||||
text: formatMessage(passwordResetNotificationMessages.text),
|
||||
type: "success",
|
||||
@@ -219,7 +217,6 @@ async function changePassword() {
|
||||
await navigateTo("/auth/sign-in");
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -130,19 +130,20 @@
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
RightArrowIcon,
|
||||
SSOGitHubIcon,
|
||||
SSOMicrosoftIcon,
|
||||
SSOSteamIcon,
|
||||
SSOGoogleIcon,
|
||||
SSODiscordIcon,
|
||||
SSOGitLabIcon,
|
||||
KeyIcon,
|
||||
MailIcon,
|
||||
RightArrowIcon,
|
||||
SSODiscordIcon,
|
||||
SSOGitHubIcon,
|
||||
SSOGitLabIcon,
|
||||
SSOGoogleIcon,
|
||||
SSOMicrosoftIcon,
|
||||
SSOSteamIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { commonMessages } from "@modrinth/ui";
|
||||
import { commonMessages, injectNotificationManager } from "@modrinth/ui";
|
||||
import HCaptcha from "@/components/ui/HCaptcha.vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -232,7 +233,6 @@ async function beginPasswordSignIn() {
|
||||
}
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -257,7 +257,6 @@ async function begin2FASignIn() {
|
||||
await finishSignIn(res.session);
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -134,20 +134,21 @@
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
RightArrowIcon,
|
||||
UserIcon,
|
||||
SSOGitHubIcon,
|
||||
SSOMicrosoftIcon,
|
||||
SSOGoogleIcon,
|
||||
SSOSteamIcon,
|
||||
SSODiscordIcon,
|
||||
KeyIcon,
|
||||
MailIcon,
|
||||
RightArrowIcon,
|
||||
SSODiscordIcon,
|
||||
SSOGitHubIcon,
|
||||
SSOGitLabIcon,
|
||||
SSOGoogleIcon,
|
||||
SSOMicrosoftIcon,
|
||||
SSOSteamIcon,
|
||||
UserIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { Checkbox, commonMessages } from "@modrinth/ui";
|
||||
import { Checkbox, commonMessages, injectNotificationManager } from "@modrinth/ui";
|
||||
import HCaptcha from "@/components/ui/HCaptcha.vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -225,7 +226,6 @@ async function createAccount() {
|
||||
try {
|
||||
if (confirmPassword.value !== password.value) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: formatMessage({
|
||||
id: "auth.sign-up.notification.password-mismatch.text",
|
||||
@@ -262,7 +262,6 @@ async function createAccount() {
|
||||
}
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -367,6 +367,7 @@ import {
|
||||
BoxIcon,
|
||||
CalendarIcon,
|
||||
EditIcon,
|
||||
GlobeIcon,
|
||||
GridIcon,
|
||||
ImageIcon,
|
||||
LibraryIcon,
|
||||
@@ -378,7 +379,6 @@ import {
|
||||
UpdatedIcon,
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
GlobeIcon,
|
||||
} from "@modrinth/assets";
|
||||
import {
|
||||
Avatar,
|
||||
@@ -387,17 +387,17 @@ import {
|
||||
ConfirmModal,
|
||||
DropdownSelect,
|
||||
FileInput,
|
||||
injectNotificationManager,
|
||||
PopoutMenu,
|
||||
useRelativeTime,
|
||||
} from "@modrinth/ui";
|
||||
|
||||
import { isAdmin } from "@modrinth/utils";
|
||||
import UpToDate from "assets/images/illustrations/up_to_date.svg";
|
||||
import { addNotification } from "~/composables/notifs.js";
|
||||
import AdPlaceholder from "~/components/ui/AdPlaceholder.vue";
|
||||
import NavRow from "~/components/ui/NavRow.vue";
|
||||
import ProjectCard from "~/components/ui/ProjectCard.vue";
|
||||
import AdPlaceholder from "~/components/ui/AdPlaceholder.vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const vintl = useVIntl();
|
||||
const { formatMessage } = vintl;
|
||||
const formatRelativeTime = useRelativeTime();
|
||||
@@ -664,7 +664,6 @@ async function saveChanges() {
|
||||
isEditing.value = false;
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err,
|
||||
type: "error",
|
||||
@@ -688,7 +687,6 @@ async function deleteCollection() {
|
||||
}
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -99,7 +99,10 @@
|
||||
import { ChevronRightIcon, HistoryIcon } from "@modrinth/assets";
|
||||
import { Avatar } from "@modrinth/ui";
|
||||
import NotificationItem from "~/components/ui/NotificationItem.vue";
|
||||
import { fetchExtraNotificationData, groupNotifications } from "~/helpers/notifications.ts";
|
||||
import {
|
||||
fetchExtraNotificationData,
|
||||
groupNotifications,
|
||||
} from "~/helpers/platform-notifications.ts";
|
||||
|
||||
useHead({
|
||||
title: "Dashboard - Modrinth",
|
||||
|
||||
@@ -56,16 +56,16 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Button, Pagination, Chips } from "@modrinth/ui";
|
||||
import { HistoryIcon, CheckCheckIcon } from "@modrinth/assets";
|
||||
import { CheckCheckIcon, HistoryIcon } from "@modrinth/assets";
|
||||
import { Button, Chips, Pagination } from "@modrinth/ui";
|
||||
import { formatProjectType } from "@modrinth/utils";
|
||||
import Breadcrumbs from "~/components/ui/Breadcrumbs.vue";
|
||||
import NotificationItem from "~/components/ui/NotificationItem.vue";
|
||||
import {
|
||||
fetchExtraNotificationData,
|
||||
groupNotifications,
|
||||
markAsRead,
|
||||
} from "~/helpers/notifications.ts";
|
||||
import NotificationItem from "~/components/ui/NotificationItem.vue";
|
||||
import Breadcrumbs from "~/components/ui/Breadcrumbs.vue";
|
||||
} from "~/helpers/platform-notifications.ts";
|
||||
|
||||
useHead({
|
||||
title: "Notifications - Modrinth",
|
||||
|
||||
@@ -301,17 +301,16 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import {
|
||||
SettingsIcon,
|
||||
TrashIcon,
|
||||
PlusIcon,
|
||||
XIcon,
|
||||
IssuesIcon,
|
||||
EditIcon,
|
||||
IssuesIcon,
|
||||
PlusIcon,
|
||||
SaveIcon,
|
||||
SettingsIcon,
|
||||
SortAscIcon,
|
||||
SortDescIcon,
|
||||
TrashIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import {
|
||||
Avatar,
|
||||
@@ -320,8 +319,10 @@ import {
|
||||
CopyCode,
|
||||
ProjectStatusBadge,
|
||||
commonMessages,
|
||||
injectNotificationManager,
|
||||
} from "@modrinth/ui";
|
||||
import { formatProjectType } from "@modrinth/utils";
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
|
||||
import Modal from "~/components/ui/Modal.vue";
|
||||
import ModalCreation from "~/components/ui/ModalCreation.vue";
|
||||
@@ -444,6 +445,8 @@ export default defineNuxtComponent({
|
||||
return sortedArray;
|
||||
},
|
||||
async bulkEditLinks() {
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
try {
|
||||
const baseData = {
|
||||
issues_url: this.editLinks.issues.clear ? null : this.editLinks.issues.val.trim(),
|
||||
@@ -477,8 +480,7 @@ export default defineNuxtComponent({
|
||||
);
|
||||
|
||||
this.$refs.editLinksModal.hide();
|
||||
this.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Success",
|
||||
text: "Bulk edited selected project's links.",
|
||||
type: "success",
|
||||
@@ -494,8 +496,7 @@ export default defineNuxtComponent({
|
||||
this.editLinks.wiki.clear = false;
|
||||
this.editLinks.discord.clear = false;
|
||||
} catch (e) {
|
||||
this.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: e,
|
||||
type: "error",
|
||||
|
||||
@@ -149,10 +149,12 @@ import {
|
||||
UnknownIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
import { formatDate } from "@modrinth/utils";
|
||||
import dayjs from "dayjs";
|
||||
import { computed } from "vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const auth = await useAuth();
|
||||
const minWithdraw = ref(0.01);
|
||||
|
||||
@@ -201,9 +203,7 @@ async function updateVenmo() {
|
||||
});
|
||||
await useAuth(auth.value.token);
|
||||
} catch (err) {
|
||||
const data = useNuxtApp();
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -94,13 +94,14 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { XIcon, PayPalIcon, UnknownIcon } from "@modrinth/assets";
|
||||
import { PayPalIcon, UnknownIcon, XIcon } from "@modrinth/assets";
|
||||
import { Badge, Breadcrumbs, DropdownSelect, injectNotificationManager } from "@modrinth/ui";
|
||||
import { capitalizeString, formatWallet } from "@modrinth/utils";
|
||||
import { Badge, Breadcrumbs, DropdownSelect } from "@modrinth/ui";
|
||||
import dayjs from "dayjs";
|
||||
import TremendousIcon from "~/assets/images/external/tremendous.svg?component";
|
||||
import VenmoIcon from "~/assets/images/external/venmo-small.svg?component";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const vintl = useVIntl();
|
||||
const { formatMessage } = vintl;
|
||||
|
||||
@@ -108,7 +109,6 @@ useHead({
|
||||
title: "Transfer history - Modrinth",
|
||||
});
|
||||
|
||||
const data = await useNuxtApp();
|
||||
const auth = await useAuth();
|
||||
|
||||
const { data: payouts, refresh } = await useAsyncData(`payout`, () =>
|
||||
@@ -155,8 +155,7 @@ async function cancelPayout(id) {
|
||||
await refresh();
|
||||
await useAuth(auth.value.token);
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -187,20 +187,21 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import {
|
||||
PayPalIcon,
|
||||
SearchIcon,
|
||||
RadioButtonIcon,
|
||||
RadioButtonCheckedIcon,
|
||||
XIcon,
|
||||
RadioButtonIcon,
|
||||
SearchIcon,
|
||||
TransferIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { Chips, Checkbox, Breadcrumbs } from "@modrinth/ui";
|
||||
import { all } from "iso-3166-1";
|
||||
import { Breadcrumbs, Checkbox, Chips, injectNotificationManager } from "@modrinth/ui";
|
||||
import { formatMoney, formatWallet } from "@modrinth/utils";
|
||||
import { all } from "iso-3166-1";
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import VenmoIcon from "~/assets/images/external/venmo.svg?component";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const auth = await useAuth();
|
||||
const data = useNuxtApp();
|
||||
|
||||
@@ -355,8 +356,7 @@ async function withdraw() {
|
||||
});
|
||||
await useAuth(auth.value.token);
|
||||
await navigateTo("/dashboard/revenue");
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Withdrawal complete",
|
||||
text:
|
||||
selectedMethod.value.type === "tremendous"
|
||||
@@ -365,8 +365,7 @@ async function withdraw() {
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</nuxt-link>
|
||||
</h2>
|
||||
<span>
|
||||
{{ $formatNumber(acceptedMembers?.length || 0) }}
|
||||
{{ formatNumber(acceptedMembers?.length || 0) }}
|
||||
member<template v-if="acceptedMembers?.length !== 1">s</template>
|
||||
</span>
|
||||
</div>
|
||||
@@ -120,11 +120,11 @@
|
||||
{
|
||||
id: 'manage-projects',
|
||||
action: () =>
|
||||
navigateTo('/organization/' + organization.slug + '/settings/projects'),
|
||||
hoverOnly: true,
|
||||
shown: auth.user && currentMember,
|
||||
router.push('/organization/' + organization?.slug + '/settings/projects'),
|
||||
hoverFilledOnly: true,
|
||||
shown: !!(auth.user && currentMember),
|
||||
},
|
||||
{ divider: true, shown: auth.user && currentMember },
|
||||
{ divider: true, shown: !!(auth?.user && currentMember) },
|
||||
{ id: 'copy-id', action: () => copyId() },
|
||||
{ id: 'copy-permalink', action: () => copyPermalink() },
|
||||
]"
|
||||
@@ -157,20 +157,20 @@
|
||||
<template v-for="member in acceptedMembers" :key="member.user.id">
|
||||
<nuxt-link
|
||||
class="details-list__item details-list__item--type-large"
|
||||
:to="`/user/${member.user.username}`"
|
||||
:to="`/user/${member?.user?.username}`"
|
||||
>
|
||||
<Avatar :src="member.user.avatar_url" circle />
|
||||
<Avatar :src="member?.user.avatar_url" circle />
|
||||
<div class="rows">
|
||||
<span class="flex items-center gap-1">
|
||||
{{ member.user.username }}
|
||||
{{ member?.user?.username }}
|
||||
<CrownIcon
|
||||
v-if="member.is_owner"
|
||||
v-if="member?.is_owner"
|
||||
v-tooltip="'Organization owner'"
|
||||
class="text-brand-orange"
|
||||
/>
|
||||
</span>
|
||||
<span class="details-list__item__text--style-secondary">
|
||||
{{ member.role ? member.role : "Member" }}
|
||||
{{ member?.role ? member.role : "Member" }}
|
||||
</span>
|
||||
</div>
|
||||
</nuxt-link>
|
||||
@@ -196,16 +196,21 @@
|
||||
<div v-if="navLinks.length > 2" class="mb-4 max-w-full overflow-x-auto">
|
||||
<NavTabs :links="navLinks" />
|
||||
</div>
|
||||
<template v-if="projects?.length > 0">
|
||||
<template v-if="projects && projects.length > 0">
|
||||
<div class="project-list display-mode--list">
|
||||
<ProjectCard
|
||||
v-for="project in (route.params.projectType !== undefined
|
||||
? projects.filter((x) =>
|
||||
? (projects ?? []).filter((x) =>
|
||||
x.project_types.includes(
|
||||
route.params.projectType.substr(0, route.params.projectType.length - 1),
|
||||
typeof route.params.projectType === 'string'
|
||||
? route.params.projectType.slice(0, route.params.projectType.length - 1)
|
||||
: route.params.projectType[0]?.slice(
|
||||
0,
|
||||
route.params.projectType[0].length - 1,
|
||||
) || '',
|
||||
),
|
||||
)
|
||||
: projects
|
||||
: (projects ?? [])
|
||||
)
|
||||
.slice()
|
||||
.sort((a, b) => b.downloads - a.downloads)"
|
||||
@@ -225,9 +230,10 @@
|
||||
:client-side="project.client_side"
|
||||
:server-side="project.server_side"
|
||||
:status="
|
||||
auth.user && (auth.user.id === user.id || tags.staffRoles.includes(auth.user.role))
|
||||
? project.status
|
||||
: null
|
||||
auth.user &&
|
||||
(auth.user.id! === (user as any).id || tags.staffRoles.includes(auth.user.role))
|
||||
? (project.status as ProjectStatus)
|
||||
: undefined
|
||||
"
|
||||
:type="project.project_types[0] ?? 'project'"
|
||||
:color="project.color"
|
||||
@@ -240,9 +246,9 @@
|
||||
<br />
|
||||
<span class="preserve-lines text">
|
||||
This organization doesn't have any projects yet.
|
||||
<template v-if="isPermission(currentMember?.organization_permissions, 1 << 4)">
|
||||
<template v-if="isPermission(currentMember?.permissions, 1 << 4)">
|
||||
Would you like to
|
||||
<a class="link" @click="$refs.modal_creation.show()">create one</a>?
|
||||
<a class="link" @click="($refs as any).modal_creation?.show()">create one</a>?
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
@@ -251,50 +257,58 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
BoxIcon,
|
||||
MoreVerticalIcon,
|
||||
UsersIcon,
|
||||
SettingsIcon,
|
||||
ChartIcon,
|
||||
CheckIcon,
|
||||
XIcon,
|
||||
ClipboardCopyIcon,
|
||||
OrganizationIcon,
|
||||
DownloadIcon,
|
||||
CrownIcon,
|
||||
DownloadIcon,
|
||||
MoreVerticalIcon,
|
||||
OrganizationIcon,
|
||||
SettingsIcon,
|
||||
UsersIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
Breadcrumbs,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
ContentPageHeader,
|
||||
OverflowMenu,
|
||||
commonMessages,
|
||||
} from "@modrinth/ui";
|
||||
import type { Organization, ProjectStatus, ProjectType, ProjectV3 } from "@modrinth/utils";
|
||||
import { formatNumber } from "@modrinth/utils";
|
||||
import UpToDate from "~/assets/images/illustrations/up_to_date.svg?component";
|
||||
import AdPlaceholder from "~/components/ui/AdPlaceholder.vue";
|
||||
import ModalCreation from "~/components/ui/ModalCreation.vue";
|
||||
import NavStack from "~/components/ui/NavStack.vue";
|
||||
import NavStackItem from "~/components/ui/NavStackItem.vue";
|
||||
import ModalCreation from "~/components/ui/ModalCreation.vue";
|
||||
import UpToDate from "~/assets/images/illustrations/up_to_date.svg?component";
|
||||
import ProjectCard from "~/components/ui/ProjectCard.vue";
|
||||
import AdPlaceholder from "~/components/ui/AdPlaceholder.vue";
|
||||
import { acceptTeamInvite, removeTeamMember } from "~/helpers/teams.js";
|
||||
import NavTabs from "~/components/ui/NavTabs.vue";
|
||||
import ProjectCard from "~/components/ui/ProjectCard.vue";
|
||||
import { acceptTeamInvite, removeTeamMember } from "~/helpers/teams.js";
|
||||
import {
|
||||
OrganizationContext,
|
||||
provideOrganizationContext,
|
||||
} from "~/providers/organization-context.ts";
|
||||
import { isPermission } from "~/utils/permissions.ts";
|
||||
|
||||
const vintl = useVIntl();
|
||||
const { formatMessage } = vintl;
|
||||
|
||||
const formatCompactNumber = useCompactNumber(true);
|
||||
|
||||
const auth = await useAuth();
|
||||
const auth: { user: any } & any = await useAuth();
|
||||
const user = await useUser();
|
||||
const cosmetics = useCosmetics();
|
||||
const route = useNativeRoute();
|
||||
const router = useRouter();
|
||||
const tags = useTags();
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
let orgId = useRouteId();
|
||||
const orgId = useRouteId();
|
||||
|
||||
// hacky way to show the edit button on the corner of the card.
|
||||
const routeHasSettings = computed(() => route.path.includes("settings"));
|
||||
@@ -303,12 +317,13 @@ const [
|
||||
{ data: organization, refresh: refreshOrganization },
|
||||
{ data: projects, refresh: refreshProjects },
|
||||
] = await Promise.all([
|
||||
useAsyncData(`organization/${orgId}`, () =>
|
||||
useBaseFetch(`organization/${orgId}`, { apiVersion: 3 }),
|
||||
useAsyncData(
|
||||
`organization/${orgId}`,
|
||||
() => useBaseFetch(`organization/${orgId}`, { apiVersion: 3 }) as Promise<Organization>,
|
||||
),
|
||||
useAsyncData(
|
||||
`organization/${orgId}/projects`,
|
||||
() => useBaseFetch(`organization/${orgId}/projects`, { apiVersion: 3 }),
|
||||
() => useBaseFetch(`organization/${orgId}/projects`, { apiVersion: 3 }) as Promise<ProjectV3[]>,
|
||||
{
|
||||
transform: (projects) => {
|
||||
for (const project of projects) {
|
||||
@@ -359,7 +374,7 @@ if (!organization.value) {
|
||||
|
||||
// Filter accepted, sort by role, then by name and Owner role always goes first
|
||||
const acceptedMembers = computed(() => {
|
||||
const acceptedMembers = organization.value.members?.filter((x) => x.accepted);
|
||||
const acceptedMembers = organization.value?.members?.filter((x) => x.accepted) ?? [];
|
||||
const owner = acceptedMembers.find((x) => x.is_owner);
|
||||
const rest = acceptedMembers.filter((x) => !x.is_owner) || [];
|
||||
|
||||
@@ -374,43 +389,14 @@ const acceptedMembers = computed(() => {
|
||||
return [owner, ...rest];
|
||||
});
|
||||
|
||||
const currentMember = computed(() => {
|
||||
if (auth.value.user && organization.value) {
|
||||
const member = organization.value.members.find((x) => x.user.id === auth.value.user.id);
|
||||
|
||||
if (member) {
|
||||
return member;
|
||||
}
|
||||
|
||||
if (tags.value.staffRoles.includes(auth.value.user.role)) {
|
||||
return {
|
||||
user: auth.value.user,
|
||||
role: auth.value.user.role,
|
||||
permissions: auth.value.user.role === "admin" ? 1023 : 12,
|
||||
accepted: true,
|
||||
payouts_split: 0,
|
||||
avatar_url: auth.value.user.avatar_url,
|
||||
name: auth.value.user.username,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
const hasPermission = computed(() => {
|
||||
const EDIT_DETAILS = 1 << 2;
|
||||
return currentMember.value && (currentMember.value.permissions & EDIT_DETAILS) === EDIT_DETAILS;
|
||||
});
|
||||
|
||||
const isInvited = computed(() => {
|
||||
return currentMember.value?.accepted === false;
|
||||
});
|
||||
|
||||
const projectTypes = computed(() => {
|
||||
const obj = {};
|
||||
const obj: Record<string, boolean> = {};
|
||||
|
||||
for (const project of projects.value) {
|
||||
for (const project of projects.value ?? []) {
|
||||
obj[project.project_types[0] ?? "project"] = true;
|
||||
}
|
||||
|
||||
@@ -421,62 +407,27 @@ const projectTypes = computed(() => {
|
||||
const sumDownloads = computed(() => {
|
||||
let sum = 0;
|
||||
|
||||
for (const project of projects.value) {
|
||||
for (const project of projects.value ?? []) {
|
||||
sum += project.downloads;
|
||||
}
|
||||
|
||||
return sum;
|
||||
});
|
||||
|
||||
const patchIcon = async (icon) => {
|
||||
const ext = icon.name.split(".").pop();
|
||||
await useBaseFetch(`organization/${organization.value.id}/icon`, {
|
||||
method: "PATCH",
|
||||
body: icon,
|
||||
query: { ext },
|
||||
apiVersion: 3,
|
||||
});
|
||||
};
|
||||
|
||||
const deleteIcon = async () => {
|
||||
await useBaseFetch(`organization/${organization.value.id}/icon`, {
|
||||
method: "DELETE",
|
||||
apiVersion: 3,
|
||||
});
|
||||
};
|
||||
|
||||
const patchOrganization = async (id, newData) => {
|
||||
await useBaseFetch(`organization/${id}`, {
|
||||
method: "PATCH",
|
||||
body: newData,
|
||||
apiVersion: 3,
|
||||
});
|
||||
|
||||
if (newData.slug) {
|
||||
orgId = newData.slug;
|
||||
}
|
||||
};
|
||||
|
||||
const onAcceptInvite = useClientTry(async () => {
|
||||
await acceptTeamInvite(organization.value.team_id);
|
||||
await acceptTeamInvite(organization.value?.team_id);
|
||||
await refreshOrganization();
|
||||
});
|
||||
|
||||
const onDeclineInvite = useClientTry(async () => {
|
||||
await removeTeamMember(organization.value.team_id, auth.value?.user.id);
|
||||
await removeTeamMember(organization.value?.team_id, auth.value?.user?.id);
|
||||
await refreshOrganization();
|
||||
});
|
||||
|
||||
provide("organizationContext", {
|
||||
organization,
|
||||
projects,
|
||||
refresh,
|
||||
currentMember,
|
||||
hasPermission,
|
||||
patchIcon,
|
||||
deleteIcon,
|
||||
patchOrganization,
|
||||
});
|
||||
const organizationContext = new OrganizationContext(organization, projects, auth, tags, refresh);
|
||||
const { currentMember } = organizationContext;
|
||||
|
||||
provideOrganizationContext(organizationContext);
|
||||
|
||||
const title = `${organization.value.name} - Organization`;
|
||||
const description = `${organization.value.description} - View the organization ${organization.value.name} on Modrinth`;
|
||||
@@ -492,13 +443,13 @@ useSeoMeta({
|
||||
const navLinks = computed(() => [
|
||||
{
|
||||
label: formatMessage(commonMessages.allProjectType),
|
||||
href: `/organization/${organization.value.slug}`,
|
||||
href: `/organization/${organization.value?.slug}`,
|
||||
},
|
||||
...projectTypes.value
|
||||
.map((x) => {
|
||||
return {
|
||||
label: formatMessage(getProjectTypeMessage(x, true)),
|
||||
href: `/organization/${organization.value.slug}/${x}s`,
|
||||
label: formatMessage(getProjectTypeMessage(x as ProjectType, true)),
|
||||
href: `/organization/${organization.value?.slug}/${x}s`,
|
||||
};
|
||||
})
|
||||
.slice()
|
||||
@@ -506,12 +457,12 @@ const navLinks = computed(() => [
|
||||
]);
|
||||
|
||||
async function copyId() {
|
||||
await navigator.clipboard.writeText(organization.value.id);
|
||||
await navigator.clipboard.writeText(organization.value?.id ?? "");
|
||||
}
|
||||
|
||||
async function copyPermalink() {
|
||||
await navigator.clipboard.writeText(
|
||||
`${config.public.siteUrl}/organization/${organization.value.id}`,
|
||||
`${config.public.siteUrl}/organization/${organization.value?.id}`,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
|
||||
<script setup>
|
||||
import ChartDisplay from "~/components/ui/charts/ChartDisplay.vue";
|
||||
import { injectOrganizationContext } from "~/providers/organization-context.ts";
|
||||
|
||||
const { projects } = inject("organizationContext");
|
||||
const { projects } = injectOrganizationContext();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<script setup>
|
||||
import { Button, FileInput, Avatar, ConfirmModal } from "@modrinth/ui";
|
||||
import { UploadIcon, SaveIcon, TrashIcon } from "@modrinth/assets";
|
||||
import { SaveIcon, TrashIcon, UploadIcon } from "@modrinth/assets";
|
||||
import { Avatar, Button, ConfirmModal, FileInput, injectNotificationManager } from "@modrinth/ui";
|
||||
import { injectOrganizationContext } from "~/providers/organization-context.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const {
|
||||
organization,
|
||||
refresh: refreshOrganization,
|
||||
@@ -9,7 +11,7 @@ const {
|
||||
deleteIcon,
|
||||
patchIcon,
|
||||
patchOrganization,
|
||||
} = inject("organizationContext");
|
||||
} = injectOrganizationContext();
|
||||
|
||||
const icon = ref(null);
|
||||
const deletedIcon = ref(false);
|
||||
@@ -74,7 +76,6 @@ const onSaveChanges = useClientTry(async () => {
|
||||
await refreshOrganization();
|
||||
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Organization updated",
|
||||
text: "Your organization has been updated.",
|
||||
type: "success",
|
||||
@@ -88,7 +89,6 @@ const onDeleteOrganization = useClientTry(async () => {
|
||||
});
|
||||
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Organization deleted",
|
||||
text: "Your organization has been deleted.",
|
||||
type: "success",
|
||||
|
||||
@@ -220,19 +220,21 @@
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
CrownIcon,
|
||||
DropdownIcon,
|
||||
SaveIcon,
|
||||
TransferIcon,
|
||||
UserPlusIcon,
|
||||
UserXIcon as UserRemoveIcon,
|
||||
DropdownIcon,
|
||||
CrownIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { Button, Badge, Avatar, Checkbox } from "@modrinth/ui";
|
||||
import { Avatar, Badge, Button, Checkbox, injectNotificationManager } from "@modrinth/ui";
|
||||
import { ref } from "vue";
|
||||
import { removeTeamMember } from "~/helpers/teams.js";
|
||||
import { injectOrganizationContext } from "~/providers/organization-context.ts";
|
||||
import { isPermission } from "~/utils/permissions.ts";
|
||||
|
||||
const { organization, refresh: refreshOrganization, currentMember } = inject("organizationContext");
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { organization, refresh: refreshOrganization, currentMember } = injectOrganizationContext();
|
||||
|
||||
const auth = await useAuth();
|
||||
|
||||
@@ -296,7 +298,6 @@ const onInviteTeamMember = useClientTry(async (teamId, username) => {
|
||||
await refreshOrganization();
|
||||
currentUsername.value = "";
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Member invited",
|
||||
text: `${user.username} has been invited to the organization.`,
|
||||
type: "success",
|
||||
@@ -307,7 +308,6 @@ const onRemoveMember = useClientTry(async (teamId, member) => {
|
||||
await removeTeamMember(teamId, member.user.id);
|
||||
await refreshOrganization();
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Member removed",
|
||||
text: `${member.user.username} has been removed from the organization.`,
|
||||
type: "success",
|
||||
@@ -332,7 +332,6 @@ const onUpdateTeamMember = useClientTry(async (teamId, member) => {
|
||||
});
|
||||
await refreshOrganization();
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Member updated",
|
||||
text: `${member.user.username} has been updated.`,
|
||||
type: "success",
|
||||
@@ -349,7 +348,6 @@ const onTransferOwnership = useClientTry(async (teamId, uid) => {
|
||||
});
|
||||
await refreshOrganization();
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Ownership transferred",
|
||||
text: `The ownership of ${organization.value.name} has been successfully transferred.`,
|
||||
type: "success",
|
||||
|
||||
@@ -298,28 +298,38 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import {
|
||||
BoxIcon,
|
||||
SettingsIcon,
|
||||
TrashIcon,
|
||||
EditIcon,
|
||||
IssuesIcon,
|
||||
PlusIcon,
|
||||
XIcon,
|
||||
EditIcon,
|
||||
SaveIcon,
|
||||
SettingsIcon,
|
||||
SortAscIcon,
|
||||
SortDescIcon,
|
||||
TrashIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { Button, Modal, Avatar, CopyCode, Badge, Checkbox, commonMessages } from "@modrinth/ui";
|
||||
|
||||
import {
|
||||
Avatar,
|
||||
Badge,
|
||||
Button,
|
||||
Checkbox,
|
||||
commonMessages,
|
||||
CopyCode,
|
||||
injectNotificationManager,
|
||||
Modal,
|
||||
} from "@modrinth/ui";
|
||||
import { formatProjectType } from "@modrinth/utils";
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import ModalCreation from "~/components/ui/ModalCreation.vue";
|
||||
import OrganizationProjectTransferModal from "~/components/ui/OrganizationProjectTransferModal.vue";
|
||||
import { injectOrganizationContext } from "~/providers/organization-context.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const { organization, projects, refresh } = inject("organizationContext");
|
||||
const { organization, projects, refresh } = injectOrganizationContext();
|
||||
|
||||
const auth = await useAuth();
|
||||
|
||||
@@ -375,14 +385,12 @@ const onProjectTransferSubmit = async (projects) => {
|
||||
await refreshUserProjects();
|
||||
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Success",
|
||||
text: "Transferred selected projects to organization.",
|
||||
type: "success",
|
||||
});
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err?.data?.description || err?.message || err || "Unknown error",
|
||||
type: "error",
|
||||
@@ -511,7 +519,6 @@ const onBulkEditLinks = useClientTry(async () => {
|
||||
editLinksModal.value.hide();
|
||||
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Success",
|
||||
text: "Bulk edited selected project's links.",
|
||||
type: "success",
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
:fetch-payment-data="fetchPaymentData"
|
||||
:on-error="
|
||||
(err) =>
|
||||
data.$notify({
|
||||
group: 'main',
|
||||
addNotification({
|
||||
title: 'An error occurred',
|
||||
type: 'error',
|
||||
text: err.message ?? (err.data ? err.data.description : err),
|
||||
@@ -87,16 +86,18 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import {
|
||||
ModrinthPlusIcon,
|
||||
HeartIcon,
|
||||
ModrinthPlusIcon,
|
||||
SettingsIcon,
|
||||
SparklesIcon,
|
||||
StarIcon,
|
||||
SettingsIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { PurchaseModal } from "@modrinth/ui";
|
||||
import { injectNotificationManager, PurchaseModal } from "@modrinth/ui";
|
||||
import { calculateSavings, formatPrice, getCurrency } from "@modrinth/utils";
|
||||
import { products } from "~/generated/state.json";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const title = "Subscribe to Modrinth Plus!";
|
||||
const description =
|
||||
"Subscribe to Modrinth Plus to go ad-free, support Modrinth's development, and get an exclusive profile badge! Half your subscription goes directly to Modrinth creators.";
|
||||
@@ -120,7 +121,6 @@ useHead({
|
||||
|
||||
const vintl = useVIntl();
|
||||
|
||||
const data = useNuxtApp();
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
const auth = await useAuth();
|
||||
|
||||
@@ -243,30 +243,33 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
CheckCircleIcon,
|
||||
CheckIcon,
|
||||
ExternalIcon,
|
||||
IssuesIcon,
|
||||
LeftArrowIcon,
|
||||
RightArrowIcon,
|
||||
ScaleIcon,
|
||||
SendIcon,
|
||||
SpinnerIcon,
|
||||
VersionIcon,
|
||||
XCircleIcon,
|
||||
} from "@modrinth/assets";
|
||||
import {
|
||||
AutoLink,
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
injectNotificationManager,
|
||||
MarkdownEditor,
|
||||
RadialHeader,
|
||||
RadioButtons,
|
||||
ButtonStyled,
|
||||
Avatar,
|
||||
AutoLink,
|
||||
} from "@modrinth/ui";
|
||||
import {
|
||||
ExternalIcon,
|
||||
LeftArrowIcon,
|
||||
RightArrowIcon,
|
||||
CheckIcon,
|
||||
SpinnerIcon,
|
||||
SendIcon,
|
||||
IssuesIcon,
|
||||
CheckCircleIcon,
|
||||
XCircleIcon,
|
||||
ScaleIcon,
|
||||
VersionIcon,
|
||||
} from "@modrinth/assets";
|
||||
import type { User, Version, Report } from "@modrinth/utils";
|
||||
import { useVIntl, defineMessages, type MessageDescriptor } from "@vintl/vintl";
|
||||
import type { Project, Report, User, Version } from "@modrinth/utils";
|
||||
import { defineMessages, useVIntl, type MessageDescriptor } from "@vintl/vintl";
|
||||
import { useImageUpload } from "~/composables/image-upload.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const tags = useTags();
|
||||
const route = useNativeRoute();
|
||||
const router = useRouter();
|
||||
@@ -439,7 +442,6 @@ const submitReport = async () => {
|
||||
|
||||
if (error instanceof Error) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: error.message,
|
||||
type: "error",
|
||||
@@ -465,7 +467,6 @@ const submitReport = async () => {
|
||||
|
||||
if (error instanceof Error) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: error.message,
|
||||
type: "error",
|
||||
|
||||
@@ -632,26 +632,31 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ButtonStyled, ModrinthServersPurchaseModal } from "@modrinth/ui";
|
||||
import {
|
||||
BoxIcon,
|
||||
GameIcon,
|
||||
RightArrowIcon,
|
||||
ServerIcon,
|
||||
TerminalSquareIcon,
|
||||
TransferIcon,
|
||||
VersionIcon,
|
||||
ServerIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { computed } from "vue";
|
||||
import {
|
||||
ButtonStyled,
|
||||
injectNotificationManager,
|
||||
ModrinthServersPurchaseModal,
|
||||
} from "@modrinth/ui";
|
||||
import { monthsInInterval } from "@modrinth/ui/src/utils/billing.ts";
|
||||
import { formatPrice } from "@modrinth/utils";
|
||||
import { useVIntl } from "@vintl/vintl";
|
||||
import { products } from "~/generated/state.json";
|
||||
import { useServersFetch } from "~/composables/servers/servers-fetch.ts";
|
||||
import { computed } from "vue";
|
||||
import OptionGroup from "~/components/ui/OptionGroup.vue";
|
||||
import LoaderIcon from "~/components/ui/servers/icons/LoaderIcon.vue";
|
||||
import ServerPlanSelector from "~/components/ui/servers/marketing/ServerPlanSelector.vue";
|
||||
import OptionGroup from "~/components/ui/OptionGroup.vue";
|
||||
import { useServersFetch } from "~/composables/servers/servers-fetch.ts";
|
||||
import { products } from "~/generated/state.json";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { locale } = useVIntl();
|
||||
|
||||
const billingPeriods = ref(["monthly", "quarterly"]);
|
||||
@@ -812,7 +817,6 @@ const startTyping = () => {
|
||||
|
||||
const handleError = (err) => {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
type: "error",
|
||||
text: err.message ?? (err.data ? err.data.description : err),
|
||||
@@ -831,7 +835,6 @@ async function fetchPaymentData() {
|
||||
} catch (error) {
|
||||
console.error("Error fetching payment data:", error);
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Error fetching payment data",
|
||||
type: "error",
|
||||
text: error.message || "An unexpected error occurred",
|
||||
@@ -886,7 +889,6 @@ const selectProduct = async (product) => {
|
||||
|
||||
if ((product === "custom" && isCustomAtCapacity.value) || isAtCapacity.value) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Server Capacity Full",
|
||||
type: "error",
|
||||
text: "We are currently at capacity. Please try again later.",
|
||||
@@ -902,7 +904,6 @@ const selectProduct = async (product) => {
|
||||
(product !== "custom" && !selectedPlan.metadata)
|
||||
) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Invalid product",
|
||||
type: "error",
|
||||
text: "The selected product was found but lacks necessary data. Please contact support.",
|
||||
|
||||
@@ -350,38 +350,43 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted, type Reactive } from "vue";
|
||||
import { reloadNuxtApp } from "#app";
|
||||
import { Intercom, shutdown } from "@intercom/messenger-js-sdk";
|
||||
import {
|
||||
SettingsIcon,
|
||||
CheckIcon,
|
||||
CopyIcon,
|
||||
FileIcon,
|
||||
IssuesIcon,
|
||||
LeftArrowIcon,
|
||||
RightArrowIcon,
|
||||
CheckIcon,
|
||||
FileIcon,
|
||||
TransferIcon,
|
||||
LockIcon,
|
||||
RightArrowIcon,
|
||||
SettingsIcon,
|
||||
TransferIcon,
|
||||
} from "@modrinth/assets";
|
||||
import DOMPurify from "dompurify";
|
||||
import { ButtonStyled, ErrorInformationCard, ServerNotice } from "@modrinth/ui";
|
||||
import { Intercom, shutdown } from "@intercom/messenger-js-sdk";
|
||||
import type { MessageDescriptor } from "@vintl/vintl";
|
||||
import {
|
||||
ButtonStyled,
|
||||
ErrorInformationCard,
|
||||
injectNotificationManager,
|
||||
ServerNotice,
|
||||
} from "@modrinth/ui";
|
||||
import {
|
||||
type Backup,
|
||||
type PowerAction,
|
||||
type ServerState,
|
||||
type Stats,
|
||||
type WSEvent,
|
||||
type WSInstallationResultEvent,
|
||||
type Backup,
|
||||
type PowerAction,
|
||||
} from "@modrinth/utils";
|
||||
import { reloadNuxtApp } from "#app";
|
||||
import { useModrinthServersConsole } from "~/store/console.ts";
|
||||
import { useServersFetch } from "~/composables/servers/servers-fetch.ts";
|
||||
import { ModrinthServer, useModrinthServers } from "~/composables/servers/modrinth-servers.ts";
|
||||
import type { MessageDescriptor } from "@vintl/vintl";
|
||||
import DOMPurify from "dompurify";
|
||||
import { computed, onMounted, onUnmounted, ref, type Reactive } from "vue";
|
||||
import ServerInstallation from "~/components/ui/servers/ServerInstallation.vue";
|
||||
import PanelErrorIcon from "~/components/ui/servers/icons/PanelErrorIcon.vue";
|
||||
import { ModrinthServer, useModrinthServers } from "~/composables/servers/modrinth-servers.ts";
|
||||
import { useServersFetch } from "~/composables/servers/servers-fetch.ts";
|
||||
import { useModrinthServersConsole } from "~/store/console.ts";
|
||||
|
||||
const app = useNuxtApp() as unknown as { $notify: any };
|
||||
const { addNotification } = injectNotificationManager();
|
||||
|
||||
const socket = ref<WebSocket | null>(null);
|
||||
const isReconnecting = ref(false);
|
||||
@@ -964,7 +969,6 @@ const sendPowerAction = async (action: PowerAction) => {
|
||||
|
||||
const notifyError = (title: string, text: string) => {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title,
|
||||
text,
|
||||
type: "error",
|
||||
@@ -1149,8 +1153,7 @@ async function dismissNotice(noticeId: number) {
|
||||
await useServersFetch(`servers/${serverId}/notices/${noticeId}/dismiss`, {
|
||||
method: "POST",
|
||||
}).catch((err) => {
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error dismissing notice",
|
||||
text: err,
|
||||
type: "error",
|
||||
|
||||
@@ -150,19 +150,20 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ButtonStyled, TagItem } from "@modrinth/ui";
|
||||
import { useStorage } from "@vueuse/core";
|
||||
import { SpinnerIcon, PlusIcon, DownloadIcon, SettingsIcon, IssuesIcon } from "@modrinth/assets";
|
||||
import { ref, computed } from "vue";
|
||||
import { DownloadIcon, IssuesIcon, PlusIcon, SettingsIcon, SpinnerIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, injectNotificationManager, TagItem } from "@modrinth/ui";
|
||||
import type { Backup } from "@modrinth/utils";
|
||||
import { useStorage } from "@vueuse/core";
|
||||
import { computed, ref } from "vue";
|
||||
import BackupCreateModal from "~/components/ui/servers/BackupCreateModal.vue";
|
||||
import BackupDeleteModal from "~/components/ui/servers/BackupDeleteModal.vue";
|
||||
import BackupItem from "~/components/ui/servers/BackupItem.vue";
|
||||
import BackupRenameModal from "~/components/ui/servers/BackupRenameModal.vue";
|
||||
import BackupCreateModal from "~/components/ui/servers/BackupCreateModal.vue";
|
||||
import BackupRestoreModal from "~/components/ui/servers/BackupRestoreModal.vue";
|
||||
import BackupDeleteModal from "~/components/ui/servers/BackupDeleteModal.vue";
|
||||
import BackupSettingsModal from "~/components/ui/servers/BackupSettingsModal.vue";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
isServerRunning: boolean;
|
||||
@@ -236,7 +237,11 @@ const prepareDownload = async (backupId: string) => {
|
||||
await props.server.backups?.prepare(backupId);
|
||||
} catch (error) {
|
||||
console.error("Failed to prepare download:", error);
|
||||
addNotification({ type: "error", title: "Failed to prepare backup for download", text: error });
|
||||
addNotification({
|
||||
type: "error",
|
||||
title: "Failed to prepare backup for download",
|
||||
text: error as string,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -335,28 +335,29 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
SearchIcon,
|
||||
EditIcon,
|
||||
TrashIcon,
|
||||
PackageClosedIcon,
|
||||
FilterIcon,
|
||||
DropdownIcon,
|
||||
PlusIcon,
|
||||
MoreVerticalIcon,
|
||||
CompassIcon,
|
||||
WrenchIcon,
|
||||
ListIcon,
|
||||
DropdownIcon,
|
||||
EditIcon,
|
||||
FileIcon,
|
||||
FilterIcon,
|
||||
IssuesIcon,
|
||||
ListIcon,
|
||||
MoreVerticalIcon,
|
||||
PackageClosedIcon,
|
||||
PlusIcon,
|
||||
SearchIcon,
|
||||
TrashIcon,
|
||||
WrenchIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { Avatar, ButtonStyled } from "@modrinth/ui";
|
||||
import { ref, computed, watch, onMounted, onUnmounted } from "vue";
|
||||
import { Avatar, ButtonStyled, injectNotificationManager } from "@modrinth/ui";
|
||||
import type { Mod } from "@modrinth/utils";
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import FilesUploadDragAndDrop from "~/components/ui/servers/FilesUploadDragAndDrop.vue";
|
||||
import FilesUploadDropdown from "~/components/ui/servers/FilesUploadDropdown.vue";
|
||||
import { acceptFileFromProjectType } from "~/helpers/fileUtils.js";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
import { acceptFileFromProjectType } from "~/helpers/fileUtils.js";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
}>();
|
||||
|
||||
@@ -266,26 +266,27 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useInfiniteScroll } from "@vueuse/core";
|
||||
import {
|
||||
UnknownIcon,
|
||||
XIcon,
|
||||
SpinnerIcon,
|
||||
PackageOpenIcon,
|
||||
CheckIcon,
|
||||
UploadIcon,
|
||||
FolderOpenIcon,
|
||||
PackageOpenIcon,
|
||||
SpinnerIcon,
|
||||
UnknownIcon,
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { computed } from "vue";
|
||||
import { ButtonStyled, ProgressBar } from "@modrinth/ui";
|
||||
import { ButtonStyled, injectNotificationManager, ProgressBar } from "@modrinth/ui";
|
||||
import type { DirectoryItem, DirectoryResponse, FilesystemOp, FSQueuedOp } from "@modrinth/utils";
|
||||
import { formatBytes, ModrinthServersFetchError } from "@modrinth/utils";
|
||||
import type { FilesystemOp, FSQueuedOp, DirectoryItem, DirectoryResponse } from "@modrinth/utils";
|
||||
import { handleError, ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
import { useInfiniteScroll } from "@vueuse/core";
|
||||
import { computed } from "vue";
|
||||
import FilesUploadConflictModal from "~/components/ui/servers/FilesUploadConflictModal.vue";
|
||||
import FilesUploadDragAndDrop from "~/components/ui/servers/FilesUploadDragAndDrop.vue";
|
||||
import FilesUploadDropdown from "~/components/ui/servers/FilesUploadDropdown.vue";
|
||||
import FilesUploadZipUrlModal from "~/components/ui/servers/FilesUploadZipUrlModal.vue";
|
||||
import FilesUploadConflictModal from "~/components/ui/servers/FilesUploadConflictModal.vue";
|
||||
import { handleError, ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const flags = useFeatureFlags();
|
||||
const baseId = useId();
|
||||
|
||||
@@ -449,7 +450,6 @@ const undoLastOperation = async () => {
|
||||
|
||||
refreshList();
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: `${lastOperation.type === "move" ? "Move" : "Rename"} undone`,
|
||||
text: `${lastOperation.fileName} has been restored to its original ${lastOperation.type === "move" ? "location" : "name"}`,
|
||||
type: "success",
|
||||
@@ -457,7 +457,6 @@ const undoLastOperation = async () => {
|
||||
} catch (error) {
|
||||
console.error(`Error undoing ${lastOperation.type}:`, error);
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "Undo failed",
|
||||
text: `Failed to undo the last ${lastOperation.type} operation`,
|
||||
type: "error",
|
||||
@@ -489,7 +488,6 @@ const redoLastOperation = async () => {
|
||||
|
||||
refreshList();
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: `${lastOperation.type === "move" ? "Move" : "Rename"} redone`,
|
||||
text: `${lastOperation.fileName} has been ${lastOperation.type === "move" ? "moved" : "renamed"} again`,
|
||||
type: "success",
|
||||
@@ -497,7 +495,6 @@ const redoLastOperation = async () => {
|
||||
} catch (error) {
|
||||
console.error(`Error redoing ${lastOperation.type}:`, error);
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "Redo failed",
|
||||
text: `Failed to redo the last ${lastOperation.type} operation`,
|
||||
type: "error",
|
||||
@@ -513,7 +510,6 @@ const handleCreateNewItem = async (name: string) => {
|
||||
refreshList();
|
||||
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: `${newItemType.value === "directory" ? "Folder" : "File"} created`,
|
||||
text: `New ${newItemType.value === "directory" ? "folder" : "file"} ${name} has been created.`,
|
||||
type: "success",
|
||||
@@ -549,7 +545,6 @@ const handleRenameItem = async (newName: string) => {
|
||||
}
|
||||
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: `${selectedItem.value.type === "directory" ? "Folder" : "File"} renamed`,
|
||||
text: `${selectedItem.value.name} has been renamed to ${newName}`,
|
||||
type: "success",
|
||||
@@ -559,7 +554,6 @@ const handleRenameItem = async (newName: string) => {
|
||||
if (error instanceof ModrinthServersFetchError) {
|
||||
if (error.statusCode === 400) {
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "Could not rename",
|
||||
text: `An item named "${newName}" already exists in this location`,
|
||||
type: "error",
|
||||
@@ -567,7 +561,6 @@ const handleRenameItem = async (newName: string) => {
|
||||
return;
|
||||
}
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "Could not rename item",
|
||||
text: "An unexpected error occurred",
|
||||
type: "error",
|
||||
@@ -625,7 +618,6 @@ const handleMoveItem = async (destination: string) => {
|
||||
|
||||
refreshList();
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: `${itemType === "directory" ? "Folder" : "File"} moved`,
|
||||
text: `${selectedItem.value.name} has been moved to ${newPath}`,
|
||||
type: "success",
|
||||
@@ -658,7 +650,6 @@ const handleDirectMove = async (moveData: {
|
||||
|
||||
refreshList();
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: `${moveData.type === "directory" ? "Folder" : "File"} moved`,
|
||||
text: `${moveData.name} has been moved to ${newPath}`,
|
||||
type: "success",
|
||||
@@ -675,7 +666,6 @@ const handleDeleteItem = async () => {
|
||||
|
||||
refreshList();
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "File deleted",
|
||||
text: "Your file has been deleted.",
|
||||
type: "success",
|
||||
@@ -717,14 +707,12 @@ const handleCreateError = (error: any) => {
|
||||
if (error instanceof ModrinthServersFetchError) {
|
||||
if (error.statusCode === 400) {
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "Error creating item",
|
||||
text: "Invalid file",
|
||||
type: "error",
|
||||
});
|
||||
} else if (error.statusCode === 500) {
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "Error creating item",
|
||||
text: "Something went wrong. The file may already exist.",
|
||||
type: "error",
|
||||
@@ -1010,7 +998,6 @@ const requestShareLink = async () => {
|
||||
if (response.success) {
|
||||
await navigator.clipboard.writeText(response.url);
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "Log URL copied",
|
||||
text: "Your log file URL has been copied to your clipboard.",
|
||||
type: "success",
|
||||
@@ -1080,7 +1067,6 @@ const saveFileContent = async (exit: boolean = true) => {
|
||||
}
|
||||
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "File saved",
|
||||
text: "Your file has been saved.",
|
||||
type: "success",
|
||||
@@ -1095,7 +1081,6 @@ const saveFileContentRestart = async () => {
|
||||
await props.server.general?.power("Restart");
|
||||
|
||||
addNotification({
|
||||
group: "files",
|
||||
title: "Server restarted",
|
||||
text: "Your server has been restarted.",
|
||||
type: "success",
|
||||
|
||||
@@ -113,9 +113,11 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { EditIcon, TransferIcon } from "@modrinth/assets";
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
import ButtonStyled from "@modrinth/ui/src/components/base/ButtonStyled.vue";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
}>();
|
||||
@@ -161,7 +163,6 @@ const saveGeneral = async () => {
|
||||
|
||||
if (!available) {
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "error",
|
||||
title: "Subdomain not available",
|
||||
text: "The subdomain you entered is already in use.",
|
||||
@@ -173,7 +174,6 @@ const saveGeneral = async () => {
|
||||
} catch (error) {
|
||||
console.error("Error checking subdomain availability:", error);
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "error",
|
||||
title: "Error checking availability",
|
||||
text: "Failed to verify if the subdomain is available.",
|
||||
@@ -184,7 +184,6 @@ const saveGeneral = async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
await props.server.refresh();
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Server settings updated",
|
||||
text: "Your server settings were successfully changed.",
|
||||
@@ -192,7 +191,6 @@ const saveGeneral = async () => {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "error",
|
||||
title: "Failed to update server settings",
|
||||
text: "An error occurred while attempting to update your server settings.",
|
||||
@@ -211,7 +209,6 @@ const uploadFile = async (e: Event) => {
|
||||
const file = (e.target as HTMLInputElement).files?.[0];
|
||||
if (!file) {
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "error",
|
||||
title: "No file selected",
|
||||
text: "Please select a file to upload.",
|
||||
@@ -267,7 +264,6 @@ const uploadFile = async (e: Event) => {
|
||||
});
|
||||
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Server icon updated",
|
||||
text: "Your server icon was successfully changed.",
|
||||
@@ -275,7 +271,6 @@ const uploadFile = async (e: Event) => {
|
||||
} catch (error) {
|
||||
console.error("Error uploading icon:", error);
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "error",
|
||||
title: "Upload failed",
|
||||
text: "Failed to upload server icon.",
|
||||
@@ -295,7 +290,6 @@ const resetIcon = async () => {
|
||||
await props.server.refresh(["general"]);
|
||||
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Server icon reset",
|
||||
text: "Your server icon was successfully reset.",
|
||||
@@ -303,7 +297,6 @@ const resetIcon = async () => {
|
||||
} catch (error) {
|
||||
console.error("Error resetting icon:", error);
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "error",
|
||||
title: "Reset failed",
|
||||
text: "Failed to reset server icon.",
|
||||
|
||||
@@ -115,10 +115,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ButtonStyled, CopyCode } from "@modrinth/ui";
|
||||
import { CopyIcon, ExternalIcon, EyeIcon, EyeOffIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, CopyCode, injectNotificationManager } from "@modrinth/ui";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
}>();
|
||||
|
||||
@@ -264,19 +264,26 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
PlusIcon,
|
||||
TrashIcon,
|
||||
EditIcon,
|
||||
VersionIcon,
|
||||
SaveIcon,
|
||||
InfoIcon,
|
||||
UploadIcon,
|
||||
IssuesIcon,
|
||||
PlusIcon,
|
||||
SaveIcon,
|
||||
TrashIcon,
|
||||
UploadIcon,
|
||||
VersionIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { ButtonStyled, NewModal, ConfirmModal, CopyCode } from "@modrinth/ui";
|
||||
import { ref, computed, nextTick } from "vue";
|
||||
import {
|
||||
ButtonStyled,
|
||||
ConfirmModal,
|
||||
CopyCode,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
} from "@modrinth/ui";
|
||||
import { computed, nextTick, ref } from "vue";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
}>();
|
||||
@@ -317,7 +324,6 @@ const addNewAllocation = async () => {
|
||||
newAllocationName.value = "";
|
||||
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Allocation reserved",
|
||||
text: "Your allocation has been reserved.",
|
||||
@@ -359,7 +365,6 @@ const confirmDeleteAllocation = async () => {
|
||||
await props.server.refresh(["network"]);
|
||||
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Allocation removed",
|
||||
text: "Your allocation has been removed.",
|
||||
@@ -379,7 +384,6 @@ const editAllocation = async () => {
|
||||
newAllocationName.value = "";
|
||||
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Allocation updated",
|
||||
text: "Your allocation has been updated.",
|
||||
@@ -397,7 +401,6 @@ const saveNetwork = async () => {
|
||||
const available = await props.server.network?.checkSubdomainAvailability(serverSubdomain.value);
|
||||
if (!available) {
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "error",
|
||||
title: "Subdomain not available",
|
||||
text: "The subdomain you entered is already in use.",
|
||||
@@ -416,7 +419,6 @@ const saveNetwork = async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
await props.server.refresh();
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Server settings updated",
|
||||
text: "Your server settings were successfully changed.",
|
||||
@@ -424,7 +426,6 @@ const saveNetwork = async () => {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "error",
|
||||
title: "Failed to update server settings",
|
||||
text: "An error occurred while attempting to update your server settings.",
|
||||
@@ -483,7 +484,6 @@ const exportDnsRecords = () => {
|
||||
const copyText = (text: string) => {
|
||||
navigator.clipboard.writeText(text);
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Text copied",
|
||||
text: `${text} has been copied to your clipboard`,
|
||||
|
||||
@@ -42,9 +42,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
import { useStorage } from "@vueuse/core";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const route = useNativeRoute();
|
||||
const serverId = route.params.id as string;
|
||||
|
||||
@@ -109,7 +111,6 @@ const hasUnsavedChanges = computed(() => {
|
||||
const savePreferences = () => {
|
||||
userPreferences.value = { ...newUserPreferences.value };
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Preferences saved",
|
||||
text: "Your preferences have been saved.",
|
||||
|
||||
@@ -143,11 +143,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, computed, inject } from "vue";
|
||||
import { EyeIcon, SearchIcon, IssuesIcon } from "@modrinth/assets";
|
||||
import { EyeIcon, IssuesIcon, SearchIcon } from "@modrinth/assets";
|
||||
import { injectNotificationManager } from "@modrinth/ui";
|
||||
import Fuse from "fuse.js";
|
||||
import { computed, inject, ref, watch } from "vue";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
}>();
|
||||
@@ -281,7 +283,6 @@ const saveProperties = async () => {
|
||||
originalProperties.value = JSON.parse(JSON.stringify(liveProperties.value));
|
||||
await props.server.refresh();
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Server properties updated",
|
||||
text: "Your server properties were successfully changed.",
|
||||
@@ -289,7 +290,6 @@ const saveProperties = async () => {
|
||||
} catch (error) {
|
||||
console.error("Error updating server properties:", error);
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "error",
|
||||
title: "Failed to update server properties",
|
||||
text: "An error occurred while attempting to update your server properties.",
|
||||
|
||||
@@ -112,10 +112,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { UpdatedIcon, IssuesIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled } from "@modrinth/ui";
|
||||
import { IssuesIcon, UpdatedIcon } from "@modrinth/assets";
|
||||
import { ButtonStyled, injectNotificationManager } from "@modrinth/ui";
|
||||
import { ModrinthServer } from "~/composables/servers/modrinth-servers.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const props = defineProps<{
|
||||
server: ModrinthServer;
|
||||
}>();
|
||||
@@ -199,7 +200,6 @@ async function saveStartup() {
|
||||
}
|
||||
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "success",
|
||||
title: "Server settings updated",
|
||||
text: "Your server settings were successfully changed.",
|
||||
@@ -207,7 +207,6 @@ async function saveStartup() {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
addNotification({
|
||||
group: "serverOptions",
|
||||
type: "error",
|
||||
title: "Failed to update server arguments",
|
||||
text: "Please try again later.",
|
||||
|
||||
@@ -408,6 +408,7 @@
|
||||
<script setup>
|
||||
import {
|
||||
CheckIcon,
|
||||
DownloadIcon,
|
||||
EditIcon,
|
||||
ExternalIcon,
|
||||
LeftArrowIcon,
|
||||
@@ -418,17 +419,16 @@ import {
|
||||
TrashIcon,
|
||||
UpdatedIcon,
|
||||
XIcon,
|
||||
DownloadIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { ConfirmModal, injectNotificationManager } from "@modrinth/ui";
|
||||
import QrcodeVue from "qrcode.vue";
|
||||
import { ConfirmModal } from "@modrinth/ui";
|
||||
import GithubIcon from "assets/icons/auth/sso-github.svg";
|
||||
import MicrosoftIcon from "assets/icons/auth/sso-microsoft.svg";
|
||||
import GoogleIcon from "assets/icons/auth/sso-google.svg";
|
||||
import SteamIcon from "assets/icons/auth/sso-steam.svg";
|
||||
import DiscordIcon from "assets/icons/auth/sso-discord.svg";
|
||||
import KeyIcon from "assets/icons/auth/key.svg";
|
||||
import DiscordIcon from "assets/icons/auth/sso-discord.svg";
|
||||
import GithubIcon from "assets/icons/auth/sso-github.svg";
|
||||
import GitLabIcon from "assets/icons/auth/sso-gitlab.svg";
|
||||
import GoogleIcon from "assets/icons/auth/sso-google.svg";
|
||||
import MicrosoftIcon from "assets/icons/auth/sso-microsoft.svg";
|
||||
import SteamIcon from "assets/icons/auth/sso-steam.svg";
|
||||
import Modal from "~/components/ui/Modal.vue";
|
||||
|
||||
useHead({
|
||||
@@ -439,7 +439,7 @@ definePageMeta({
|
||||
middleware: "auth",
|
||||
});
|
||||
|
||||
const data = useNuxtApp();
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const auth = await useAuth();
|
||||
|
||||
const changeEmailModal = ref();
|
||||
@@ -460,8 +460,7 @@ async function saveEmail() {
|
||||
changeEmailModal.value.hide();
|
||||
await useAuth(auth.value.token);
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -492,8 +491,7 @@ async function savePassword() {
|
||||
managePasswordModal.value.hide();
|
||||
await useAuth(auth.value.token);
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -529,8 +527,7 @@ async function showTwoFactorModal() {
|
||||
twoFactorSecret.value = res.secret;
|
||||
twoFactorFlow.value = res.flow;
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -619,8 +616,7 @@ async function deleteAccount() {
|
||||
method: "DELETE",
|
||||
});
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -649,8 +645,7 @@ async function exportData() {
|
||||
const blob = new Blob([jsonString], { type: "application/json" });
|
||||
generated.value = URL.createObjectURL(blob);
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -215,26 +215,27 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { UploadIcon, PlusIcon, XIcon, TrashIcon, EditIcon, SaveIcon } from "@modrinth/assets";
|
||||
import { EditIcon, PlusIcon, SaveIcon, TrashIcon, UploadIcon, XIcon } from "@modrinth/assets";
|
||||
import {
|
||||
CopyCode,
|
||||
ConfirmModal,
|
||||
Avatar,
|
||||
Button,
|
||||
Checkbox,
|
||||
Avatar,
|
||||
ConfirmModal,
|
||||
CopyCode,
|
||||
FileInput,
|
||||
commonSettingsMessages,
|
||||
injectNotificationManager,
|
||||
} from "@modrinth/ui";
|
||||
import Modal from "~/components/ui/Modal.vue";
|
||||
|
||||
import {
|
||||
scopeList,
|
||||
getScopeValue,
|
||||
hasScope,
|
||||
scopeList,
|
||||
toggleScope,
|
||||
useScopes,
|
||||
getScopeValue,
|
||||
} from "~/composables/auth/scopes.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
definePageMeta({
|
||||
@@ -245,7 +246,6 @@ useHead({
|
||||
title: "Applications - Modrinth",
|
||||
});
|
||||
|
||||
const data = useNuxtApp();
|
||||
const { scopesToLabels } = useScopes();
|
||||
|
||||
const appModal = ref();
|
||||
@@ -343,8 +343,7 @@ async function onImageSelection(files) {
|
||||
setForm(app);
|
||||
}
|
||||
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Icon updated",
|
||||
text: "Your application icon has been updated.",
|
||||
type: "success",
|
||||
@@ -374,8 +373,7 @@ async function createApp() {
|
||||
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -443,8 +441,7 @@ async function editApp() {
|
||||
|
||||
appModal.value.hide();
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -467,8 +464,7 @@ async function removeApp() {
|
||||
await refresh();
|
||||
editingId.value = null;
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -88,10 +88,17 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Button, ConfirmModal, Avatar, commonSettingsMessages } from "@modrinth/ui";
|
||||
import { TrashIcon, CheckIcon } from "@modrinth/assets";
|
||||
import { CheckIcon, TrashIcon } from "@modrinth/assets";
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
commonSettingsMessages,
|
||||
ConfirmModal,
|
||||
injectNotificationManager,
|
||||
} from "@modrinth/ui";
|
||||
import { useScopes } from "~/composables/auth/scopes.ts";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const { scopesToDefinitions } = useScopes();
|
||||
@@ -163,8 +170,7 @@ async function revokeApp(id) {
|
||||
revokingId.value = null;
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -392,8 +392,7 @@
|
||||
"
|
||||
:on-error="
|
||||
(err) =>
|
||||
data.$notify({
|
||||
group: 'main',
|
||||
addNotification({
|
||||
title: 'An error occurred',
|
||||
type: 'error',
|
||||
text: err.message ?? (err.data ? err.data.description : err),
|
||||
@@ -422,8 +421,7 @@
|
||||
:renewal-date="currentSubRenewalDate"
|
||||
:on-error="
|
||||
(err) =>
|
||||
data.$notify({
|
||||
group: 'main',
|
||||
addNotification({
|
||||
title: 'An error occurred',
|
||||
type: 'error',
|
||||
text: err.message ?? (err.data ? err.data.description : err),
|
||||
@@ -554,43 +552,44 @@
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ConfirmModal,
|
||||
ArrowBigUpDashIcon,
|
||||
CardIcon,
|
||||
CheckCircleIcon,
|
||||
CurrencyIcon,
|
||||
EditIcon,
|
||||
HistoryIcon,
|
||||
ModrinthPlusIcon,
|
||||
MoreVerticalIcon,
|
||||
PayPalIcon,
|
||||
PlusIcon,
|
||||
RightArrowIcon,
|
||||
SpinnerIcon,
|
||||
StarIcon,
|
||||
TransferIcon,
|
||||
TrashIcon,
|
||||
UpdatedIcon,
|
||||
XIcon,
|
||||
} from "@modrinth/assets";
|
||||
import {
|
||||
AddPaymentMethodModal,
|
||||
ButtonStyled,
|
||||
ConfirmModal,
|
||||
CopyCode,
|
||||
OverflowMenu,
|
||||
PurchaseModal,
|
||||
ButtonStyled,
|
||||
CopyCode,
|
||||
commonMessages,
|
||||
injectNotificationManager,
|
||||
} from "@modrinth/ui";
|
||||
import {
|
||||
PlusIcon,
|
||||
TransferIcon,
|
||||
SpinnerIcon,
|
||||
ArrowBigUpDashIcon,
|
||||
XIcon,
|
||||
CardIcon,
|
||||
MoreVerticalIcon,
|
||||
TrashIcon,
|
||||
EditIcon,
|
||||
StarIcon,
|
||||
PayPalIcon,
|
||||
CurrencyIcon,
|
||||
CheckCircleIcon,
|
||||
RightArrowIcon,
|
||||
ModrinthPlusIcon,
|
||||
UpdatedIcon,
|
||||
HistoryIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { calculateSavings, formatPrice, getCurrency } from "@modrinth/utils";
|
||||
import { ref, computed } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
import { useServersFetch } from "~/composables/servers/servers-fetch.ts";
|
||||
import { products } from "~/generated/state.json";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
definePageMeta({
|
||||
middleware: "auth",
|
||||
});
|
||||
|
||||
const app = useNuxtApp();
|
||||
const auth = await useAuth();
|
||||
const baseId = useId();
|
||||
|
||||
@@ -604,7 +603,6 @@ useHead({
|
||||
],
|
||||
});
|
||||
|
||||
const data = useNuxtApp();
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
const vintl = useVIntl();
|
||||
@@ -845,8 +843,7 @@ async function editPaymentMethod(index, primary) {
|
||||
});
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -864,8 +861,7 @@ async function removePaymentMethod(index) {
|
||||
});
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -887,8 +883,7 @@ async function cancelSubscription(id, cancelled) {
|
||||
});
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -955,8 +950,7 @@ const showPyroUpgradeModal = async (subscription) => {
|
||||
|
||||
if (!currentProduct.value) {
|
||||
console.error("Could not find product for current subscription");
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "An error occurred",
|
||||
text: "Could not find product for current subscription",
|
||||
type: "error",
|
||||
@@ -988,8 +982,7 @@ async function fetchCapacityStatuses(serverId, product) {
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error checking server capacities:", error);
|
||||
app.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error checking server capacities",
|
||||
text: error,
|
||||
type: "error",
|
||||
@@ -1015,23 +1008,20 @@ const resubscribePyro = async (subscriptionId, wasSuspended) => {
|
||||
});
|
||||
await refresh();
|
||||
if (wasSuspended) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Resubscription request submitted",
|
||||
text: "If the server is currently suspended, it may take up to 10 minutes for another charge attempt to be made.",
|
||||
type: "success",
|
||||
});
|
||||
} else {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Success",
|
||||
text: "Server subscription resubscribed successfully",
|
||||
type: "success",
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: "Error resubscribing",
|
||||
text: "An error occurred while resubscribing to your Modrinth server.",
|
||||
type: "error",
|
||||
|
||||
@@ -199,7 +199,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CodeIcon, RadioButtonCheckedIcon, RadioButtonIcon } from "@modrinth/assets";
|
||||
import { Button, ThemeSelector } from "@modrinth/ui";
|
||||
import { Button, injectNotificationManager, ThemeSelector } from "@modrinth/ui";
|
||||
import { formatProjectType } from "@modrinth/utils";
|
||||
import MessageBanner from "~/components/ui/MessageBanner.vue";
|
||||
import type { DisplayLocation } from "~/plugins/cosmetics";
|
||||
@@ -209,6 +209,7 @@ useHead({
|
||||
title: "Display settings - Modrinth",
|
||||
});
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const developerModeBanner = defineMessages({
|
||||
@@ -377,7 +378,6 @@ function disableDeveloperMode() {
|
||||
flags.value.developerMode = !flags.value.developerMode;
|
||||
saveFeatureFlags();
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Developer mode deactivated",
|
||||
text: "Developer mode has been disabled",
|
||||
type: "success",
|
||||
|
||||
@@ -202,26 +202,26 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { PlusIcon, XIcon, TrashIcon, EditIcon, SaveIcon } from "@modrinth/assets";
|
||||
import { EditIcon, PlusIcon, SaveIcon, TrashIcon, XIcon } from "@modrinth/assets";
|
||||
import {
|
||||
Checkbox,
|
||||
CopyCode,
|
||||
ConfirmModal,
|
||||
commonSettingsMessages,
|
||||
CopyCode,
|
||||
commonMessages,
|
||||
commonSettingsMessages,
|
||||
injectNotificationManager,
|
||||
useRelativeTime,
|
||||
} from "@modrinth/ui";
|
||||
|
||||
import Modal from "~/components/ui/Modal.vue";
|
||||
import {
|
||||
getScopeValue,
|
||||
hasScope,
|
||||
scopeList,
|
||||
toggleScope,
|
||||
useScopes,
|
||||
getScopeValue,
|
||||
} from "~/composables/auth/scopes.ts";
|
||||
|
||||
import Modal from "~/components/ui/Modal.vue";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const formatRelativeTime = useRelativeTime();
|
||||
@@ -346,8 +346,7 @@ async function createPat() {
|
||||
pats.value.push(res);
|
||||
patModal.value.hide();
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -372,8 +371,7 @@ async function editPat() {
|
||||
await refresh();
|
||||
patModal.value.hide();
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
@@ -392,8 +390,7 @@ async function removePat(id) {
|
||||
});
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -90,8 +90,11 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { UserIcon, SaveIcon, UploadIcon, UndoIcon, XIcon, TrashIcon } from "@modrinth/assets";
|
||||
import { Avatar, FileInput, Button, commonMessages } from "@modrinth/ui";
|
||||
import { SaveIcon, TrashIcon, UndoIcon, UploadIcon, UserIcon, XIcon } from "@modrinth/assets";
|
||||
import { Avatar, Button, commonMessages, FileInput, injectNotificationManager } from "@modrinth/ui";
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
useHead({
|
||||
title: "Profile settings - Modrinth",
|
||||
@@ -101,8 +104,6 @@ definePageMeta({
|
||||
middleware: "auth",
|
||||
});
|
||||
|
||||
const { formatMessage } = useVIntl();
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: "settings.profile.profile-info",
|
||||
@@ -222,7 +223,6 @@ async function saveChanges() {
|
||||
saved.value = true;
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "An error occurred",
|
||||
text: err
|
||||
? err.data
|
||||
|
||||
@@ -57,12 +57,18 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { XIcon } from "@modrinth/assets";
|
||||
import { commonMessages, commonSettingsMessages, useRelativeTime } from "@modrinth/ui";
|
||||
import {
|
||||
commonMessages,
|
||||
commonSettingsMessages,
|
||||
injectNotificationManager,
|
||||
useRelativeTime,
|
||||
} from "@modrinth/ui";
|
||||
|
||||
definePageMeta({
|
||||
middleware: "auth",
|
||||
});
|
||||
|
||||
const { addNotification } = injectNotificationManager();
|
||||
const { formatMessage } = useVIntl();
|
||||
const formatRelativeTime = useRelativeTime();
|
||||
|
||||
@@ -102,7 +108,6 @@ useHead({
|
||||
title: () => `${formatMessage(commonSettingsMessages.sessions)} - Modrinth`,
|
||||
});
|
||||
|
||||
const data = useNuxtApp();
|
||||
const { data: sessions, refresh } = await useAsyncData("session/list", () =>
|
||||
useBaseFetch("session/list"),
|
||||
);
|
||||
@@ -116,8 +121,7 @@ async function revokeSession(id) {
|
||||
});
|
||||
await refresh();
|
||||
} catch (err) {
|
||||
data.$notify({
|
||||
group: "main",
|
||||
addNotification({
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: "error",
|
||||
|
||||
@@ -120,7 +120,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
nuxtApp.provide("notify", (notif) => addNotification(notif));
|
||||
});
|
||||
export const formatNumber = (number, abbreviate = true) => {
|
||||
const x = +number;
|
||||
|
||||
51
apps/frontend/src/providers/frontend-notifications.ts
Normal file
51
apps/frontend/src/providers/frontend-notifications.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useState } from "#app";
|
||||
import {
|
||||
type NotificationPanelLocation,
|
||||
type WebNotification,
|
||||
AbstractWebNotificationManager,
|
||||
} from "@modrinth/ui";
|
||||
|
||||
export class FrontendNotificationManager extends AbstractWebNotificationManager {
|
||||
private readonly state: Ref<WebNotification[]>;
|
||||
private readonly locationState: Ref<NotificationPanelLocation>;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this.state = useState<WebNotification[]>("notifications", () => []);
|
||||
this.locationState = useState<NotificationPanelLocation>(
|
||||
"notifications.location",
|
||||
() => "right",
|
||||
);
|
||||
}
|
||||
|
||||
public getNotificationLocation(): NotificationPanelLocation {
|
||||
return this.locationState.value;
|
||||
}
|
||||
|
||||
public setNotificationLocation(location: NotificationPanelLocation): void {
|
||||
this.locationState.value = location;
|
||||
}
|
||||
|
||||
public getNotifications(): WebNotification[] {
|
||||
return this.state.value;
|
||||
}
|
||||
|
||||
protected addNotificationToStorage(notification: WebNotification): void {
|
||||
this.state.value.push(notification);
|
||||
}
|
||||
|
||||
protected removeNotificationFromStorage(id: string | number): void {
|
||||
const index = this.state.value.findIndex((n) => n.id === id);
|
||||
if (index > -1) {
|
||||
this.state.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
protected removeNotificationFromStorageByIndex(index: number): void {
|
||||
this.state.value.splice(index, 1);
|
||||
}
|
||||
|
||||
protected clearAllNotificationsFromStorage(): void {
|
||||
this.state.value.splice(0);
|
||||
}
|
||||
}
|
||||
108
apps/frontend/src/providers/organization-context.ts
Normal file
108
apps/frontend/src/providers/organization-context.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { createContext } from "@modrinth/ui";
|
||||
import { type Organization, type OrganizationMember, type ProjectV3 } from "@modrinth/utils";
|
||||
|
||||
export class OrganizationContext {
|
||||
public readonly organization: Ref<Organization | null>;
|
||||
public readonly projects: Ref<ProjectV3[] | null>;
|
||||
private readonly auth: Ref<any>;
|
||||
private readonly tags: Ref<any>;
|
||||
private readonly refreshFunction: () => Promise<void>;
|
||||
|
||||
public constructor(
|
||||
organization: Ref<Organization | null>,
|
||||
projects: Ref<ProjectV3[] | null>,
|
||||
auth: Ref<any>,
|
||||
tags: Ref<any>,
|
||||
refreshFunction: () => Promise<void>,
|
||||
) {
|
||||
this.organization = organization;
|
||||
this.projects = projects;
|
||||
this.auth = auth;
|
||||
this.tags = tags;
|
||||
this.refreshFunction = refreshFunction;
|
||||
}
|
||||
|
||||
public refresh = async () => {
|
||||
if (this.organization.value === null) {
|
||||
throw new Error("Organization is not set.");
|
||||
}
|
||||
|
||||
await this.refreshFunction();
|
||||
};
|
||||
|
||||
public currentMember = computed<Partial<OrganizationMember> | null>(() => {
|
||||
if (this.auth.value.user && this.organization.value) {
|
||||
const member = this.organization.value.members.find(
|
||||
(x) => x.user.id === this.auth.value.user.id,
|
||||
);
|
||||
|
||||
if (member) {
|
||||
return member;
|
||||
}
|
||||
|
||||
if (this.tags.value.staffRoles.includes(this.auth.value.user.role)) {
|
||||
return {
|
||||
user: this.auth.value.user,
|
||||
role: this.auth.value.user.role,
|
||||
permissions: this.auth.value.user.role === "admin" ? 1023 : 12,
|
||||
accepted: true,
|
||||
payouts_split: 0,
|
||||
avatar_url: this.auth.value.user.avatar_url,
|
||||
name: this.auth.value.user.username,
|
||||
} as Partial<OrganizationMember>;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
public hasPermission = computed(() => {
|
||||
const EDIT_DETAILS = 1 << 2;
|
||||
return (
|
||||
this.currentMember.value &&
|
||||
(this.currentMember.value.permissions & EDIT_DETAILS) === EDIT_DETAILS
|
||||
);
|
||||
});
|
||||
|
||||
public patchIcon = async (icon: { name: string }) => {
|
||||
if (this.organization.value === null) {
|
||||
throw new Error("Organization is not set.");
|
||||
}
|
||||
|
||||
const ext = icon.name.split(".").pop();
|
||||
await useBaseFetch(`organization/${this.organization.value.id}/icon`, {
|
||||
method: "PATCH",
|
||||
body: icon,
|
||||
query: { ext },
|
||||
apiVersion: 3,
|
||||
});
|
||||
};
|
||||
|
||||
public deleteIcon = async () => {
|
||||
if (this.organization.value === null) {
|
||||
throw new Error("Organization is not set.");
|
||||
}
|
||||
|
||||
await useBaseFetch(`organization/${this.organization.value.id}/icon`, {
|
||||
method: "DELETE",
|
||||
apiVersion: 3,
|
||||
});
|
||||
};
|
||||
|
||||
public patchOrganization = async (newData: { slug: any }) => {
|
||||
if (this.organization.value === null) {
|
||||
throw new Error("Organization is not set.");
|
||||
}
|
||||
|
||||
await useBaseFetch(`organization/${this.organization.value.id}`, {
|
||||
method: "PATCH",
|
||||
body: newData,
|
||||
apiVersion: 3,
|
||||
});
|
||||
|
||||
await this.refreshFunction();
|
||||
};
|
||||
}
|
||||
|
||||
export const [injectOrganizationContext, provideOrganizationContext] =
|
||||
createContext<OrganizationContext>("[id].vue", "organizationContext");
|
||||
Reference in New Issue
Block a user