feat: start work implementing validation checks using new nag system
This commit is contained in:
1 parent
59ad8eb426
commit
729d584757
9 files changed
+270
-7
No files matched your search
@@ -22,6 +22,10 @@
|
||||
"
|
||||
:on-image-upload="onUploadHandler"
|
||||
/>
|
||||
<div v-if="descriptionWarning" class="flex items-center gap-1.5 text-orange">
|
||||
<TriangleAlertIcon class="my-auto" />
|
||||
{{ descriptionWarning }}
|
||||
</div>
|
||||
<div class="input-group markdown-disclaimer">
|
||||
<button
|
||||
:disabled="!hasChanges"
|
||||
@@ -38,7 +42,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { SaveIcon } from "@modrinth/assets";
|
||||
import { SaveIcon, TriangleAlertIcon } from "@modrinth/assets";
|
||||
import { MIN_DESCRIPTION_CHARS } from "@modrinth/moderation";
|
||||
import { MarkdownEditor } from "@modrinth/ui";
|
||||
import { type Project, type TeamMember, TeamMemberPermission } from "@modrinth/utils";
|
||||
import { computed, ref } from "vue";
|
||||
@@ -53,6 +58,17 @@ const props = defineProps<{
|
||||
|
||||
const description = ref(props.project.body);
|
||||
|
||||
const descriptionWarning = computed(() => {
|
||||
const text = description.value?.trim() || "";
|
||||
const charCount = text.length;
|
||||
|
||||
if (charCount < MIN_DESCRIPTION_CHARS) {
|
||||
return `It's recommended to have a description with at least ${MIN_DESCRIPTION_CHARS} characters. (${charCount}/${MIN_DESCRIPTION_CHARS})`;
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
const patchRequestPayload = computed(() => {
|
||||
const payload: {
|
||||
body?: string;
|
||||
|
||||
@@ -82,6 +82,10 @@
|
||||
<label for="project-summary">
|
||||
<span class="label__title">Summary</span>
|
||||
</label>
|
||||
<div v-if="summaryWarning" class="my-2 flex items-center gap-1.5 text-orange">
|
||||
<TriangleAlertIcon class="my-auto" />
|
||||
{{ summaryWarning }}
|
||||
</div>
|
||||
<div class="textarea-wrapper summary-input">
|
||||
<textarea
|
||||
id="project-summary"
|
||||
@@ -240,10 +244,19 @@
|
||||
|
||||
<script setup>
|
||||
import { formatProjectStatus, formatProjectType } from "@modrinth/utils";
|
||||
import { UploadIcon, SaveIcon, TrashIcon, XIcon, IssuesIcon, CheckIcon } from "@modrinth/assets";
|
||||
import {
|
||||
UploadIcon,
|
||||
SaveIcon,
|
||||
TrashIcon,
|
||||
XIcon,
|
||||
IssuesIcon,
|
||||
CheckIcon,
|
||||
TriangleAlertIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { Multiselect } from "vue-multiselect";
|
||||
import { ConfirmModal, Avatar } from "@modrinth/ui";
|
||||
import FileInput from "~/components/ui/FileInput.vue";
|
||||
import { MIN_SUMMARY_CHARS } from "@modrinth/moderation";
|
||||
|
||||
const props = defineProps({
|
||||
project: {
|
||||
@@ -300,6 +313,17 @@ const hasDeletePermission = computed(() => {
|
||||
return (props.currentMember.permissions & DELETE_PROJECT) === DELETE_PROJECT;
|
||||
});
|
||||
|
||||
const summaryWarning = computed(() => {
|
||||
const text = summary.value?.trim() || "";
|
||||
const charCount = text.length;
|
||||
|
||||
if (charCount < MIN_SUMMARY_CHARS) {
|
||||
return `It's recommended to have a summary with at least ${MIN_SUMMARY_CHARS} characters. (${charCount}/${MIN_SUMMARY_CHARS})`;
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
const sideTypes = ["required", "optional", "unsupported"];
|
||||
|
||||
const patchData = computed(() => {
|
||||
|
||||
@@ -7,11 +7,16 @@
|
||||
id="project-issue-tracker"
|
||||
title="A place for users to report bugs, issues, and concerns about your project."
|
||||
>
|
||||
<span class="label__title">Issue tracker</span>
|
||||
<span class="label__title">Issue tracker </span>
|
||||
<span class="label__description">
|
||||
A place for users to report bugs, issues, and concerns about your project.
|
||||
</span>
|
||||
</label>
|
||||
<TriangleAlertIcon
|
||||
v-if="!isIssuesUrlCommon"
|
||||
class="size-6 animate-pulse text-orange"
|
||||
v-tooltip="`You're using a link which isn't common for this link type.`"
|
||||
/>
|
||||
<input
|
||||
id="project-issue-tracker"
|
||||
v-model="issuesUrl"
|
||||
@@ -26,11 +31,16 @@
|
||||
id="project-source-code"
|
||||
title="A page/repository containing the source code for your project"
|
||||
>
|
||||
<span class="label__title">Source code</span>
|
||||
<span class="label__title">Source code </span>
|
||||
<span class="label__description">
|
||||
A page/repository containing the source code for your project
|
||||
</span>
|
||||
</label>
|
||||
<TriangleAlertIcon
|
||||
v-if="!isSourceUrlCommon"
|
||||
class="size-6 animate-pulse text-orange"
|
||||
v-tooltip="`You're using a link which isn't common for this link type.`"
|
||||
/>
|
||||
<input
|
||||
id="project-source-code"
|
||||
v-model="sourceUrl"
|
||||
@@ -61,9 +71,14 @@
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<label id="project-discord-invite" title="An invitation link to your Discord server.">
|
||||
<span class="label__title">Discord invite</span>
|
||||
<span class="label__title">Discord invite </span>
|
||||
<span class="label__description"> An invitation link to your Discord server. </span>
|
||||
</label>
|
||||
<TriangleAlertIcon
|
||||
v-if="!isDiscordUrlCommon"
|
||||
class="size-6 animate-pulse text-orange"
|
||||
v-tooltip="`You're using a link which isn't common for this link type.`"
|
||||
/>
|
||||
<input
|
||||
id="project-discord-invite"
|
||||
v-model="discordUrl"
|
||||
@@ -123,7 +138,8 @@
|
||||
|
||||
<script setup>
|
||||
import { DropdownSelect } from "@modrinth/ui";
|
||||
import { SaveIcon } from "@modrinth/assets";
|
||||
import { SaveIcon, TriangleAlertIcon } from "@modrinth/assets";
|
||||
import { isCommonUrl, commonLinkDomains } from "@modrinth/moderation";
|
||||
|
||||
const tags = useTags();
|
||||
|
||||
@@ -153,6 +169,21 @@ const sourceUrl = ref(props.project.source_url);
|
||||
const wikiUrl = ref(props.project.wiki_url);
|
||||
const discordUrl = ref(props.project.discord_url);
|
||||
|
||||
const isIssuesUrlCommon = computed(() => {
|
||||
if (issuesUrl.value.trim() === "") return true;
|
||||
return isCommonUrl(issuesUrl.value, commonLinkDomains.issues);
|
||||
});
|
||||
|
||||
const isSourceUrlCommon = computed(() => {
|
||||
if (sourceUrl.value.trim() === "") return true;
|
||||
return isCommonUrl(sourceUrl.value, commonLinkDomains.source);
|
||||
});
|
||||
|
||||
const isDiscordUrlCommon = computed(() => {
|
||||
if (discordUrl.value.trim() === "") return true;
|
||||
return isCommonUrl(discordUrl.value, commonLinkDomains.discord);
|
||||
});
|
||||
|
||||
const rawDonationLinks = JSON.parse(JSON.stringify(props.project.donation_urls));
|
||||
rawDonationLinks.push({
|
||||
id: null,
|
||||
|
||||
Reference in new issue
Block a user