mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-07 02:58:11 +00:00
fix(web): clear the 84 type errors blocking check-types
`apps/web` extends a tsconfig with `noUncheckedIndexedAccess`, so index
access and a few genuine defects had accumulated behind a gate that has
never been green.
Most of it traced to one expression: `useProject().selectedProject` was
`normalizedProjects[0]`, typed `string | undefined` even though the array is
never empty. Defaulting it to the same tag the array falls back to fixed ~20
errors across chat, add-document, app-experience, quick-note-card and the
note modals in one line.
The rest:
- orbit-memory: type `ring` as `0 | 1` and RR/SPEED as tuples so ring lookups
stay `number`, iterate INTEG with `.entries()`, guard the comet refs, and
fall back to an empty icon when a node has no key
- memory-graph `use-graph-data` and `graph-card`: iterate with `.entries()`
and skip edges whose endpoints are missing instead of indexing blind
- chat history buckets and user initials: optional access on fixed-shape
arrays that TypeScript cannot narrow
- `stores/chat`: drop the `msgA.content !== msgB.content` comparison —
UIMessage keeps its text in `parts`, so both sides were always undefined —
and type the conversations fallback so entries aren't `unknown`
- `useResetOrganization`: `retry: 0`, since the object form of RetryOptions
needs type/baseDelay/maxDelay
- SyncLogoIcon: accept the `style` prop timeline-view already passes it
One real bug surfaced on the way: the iOS-shortcut mutation in settings
returned `res.key` from `authClient.apiKey.create()`, which resolves to
`{ data, error }`. The key was always undefined, so the modal showed nothing
and the clipboard copy had nothing to copy. It now unwraps the result the same
way the Raycast mutation right below it does.
This commit is contained in:
parent
18a2dfbe39
commit
f0baf904ff
10 changed files with 67 additions and 50 deletions
|
|
@ -1612,11 +1612,11 @@ export function ChatSidebar({
|
|||
]
|
||||
for (const t of filtered) {
|
||||
const ts = new Date(t.updatedAt).getTime()
|
||||
if (ts >= startOfToday) buckets[0].items.push(t)
|
||||
else if (ts >= startOfToday - day) buckets[1].items.push(t)
|
||||
else if (ts >= startOfToday - 7 * day) buckets[2].items.push(t)
|
||||
else if (ts >= startOfToday - 30 * day) buckets[3].items.push(t)
|
||||
else buckets[4].items.push(t)
|
||||
if (ts >= startOfToday) buckets[0]?.items.push(t)
|
||||
else if (ts >= startOfToday - day) buckets[1]?.items.push(t)
|
||||
else if (ts >= startOfToday - 7 * day) buckets[2]?.items.push(t)
|
||||
else if (ts >= startOfToday - 30 * day) buckets[3]?.items.push(t)
|
||||
else buckets[4]?.items.push(t)
|
||||
}
|
||||
return buckets.filter((b) => b.items.length > 0)
|
||||
}, [threads, historySearch])
|
||||
|
|
|
|||
|
|
@ -67,15 +67,13 @@ export function StaticGraphPreview({
|
|||
const result: { x1: number; y1: number; x2: number; y2: number }[] = []
|
||||
const edgeCount = Math.min(nodes.length - 1, 20)
|
||||
for (let i = 0; i < edgeCount; i++) {
|
||||
const a = Math.floor(rand() * nodes.length)
|
||||
let b = Math.floor(rand() * nodes.length)
|
||||
if (b === a) b = (a + 1) % nodes.length
|
||||
result.push({
|
||||
x1: nodes[a]?.x,
|
||||
y1: nodes[a]?.y,
|
||||
x2: nodes[b]?.x,
|
||||
y2: nodes[b]?.y,
|
||||
})
|
||||
const aIdx = Math.floor(rand() * nodes.length)
|
||||
let bIdx = Math.floor(rand() * nodes.length)
|
||||
if (bIdx === aIdx) bIdx = (aIdx + 1) % nodes.length
|
||||
const a = nodes[aIdx]
|
||||
const b = nodes[bIdx]
|
||||
if (!a || !b) continue
|
||||
result.push({ x1: a.x, y1: a.y, x2: b.x, y2: b.y })
|
||||
}
|
||||
return result
|
||||
}, [nodes])
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const INTEG: {
|
|||
key?: string
|
||||
label?: string
|
||||
sub?: string
|
||||
ring: number
|
||||
ring: 0 | 1
|
||||
ang: number
|
||||
size: number
|
||||
dim: boolean
|
||||
|
|
@ -76,8 +76,8 @@ const DW = 780
|
|||
const DH = 1024
|
||||
const CX = 390
|
||||
const CY = 512
|
||||
const RR = [200, 335]
|
||||
const SPEED = [1.0, 0.78]
|
||||
const RR: [number, number] = [200, 335]
|
||||
const SPEED: [number, number] = [1.0, 0.78]
|
||||
const DRAW: [number, number, number, string][] = [
|
||||
[125, 0.28, 1.7, "#74a8f6"],
|
||||
[200, 0.18, 1.9, "#4389ff"],
|
||||
|
|
@ -167,16 +167,15 @@ export default function OrbitMemory({
|
|||
track.setAttribute("stroke-opacity", "0")
|
||||
dtrack.setAttribute("stroke-opacity", "0")
|
||||
for (let k = 0; k < NC; k++) {
|
||||
cms[k].setAttribute("opacity", "0")
|
||||
cmgs[k].setAttribute("opacity", "0")
|
||||
oms[k].setAttribute("opacity", "0")
|
||||
omgs[k].setAttribute("opacity", "0")
|
||||
cms[k]?.setAttribute("opacity", "0")
|
||||
cmgs[k]?.setAttribute("opacity", "0")
|
||||
oms[k]?.setAttribute("opacity", "0")
|
||||
omgs[k]?.setAttribute("opacity", "0")
|
||||
}
|
||||
}
|
||||
let angle = 0
|
||||
const place = () => {
|
||||
for (let i = 0; i < INTEG.length; i++) {
|
||||
const it = INTEG[i]
|
||||
for (const [i, it] of INTEG.entries()) {
|
||||
const a = ((it.ang + angle * SPEED[it.ring]) * Math.PI) / 180
|
||||
const R = RR[it.ring]
|
||||
const ux = CX + R * Math.cos(a)
|
||||
|
|
@ -199,8 +198,8 @@ export default function OrbitMemory({
|
|||
const DISC = 700
|
||||
const INN: number[] = []
|
||||
const OUT: number[] = []
|
||||
for (let i = 0; i < INTEG.length; i++) {
|
||||
;(INTEG[i].ring === 0 ? INN : OUT).push(i)
|
||||
for (const [i, it] of INTEG.entries()) {
|
||||
;(it.ring === 0 ? INN : OUT).push(i)
|
||||
}
|
||||
let phase = "orbit"
|
||||
let pT0 = 0
|
||||
|
|
@ -259,12 +258,16 @@ export default function OrbitMemory({
|
|||
const ay = pyc - uy * HL
|
||||
const bx = pxc + ux * HL
|
||||
const by = pyc + uy * HL
|
||||
setLine(gr[k], ax, ay, bx, by)
|
||||
setLine(cr[k], ax, ay, bx, by)
|
||||
setLine(gl[k], ax, ay, bx, by)
|
||||
const grad = gr[k]
|
||||
const comet = cr[k]
|
||||
const glow = gl[k]
|
||||
if (!grad || !comet || !glow) continue
|
||||
setLine(grad, ax, ay, bx, by)
|
||||
setLine(comet, ax, ay, bx, by)
|
||||
setLine(glow, ax, ay, bx, by)
|
||||
const o = Math.sin(f * Math.PI) * P
|
||||
cr[k].setAttribute("opacity", o.toFixed(2))
|
||||
gl[k].setAttribute("opacity", (0.6 * o).toFixed(2))
|
||||
comet.setAttribute("opacity", o.toFixed(2))
|
||||
glow.setAttribute("opacity", (0.6 * o).toFixed(2))
|
||||
}
|
||||
}
|
||||
const frame = (now: number) => {
|
||||
|
|
@ -276,13 +279,13 @@ export default function OrbitMemory({
|
|||
if (phase === "orbit" && pt > ORBIT) {
|
||||
phase = "receive"
|
||||
pT0 = now
|
||||
src = INN[(ci * 5) % INN.length]
|
||||
dst = OUT[(ci * 7) % OUT.length]
|
||||
src = INN[(ci * 5) % INN.length] ?? 0
|
||||
dst = OUT[(ci * 7) % OUT.length] ?? 0
|
||||
ci++
|
||||
nodes[src]?.classList.add("sm-active")
|
||||
stage.style.setProperty(
|
||||
"--cm",
|
||||
`rgb(${ACCENT[INTEG[src].key!] || "91,157,255"})`,
|
||||
`rgb(${ACCENT[INTEG[src]?.key ?? ""] || "91,157,255"})`,
|
||||
)
|
||||
} else if (phase === "receive" && pt > RECV) {
|
||||
phase = "send"
|
||||
|
|
@ -318,8 +321,8 @@ export default function OrbitMemory({
|
|||
seg(
|
||||
now,
|
||||
track,
|
||||
INTEG[src]._x!,
|
||||
INTEG[src]._y!,
|
||||
INTEG[src]?._x ?? 0,
|
||||
INTEG[src]?._y ?? 0,
|
||||
ps,
|
||||
grads,
|
||||
cms,
|
||||
|
|
@ -330,8 +333,8 @@ export default function OrbitMemory({
|
|||
seg(
|
||||
now,
|
||||
dtrack,
|
||||
INTEG[dst]._x!,
|
||||
INTEG[dst]._y!,
|
||||
INTEG[dst]?._x ?? 0,
|
||||
INTEG[dst]?._y ?? 0,
|
||||
pd,
|
||||
ogrs,
|
||||
oms,
|
||||
|
|
@ -508,7 +511,9 @@ export default function OrbitMemory({
|
|||
<span
|
||||
className="sm-glyph"
|
||||
// biome-ignore lint/security/noDangerouslySetInnerHtml: static, vetted inline brand SVG markup
|
||||
dangerouslySetInnerHTML={{ __html: ICONS[it.key!] }}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: (it.key && ICONS[it.key]) || "",
|
||||
}}
|
||||
/>
|
||||
<span className="sm-gsub">{it.sub}</span>
|
||||
</span>
|
||||
|
|
@ -518,7 +523,9 @@ export default function OrbitMemory({
|
|||
<span
|
||||
className="sm-glyph"
|
||||
// biome-ignore lint/security/noDangerouslySetInnerHtml: static, vetted inline brand SVG markup
|
||||
dangerouslySetInnerHTML={{ __html: ICONS[it.key!] }}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: (it.key && ICONS[it.key]) || "",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -152,7 +152,10 @@ export default function Integrations() {
|
|||
name: `ios-${generateId().slice(0, 8)}`,
|
||||
prefix: `sm_${org?.id}_`,
|
||||
})
|
||||
return res.key
|
||||
if (res.error)
|
||||
throw new Error(res.error.message ?? "Failed to create API key")
|
||||
if (!res.data?.key) throw new Error("API key missing from response")
|
||||
return res.data.key
|
||||
},
|
||||
onSuccess: (key) => {
|
||||
setApiKey(key)
|
||||
|
|
|
|||
|
|
@ -79,9 +79,11 @@ export function UserProfileMenu({
|
|||
const initials = (() => {
|
||||
if (user.name) {
|
||||
const parts = user.name.trim().split(/\s+/)
|
||||
const first = parts[0] ?? ""
|
||||
const last = parts[parts.length - 1] ?? ""
|
||||
return parts.length >= 2
|
||||
? `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase()
|
||||
: parts[0].slice(0, 2).toUpperCase()
|
||||
? `${first.slice(0, 1)}${last.slice(0, 1)}`.toUpperCase()
|
||||
: first.slice(0, 2).toUpperCase()
|
||||
}
|
||||
if (user.email) return user.email.slice(0, 2).toUpperCase()
|
||||
return "SM"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export function useResetOrganization() {
|
|||
mutationFn: async (body: { confirmation: string }) => {
|
||||
const res = await $fetch("@post/settings/reset", {
|
||||
body,
|
||||
retry: { attempts: 0 },
|
||||
retry: 0,
|
||||
})
|
||||
if (res.error) {
|
||||
const e = res.error as Record<string, unknown>
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ export function areUIMessageArraysEqual(
|
|||
return false
|
||||
}
|
||||
|
||||
if (msgA.content !== msgB.content) return false
|
||||
|
||||
if (JSON.stringify(msgA.parts) !== JSON.stringify(msgB.parts)) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -202,7 +200,8 @@ export function usePersistentChat() {
|
|||
)
|
||||
|
||||
const conversations: ConversationSummary[] = (() => {
|
||||
const convs = projectState?.conversations ?? {}
|
||||
const convs: Record<string, ConversationRecord> =
|
||||
projectState?.conversations ?? {}
|
||||
return Object.entries(convs).map(([id, rec]) => ({
|
||||
id,
|
||||
title: rec.title,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export function useProject() {
|
|||
const normalizedProjects =
|
||||
selectedProjects.length === 0 ? [defaultTag] : selectedProjects
|
||||
|
||||
const selectedProject = normalizedProjects[0]
|
||||
const selectedProject = normalizedProjects[0] ?? defaultTag
|
||||
|
||||
const effectiveContainerTags = normalizedProjects
|
||||
|
||||
|
|
|
|||
|
|
@ -507,8 +507,7 @@ export function useGraphData(
|
|||
// Golden angle (~137.5 deg) produces optimal packing in a spiral
|
||||
const goldenAngle = Math.PI * (3 - Math.sqrt(5))
|
||||
|
||||
for (let docIdx = 0; docIdx < docCount; docIdx++) {
|
||||
const doc = documents[docIdx]
|
||||
for (const [docIdx, doc] of documents.entries()) {
|
||||
const docCluster = getDocumentClusterAssignment(doc, clusterAssignments)
|
||||
const angle = docIdx * goldenAngle
|
||||
const radius = spiralScale * Math.sqrt((docIdx + 1) / docCount)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import type { CSSProperties } from "react"
|
||||
|
||||
export const OneDrive = ({ className }: { className?: string }) => (
|
||||
<svg
|
||||
className={className}
|
||||
|
|
@ -237,7 +239,13 @@ export const PDF = ({ className }: { className?: string }) => (
|
|||
</svg>
|
||||
)
|
||||
|
||||
export const SyncLogoIcon = ({ className }: { className?: string }) => {
|
||||
export const SyncLogoIcon = ({
|
||||
className,
|
||||
style,
|
||||
}: {
|
||||
className?: string
|
||||
style?: CSSProperties
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
width="11"
|
||||
|
|
@ -246,6 +254,7 @@ export const SyncLogoIcon = ({ className }: { className?: string }) => {
|
|||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<title>Sync Logo</title>
|
||||
<g clipPath="url(#clip0_344_4856)">
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue