Skip to content

Commit 3887eb4

Browse files
committed
fix: handle identified files properly in the checklist (#4004)
* fix: handle identified files from the backend * fix: allFiles not being emitted after permissions flow completed * fix: properly handle identified projects * fix: jade issues * fix: import * fix: issue with perm gen msgs * fix: incomplete error
1 parent 48c3b64 commit 3887eb4

File tree

4 files changed

+193
-65
lines changed

4 files changed

+193
-65
lines changed

apps/frontend/src/components/ui/moderation/checklist/ModerationChecklist.vue

Lines changed: 77 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -240,24 +240,6 @@
240240
</div>
241241

242242
<div v-else-if="generatedMessage" class="flex items-center gap-2">
243-
<OverflowMenu :options="stageOptions" class="bg-transparent p-0">
244-
<ButtonStyled circular>
245-
<button v-tooltip="`Stages`">
246-
<ListBulletedIcon />
247-
</button>
248-
</ButtonStyled>
249-
250-
<template
251-
v-for="opt in stageOptions.filter(
252-
(opt) => 'id' in opt && 'text' in opt && 'icon' in opt,
253-
)"
254-
#[opt.id]
255-
:key="opt.id"
256-
>
257-
<component :is="opt.icon" v-if="opt.icon" class="mr-2" />
258-
{{ opt.text }}
259-
</template>
260-
</OverflowMenu>
261243
<ButtonStyled>
262244
<button @click="goBackToStages">
263245
<LeftArrowIcon aria-hidden="true" />
@@ -368,18 +350,23 @@ import {
368350
DropdownSelect,
369351
MarkdownEditor,
370352
} from "@modrinth/ui";
371-
import { type Project, renderHighlightedString, type ModerationJudgements } from "@modrinth/utils";
353+
import {
354+
type Project,
355+
renderHighlightedString,
356+
type ModerationJudgements,
357+
type ModerationModpackItem,
358+
} from "@modrinth/utils";
372359
import { computedAsync, useLocalStorage } from "@vueuse/core";
373-
import type {
374-
Action,
375-
MultiSelectChipsAction,
376-
DropdownAction,
377-
ButtonAction,
378-
ToggleAction,
379-
ConditionalButtonAction,
380-
Stage,
360+
import {
361+
type Action,
362+
type MultiSelectChipsAction,
363+
type DropdownAction,
364+
type ButtonAction,
365+
type ToggleAction,
366+
type ConditionalButtonAction,
367+
type Stage,
368+
finalPermissionMessages,
381369
} from "@modrinth/moderation";
382-
import { finalPermissionMessages } from "@modrinth/moderation/data/modpack-permissions-stage";
383370
import * as prettier from "prettier";
384371
import ModpackPermissionsFlow from "./ModpackPermissionsFlow.vue";
385372
import KeybindsModal from "./ChecklistKeybindsModal.vue";
@@ -411,7 +398,6 @@ const done = ref(false);
411398
412399
function handleModpackPermissionsComplete() {
413400
modpackPermissionsComplete.value = true;
414-
nextStage();
415401
}
416402
417403
const emit = defineEmits<{
@@ -815,6 +801,31 @@ const isAnyVisibleInputs = computed(() => {
815801
});
816802
});
817803
804+
function getModpackFilesFromStorage(): {
805+
interactive: ModerationModpackItem[];
806+
permanentNo: ModerationModpackItem[];
807+
} {
808+
try {
809+
const sessionData = sessionStorage.getItem(`modpack-permissions-data-${props.project.id}`);
810+
const interactive = sessionData ? (JSON.parse(sessionData) as ModerationModpackItem[]) : [];
811+
812+
const permanentNoData = sessionStorage.getItem(
813+
`modpack-permissions-permanent-no-${props.project.id}`,
814+
);
815+
const permanentNo = permanentNoData
816+
? (JSON.parse(permanentNoData) as ModerationModpackItem[])
817+
: [];
818+
819+
return {
820+
interactive: interactive || [],
821+
permanentNo: permanentNo || [],
822+
};
823+
} catch (error) {
824+
console.warn("Failed to parse session storage modpack data:", error);
825+
return { interactive: [], permanentNo: [] };
826+
}
827+
}
828+
818829
async function assembleFullMessage() {
819830
const messageParts: MessagePart[] = [];
820831
@@ -1084,13 +1095,14 @@ async function generateMessage() {
10841095
const baseMessage = await assembleFullMessage();
10851096
let fullMessage = baseMessage;
10861097
1087-
if (
1088-
props.project.project_type === "modpack" &&
1089-
Object.keys(modpackJudgements.value).length > 0
1090-
) {
1091-
const modpackMessage = generateModpackMessage(modpackJudgements.value);
1092-
if (modpackMessage) {
1093-
fullMessage = baseMessage ? `${baseMessage}\n\n${modpackMessage}` : modpackMessage;
1098+
if (props.project.project_type === "modpack") {
1099+
const modpackFilesData = getModpackFilesFromStorage();
1100+
1101+
if (modpackFilesData.interactive.length > 0 || modpackFilesData.permanentNo.length > 0) {
1102+
const modpackMessage = generateModpackMessage(modpackFilesData);
1103+
if (modpackMessage) {
1104+
fullMessage = baseMessage ? `${baseMessage}\n\n${modpackMessage}` : modpackMessage;
1105+
}
10941106
}
10951107
}
10961108
@@ -1121,25 +1133,32 @@ async function generateMessage() {
11211133
}
11221134
}
11231135
1124-
function generateModpackMessage(judgements: ModerationJudgements) {
1136+
function generateModpackMessage(allFiles: {
1137+
interactive: ModerationModpackItem[];
1138+
permanentNo: ModerationModpackItem[];
1139+
}) {
11251140
const issues = [];
11261141
1127-
const attributeMods = [];
1128-
const noMods = [];
1129-
const permanentNoMods = [];
1130-
const unidentifiedMods = [];
1131-
1132-
for (const [, judgement] of Object.entries(judgements)) {
1133-
if (judgement.status === "with-attribution") {
1134-
attributeMods.push(judgement.file_name);
1135-
} else if (judgement.status === "no") {
1136-
noMods.push(judgement.file_name);
1137-
} else if (judgement.status === "permanent-no") {
1138-
permanentNoMods.push(judgement.file_name);
1139-
} else if (judgement.status === "unidentified") {
1140-
unidentifiedMods.push(judgement.file_name);
1142+
const attributeMods: string[] = [];
1143+
const noMods: string[] = [];
1144+
const permanentNoMods: string[] = [];
1145+
const unidentifiedMods: string[] = [];
1146+
1147+
allFiles.interactive.forEach((file) => {
1148+
if (file.status === "unidentified") {
1149+
if (file.approved === "no") {
1150+
unidentifiedMods.push(file.file_name);
1151+
}
1152+
} else if (file.status === "with-attribution" && file.approved === "no") {
1153+
attributeMods.push(file.file_name);
1154+
} else if (file.status === "no" && file.approved === "no") {
1155+
noMods.push(file.file_name);
11411156
}
1142-
}
1157+
});
1158+
1159+
allFiles.permanentNo.forEach((file) => {
1160+
permanentNoMods.push(file.file_name);
1161+
});
11431162
11441163
if (
11451164
attributeMods.length > 0 ||
@@ -1149,6 +1168,12 @@ function generateModpackMessage(judgements: ModerationJudgements) {
11491168
) {
11501169
issues.push("## Copyrighted content");
11511170
1171+
if (unidentifiedMods.length > 0) {
1172+
issues.push(
1173+
`${finalPermissionMessages.unidentified}\n${unidentifiedMods.map((mod) => `- ${mod}`).join("\n")}`,
1174+
);
1175+
}
1176+
11521177
if (attributeMods.length > 0) {
11531178
issues.push(
11541179
`${finalPermissionMessages["with-attribution"]}\n${attributeMods.map((mod) => `- ${mod}`).join("\n")}`,
@@ -1164,12 +1189,6 @@ function generateModpackMessage(judgements: ModerationJudgements) {
11641189
`${finalPermissionMessages["permanent-no"]}\n${permanentNoMods.map((mod) => `- ${mod}`).join("\n")}`,
11651190
);
11661191
}
1167-
1168-
if (unidentifiedMods.length > 0) {
1169-
issues.push(
1170-
`${finalPermissionMessages.unidentified}\n${unidentifiedMods.map((mod) => `- ${mod}`).join("\n")}`,
1171-
);
1172-
}
11731192
}
11741193
11751194
return issues.join("\n\n");

apps/frontend/src/components/ui/moderation/checklist/ModpackPermissionsFlow.vue

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<div v-if="!modPackData">Loading data...</div>
99

1010
<div v-else-if="modPackData.length === 0">
11-
<p>All permissions obtained. You may skip this step!</p>
11+
<p>All permissions already obtained.</p>
1212
</div>
1313

1414
<div v-else-if="!modPackData[currentIndex]">
@@ -157,7 +157,7 @@ import type {
157157
} from "@modrinth/utils";
158158
import { ButtonStyled } from "@modrinth/ui";
159159
import { ref, computed, watch, onMounted } from "vue";
160-
import { useLocalStorage } from "@vueuse/core";
160+
import { useLocalStorage, useSessionStorage } from "@vueuse/core";
161161
162162
const props = defineProps<{
163163
projectId: string;
@@ -182,7 +182,26 @@ const persistedModPackData = useLocalStorage<ModerationModpackItem[] | null>(
182182
183183
const persistedIndex = useLocalStorage<number>(`modpack-permissions-index-${props.projectId}`, 0);
184184
185-
const modPackData = ref<ModerationModpackItem[] | null>(null);
185+
const modPackData = useSessionStorage<ModerationModpackItem[] | null>(
186+
`modpack-permissions-data-${props.projectId}`,
187+
null,
188+
{
189+
serializer: {
190+
read: (v: any) => (v ? JSON.parse(v) : null),
191+
write: (v: any) => JSON.stringify(v),
192+
},
193+
},
194+
);
195+
const permanentNoFiles = useSessionStorage<ModerationModpackItem[]>(
196+
`modpack-permissions-permanent-no-${props.projectId}`,
197+
[],
198+
{
199+
serializer: {
200+
read: (v: any) => (v ? JSON.parse(v) : []),
201+
write: (v: any) => JSON.stringify(v),
202+
},
203+
},
204+
);
186205
const currentIndex = ref(0);
187206
188207
const fileApprovalTypes: ModerationModpackPermissionApprovalType[] = [
@@ -251,7 +270,45 @@ async function fetchModPackData(): Promise<void> {
251270
const data = (await useBaseFetch(`moderation/project/${props.projectId}`, {
252271
internal: true,
253272
})) as ModerationModpackResponse;
273+
274+
const permanentNoItems: ModerationModpackItem[] = Object.entries(data.identified || {})
275+
.filter(([_, file]) => file.status === "permanent-no")
276+
.map(
277+
([sha1, file]): ModerationModpackItem => ({
278+
sha1,
279+
file_name: file.file_name,
280+
type: "identified",
281+
status: file.status,
282+
approved: null,
283+
}),
284+
)
285+
.sort((a, b) => a.file_name.localeCompare(b.file_name));
286+
287+
permanentNoFiles.value = permanentNoItems;
288+
254289
const sortedData: ModerationModpackItem[] = [
290+
...Object.entries(data.identified || {})
291+
.filter(
292+
([_, file]) =>
293+
file.status !== "yes" &&
294+
file.status !== "with-attribution-and-source" &&
295+
file.status !== "permanent-no",
296+
)
297+
.map(
298+
([sha1, file]): ModerationModpackItem => ({
299+
sha1,
300+
file_name: file.file_name,
301+
type: "identified",
302+
status: file.status,
303+
approved: null,
304+
...(file.status === "unidentified" && {
305+
proof: "",
306+
url: "",
307+
title: "",
308+
}),
309+
}),
310+
)
311+
.sort((a, b) => a.file_name.localeCompare(b.file_name)),
255312
...Object.entries(data.unknown_files || {})
256313
.map(
257314
([sha1, fileName]): ModerationUnknownModpackItem => ({
@@ -310,6 +367,7 @@ async function fetchModPackData(): Promise<void> {
310367
} catch (error) {
311368
console.error("Failed to fetch modpack data:", error);
312369
modPackData.value = [];
370+
permanentNoFiles.value = [];
313371
persistAll();
314372
}
315373
}
@@ -321,6 +379,14 @@ function goToPrevious(): void {
321379
}
322380
}
323381
382+
watch(
383+
modPackData,
384+
(newValue) => {
385+
persistedModPackData.value = newValue;
386+
},
387+
{ deep: true },
388+
);
389+
324390
function goToNext(): void {
325391
if (modPackData.value && currentIndex.value < modPackData.value.length) {
326392
currentIndex.value++;
@@ -396,6 +462,17 @@ onMounted(() => {
396462
}
397463
});
398464
465+
watch(
466+
modPackData,
467+
(newValue) => {
468+
if (newValue && newValue.length === 0) {
469+
emit("complete");
470+
clearPersistedData();
471+
}
472+
},
473+
{ immediate: true },
474+
);
475+
399476
watch(
400477
() => props.projectId,
401478
() => {
@@ -406,6 +483,20 @@ watch(
406483
}
407484
},
408485
);
486+
487+
function getModpackFiles(): {
488+
interactive: ModerationModpackItem[];
489+
permanentNo: ModerationModpackItem[];
490+
} {
491+
return {
492+
interactive: modPackData.value || [],
493+
permanentNo: permanentNoFiles.value,
494+
};
495+
}
496+
497+
defineExpose({
498+
getModpackFiles,
499+
});
409500
</script>
410501

411502
<style scoped>

packages/moderation/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ export * from './types/stage'
44
export * from './types/keybinds'
55
export * from './utils'
66

7+
export { finalPermissionMessages } from './data/modpack-permissions-stage'
78
export { default as checklist } from './data/checklist'
89
export { default as keybinds } from './data/keybinds'

0 commit comments

Comments
 (0)