Spaces:
Running
Running
Ask for a reason when reporting assistants (#825)
Browse files* Show modal asking for assistant report reason
* fix disabled button styling
* parse with zod
* Update src/routes/settings/assistants/[assistantId]/ReportModal.svelte
Co-authored-by: Victor Muštar <victor.mustar@gmail.com>
* use a text area with max-w
---------
Co-authored-by: Victor Muštar <victor.mustar@gmail.com>
src/lib/components/Modal.svelte
CHANGED
|
@@ -46,7 +46,7 @@
|
|
| 46 |
role="presentation"
|
| 47 |
tabindex="-1"
|
| 48 |
bind:this={backdropEl}
|
| 49 |
-
on:click={handleBackdropClick}
|
| 50 |
transition:fade|global={{ easing: cubicOut, duration: 300 }}
|
| 51 |
class="fixed inset-0 z-40 flex items-center justify-center bg-black/80 p-8 backdrop-blur-sm dark:bg-black/50"
|
| 52 |
>
|
|
|
|
| 46 |
role="presentation"
|
| 47 |
tabindex="-1"
|
| 48 |
bind:this={backdropEl}
|
| 49 |
+
on:click|stopPropagation={handleBackdropClick}
|
| 50 |
transition:fade|global={{ easing: cubicOut, duration: 300 }}
|
| 51 |
class="fixed inset-0 z-40 flex items-center justify-center bg-black/80 p-8 backdrop-blur-sm dark:bg-black/50"
|
| 52 |
>
|
src/lib/types/Report.ts
CHANGED
|
@@ -7,4 +7,5 @@ export interface Report extends Timestamps {
|
|
| 7 |
_id: ObjectId;
|
| 8 |
createdBy: User["_id"] | string;
|
| 9 |
assistantId: Assistant["_id"];
|
|
|
|
| 10 |
}
|
|
|
|
| 7 |
_id: ObjectId;
|
| 8 |
createdBy: User["_id"] | string;
|
| 9 |
assistantId: Assistant["_id"];
|
| 10 |
+
reason?: string;
|
| 11 |
}
|
src/routes/settings/assistants/[assistantId]/+page.server.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { authCondition } from "$lib/server/auth";
|
|
| 5 |
import { base } from "$app/paths";
|
| 6 |
import { PUBLIC_ORIGIN, PUBLIC_SHARE_PREFIX } from "$env/static/public";
|
| 7 |
import { WEBHOOK_URL_REPORT_ASSISTANT } from "$env/static/private";
|
| 8 |
-
|
| 9 |
async function assistantOnlyIfAuthor(locals: App.Locals, assistantId?: string) {
|
| 10 |
const assistant = await collections.assistants.findOne({ _id: new ObjectId(assistantId) });
|
| 11 |
|
|
@@ -53,7 +53,7 @@ export const actions: Actions = {
|
|
| 53 |
|
| 54 |
throw redirect(302, `${base}/settings`);
|
| 55 |
},
|
| 56 |
-
report: async ({ params, locals, url }) => {
|
| 57 |
// is there already a report from this user for this model ?
|
| 58 |
const report = await collections.reports.findOne({
|
| 59 |
assistantId: new ObjectId(params.assistantId),
|
|
@@ -64,12 +64,20 @@ export const actions: Actions = {
|
|
| 64 |
return fail(400, { error: true, message: "Already reported" });
|
| 65 |
}
|
| 66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
const { acknowledged } = await collections.reports.insertOne({
|
| 68 |
_id: new ObjectId(),
|
| 69 |
assistantId: new ObjectId(params.assistantId),
|
| 70 |
createdBy: locals.user?._id ?? locals.sessionId,
|
| 71 |
createdAt: new Date(),
|
| 72 |
updatedAt: new Date(),
|
|
|
|
| 73 |
});
|
| 74 |
|
| 75 |
if (!acknowledged) {
|
|
@@ -91,7 +99,7 @@ export const actions: Actions = {
|
|
| 91 |
"Content-type": "application/json",
|
| 92 |
},
|
| 93 |
body: JSON.stringify({
|
| 94 |
-
text: `Assistant <${assistantUrl}|${assistant?.name}> reported by <http://hf.co/${locals.user?.username}|${locals.user?.username}
|
| 95 |
}),
|
| 96 |
});
|
| 97 |
|
|
|
|
| 5 |
import { base } from "$app/paths";
|
| 6 |
import { PUBLIC_ORIGIN, PUBLIC_SHARE_PREFIX } from "$env/static/public";
|
| 7 |
import { WEBHOOK_URL_REPORT_ASSISTANT } from "$env/static/private";
|
| 8 |
+
import { z } from "zod";
|
| 9 |
async function assistantOnlyIfAuthor(locals: App.Locals, assistantId?: string) {
|
| 10 |
const assistant = await collections.assistants.findOne({ _id: new ObjectId(assistantId) });
|
| 11 |
|
|
|
|
| 53 |
|
| 54 |
throw redirect(302, `${base}/settings`);
|
| 55 |
},
|
| 56 |
+
report: async ({ request, params, locals, url }) => {
|
| 57 |
// is there already a report from this user for this model ?
|
| 58 |
const report = await collections.reports.findOne({
|
| 59 |
assistantId: new ObjectId(params.assistantId),
|
|
|
|
| 64 |
return fail(400, { error: true, message: "Already reported" });
|
| 65 |
}
|
| 66 |
|
| 67 |
+
const formData = await request.formData();
|
| 68 |
+
const result = z.string().min(1).max(128).safeParse(formData?.get("reportReason"));
|
| 69 |
+
|
| 70 |
+
if (!result.success) {
|
| 71 |
+
return fail(400, { error: true, message: "Invalid report reason" });
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
const { acknowledged } = await collections.reports.insertOne({
|
| 75 |
_id: new ObjectId(),
|
| 76 |
assistantId: new ObjectId(params.assistantId),
|
| 77 |
createdBy: locals.user?._id ?? locals.sessionId,
|
| 78 |
createdAt: new Date(),
|
| 79 |
updatedAt: new Date(),
|
| 80 |
+
reason: result.data,
|
| 81 |
});
|
| 82 |
|
| 83 |
if (!acknowledged) {
|
|
|
|
| 99 |
"Content-type": "application/json",
|
| 100 |
},
|
| 101 |
body: JSON.stringify({
|
| 102 |
+
text: `Assistant <${assistantUrl}|${assistant?.name}> reported by <http://hf.co/${locals.user?.username}|${locals.user?.username}>. The following reason was given \n\n> ${result.data}`,
|
| 103 |
}),
|
| 104 |
});
|
| 105 |
|
src/routes/settings/assistants/[assistantId]/+page.svelte
CHANGED
|
@@ -12,6 +12,7 @@
|
|
| 12 |
import CarbonFlag from "~icons/carbon/flag";
|
| 13 |
import CarbonLink from "~icons/carbon/link";
|
| 14 |
import CopyToClipBoardBtn from "$lib/components/CopyToClipBoardBtn.svelte";
|
|
|
|
| 15 |
|
| 16 |
export let data: PageData;
|
| 17 |
|
|
@@ -24,8 +25,13 @@
|
|
| 24 |
const prefix = PUBLIC_SHARE_PREFIX || `${PUBLIC_ORIGIN || $page.url.origin}${base}`;
|
| 25 |
|
| 26 |
$: shareUrl = `${prefix}/assistant/${assistant?._id}`;
|
|
|
|
|
|
|
| 27 |
</script>
|
| 28 |
|
|
|
|
|
|
|
|
|
|
| 29 |
<div class="flex h-full flex-col gap-2">
|
| 30 |
<div class="flex gap-6">
|
| 31 |
{#if assistant?.avatar}
|
|
@@ -102,11 +108,15 @@
|
|
| 102 |
>
|
| 103 |
</form>
|
| 104 |
{#if !assistant?.reported}
|
| 105 |
-
<
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
{:else}
|
| 111 |
<button type="button" disabled class="text-gray-700">
|
| 112 |
<CarbonFlag class="mr-1.5 inline text-xs" />Reported</button
|
|
|
|
| 12 |
import CarbonFlag from "~icons/carbon/flag";
|
| 13 |
import CarbonLink from "~icons/carbon/link";
|
| 14 |
import CopyToClipBoardBtn from "$lib/components/CopyToClipBoardBtn.svelte";
|
| 15 |
+
import ReportModal from "./ReportModal.svelte";
|
| 16 |
|
| 17 |
export let data: PageData;
|
| 18 |
|
|
|
|
| 25 |
const prefix = PUBLIC_SHARE_PREFIX || `${PUBLIC_ORIGIN || $page.url.origin}${base}`;
|
| 26 |
|
| 27 |
$: shareUrl = `${prefix}/assistant/${assistant?._id}`;
|
| 28 |
+
|
| 29 |
+
let displayReportModal = false;
|
| 30 |
</script>
|
| 31 |
|
| 32 |
+
{#if displayReportModal}
|
| 33 |
+
<ReportModal on:close={() => (displayReportModal = false)} />
|
| 34 |
+
{/if}
|
| 35 |
<div class="flex h-full flex-col gap-2">
|
| 36 |
<div class="flex gap-6">
|
| 37 |
{#if assistant?.avatar}
|
|
|
|
| 108 |
>
|
| 109 |
</form>
|
| 110 |
{#if !assistant?.reported}
|
| 111 |
+
<button
|
| 112 |
+
type="button"
|
| 113 |
+
on:click={() => {
|
| 114 |
+
displayReportModal = true;
|
| 115 |
+
}}
|
| 116 |
+
class="underline"
|
| 117 |
+
>
|
| 118 |
+
<CarbonFlag class="mr-1.5 inline text-xs" />Report
|
| 119 |
+
</button>
|
| 120 |
{:else}
|
| 121 |
<button type="button" disabled class="text-gray-700">
|
| 122 |
<CarbonFlag class="mr-1.5 inline text-xs" />Reported</button
|
src/routes/settings/assistants/[assistantId]/ReportModal.svelte
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import { applyAction, enhance } from "$app/forms";
|
| 3 |
+
import { invalidateAll } from "$app/navigation";
|
| 4 |
+
import Modal from "$lib/components/Modal.svelte";
|
| 5 |
+
import { createEventDispatcher } from "svelte";
|
| 6 |
+
|
| 7 |
+
const dispatch = createEventDispatcher<{ close: void }>();
|
| 8 |
+
|
| 9 |
+
let reason = "";
|
| 10 |
+
</script>
|
| 11 |
+
|
| 12 |
+
<Modal on:close>
|
| 13 |
+
<form
|
| 14 |
+
method="POST"
|
| 15 |
+
action="?/report"
|
| 16 |
+
use:enhance={() => {
|
| 17 |
+
return async ({ result }) => {
|
| 18 |
+
await applyAction(result);
|
| 19 |
+
dispatch("close");
|
| 20 |
+
invalidateAll();
|
| 21 |
+
};
|
| 22 |
+
}}
|
| 23 |
+
class="w-full min-w-64 p-4"
|
| 24 |
+
>
|
| 25 |
+
<span class="mb-1 text-sm font-semibold">Report an assistant</span>
|
| 26 |
+
|
| 27 |
+
<p class="text-sm text-gray-500">
|
| 28 |
+
Please provide a brief description of why you are reporting this assistant.
|
| 29 |
+
</p>
|
| 30 |
+
|
| 31 |
+
<textarea
|
| 32 |
+
name="reportReason"
|
| 33 |
+
class="mt-6 max-h-48 w-full resize-y rounded-lg border-2 border-gray-200 bg-gray-100 p-2 text-smd"
|
| 34 |
+
placeholder="Reason(s) for the report"
|
| 35 |
+
maxlength="128"
|
| 36 |
+
bind:value={reason}
|
| 37 |
+
/>
|
| 38 |
+
|
| 39 |
+
<div class="flex w-full flex-row justify-between px-2 pt-4">
|
| 40 |
+
<button
|
| 41 |
+
type="button"
|
| 42 |
+
class="text-sm text-gray-700 hover:underline"
|
| 43 |
+
on:click={() => dispatch("close")}>Cancel</button
|
| 44 |
+
>
|
| 45 |
+
|
| 46 |
+
<button
|
| 47 |
+
type="submit"
|
| 48 |
+
class="rounded-full bg-black px-4 py-2 text-sm font-semibold text-white md:px-8"
|
| 49 |
+
disabled={!reason}
|
| 50 |
+
class:bg-gray-200={!reason}
|
| 51 |
+
class:!text-gray-400={!reason}
|
| 52 |
+
>
|
| 53 |
+
Submit report
|
| 54 |
+
</button>
|
| 55 |
+
</div>
|
| 56 |
+
</form>
|
| 57 |
+
</Modal>
|