diff --git a/apps/web/components/dashboard-view.tsx b/apps/web/components/dashboard-view.tsx
index 2632446d..411f0b89 100644
--- a/apps/web/components/dashboard-view.tsx
+++ b/apps/web/components/dashboard-view.tsx
@@ -723,10 +723,16 @@ export function DashboardView({
firstName,
)
+ const [tipIndex, setTipIndex] = useState(0)
+
+ useEffect(() => {
+ setTipIndex(Math.floor(Math.random() * TIPS[profession].length))
+ }, [profession])
+
const tip = useMemo(() => {
const tips = TIPS[profession]
- return tips[Math.floor(Math.random() * tips.length)]
- }, [profession])
+ return tips[tipIndex % tips.length] ?? tips[0]
+ }, [profession, tipIndex])
return (
(
null,
@@ -455,15 +456,19 @@ export function SelectSpacesModal({
return byCategory.filter((p) => {
const plugin = detectPluginSpace(p.containerTag)
const projectName = pluginMetaMap.get(p.containerTag)?.projectName
+ const displayName = spaceSelectorDisplayName(p, p.containerTag, {
+ currentUserId: user?.id,
+ })
return (
p.containerTag.toLowerCase().includes(query) ||
(p.name ?? "").toLowerCase().includes(query) ||
+ displayName.toLowerCase().includes(query) ||
(plugin?.label.toLowerCase().includes(query) ?? false) ||
(plugin?.projectId?.toLowerCase().includes(query) ?? false) ||
(projectName?.toLowerCase().includes(query) ?? false)
)
})
- }, [allSpaces, activeCategory, searchQuery, pluginMetaMap])
+ }, [allSpaces, activeCategory, searchQuery, pluginMetaMap, user?.id])
const recentProjects = useMemo
(() => {
if (!recents?.length) return []
@@ -551,10 +556,12 @@ export function SelectSpacesModal({
)
.map((project) => ({
id: project.id,
- name: project.name ?? project.containerTag,
+ name: spaceSelectorDisplayName(project, project.containerTag, {
+ currentUserId: user?.id,
+ }),
containerTag: project.containerTag,
})),
- [allSpaces, bulkDeleteTags],
+ [allSpaces, bulkDeleteTags, user?.id],
)
const bulkDeleteCount = bulkDeleteProjects.length
@@ -567,8 +574,16 @@ export function SelectSpacesModal({
project.containerTag,
)?.projectName
const pluginIdLabel = pluginProjectName || plugin?.projectId
+ const displayName = spaceSelectorDisplayName(
+ project,
+ project.containerTag,
+ {
+ currentUserId: user?.id,
+ },
+ )
const isDefault = project.containerTag === DEFAULT_PROJECT_ID
- const canEdit = !isDefault && !plugin
+ const isOwnSpace = isOwnConversationSpace(project, user?.id)
+ const canEdit = !isDefault && !plugin && !isOwnSpace
const canBulkDelete = enableDelete && !isDefault
const isEditing = editingProject?.containerTag === project.containerTag
const isBulkDeleteSelected = bulkDeleteTags.has(project.containerTag)
@@ -697,7 +712,7 @@ export function SelectSpacesModal({
)}
{plugin ? (
<>
@@ -709,7 +724,7 @@ export function SelectSpacesModal({
)}
>
) : (
- spaceSelectorDisplayName(project, project.containerTag)
+ displayName
)}
@@ -738,7 +753,7 @@ export function SelectSpacesModal({
e.stopPropagation()
onDeleteRequest({
id: project.id,
- name: project.name ?? project.containerTag,
+ name: displayName,
containerTag: project.containerTag,
})
}}
@@ -766,6 +781,7 @@ export function SelectSpacesModal({
startEditing,
toggleBulkDeleteTag,
updateProjectMutation.isPending,
+ user?.id,
],
)
diff --git a/apps/web/components/space-selector.tsx b/apps/web/components/space-selector.tsx
index 689219b1..40d5947e 100644
--- a/apps/web/components/space-selector.tsx
+++ b/apps/web/components/space-selector.tsx
@@ -31,6 +31,7 @@ import {
} from "@repo/ui/components/select"
import { Button } from "@repo/ui/components/button"
import { Tooltip, TooltipContent, TooltipTrigger } from "@ui/components/tooltip"
+import { useAuth } from "@lib/auth-context"
import { analytics } from "@/lib/analytics"
import {
compareSpacesUserFirst,
@@ -135,6 +136,7 @@ export function SpaceSelector({
const { deleteProjectMutation, deleteProjectsMutation } =
useProjectMutations()
const { allProjects, isLoading } = useContainerTags()
+ const { user } = useAuth()
useEffect(() => {
setRecents(readRecents())
@@ -199,12 +201,14 @@ export function SpaceSelector({
? idForLabel
? `${plugin.label} ยท ${idForLabel}`
: plugin.label
- : spaceSelectorDisplayName(found, containerTag),
+ : spaceSelectorDisplayName(found, containerTag, {
+ currentUserId: user?.id,
+ }),
emoji: found?.emoji || "๐",
plugin,
isAuto: false,
}
- }, [allProjects, selectedProjects, pluginMetaMap, includeAuto])
+ }, [allProjects, selectedProjects, pluginMetaMap, includeAuto, user?.id])
const pushRecent = useCallback((tag: string) => {
setRecents((prev) => {
@@ -615,7 +619,13 @@ export function SpaceSelector({
)}
>
) : (
- spaceSelectorDisplayName(p, p.containerTag)
+ spaceSelectorDisplayName(
+ p,
+ p.containerTag,
+ {
+ currentUserId: user?.id,
+ },
+ )
)}
diff --git a/apps/web/hooks/use-personalization.ts b/apps/web/hooks/use-personalization.ts
index 256fab3c..619b3ac2 100644
--- a/apps/web/hooks/use-personalization.ts
+++ b/apps/web/hooks/use-personalization.ts
@@ -2,7 +2,7 @@
import { useState, useEffect, useCallback } from "react"
import { $fetch } from "@lib/api"
-import type { SearchResult } from "@repo/lib/api"
+import type { SearchResult } from "@repo/validation/api"
const CACHE_KEY = "sm_profession_v1"
const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000
@@ -235,6 +235,15 @@ function pickCopy(p: Profession): PersonalizedCopy {
}
}
+function defaultCopy(p: Profession): PersonalizedCopy {
+ const pool = COPY_POOLS[p]
+ return {
+ saveLink: pool.saveLink[0] ?? "",
+ writeNote: pool.writeNote[0] ?? "",
+ chatPlaceholder: pool.chatPlaceholder[0] ?? "",
+ }
+}
+
const sessionCopyCache: Partial> = {}
function getSessionCopy(p: Profession): PersonalizedCopy {
@@ -398,7 +407,7 @@ export function usePersonalization(): {
setProfession: (p: Profession) => void
} {
const [copy, setCopy] = useState(() =>
- getSessionCopy("default"),
+ defaultCopy("default"),
)
const [profession, setProfessionState] = useState("default")
@@ -410,8 +419,9 @@ export function usePersonalization(): {
)
} catch {}
// Re-pick on explicit change so the user sees fresh copy for the new identity
- sessionCopyCache[p] = pickCopy(p)
- setCopy(sessionCopyCache[p]!)
+ const freshCopy = pickCopy(p)
+ sessionCopyCache[p] = freshCopy
+ setCopy(freshCopy)
setProfessionState(p)
}, [])
diff --git a/apps/web/lib/ingest-auto-space.ts b/apps/web/lib/ingest-auto-space.ts
index 9768a27e..3f38a85a 100644
--- a/apps/web/lib/ingest-auto-space.ts
+++ b/apps/web/lib/ingest-auto-space.ts
@@ -1,6 +1,8 @@
import { DEFAULT_PROJECT_ID } from "@lib/constants"
import type { ContainerTagListType } from "@lib/types"
+export const OWN_CONVERSATIONS_SPACE_NAME = "Your conversations"
+
/**
* Spaces auto-created on first ingest use `name === \`Space ${containerTag}\``
* (mono `apps/api/src/routes/memories/handler-effect.ts`). Those are noisy in the
@@ -24,10 +26,22 @@ export function compareSpacesUserFirst(
)
}
+export function isOwnConversationSpace(
+ p: Pick | undefined,
+ currentUserId?: string | null,
+): boolean {
+ return !!currentUserId && p?.containerTag === currentUserId
+}
+
export function spaceSelectorDisplayName(
p: Pick | undefined,
fallback: string,
+ options?: { currentUserId?: string | null },
): string {
+ const containerTag = p?.containerTag ?? fallback
+ if (containerTag === options?.currentUserId) {
+ return OWN_CONVERSATIONS_SPACE_NAME
+ }
if (!p) return fallback
const name = p.name ?? p.containerTag
const long = name.length > 44