Mishig victor HF staff commited on
Commit
08e8583
1 Parent(s): 38362bd

[Assitants] Community | User tabs (#773)

Browse files

* [Assistants] Add pagination

* [Assitants] Community | User tabs

* format

* minimize diff

* Update src/routes/assistants/+page.svelte

Co-authored-by: Victor Muštar <victor.mustar@gmail.com>

* use data.user

* rm unused import

* Use a href & simplify overall

* lint

* it will never be a button

* statements need to be reactive

* format

* set filter differntly

* Revert "set filter differntly"

This reverts commit fc8a2fc67463fb5ad39be3c3ae16ce74caa1f05d.

* use inline

* avoid ugly image change

* fix query

* ui update

* update link to profiles

* link to HF profile

* dark mode

* Update +page.svelte

* refactor getHref to be more descriptive

* Preserve `user` searchQuery when chaning model ids

* `getHref` utility

* dont show single "Community" btn for non-logged in users

* fix iterator

---------

Co-authored-by: Victor Muštar <victor.mustar@gmail.com>

src/lib/components/Pagination.svelte CHANGED
@@ -1,5 +1,6 @@
1
  <script lang="ts">
2
  import { page } from "$app/stores";
 
3
  import PaginationArrow from "./PaginationArrow.svelte";
4
 
5
  export let classNames = "";
@@ -12,12 +13,6 @@
12
  $: pageIndex = parseInt($page.url.searchParams.get("p") ?? "0");
13
  $: pageIndexes = getPageIndexes(pageIndex, numTotalPages);
14
 
15
- function getHref(url: URL | string, pageIdx: number) {
16
- const newUrl = new URL(url);
17
- newUrl.searchParams.set("p", pageIdx.toString());
18
- return newUrl.toString();
19
- }
20
-
21
  function getPageIndexes(pageIdx: number, nTotalPages: number) {
22
  let pageIdxs: number[] = [];
23
 
@@ -66,7 +61,7 @@
66
  >
67
  <li>
68
  <PaginationArrow
69
- href={getHref($page.url, pageIndex - 1)}
70
  direction="previous"
71
  isDisabled={pageIndex - 1 < 0}
72
  />
@@ -81,7 +76,7 @@
81
  : ''}
82
  "
83
  class:pointer-events-none={pageIdx === ELLIPSIS_IDX || pageIndex === pageIdx}
84
- href={getHref($page.url, pageIdx)}
85
  >
86
  {pageIdx === ELLIPSIS_IDX ? "..." : pageIdx + 1}
87
  </a>
@@ -89,7 +84,7 @@
89
  {/each}
90
  <li>
91
  <PaginationArrow
92
- href={getHref($page.url, pageIndex + 1)}
93
  direction="next"
94
  isDisabled={pageIndex + 1 >= numTotalPages}
95
  />
 
1
  <script lang="ts">
2
  import { page } from "$app/stores";
3
+ import { getHref } from "$lib/utils/getHref";
4
  import PaginationArrow from "./PaginationArrow.svelte";
5
 
6
  export let classNames = "";
 
13
  $: pageIndex = parseInt($page.url.searchParams.get("p") ?? "0");
14
  $: pageIndexes = getPageIndexes(pageIndex, numTotalPages);
15
 
 
 
 
 
 
 
16
  function getPageIndexes(pageIdx: number, nTotalPages: number) {
17
  let pageIdxs: number[] = [];
18
 
 
61
  >
62
  <li>
63
  <PaginationArrow
64
+ href={getHref($page.url, { newKeys: { p: (pageIndex - 1).toString() } })}
65
  direction="previous"
66
  isDisabled={pageIndex - 1 < 0}
67
  />
 
76
  : ''}
77
  "
78
  class:pointer-events-none={pageIdx === ELLIPSIS_IDX || pageIndex === pageIdx}
79
+ href={getHref($page.url, { newKeys: { p: pageIdx.toString() } })}
80
  >
81
  {pageIdx === ELLIPSIS_IDX ? "..." : pageIdx + 1}
82
  </a>
 
84
  {/each}
85
  <li>
86
  <PaginationArrow
87
+ href={getHref($page.url, { newKeys: { p: (pageIndex + 1).toString() } })}
88
  direction="next"
89
  isDisabled={pageIndex + 1 >= numTotalPages}
90
  />
src/lib/components/chat/AssistantIntroduction.svelte CHANGED
@@ -47,8 +47,7 @@
47
  <p class="pt-2 text-sm text-gray-400 dark:text-gray-500">
48
  Created by <a
49
  class="hover:underline"
50
- href="https://hf.co/{assistant.createdByName}"
51
- target="_blank"
52
  >
53
  {assistant.createdByName}
54
  </a>
 
47
  <p class="pt-2 text-sm text-gray-400 dark:text-gray-500">
48
  Created by <a
49
  class="hover:underline"
50
+ href="{base}/assistants?user={assistant.createdByName}"
 
51
  >
52
  {assistant.createdByName}
53
  </a>
src/lib/utils/getHref.ts ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export function getHref(
2
+ url: URL | string,
3
+ modifications: {
4
+ newKeys?: Record<string, string | undefined | null>;
5
+ existingKeys?: { behaviour: "delete_except" | "delete"; keys: string[] };
6
+ }
7
+ ) {
8
+ const newUrl = new URL(url);
9
+ const { newKeys, existingKeys } = modifications;
10
+
11
+ // exsiting keys logic
12
+ if (existingKeys) {
13
+ const { behaviour, keys } = existingKeys;
14
+ if (behaviour === "delete") {
15
+ for (const key of keys) {
16
+ newUrl.searchParams.delete(key);
17
+ }
18
+ } else {
19
+ // delete_except
20
+ const keysToPreserve = keys;
21
+ for (const key of [...newUrl.searchParams.keys()]) {
22
+ if (!keysToPreserve.includes(key)) {
23
+ newUrl.searchParams.delete(key);
24
+ }
25
+ }
26
+ }
27
+ }
28
+
29
+ // new keys logic
30
+ if (newKeys) {
31
+ for (const [key, val] of Object.entries(newKeys)) {
32
+ if (val) {
33
+ newUrl.searchParams.set(key, val);
34
+ } else {
35
+ newUrl.searchParams.delete(key);
36
+ }
37
+ }
38
+ }
39
+
40
+ return newUrl.toString();
41
+ }
src/routes/assistant/[assistantId]/+page.svelte CHANGED
@@ -73,8 +73,7 @@
73
  <p class="mt-2 text-sm text-gray-500">
74
  Created by <a
75
  class="hover:underline"
76
- href="https://hf.co/{data.assistant.createdByName}"
77
- target="_blank"
78
  >
79
  {data.assistant.createdByName}
80
  </a>
 
73
  <p class="mt-2 text-sm text-gray-500">
74
  Created by <a
75
  class="hover:underline"
76
+ href="{base}/assistants?user={data.assistant.createdByName}"
 
77
  >
78
  {data.assistant.createdByName}
79
  </a>
src/routes/assistants/+page.server.ts CHANGED
@@ -2,7 +2,7 @@ import { base } from "$app/paths";
2
  import { ENABLE_ASSISTANTS } from "$env/static/private";
3
  import { collections } from "$lib/server/database.js";
4
  import type { Assistant } from "$lib/types/Assistant";
5
- import { redirect } from "@sveltejs/kit";
6
  import type { Filter } from "mongodb";
7
 
8
  const NUM_PER_PAGE = 24;
@@ -14,12 +14,21 @@ export const load = async ({ url }) => {
14
 
15
  const modelId = url.searchParams.get("modelId");
16
  const pageIndex = parseInt(url.searchParams.get("p") ?? "0");
 
 
 
 
 
 
 
 
17
 
18
  // fetch the top assistants sorted by user count from biggest to smallest, filter out all assistants with only 1 users. filter by model too if modelId is provided
19
  const filter: Filter<Assistant> = {
20
  userCount: { $gt: 1 },
21
  modelId: modelId ?? { $exists: true },
22
  featured: true,
 
23
  };
24
  const assistants = await collections.assistants
25
  .find(filter)
 
2
  import { ENABLE_ASSISTANTS } from "$env/static/private";
3
  import { collections } from "$lib/server/database.js";
4
  import type { Assistant } from "$lib/types/Assistant";
5
+ import { error, redirect } from "@sveltejs/kit";
6
  import type { Filter } from "mongodb";
7
 
8
  const NUM_PER_PAGE = 24;
 
14
 
15
  const modelId = url.searchParams.get("modelId");
16
  const pageIndex = parseInt(url.searchParams.get("p") ?? "0");
17
+ const createdByName = url.searchParams.get("user");
18
+
19
+ if (createdByName) {
20
+ const existingUser = await collections.users.findOne({ username: createdByName });
21
+ if (!existingUser) {
22
+ throw error(404, `User "${createdByName}" doesn't exist`);
23
+ }
24
+ }
25
 
26
  // fetch the top assistants sorted by user count from biggest to smallest, filter out all assistants with only 1 users. filter by model too if modelId is provided
27
  const filter: Filter<Assistant> = {
28
  userCount: { $gt: 1 },
29
  modelId: modelId ?? { $exists: true },
30
  featured: true,
31
+ ...(createdByName && { createdByName }),
32
  };
33
  const assistants = await collections.assistants
34
  .find(filter)
src/routes/assistants/+page.svelte CHANGED
@@ -10,16 +10,22 @@
10
 
11
  import CarbonAdd from "~icons/carbon/add";
12
  import CarbonHelpFilled from "~icons/carbon/help-filled";
 
 
 
13
  import Pagination from "$lib/components/Pagination.svelte";
 
14
 
15
  export let data: PageData;
16
 
 
 
 
17
  const onModelChange = (e: Event) => {
18
- const newUrl = new URL($page.url);
19
- newUrl.search = ""; // clear searchParams (such as "p" for pagination)
20
- if ((e.target as HTMLSelectElement).value) {
21
- newUrl.searchParams.set("modelId", (e.target as HTMLSelectElement).value);
22
- }
23
  goto(newUrl);
24
  };
25
  </script>
@@ -79,8 +85,60 @@
79
  <CarbonAdd />Create New assistant
80
  </a>
81
  </div>
82
- <div class="mt-10 grid grid-cols-2 gap-3 sm:gap-5 md:grid-cols-3 lg:grid-cols-4">
83
- {#each data.assistants as assistant}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  <a
85
  href="{base}/assistant/{assistant._id}"
86
  class="flex flex-col items-center justify-center overflow-hidden text-balance rounded-xl border bg-gray-50/50 px-4 py-6 text-center shadow hover:bg-gray-50 hover:shadow-inner max-sm:px-4 sm:h-64 sm:pb-4 dark:border-gray-800/70 dark:bg-gray-950/20 dark:hover:bg-gray-950/40"
@@ -110,8 +168,7 @@
110
  <p class="mt-auto pt-2 text-xs text-gray-400 dark:text-gray-500">
111
  Created by <a
112
  class="hover:underline"
113
- href="https://hf.co/{assistant.createdByName}"
114
- target="_blank"
115
  >
116
  {assistant.createdByName}
117
  </a>
 
10
 
11
  import CarbonAdd from "~icons/carbon/add";
12
  import CarbonHelpFilled from "~icons/carbon/help-filled";
13
+ import CarbonClose from "~icons/carbon/close";
14
+ import CarbonArrowUpRight from "~icons/carbon/arrow-up-right";
15
+ import CarbonEarthAmerica from "~icons/carbon/earth-americas-filled";
16
  import Pagination from "$lib/components/Pagination.svelte";
17
+ import { getHref } from "$lib/utils/getHref";
18
 
19
  export let data: PageData;
20
 
21
+ $: assistantsCreator = $page.url.searchParams.get("user");
22
+ $: createdByMe = data.user?.username && data.user.username === assistantsCreator;
23
+
24
  const onModelChange = (e: Event) => {
25
+ const newUrl = getHref($page.url, {
26
+ newKeys: { modelId: (e.target as HTMLSelectElement).value },
27
+ existingKeys: { behaviour: "delete_except", keys: ["user"] },
28
+ });
 
29
  goto(newUrl);
30
  };
31
  </script>
 
85
  <CarbonAdd />Create New assistant
86
  </a>
87
  </div>
88
+
89
+ <div class="mt-7 flex items-center gap-x-2 text-sm">
90
+ {#if assistantsCreator && !createdByMe}
91
+ <div
92
+ class="flex items-center gap-1.5 rounded-full border border-gray-300 bg-gray-50 px-3 py-1 dark:border-gray-600 dark:bg-gray-700 dark:text-white"
93
+ >
94
+ {assistantsCreator}'s Assistants
95
+ <a
96
+ href={getHref($page.url, {
97
+ existingKeys: { behaviour: "delete", keys: ["user", "modelId", "p"] },
98
+ })}
99
+ class="group"
100
+ ><CarbonClose
101
+ class="text-xs group-hover:text-gray-800 dark:group-hover:text-gray-300"
102
+ /></a
103
+ >
104
+ </div>
105
+ {#if isHuggingChat}
106
+ <a
107
+ href="https://hf.co/{assistantsCreator}"
108
+ target="_blank"
109
+ class="ml-auto flex items-center text-xs text-gray-500 underline hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-300"
110
+ ><CarbonArrowUpRight class="mr-1 flex-none text-[0.58rem]" target="_blank" />View {assistantsCreator}
111
+ on HF</a
112
+ >
113
+ {/if}
114
+ {:else if data.user?.username}
115
+ <a
116
+ href={getHref($page.url, {
117
+ existingKeys: { behaviour: "delete", keys: ["user", "modelId", "p"] },
118
+ })}
119
+ class="flex items-center gap-1.5 rounded-full border px-3 py-1 {!assistantsCreator
120
+ ? 'border-gray-300 bg-gray-50 dark:border-gray-600 dark:bg-gray-700 dark:text-white'
121
+ : 'border-transparent text-gray-400 hover:text-gray-800 dark:hover:text-gray-300'}"
122
+ >
123
+ <CarbonEarthAmerica class="text-xs" />
124
+ Community
125
+ </a>
126
+ <a
127
+ href={getHref($page.url, {
128
+ newKeys: { user: data.user.username },
129
+ existingKeys: { behaviour: "delete", keys: ["modelId", "p"] },
130
+ })}
131
+ class="flex items-center gap-1.5 rounded-full border px-3 py-1 {assistantsCreator &&
132
+ createdByMe
133
+ ? 'border-gray-300 bg-gray-50 dark:border-gray-600 dark:bg-gray-700 dark:text-white'
134
+ : 'border-transparent text-gray-400 hover:text-gray-800 dark:hover:text-gray-300'}"
135
+ >{data.user.username}
136
+ </a>
137
+ {/if}
138
+ </div>
139
+
140
+ <div class="mt-8 grid grid-cols-2 gap-3 sm:gap-5 md:grid-cols-3 lg:grid-cols-4">
141
+ {#each data.assistants as assistant (assistant._id)}
142
  <a
143
  href="{base}/assistant/{assistant._id}"
144
  class="flex flex-col items-center justify-center overflow-hidden text-balance rounded-xl border bg-gray-50/50 px-4 py-6 text-center shadow hover:bg-gray-50 hover:shadow-inner max-sm:px-4 sm:h-64 sm:pb-4 dark:border-gray-800/70 dark:bg-gray-950/20 dark:hover:bg-gray-950/40"
 
168
  <p class="mt-auto pt-2 text-xs text-gray-400 dark:text-gray-500">
169
  Created by <a
170
  class="hover:underline"
171
+ href="{base}/assistants?user={assistant.createdByName}"
 
172
  >
173
  {assistant.createdByName}
174
  </a>
src/routes/settings/assistants/[assistantId]/+page.svelte CHANGED
@@ -62,7 +62,7 @@
62
  <p class="text-sm text-gray-500">
63
  Model: <span class="font-semibold"> {assistant?.modelId} </span>
64
  <span class="text-gray-300">•</span> Created by
65
- <a class="underline" target="_blank" href={"https://hf.co/" + assistant?.createdByName}>
66
  {assistant?.createdByName}
67
  </a>
68
  </p>
 
62
  <p class="text-sm text-gray-500">
63
  Model: <span class="font-semibold"> {assistant?.modelId} </span>
64
  <span class="text-gray-300">•</span> Created by
65
+ <a class="underline" href="{base}/assistants?user={assistant?.createdByName}">
66
  {assistant?.createdByName}
67
  </a>
68
  </p>