fix: remaining dependabot security issues (#890)

* Upgrade docs deps

* Upgrade frontend to latest deps

* Update package overrides

* Remove redundant deps

* Add tailwind postcss plugin

* Replace language select with chakra

* Fix main nav

* Patch gray matter

* Fix webpack override

* Replace python-jose with pyjwt

* Override kv url for frontend in compose

* Upgrade hatchet sdk

* Update docs

* Supress pydantic warnings
This commit is contained in:
Sergey Mankovsky
2026-03-02 17:17:40 +01:00
committed by GitHub
parent 4d915e2a9f
commit 0931095f49
34 changed files with 20117 additions and 26696 deletions

View File

@@ -1,10 +1,8 @@
import { Container, Flex } from "@chakra-ui/react";
import { featureEnabled } from "../lib/features";
import NextLink from "next/link";
import Image from "next/image";
import UserInfo from "../(auth)/userInfo";
import AuthWrapper from "./AuthWrapper";
import { RECORD_A_MEETING_URL } from "../api/urls";
import MainNav from "../components/MainNav";
export default async function AppLayout({
children,
@@ -47,44 +45,7 @@ export default async function AppLayout({
</p>
</div>
</NextLink>
<div>
{/* Text link on the right */}
<NextLink href={RECORD_A_MEETING_URL} className="font-light px-2">
Create
</NextLink>
{featureEnabled("browse") ? (
<>
&nbsp;·&nbsp;
<NextLink href="/browse" className="font-light px-2">
Browse
</NextLink>
</>
) : (
<></>
)}
{featureEnabled("rooms") ? (
<>
&nbsp;·&nbsp;
<NextLink href="/rooms" className="font-light px-2">
Rooms
</NextLink>
</>
) : (
<></>
)}
{featureEnabled("requireLogin") ? (
<>
&nbsp;·&nbsp;
<NextLink href="/settings/api-keys" className="font-light px-2">
Settings
</NextLink>
&nbsp;·&nbsp;
<UserInfo />
</>
) : (
<></>
)}
</div>
<MainNav />
</Flex>
<AuthWrapper>{children}</AuthWrapper>

View File

@@ -1,13 +1,11 @@
"use client";
import React, { useEffect, useState } from "react";
import useAudioDevice from "../useAudioDevice";
import "react-select-search/style.css";
import "../../../styles/form.scss";
import About from "../../../(aboutAndPrivacy)/about";
import Privacy from "../../../(aboutAndPrivacy)/privacy";
import { useRouter } from "next/navigation";
import useCreateTranscript from "../createTranscript";
import SelectSearch from "react-select-search";
import { supportedLanguages } from "../../../supportedLanguages";
import {
Flex,
@@ -21,6 +19,7 @@ import {
} from "@chakra-ui/react";
import { useAuth } from "../../../lib/AuthProvider";
import { featureEnabled } from "../../../lib/features";
import { SearchableLanguageSelect } from "../../../components/SearchableLanguageSelect";
const TranscriptCreate = () => {
const router = useRouter();
@@ -147,31 +146,27 @@ const TranscriptCreate = () => {
p={8}
flexDir="column"
my={4}
className="form-on-primary"
>
<Heading size="xl" mb={4}>
Try Reflector
</Heading>
<Box mb={4}>
<Text>Recording name</Text>
<div className="select-search-container">
<input
className="select-search-input"
type="text"
onChange={nameChange}
placeholder="Optional"
/>
</div>
<Text mb={1}>Recording name</Text>
<input
className="form-field-input"
type="text"
onChange={nameChange}
placeholder="Optional"
/>
</Box>
<Box mb={4}>
<Text>Do you want to enable live translation?</Text>
<SelectSearch
search
<Text mb={1}>Do you want to enable live translation?</Text>
<SearchableLanguageSelect
options={supportedLanguages}
value={targetLanguage}
onChange={onLanguageChange}
onBlur={() => {}}
onFocus={() => {}}
placeholder="Choose your language"
placeholder="No translation"
/>
</Box>
{!loading ? (

View File

@@ -0,0 +1,46 @@
import NextLink from "next/link";
import { featureEnabled } from "../lib/features";
import UserInfo from "../(auth)/userInfo";
import { RECORD_A_MEETING_URL } from "../api/urls";
function NavLink({
href,
children,
}: {
href: string;
children: React.ReactNode;
}) {
return (
<NextLink href={href} className="font-light px-10">
{children}
</NextLink>
);
}
export default function MainNav() {
return (
<nav>
<NavLink href={RECORD_A_MEETING_URL}>Create</NavLink>
{featureEnabled("browse") && (
<>
&nbsp;·&nbsp;
<NavLink href="/browse">Browse</NavLink>
</>
)}
{featureEnabled("rooms") && (
<>
&nbsp;·&nbsp;
<NavLink href="/rooms">Rooms</NavLink>
</>
)}
{featureEnabled("requireLogin") && (
<>
&nbsp;·&nbsp;
<NavLink href="/settings/api-keys">Settings</NavLink>
&nbsp;·&nbsp;
<UserInfo />
</>
)}
</nav>
);
}

View File

@@ -0,0 +1,98 @@
"use client";
import React, { useMemo } from "react";
import {
Combobox,
createListCollection,
useComboboxContext,
} from "@chakra-ui/react";
export type LangOption = { value: string | undefined; name: string };
type Item = { label: string; value: string };
function FilteredComboboxItems({ items }: { items: Item[] }) {
const ctx = useComboboxContext();
const inputValue = (ctx as { inputValue?: string }).inputValue ?? "";
const filtered = useMemo(() => {
const q = inputValue.trim().toLowerCase();
if (!q) return items;
return items.filter((item) => item.label.toLowerCase().includes(q));
}, [items, inputValue]);
return (
<>
<Combobox.Empty>No matches</Combobox.Empty>
{filtered.map((item) => (
<Combobox.Item key={item.value} item={item}>
{item.label}
</Combobox.Item>
))}
</>
);
}
type Props = {
options: LangOption[];
value: string;
onChange: (value: string) => void;
placeholder: string;
};
export function SearchableLanguageSelect({
options,
value,
onChange,
placeholder,
}: Props) {
const items = useMemo(() => {
const result: Item[] = [];
let addedNone = false;
for (const opt of options) {
const val = opt.value ?? "NOTRANSLATION";
if (val === "NOTRANSLATION" || val === "") {
if (addedNone) continue;
addedNone = true;
result.push({ label: "No translation", value: "NOTRANSLATION" });
} else {
result.push({ label: opt.name, value: val });
}
}
return result.sort((a, b) => {
if (a.value === "NOTRANSLATION") return -1;
if (b.value === "NOTRANSLATION") return 1;
return a.label.localeCompare(b.label);
});
}, [options]);
const collection = useMemo(() => createListCollection({ items }), [items]);
const selectedValues = value && value !== "NOTRANSLATION" ? [value] : [];
return (
<Combobox.Root
collection={collection}
value={selectedValues}
onValueChange={(e) => onChange(e.value[0] ?? "NOTRANSLATION")}
openOnClick
closeOnSelect
selectionBehavior="replace"
placeholder={placeholder}
className="form-combobox"
size="md"
positioning={{ strategy: "fixed", hideWhenDetached: true }}
>
<Combobox.Control>
<Combobox.Input />
<Combobox.IndicatorGroup>
<Combobox.Trigger />
</Combobox.IndicatorGroup>
</Combobox.Control>
<Combobox.Positioner>
<Combobox.Content>
<FilteredComboboxItems items={items} />
</Combobox.Content>
</Combobox.Positioner>
</Combobox.Root>
);
}

View File

@@ -1,42 +1,74 @@
@media (prefers-color-scheme: dark) {
.select-search-container,
.input-container {
--select-search-background: #fff;
--select-search-border: #dce0e8;
--select-search-selected: #1e66f5;
--select-search-text: #000;
--select-search-subtle-text: #6c6f85;
--select-search-highlight: #eff1f5;
/* Form fields on primary (blue) card white inputs like previous react-select */
.form-on-primary {
--form-bg: #fff;
--form-border: #dce0e8;
--form-focus-border: #1e66f5;
--form-text: #000;
--form-placeholder: #6c6f85;
--form-option-bg: #fff;
--form-option-hover: #eff1f5;
--form-dropdown-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
--form-radius: 0.5rem; /* 8px, matches rounded-lg elsewhere */
}
.form-on-primary .form-field-input,
.form-on-primary .form-field-select,
.form-on-primary .form-field-search-input {
box-sizing: border-box;
width: 100%;
padding: 0.5rem 0.75rem;
border-radius: var(--form-radius);
border: 1px solid var(--form-border);
background-color: var(--form-bg);
color: var(--form-text);
font-size: 0.9375rem;
outline: none;
cursor: pointer;
&::placeholder {
color: var(--form-placeholder);
}
&:focus {
border-color: var(--form-focus-border);
}
}
body.is-dark-mode .select-search-container,
body.is-dark-mode .input-container {
--select-search-background: #fff;
--select-search-border: #dce0e8;
--select-search-selected: #1e66f5;
--select-search-text: #000;
--select-search-subtle-text: #6c6f85;
--select-search-highlight: #eff1f5;
.form-on-primary .form-field-select option {
background: var(--form-option-bg);
color: var(--form-text);
}
body.is-light-mode .select-search-container,
body.is-light-mode .input-container {
--select-search-background: #fff;
--select-search-border: #dce0e8;
--select-search-selected: #1e66f5;
--select-search-text: #000;
--select-search-subtle-text: #6c6f85;
--select-search-highlight: #eff1f5;
}
/* Chakra Combobox inside form-on-primary: white input + dropdown, dark text */
.form-on-primary .form-combobox {
width: 100%;
.input-container,
.select-search-container {
max-width: 100%;
width: auto;
}
[data-part="control"],
& input {
border-radius: var(--form-radius);
border-color: var(--form-border);
background-color: var(--form-bg);
color: var(--form-text);
body .select-search-container .select-search--top.select-search-select {
top: auto;
bottom: 46px;
&:focus,
&[data-focus] {
border-color: var(--form-focus-border);
}
}
[data-part="content"] {
border-radius: var(--form-radius);
border: 1px solid var(--form-border);
background: var(--form-bg);
box-shadow: var(--form-dropdown-shadow);
color: var(--form-text);
}
[data-part="item"] {
color: var(--form-text);
&:hover {
background: var(--form-option-hover);
}
}
}