Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot] 9d4d26517b ⬆️(dependencies) update python dependencies 2026-03-23 01:07:12 +00:00
37 changed files with 2012 additions and 1427 deletions
-9
View File
@@ -13,15 +13,6 @@ and this project adheres to
- ✨(back) add projects with custom LLM instructions
- ✨(front) projects management UI
### Changed
- ⬆️(dependencies) upgrade Next.js 15 to 16, upgrade python dependencies
### Fixed
- 🐛(back) add missing color option for project colors
- 💄(project) ui fix project
## [0.0.14] - 2026-03-11
### Added
@@ -87,7 +87,6 @@ class Migration(migrations.Migration):
("color_7", "Color 7"),
("color_8", "Color 8"),
("color_9", "Color 9"),
("color_10", "Color 10"),
],
help_text="Project icon color",
max_length=20,
-1
View File
@@ -52,7 +52,6 @@ class ChatProjectColor(models.TextChoices):
COLOR_7 = "color_7", "Color 7"
COLOR_8 = "color_8", "Color 8"
COLOR_9 = "color_9", "Color 9"
COLOR_10 = "color_10", "Color 10"
class ChatProject(BaseModel):
@@ -78,24 +78,6 @@ def test_create_project_with_llm_instructions(api_client):
assert project.llm_instructions == "Always answer in French."
@pytest.mark.parametrize("color", ChatProjectColor)
def test_create_project_with_each_color(api_client, color):
"""Test creating a project with each available color."""
user = UserFactory()
url = "/api/v1.0/projects/"
data = {
"title": "Color Project",
"icon": ChatProjectIcon.FOLDER,
"color": color,
}
api_client.force_login(user)
response = api_client.post(url, data, format="json")
assert response.status_code == status.HTTP_201_CREATED
project = ChatProject.objects.get(id=response.data["id"])
assert project.color == color
def test_create_project_anonymous(api_client):
"""Test creating a project as an anonymous user returns a 401 error."""
url = "/api/v1.0/projects/"
-1
View File
@@ -368,7 +368,6 @@ class Base(BraveSettings, Configuration):
"django.contrib.staticfiles",
# OIDC third party
"mozilla_django_oidc",
"lasuite.malware_detection",
]
# Cache
+30 -31
View File
@@ -23,15 +23,15 @@ description = "An application to chat with your own AI."
keywords = ["Django", "AI", "Chatbot", "OpenAI", "Pydantic AI", "Conversations"]
license = { file = "LICENSE" }
readme = "README.md"
requires-python = "~=3.13.0"
requires-python = "~=3.14.3"
dependencies = [
"deprecated",
"beautifulsoup4==4.14.2",
"boto3==1.40.73",
"beautifulsoup4==4.14.3",
"boto3==1.42.68",
"Brotli==1.2.0",
"django-configurations==2.5.1",
"django-cors-headers==4.9.0",
"django-countries==8.1.0",
"django-countries==8.2.0",
"django-filter==25.2",
"django-lasuite[all]==0.0.25",
"django-parler==2.3",
@@ -39,35 +39,35 @@ dependencies = [
"django-redis==6.0.0",
"django-storages[s3]==1.14.6",
"django-timezone-field>=5.1",
"django==5.2.12",
"django==6.0.3",
"djangorestframework==3.16.1",
"drf_spectacular==0.29.0",
"dockerflow==2024.4.2",
"dockerflow==2026.3.4",
"easy_thumbnails==2.10.1",
"factory_boy==3.3.3",
"gunicorn==23.0.0",
"gunicorn==25.1.0",
"jaraco.context>=6.1.0",
"jsonschema==4.25.1",
"langfuse==3.10.0",
"jsonschema==4.26.0",
"langfuse==4.0.0",
"lxml==5.4.0",
"markdown==3.10",
"markdown==3.10.2",
"markitdown==0.0.2",
"mozilla-django-oidc==4.0.1",
"mozilla-django-oidc==5.0.2",
"nested-multipart-parser==1.6.0",
"posthog==7.0.0",
"pydantic==2.12.4",
"pydantic-ai-slim[openai,mistral,mcp,evals,logfire]==1.62.0",
"psycopg[binary]==3.2.12",
"PyJWT==2.12.0",
"posthog==7.9.12",
"pydantic==2.12.5",
"pydantic-ai-slim[openai,mistral,mcp,evals,logfire]==1.68.0",
"psycopg[binary]==3.3.3",
"PyJWT==2.10.1",
"python-magic==0.4.27",
"redis<6.0.0",
"requests==2.32.5",
"semchunk==3.2.5",
"sentry-sdk==2.44.0",
"sentry-sdk==2.54.0",
"trafilatura==2.0.0",
"uvicorn==0.38.0",
"whitenoise==6.11.0",
"pypdf==6.9.1",
"uvicorn==0.41.0",
"whitenoise==6.12.0",
"pypdf==6.8.0",
]
[project.urls]
@@ -78,27 +78,27 @@ dependencies = [
[project.optional-dependencies]
dev = [
"dirty-equals==0.10.0",
"dirty-equals==0.11",
"django-extensions==4.1",
"django-test-migrations==1.5.0",
"drf-spectacular-sidecar==2025.10.1",
"drf-spectacular-sidecar==2026.3.1",
"freezegun==1.5.5",
"ipdb==0.13.13",
"ipython==9.7.0",
"pyfakefs==5.10.2",
"pylint-django==2.6.1",
"ipython==9.11.0",
"pyfakefs==6.1.5",
"pylint-django==2.7.0",
"pylint==3.3.9",
"pylint-pydantic==0.4.1",
"pytest-asyncio==1.3.0",
"pytest-cov==7.0.0",
"pytest-django==4.11.1",
"pytest==9.0.1",
"pytest-django==4.12.0",
"pytest==9.0.2",
"pytest-icdiff==0.9",
"pytest-xdist==3.8.0",
"responses==0.25.8",
"responses==0.26.0",
"respx==0.22.0",
"ruff==0.14.5",
"types-requests==2.32.4.20250913",
"ruff==0.15.6",
"types-requests==2.32.4.20260107",
]
[tool.setuptools]
@@ -115,7 +115,6 @@ required-environments = [
]
override-dependencies = [
"cryptography>=46.0.5", # CVE-2026-26007
"joserfc>=1.6.3", # CVE-2026-27932
"pillow>=12.1.1", #CVE-2026-25990
]
+502 -469
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -1,6 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
+33 -9
View File
@@ -1,5 +1,7 @@
const crypto = require('crypto');
const { InjectManifest } = require('workbox-webpack-plugin');
const buildId = crypto.randomBytes(256).toString('hex').slice(0, 8);
/** @type {import('next').NextConfig} */
@@ -10,22 +12,44 @@ const nextConfig = {
unoptimized: true,
},
compiler: {
// Enables the styled-components SWC transform
styledComponents: true,
},
generateBuildId: () => buildId,
env: {
NEXT_PUBLIC_BUILD_ID: buildId,
},
turbopack: {
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
webpack(config, { isServer }) {
// Grab the existing rule that handles SVG imports
const fileLoaderRule = config.module.rules.find((rule) =>
rule.test?.test?.('.svg'),
);
config.module.rules.push(
// Reapply the existing rule, but only for svg imports ending in ?url
{
...fileLoaderRule,
test: /\.svg$/i,
resourceQuery: /url/, // *.svg?url
},
},
resolveAlias: {
'micromark-extension-math': 'micromark-extension-llm-math',
},
// Convert all other *.svg imports to React components
{
test: /\.svg$/i,
issuer: fileLoaderRule.issuer,
resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // exclude if *.svg?url
use: ['@svgr/webpack'],
},
);
// Modify the file loader rule to ignore *.svg, since we have it handled now.
fileLoaderRule.exclude = /\.svg$/i;
// Formula rendering in markdown, replace dollar-sign with \(...\) and \[...\]
// https://github.com/remarkjs/remark-math/issues/39#issuecomment-2636184992
config.resolve.alias['micromark-extension-math'] =
'micromark-extension-llm-math';
return config;
},
};
+11 -12
View File
@@ -37,11 +37,11 @@
"lottie-react": "^2.4.1",
"luxon": "3.6.1",
"micromark-extension-llm-math": "3.1.1-20250610",
"next": "16.2.0",
"next": "15.3.9",
"posthog-js": "1.249.3",
"react": "19.2.4",
"react": "19.2.1",
"react-aria-components": "1.9.0",
"react-dom": "19.2.4",
"react-dom": "19.2.1",
"react-i18next": "15.5.2",
"react-intersection-observer": "9.16.0",
"react-markdown": "10.1.0",
@@ -65,23 +65,22 @@
"@types/lodash": "4.17.17",
"@types/luxon": "3.6.2",
"@types/node": "*",
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
"@types/react": "*",
"@types/react-dom": "*",
"cross-env": "7.0.3",
"dotenv": "16.5.0",
"eslint": "^9",
"eslint-config-conversations": "*",
"eslint-config-next": "16.2.0",
"fetch-mock": "9.11.0",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"node-fetch": "2.7.0",
"prettier": "3.5.3",
"sass": "^1.97.3",
"stylelint": "16.20.0",
"stylelint-config-standard": "38.0.0",
"stylelint-prettier": "5.0.3",
"typescript": "*"
},
"resolutions": {
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3"
"typescript": "*",
"webpack": "5.99.9",
"workbox-webpack-plugin": "7.1.0"
}
}
@@ -1,4 +1,4 @@
<svg width="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.0909 6.11002H6.30726C5.51461 6.11002 4.92401 6.30619 4.53649 6.69958C4.14908 7.09297 3.95521 7.67436 3.95521 8.44342V15.1722C3.95526 15.947 4.14902 16.532 4.53649 16.9253C4.92401 17.3184 5.50902 17.5149 6.28965 17.5149H11.6175C11.8993 17.5149 12.1259 17.5501 12.2962 17.6206C12.4604 17.6852 12.6428 17.818 12.8422 18.0174L15.6253 20.756V18.2723C15.6253 17.9965 15.6866 17.8026 15.8098 17.691C15.9331 17.5736 16.1244 17.5149 16.3828 17.5149H17.6593C18.4518 17.5149 19.0425 17.3186 19.4301 16.9253C19.8175 16.532 20.0113 15.947 20.0113 15.1722V8.75944L21.7997 6.96484C21.9094 7.38948 21.9665 7.85602 21.9665 8.36467V15.2602C21.9665 16.1408 21.7987 16.896 21.464 17.5242C21.1235 18.1521 20.6452 18.634 20.029 18.9686C19.4125 19.3032 18.6867 19.4701 17.853 19.4701H17.3339V21.5579C17.3338 21.9803 17.2247 22.3179 17.0076 22.5702C16.7904 22.8225 16.4881 22.9494 16.1009 22.9495C15.831 22.9495 15.5782 22.8812 15.3435 22.7464C15.1028 22.6114 14.8174 22.3999 14.4887 22.1123L11.4859 19.4701H6.20986C5.31757 19.4701 4.55991 19.3031 3.93759 18.9686C3.30964 18.6341 2.83132 18.152 2.50253 17.5242C2.1679 16.896 2.00004 16.1408 2 15.2602V8.36467C2 7.48407 2.16449 6.72889 2.49321 6.10069C2.82786 5.47249 3.30941 4.99098 3.93759 4.6563C4.56584 4.31576 5.32672 4.14548 6.21919 4.14548H15.0534L13.0909 6.11002Z" fill="currentColor"/>
<path d="M20.2766 5.29043L12.2475 13.3206L10.2021 14.1909C10.0759 14.2351 9.95923 14.207 9.85192 14.106C9.74466 13.9987 9.71948 13.882 9.77628 13.7557L10.6757 11.7581L18.6954 3.72895L20.2766 5.29043Z" fill="currentColor"/>
<path d="M20.7791 2.0048C21.0377 1.97969 21.2583 2.0531 21.4412 2.22343L21.7158 2.49801C21.9114 2.69368 22.006 2.92102 21.9997 3.17979C21.9933 3.43841 21.8867 3.66903 21.6785 3.8709L21.0154 4.55269L19.4435 2.97153L20.1067 2.31772C20.296 2.12842 20.5204 2.02374 20.7791 2.0048Z" fill="currentColor"/>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -1,4 +1,4 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.6875 11.1467C17.2283 11.3776 17.8056 11.4931 18.4193 11.4931C19.0208 11.4931 19.592 11.3776 20.1328 11.1467C20.6736 10.9097 21.1476 10.5847 21.5547 10.1715C21.9679 9.75827 22.2899 9.28432 22.5208 8.74959C22.7578 8.2088 22.8763 7.63458 22.8763 7.02694C22.8763 6.20662 22.6758 5.45923 22.2747 4.78475C21.8737 4.11027 21.3329 3.57251 20.6523 3.17147C19.9779 2.76435 19.2335 2.56079 18.4193 2.56079C17.599 2.56079 16.8516 2.76435 16.1771 3.17147C15.5026 3.57251 14.9618 4.11027 14.5547 4.78475C14.1536 5.45923 13.9531 6.20662 13.9531 7.02694C13.9531 7.63458 14.0686 8.2088 14.2995 8.74959C14.5365 9.29039 14.8585 9.76739 15.2656 10.1806C15.6788 10.5877 16.1528 10.9097 16.6875 11.1467ZM18.8659 9.70662C18.7565 9.816 18.6107 9.87069 18.4284 9.87069C18.24 9.87069 18.0881 9.816 17.9727 9.70662C17.8633 9.59117 17.8086 9.4423 17.8086 9.26001V7.63761H16.1953C16.013 7.63761 15.8642 7.58293 15.7487 7.47355C15.6393 7.3581 15.5846 7.20923 15.5846 7.02694C15.5846 6.83857 15.6393 6.6897 15.7487 6.58032C15.8642 6.47095 16.013 6.41626 16.1953 6.41626H17.8086V4.80298C17.8086 4.62069 17.8633 4.47485 17.9727 4.36548C18.0881 4.25003 18.24 4.1923 18.4284 4.1923C18.6107 4.1923 18.7565 4.25003 18.8659 4.36548C18.9813 4.47485 19.0391 4.62069 19.0391 4.80298V6.41626H20.6523C20.8346 6.41626 20.9805 6.47095 21.0898 6.58032C21.2053 6.6897 21.263 6.83857 21.263 7.02694C21.263 7.20923 21.2053 7.3581 21.0898 7.47355C20.9805 7.58293 20.8346 7.63761 20.6523 7.63761H19.0391V9.26001C19.0391 9.4423 18.9813 9.59117 18.8659 9.70662Z" fill="currentColor"/>
<path d="M11.0156 5.00098H13.2079C12.9971 5.54224 12.8683 6.12447 12.8367 6.73242H10.5586C10.2539 6.73242 9.9873 6.71191 9.75879 6.6709C9.53613 6.62988 9.32812 6.5625 9.13477 6.46875C8.94727 6.36914 8.75391 6.2373 8.55469 6.07324L8.05371 5.66016C7.80762 5.46094 7.57617 5.32031 7.35938 5.23828C7.14844 5.15039 6.8877 5.10645 6.57715 5.10645H4.88086C4.48828 5.10645 4.18652 5.21191 3.97559 5.42285C3.76465 5.62793 3.65918 5.93262 3.65918 6.33691V8.52539H13.0324C13.1837 9.07028 13.4156 9.58166 13.7144 10.0459H3.65918V16.752C3.65918 17.1797 3.76465 17.499 3.97559 17.71C4.19238 17.9209 4.50586 18.0264 4.91602 18.0264H19.0752C19.4795 18.0264 19.793 17.9209 20.0156 17.71C20.2383 17.499 20.3496 17.1826 20.3496 16.7607V12.2683C20.9865 12.0331 21.5688 11.6851 22.0723 11.2485V16.9014C22.0723 17.8389 21.8379 18.5479 21.3691 19.0283C20.9004 19.5146 20.2471 19.7578 19.4092 19.7578H4.81055C3.86133 19.7578 3.14355 19.5146 2.65723 19.0283C2.1709 18.5479 1.92773 17.8389 1.92773 16.9014V6.1875C1.92773 5.26172 2.15625 4.56445 2.61328 4.0957C3.07617 3.62109 3.71777 3.38379 4.53809 3.38379H7.02539C7.33008 3.38379 7.59375 3.4043 7.81641 3.44531C8.03906 3.48633 8.24414 3.55664 8.43164 3.65625C8.61914 3.75 8.81543 3.88184 9.02051 4.05176L9.52148 4.46484C9.76758 4.6582 9.99902 4.7959 10.2158 4.87793C10.4326 4.95996 10.6992 5.00098 11.0156 5.00098Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.6875 11.1467C17.2283 11.3776 17.8056 11.4931 18.4193 11.4931C19.0208 11.4931 19.592 11.3776 20.1328 11.1467C20.6736 10.9097 21.1476 10.5847 21.5547 10.1715C21.9679 9.75827 22.2899 9.28432 22.5208 8.74959C22.7578 8.2088 22.8763 7.63458 22.8763 7.02694C22.8763 6.20662 22.6758 5.45923 22.2747 4.78475C21.8737 4.11027 21.3329 3.57251 20.6523 3.17147C19.9779 2.76435 19.2335 2.56079 18.4193 2.56079C17.599 2.56079 16.8516 2.76435 16.1771 3.17147C15.5026 3.57251 14.9618 4.11027 14.5547 4.78475C14.1536 5.45923 13.9531 6.20662 13.9531 7.02694C13.9531 7.63458 14.0686 8.2088 14.2995 8.74959C14.5365 9.29039 14.8585 9.76739 15.2656 10.1806C15.6788 10.5877 16.1528 10.9097 16.6875 11.1467ZM18.8659 9.70662C18.7565 9.816 18.6107 9.87069 18.4284 9.87069C18.24 9.87069 18.0881 9.816 17.9727 9.70662C17.8633 9.59117 17.8086 9.4423 17.8086 9.26001V7.63761H16.1953C16.013 7.63761 15.8642 7.58293 15.7487 7.47355C15.6393 7.3581 15.5846 7.20923 15.5846 7.02694C15.5846 6.83857 15.6393 6.6897 15.7487 6.58032C15.8642 6.47095 16.013 6.41626 16.1953 6.41626H17.8086V4.80298C17.8086 4.62069 17.8633 4.47485 17.9727 4.36548C18.0881 4.25003 18.24 4.1923 18.4284 4.1923C18.6107 4.1923 18.7565 4.25003 18.8659 4.36548C18.9813 4.47485 19.0391 4.62069 19.0391 4.80298V6.41626H20.6523C20.8346 6.41626 20.9805 6.47095 21.0898 6.58032C21.2053 6.6897 21.263 6.83857 21.263 7.02694C21.263 7.20923 21.2053 7.3581 21.0898 7.47355C20.9805 7.58293 20.8346 7.63761 20.6523 7.63761H19.0391V9.26001C19.0391 9.4423 18.9813 9.59117 18.8659 9.70662Z" fill="#222631"/>
<path d="M11.0156 5.00098H13.2079C12.9971 5.54224 12.8683 6.12447 12.8367 6.73242H10.5586C10.2539 6.73242 9.9873 6.71191 9.75879 6.6709C9.53613 6.62988 9.32812 6.5625 9.13477 6.46875C8.94727 6.36914 8.75391 6.2373 8.55469 6.07324L8.05371 5.66016C7.80762 5.46094 7.57617 5.32031 7.35938 5.23828C7.14844 5.15039 6.8877 5.10645 6.57715 5.10645H4.88086C4.48828 5.10645 4.18652 5.21191 3.97559 5.42285C3.76465 5.62793 3.65918 5.93262 3.65918 6.33691V8.52539H13.0324C13.1837 9.07028 13.4156 9.58166 13.7144 10.0459H3.65918V16.752C3.65918 17.1797 3.76465 17.499 3.97559 17.71C4.19238 17.9209 4.50586 18.0264 4.91602 18.0264H19.0752C19.4795 18.0264 19.793 17.9209 20.0156 17.71C20.2383 17.499 20.3496 17.1826 20.3496 16.7607V12.2683C20.9865 12.0331 21.5688 11.6851 22.0723 11.2485V16.9014C22.0723 17.8389 21.8379 18.5479 21.3691 19.0283C20.9004 19.5146 20.2471 19.7578 19.4092 19.7578H4.81055C3.86133 19.7578 3.14355 19.5146 2.65723 19.0283C2.1709 18.5479 1.92773 17.8389 1.92773 16.9014V6.1875C1.92773 5.26172 2.15625 4.56445 2.61328 4.0957C3.07617 3.62109 3.71777 3.38379 4.53809 3.38379H7.02539C7.33008 3.38379 7.59375 3.4043 7.81641 3.44531C8.03906 3.48633 8.24414 3.55664 8.43164 3.65625C8.61914 3.75 8.81543 3.88184 9.02051 4.05176L9.52148 4.46484C9.76758 4.6582 9.99902 4.7959 10.2158 4.87793C10.4326 4.95996 10.6992 5.00098 11.0156 5.00098Z" fill="#222631"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

@@ -14,7 +14,7 @@ import { BoxProps } from './Box';
const StyledPopover = styled(Popover)`
background-color: var(--c--contextuals--background--surface--primary);
border-radius: 4px;
border-radius: var(--c--globals--spacings--st);
box-shadow: 0 0 6px 0 rgba(0, 0, 145, 0.1);
border: 1px solid var(--c--contextuals--border--surface--primary);
transition: opacity var(--c--globals--transitions--duration)
@@ -33,7 +33,7 @@ const StyledButton = styled(Button)<StyledButtonProps>`
font-weight: var(--c--components--button--font-weight);
font-size: var(--c--components--button--medium-font-size);
padding: var(--c--globals--spacings--0);
border-radius: 4px;
border-radius: var(--c--globals--spacings--st);
color: var(--c--contextuals--content--semantic--brand--tertiary);
&:hover {
background-color: var(
@@ -45,7 +45,7 @@ const StyledButton = styled(Button)<StyledButtonProps>`
background-color: var(
--c--contextuals--background--semantic--brand--tertiary-hover
);
border-radius: 4px;
border-radius: var(--c--globals--spacings--st);
}
${({ $css }) => $css};
`;
@@ -131,6 +131,7 @@ export const QuickSearchStyle = createGlobalStyle`
.c__modal__title {
font-size: var(--c--globals--font--sizes--xs);
padding: var(--c--globals--spacings--sm) var(--c--globals--spacings--base) var(--c--globals--spacings--xs) var(--c--globals--spacings--base);
margin-bottom: var(--c--globals--spacings--0);
}
}
`;
@@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M9.50895 1.276C10.1747 1.27604 10.6782 1.4467 11.0194 1.78772C11.3606 2.12484 11.5317 2.62277 11.5317 3.28056V4.20569H12.5799C13.2458 4.20571 13.7491 4.37625 14.0903 4.71741C14.4316 5.05863 14.6027 5.55592 14.6027 6.20959V12.5C14.6027 13.1577 14.4315 13.6551 14.0903 13.9921C13.7491 14.3332 13.2458 14.5038 12.5799 14.5039H6.33252C5.66664 14.5038 5.16329 14.3351 4.8221 13.998C4.48094 13.6609 4.31042 13.1617 4.31038 12.5V11.5683H3.26156C2.59579 11.5683 2.09234 11.4 1.75114 11.0631C1.40992 10.726 1.23878 10.2263 1.23877 9.56441V3.28056C1.23877 2.61865 1.40991 2.11898 1.75114 1.78186C2.09234 1.44486 2.59571 1.27603 3.26156 1.276H9.50895ZM6.40674 5.42053C6.11908 5.42054 5.89933 5.4964 5.74723 5.6484C5.59512 5.7964 5.51872 6.0208 5.51872 6.32092V12.3951C5.51875 12.6951 5.59516 12.919 5.74723 13.067C5.89933 13.2191 6.11905 13.2955 6.40674 13.2955H12.5057C12.7894 13.2955 13.0072 13.2191 13.1593 13.067C13.3114 12.919 13.3878 12.6951 13.3879 12.3951V6.32092C13.3879 6.0208 13.3115 5.7964 13.1593 5.6484C13.0072 5.49633 12.7893 5.42053 12.5057 5.42053H6.40674ZM3.33577 2.48499C3.04799 2.48499 2.82773 2.56074 2.67562 2.71285C2.52764 2.86085 2.45361 3.08529 2.45361 3.38538V9.45959C2.45363 9.75963 2.52768 9.98588 2.67562 10.138C2.82773 10.286 3.04799 10.36 3.33577 10.36H4.31038V6.20959C4.31039 5.55181 4.48088 5.05452 4.8221 4.71741C5.16329 4.37623 5.66665 4.20574 6.33252 4.20569H10.3162V3.38538C10.3162 3.08526 10.2405 2.86085 10.0884 2.71285C9.93627 2.5608 9.71833 2.48499 9.43473 2.48499H3.33577Z"
fill="#555E74"
/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

@@ -2,7 +2,6 @@ import { Message, SourceUIPart, ToolInvocationUIPart } from '@ai-sdk/ui-utils';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Button } from '@gouvfr-lasuite/cunningham-react';
import { Box, Icon, Loader, Text } from '@/components';
import { AttachmentList } from '@/features/chat/components/AttachmentList';
import { FeedbackButtons } from '@/features/chat/components/FeedbackButtons';
@@ -13,8 +12,6 @@ import {
import { SourceItemList } from '@/features/chat/components/SourceItemList';
import { ToolInvocationItem } from '@/features/chat/components/ToolInvocationItem';
import CopyIcon from '../assets/copy.svg';
// Memoized blocks list to prevent parent re-renders from causing block remounts
const BlocksList = React.memo(
({ blocks, pending }: { blocks: string[]; pending: string }) => (
@@ -246,10 +243,30 @@ const MessageItemComponent: React.FC<MessageItemProps> = ({
onCopyToClipboard(message.content);
}, [onCopyToClipboard, message.content]);
const handleCopyKeyDown = React.useCallback(
(e: React.KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onCopyToClipboard(message.content);
}
},
[onCopyToClipboard, message.content],
);
const handleOpenSources = React.useCallback(() => {
onOpenSources(message.id);
}, [onOpenSources, message.id]);
const handleOpenSourcesKeyDown = React.useCallback(
(e: React.KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onOpenSources(message.id);
}
},
[onOpenSources, message.id],
);
return (
<Box
data-message-id={message.id}
@@ -370,42 +387,57 @@ const MessageItemComponent: React.FC<MessageItemProps> = ({
$margin={{ top: 'base' }}
>
<Box $direction="row" $gap="4px">
<Button
size="nano"
color="neutral"
variant="tertiary"
onClick={handleCopy}
aria-label={t('Copy')}
icon={<CopyIcon className="action-chat-button-icon" />}
<Box
$direction="row"
$align="center"
$gap="4px"
className="c__button--neutral action-chat-button"
></Button>
onClick={handleCopy}
onKeyDown={handleCopyKeyDown}
role="button"
tabIndex={0}
>
<Icon
iconName="content_copy"
$theme="greyscale"
$variation="550"
$size="16px"
className="action-chat-button-icon"
/>
{!isMobile && (
<Text $theme="greyscale" $variation="550">
{t('Copy')}
</Text>
)}
</Box>
{sourceParts.length > 0 && (
<Button
size="nano"
variant="tertiary"
color="neutral"
<Box
$direction="row"
$align="center"
$gap="4px"
className={`c__button--neutral action-chat-button ${isSourceOpen === message.id ? 'action-chat-button--open' : ''}`}
onClick={handleOpenSources}
aria-label={t('Show sources')}
icon={
<Icon
iconName="book"
$theme="neutral"
$variation="550"
$size="16px"
className="action-chat-button-icon"
/>
}
className={`c__button--neutral action-chat-button ${
isSourceOpen === message.id
? 'action-chat-button--open'
: ''
}`}
onKeyDown={handleOpenSourcesKeyDown}
role="button"
tabIndex={0}
>
<Text>
<Icon
iconName="book"
$theme="greyscale"
$variation="550"
$size="16px"
className="action-chat-button-icon"
/>
<Text
$theme="greyscale"
$variation="550"
$weight="500"
$size="12px"
>
{t('Show')} {sourceParts.length}{' '}
{sourceParts.length !== 1 ? t('sources') : t('source')}
</Text>
</Button>
</Box>
)}
</Box>
<Box $direction="row" $gap="4px">
@@ -1,5 +1,4 @@
import { type ReactNode, memo } from 'react';
import { css } from 'styled-components';
import { Box, Text } from '@/components';
@@ -11,16 +10,6 @@ const WELCOME_MARGIN = {
} as const;
const WELCOME_TEXT_MARGIN = { all: '0' } as const;
const titleStyles = css`
overflow: hidden;
text-overflow: ellipsis;
white-space: initial;
display: -webkit-box;
line-clamp: 1;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
`;
interface WelcomeLayoutProps {
title: string;
icon?: ReactNode;
@@ -34,13 +23,7 @@ export const WelcomeLayout = memo(function WelcomeLayout({
<Box $padding={WELCOME_PADDING} $align="center" $margin={WELCOME_MARGIN}>
<Box $direction="row" $align="center" $gap="10px">
{icon}
<Text
$css={titleStyles}
as="h2"
$size="xl"
$weight="600"
$margin={WELCOME_TEXT_MARGIN}
>
<Text as="h2" $size="xl" $weight="600" $margin={WELCOME_TEXT_MARGIN}>
{title}
</Text>
</Box>
@@ -84,7 +84,7 @@ export const Header = () => {
aria-label={t('New chat')}
color="brand"
variant="tertiary"
icon={<NewChatIcon height="25px" />}
icon={<NewChatIcon />}
/>
</Box>
) : (
@@ -15,7 +15,6 @@ type ConversationRowProps = {
const linkStyles = css`
overflow: auto;
flex-grow: 1;
flex-shrink: 1;
color: var(--c--theme--colors--greyscale-900);
`;
@@ -1,23 +0,0 @@
import { Box } from '@/components';
import { useAuth } from '@/features/auth/hooks';
import { LeftPanelConversations } from '@/features/left-panel/components/left-panel/LeftPanelConversations';
import { useResponsiveStore } from '@/stores';
export const LeftPanelContent = () => {
const { isDesktop } = useResponsiveStore();
const { authenticated } = useAuth();
return (
<Box
$width="100%"
$css={`
overflow-y: auto;
overflow-x: hidden;
position: relative;
height: calc(100dvh - ${isDesktop ? '52px' : '52px'};
`}
>
{authenticated && <LeftPanelConversations />}
</Box>
);
};
@@ -43,7 +43,7 @@ export const ModalRemoveConversation = ({
<>
<Button
aria-label={t('Close the modal')}
color="neutral"
color="brand"
variant="bordered"
fullWidth
onClick={() => onClose()}
@@ -61,7 +61,7 @@ export const ModalRenameConversation = ({
<>
<Button
aria-label={t('Close the modal')}
color="neutral"
color="brand"
variant="bordered"
onClick={() => onClose()}
>
@@ -96,12 +96,11 @@ export const ModalRenameConversation = ({
onSubmit={handleSubmit}
id="rename-chat-form"
data-testid="rename-chat-form"
className="mt-base"
className="mt-s"
>
<Input
className="inputName__text"
type="text"
placeholder={t('New name')}
label={t('New name')}
maxLength={100}
value={newName}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
@@ -68,11 +68,11 @@ export const LeftPanel = () => {
z-index: 1000;
overflow: hidden;
width: ${isPanelOpen ? '100%' : '200px'};
width: 100vw;
height: calc(100dvh - 52px);
border-right: 1px solid
var(--c--contextuals--border--surface-primary);
position: relative;
top: 0px;
position: fixed;
top: 52px;
left: ${isPanelOpen ? '0' : '-300px'};
background-color: var(
--c--contextuals--background--surface--secondary
@@ -83,43 +83,43 @@ export const LeftPanel = () => {
<Box
data-testid="left-panel-mobile"
$css={css`
display: flex;
flex-direction: column;
width: 100%;
height: 100vh;
justify-content: center;
align-items: center;
gap: ${spacingsTokens['base']};
`}
>
<LeftPanelHeader />
<LeftPanelContent />
<SeparatedSection showSeparator={false}></SeparatedSection>
<Box
$css={css`
display: flex;
bottom: 0;
height: 52px;
width: 100%;
gap: ${spacingsTokens['base']};
border-top: 1px solid
var(--c--contextuals--border--surface--primary);
`}
$justify="space-between"
$align="center"
$direction="row"
$padding={{ horizontal: 'sm' }}
$gap={spacingsTokens['sm']}
>
<ButtonLogin />
<SeparatedSection showSeparator={false}>
<Box
$direction="row"
$gap={spacingsTokens['sm']}
$css={css`
display: flex;
position: absolute;
bottom: 0;
height: 52px;
width: 100%;
gap: ${spacingsTokens['base']};
border-top: 1px solid
var(--c--contextuals--border--surface--primary);
`}
$justify="space-between"
$align="center"
$direction="row"
$padding={{ horizontal: 'sm' }}
$gap={spacingsTokens['sm']}
>
<LanguagePicker />
<SettingsButton />
<ButtonLogin />
<Box
$direction="row"
$gap={spacingsTokens['sm']}
$align="center"
>
<LanguagePicker />
<SettingsButton />
</Box>
</Box>
</Box>
</SeparatedSection>
</Box>
</Box>
</>
@@ -27,7 +27,7 @@ export const LeftPanelConversations = () => {
return (
<Box
$padding={{ horizontal: 'sm' }}
$padding={{ horizontal: 'xs' }}
$gap={spacingsTokens['2xs']}
$height="50vh"
data-testid="left-panel-favorites"
@@ -5,7 +5,6 @@ import { Box } from '@/components';
import { useAuth } from '@/features/auth';
import { useChatPreferencesStore } from '@/features/chat/stores/useChatPreferencesStore';
import { useOwnModal } from '@/features/left-panel/hooks/useModalHook';
import { usePendingChatStore } from '@/features/chat/stores/usePendingChatStore';
import { useResponsiveStore } from '@/stores';
import { ModalProjectForm } from '../projects/ModalProjectForm';
@@ -19,7 +18,6 @@ export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
const { isDesktop } = useResponsiveStore();
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false);
const createProjectModal = useOwnModal();
const setProjectId = usePendingChatStore((s) => s.setProjectId);
const { setPanelOpen } = useChatPreferencesStore();
@@ -35,7 +33,6 @@ export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
}, []);
const goToHome = () => {
setProjectId(null);
void router.push('/');
if (!isDesktop) {
setPanelOpen(false);
@@ -42,7 +42,7 @@ export const LeftPanelHeaderActions = ({
<LeftPanelMenuItem
icon={
<Box $css={iconWrapperCss} $display="flex" $align="center">
<NewChatIcon width="24" height="24" aria-hidden />
<NewChatIcon aria-hidden />
</Box>
}
label={t('New chat')}
@@ -4,12 +4,10 @@ import { memo, useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import NewChatIcon from '@/assets/icons/new-message-bold.svg';
import { Box, Icon, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { usePendingChatStore } from '@/features/chat/stores/usePendingChatStore';
import { ChatProject } from '@/features/chat/types';
import { useChatPreferencesStore } from '@/features/chat/stores/useChatPreferencesStore';
import { ConversationItemActions } from '@/features/left-panel/components/ConversationItemActions';
import { ConversationRow } from '@/features/left-panel/components/ConversationRow';
import { ProjectItemActions } from '@/features/left-panel/components/projects/ProjectItemActions';
@@ -17,8 +15,6 @@ import {
PROJECT_COLORS,
PROJECT_ICONS,
} from '@/features/left-panel/components/projects/project-constants';
import { useResponsiveStore } from '@/stores';
type LeftPanelProjectItemProps = {
project: ChatProject;
currentConversationId?: string;
@@ -43,40 +39,16 @@ const headerStyles = css`
opacity: 1;
}
}
@media (width <= 768px) {
&[data-project-open='true'] {
.pinned-actions {
opacity: 1;
}
}
}
`;
const conversationListStyles = css`
margin-top: 2px;
overflow: hidden;
`;
const titleTextStyles = css`
overflow: hidden;
text-overflow: ellipsis;
white-space: initial;
display: -webkit-box;
line-clamp: 1;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
`;
const titleStyles = css`
overflow: hidden;
text-overflow: ellipsis;
white-space: initial;
display: -webkit-box;
line-clamp: 1;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
padding-left: 24px;
white-space: nowrap;
`;
export const LeftPanelProjectItem = memo(function LeftPanelProjectItem({
@@ -88,8 +60,6 @@ export const LeftPanelProjectItem = memo(function LeftPanelProjectItem({
const router = useRouter();
const pendingProjectId = usePendingChatStore((s) => s.projectId);
const setProjectId = usePendingChatStore((s) => s.setProjectId);
const { isDesktop } = useResponsiveStore();
const { setPanelOpen } = useChatPreferencesStore();
const [isOpen, setIsOpen] = useState(false);
@@ -117,9 +87,6 @@ export const LeftPanelProjectItem = memo(function LeftPanelProjectItem({
const handleNewConversation = useCallback(() => {
setProjectId(project.id);
void router.push('/chat/');
if (!isDesktop) {
setPanelOpen(false);
}
}, [router, project.id, setProjectId]);
return (
@@ -132,7 +99,6 @@ export const LeftPanelProjectItem = memo(function LeftPanelProjectItem({
$gap="2px"
$justify="space-between"
$css={headerStyles}
data-project-open={isOpen ? 'true' : 'false'}
>
<Box
$direction="row"
@@ -152,15 +118,10 @@ export const LeftPanelProjectItem = memo(function LeftPanelProjectItem({
}}
>
<Icon
iconName={
isOpen && project.conversations.length > 0
? 'keyboard_arrow_down'
: 'keyboard_arrow_right'
}
$theme="neutral"
$variation="tertiary"
iconName={isOpen ? 'keyboard_arrow_down' : 'keyboard_arrow_right'}
$theme="greyscale"
$variation="600"
$size="18px"
$css={`opacity: ${project.conversations.length === 0 ? '0' : '1'};`}
/>
<Box
@@ -180,7 +141,7 @@ export const LeftPanelProjectItem = memo(function LeftPanelProjectItem({
<Text
$size="sm"
$variation="primary"
$weight={isOpen ? '700' : '500'}
$weight="500"
$css={titleTextStyles}
>
{project.title}
@@ -190,24 +151,32 @@ export const LeftPanelProjectItem = memo(function LeftPanelProjectItem({
<div
className="pinned-actions"
role="presentation"
style={{ display: 'flex', alignItems: 'center', gap: '2px' }}
style={{ display: 'flex', alignItems: 'center', gap: 0 }}
>
<ProjectItemActions project={project} />
<Button
aria-label={t('New conversation in project')}
onClick={handleNewConversation}
color="brand"
variant="tertiary"
color="info"
variant="bordered"
size="nano"
icon={<NewChatIcon width="16" height="16" />}
icon={<Icon iconName="add" $size="18px" $theme="primary" />}
/>
</div>
</Box>
{/* Conversations list */}
{isOpen && (
<Box $padding={{ left: '0px' }} $css={conversationListStyles}>
{project.conversations.length > 0 &&
<Box $padding={{ left: '28px' }} $css={conversationListStyles}>
{project.conversations.length === 0 ? (
<Text
$size="xs"
$variation="tertiary"
$padding={{ horizontal: 'xs', vertical: '4px' }}
>
{t('No conversations')}
</Text>
) : (
project.conversations.map((conv) => (
<ConversationRow
key={conv.id}
@@ -215,16 +184,12 @@ export const LeftPanelProjectItem = memo(function LeftPanelProjectItem({
isActive={conv.id === currentConversationId}
actions={<ConversationItemActions conversation={conv} />}
>
<Text
$css={titleStyles}
$size="sm"
$variation="primary"
$weight="400"
>
<Text $size="sm" $variation="primary" $weight="400">
{conv.title || t('Untitled conversation')}
</Text>
</ConversationRow>
))}
))
)}
</Box>
)}
</Box>
@@ -26,7 +26,7 @@ export const LeftPanelProjects = () => {
return (
<Box
$padding={{ horizontal: 'sm' }}
$padding={{ horizontal: 'xs' }}
$margin={{ vertical: 'base' }}
$gap={spacingsTokens['2xs']}
data-testid="left-panel-projects"
@@ -16,13 +16,13 @@ const gridCss = css`
justify-items: center;
`;
const cellCss = css`
width: 32px;
height: 32px;
const iconCellCss = css`
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
border-radius: 8px;
cursor: pointer;
border: none;
background-color: transparent;
@@ -35,13 +35,39 @@ const cellCss = css`
&:hover {
background-color: var(
--c--contextuals--background--semantic--neutral--secondary
--c--contextuals--background--semantic--overlay--primary
);
}
`;
const cellSelectedCss = css`
${cellCss}
const iconSelectedCss = css`
${iconCellCss}
background-color: var(
--c--contextuals--background--semantic--overlay--primary
);
`;
const colorCellCss = css`
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
cursor: pointer;
border: none;
background-color: transparent;
transition: background-color 0.15s ease;
&:hover {
background-color: var(
--c--contextuals--background--semantic--overlay--primary
);
}
`;
const colorSelectedCss = css`
${colorCellCss}
background-color: var(
--c--contextuals--background--semantic--overlay--primary
);
@@ -66,19 +92,17 @@ export const ModalIconColorPicker = ({
return (
<Box
$direction="column"
$gap="base"
$gap="sm"
$padding={{ all: 'xs' }}
aria-label={t('Choose icon and color')}
>
<Box
$css={gridCss}
$margin={{ horizontal: 'base', top: 'base', bottom: '12px' }}
>
<Box $css={gridCss}>
{iconEntries.map(([key, IconComp]) => (
<Box
key={key}
as="button"
type="button"
$css={icon === key ? cellSelectedCss : cellCss}
$css={icon === key ? iconSelectedCss : iconCellCss}
onClick={() => onIconChange(key)}
aria-label={key}
aria-pressed={icon === key}
@@ -90,24 +114,21 @@ export const ModalIconColorPicker = ({
<HorizontalSeparator $withPadding={false} />
<Box
$css={gridCss}
$margin={{ horizontal: 'base', bottom: 'base', top: '12px' }}
>
<Box $css={gridCss}>
{colorEntries.map(([key, token]) => (
<Box
key={key}
as="button"
type="button"
$css={color === key ? cellSelectedCss : cellCss}
$css={color === key ? colorSelectedCss : colorCellCss}
onClick={() => onColorChange(key)}
aria-label={key}
aria-pressed={color === key}
>
<Box
$css={css`
width: 22px;
height: 22px;
width: 32px;
height: 32px;
border-radius: 50%;
`}
style={{
@@ -5,7 +5,6 @@ import {
ModalSize,
TextArea,
} from '@gouvfr-lasuite/cunningham-react';
import { useReducer } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
@@ -46,23 +45,19 @@ const formReducer = (state: FormState, action: FormAction): FormState => {
};
const avatarButtonCss = css`
width: 42px;
height: 42px;
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid var(--c--contextuals--border--semantic--neutral--tertiary);
border-radius: 4px;
border: 1px solid #ccc;
border-radius: 8px;
background-color: transparent;
cursor: pointer;
flex-shrink: 0;
transition: border-color 0.15s ease;
`;
const inputNameCss = css`
height: 38px !important;
`;
interface ModalProjectFormProps {
project?: ChatProject;
onClose: () => void;
@@ -76,7 +71,7 @@ export const ModalProjectForm = ({
const { showToast } = useToast();
const { t } = useTranslation();
const { colorsTokens } = useCunninghamTheme();
const { colorsTokens, spacingsTokens } = useCunninghamTheme();
const [form, dispatch] = useReducer(formReducer, {
name: project?.title ?? '',
@@ -164,7 +159,7 @@ export const ModalProjectForm = ({
</Button>
<Button
aria-label={
isEditing ? t('Save project settings') : t('Create project')
isEditing ? t('Save project settings') : t('New project')
}
color="brand"
variant="primary"
@@ -172,7 +167,7 @@ export const ModalProjectForm = ({
form={formId}
disabled={!form.name.trim() || isPending}
>
{isEditing ? t('Save') : t('Create project')}
{isEditing ? t('Save') : t('New project')}
</Button>
</>
}
@@ -204,12 +199,12 @@ export const ModalProjectForm = ({
data-testid={formId}
className="mt-s"
>
<Box $direction="column">
<Box $direction="column" $gap="8px" $margin={{ bottom: 'base' }}>
<Text $size="sm" $theme="neutral" $weight="500">
{t('Avatar and name')}
<Box $gap={spacingsTokens['base']} $direction="column">
<Box $direction="column">
<Text $size="sm" $variation="600" $weight="500">
{t('Project avatar and name')}
</Text>
<Box $direction="row" $align="top" $gap="8px" $height="42px">
<Box $direction="row" $align="center" $gap={spacingsTokens['xs']}>
<DropButton
button={
<Box $css={avatarButtonCss} style={{ color: iconColor }}>
@@ -234,45 +229,23 @@ export const ModalProjectForm = ({
/>
</DropButton>
<Box $width="100%" $height="40px">
<Input
className="inputName__text"
type="text"
aria-label={t('Project name')}
maxLength={100}
value={form.name}
fullWidth
placeholder={t('Project name')}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
dispatch({ type: 'SET_NAME', value: e.target.value })
}
required
/>
</Box>
<Input
type="text"
label={t('Project name')}
maxLength={100}
value={form.name}
fullWidth={true}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
dispatch({ type: 'SET_NAME', value: e.target.value })
}
required
/>
</Box>
</Box>
<Box $direction="column">
<Text
$size="sm"
$theme="neutral"
$weight="500"
$margin={{ bottom: 'xs' }}
>
{t('Instructions (experimental)')}
</Text>
<Text
$size="sm"
$theme="neutral"
$variation="secondary"
$margin={{ bottom: 'xxs' }}
>
{t(
'Use this field to provide any additional context the Assistant may need. This feature is being tested. It may not work as expected.',
)}
</Text>
<TextArea
aria-label={t('Instructions (experimental)')}
label={t('Instructions (experimental)')}
rows={6}
maxLength={4000} // cf. backend LLM_INSTRUCTIONS_MAX_LENGTH
value={form.instructions}
@@ -283,6 +256,11 @@ export const ModalProjectForm = ({
'Example: Be concise and maintain a professional tone.',
)}
/>
<Text $size="sm" $variation="600">
{t(
'Use this field to provide any additional context the Assistant may need. This feature is being tested. It may not work as expected.',
)}
</Text>
</Box>
</Box>
</form>
@@ -43,28 +43,27 @@ export const ModalRemoveProject = ({
aria-label={t('Content modal to delete project')}
rightActions={
<>
<Button
aria-label={t('Close the modal')}
color="neutral"
variant="bordered"
fullWidth
onClick={() => onClose()}
>
{t('Cancel')}
</Button>
<Button
aria-label={t('Confirm deletion')}
color="error"
variant="primary"
fullWidth
variant="bordered"
disabled={isRemoving}
fullWidth
onClick={() =>
removeProject({
projectId: project.id,
})
}
>
{t('Delete')}
{t('Delete anyway')}
</Button>
<Button
aria-label={t('Close the modal')}
color="brand"
fullWidth
onClick={() => onClose()}
>
{t('Cancel')}
</Button>
</>
}
@@ -60,7 +60,6 @@ nextjs-portal {
}
.c__modal {
border: 1px solid var(--c--contextuals--border--surface--primary);
box-shadow: 0 6px 18px 0 rgb(0 0 0 / 16%);
}
@@ -96,6 +95,24 @@ nextjs-portal {
border: none;
}
.c__button--neutral {
transition: background-color 0.4s !important;
color: var(--c--theme--colors--greyscale-550) !important;
font-weight: 500 !important;
cursor: pointer !important;
background-color: inherit !important;
border: none !important;
z-index: 100;
font-size: 12px !important;
padding: 4px !important;
padding-right: 9px !important;
border-radius: 4px !important;
@media (width <= 768px) {
padding-right: 4px !important;
}
}
.c__button--neutral.c__button--neutral--icon {
padding-right: 4px !important;
}
@@ -120,6 +137,13 @@ nextjs-portal {
}
}
/* .c__button--neutral:hover,
.c__button--neutral:active,
.action-chat-button--open {
background-color: #f2f5f4 !important;
border: none !important;
} */
.c__button--neutral:active {
background-color: inherit !important;
}
@@ -239,55 +263,10 @@ ul a:hover {
}
}
.labelled-box__children {
padding: 6px 8px !important;
}
.c__button--small {
padding: 0.2rem !important;
}
.inputName__text {
height: 40px !important;
}
.c__input__wrapper {
padding: 0 !important;
}
.c__textarea__wrapper,
.c__textarea__wrapper:hover,
.c__textarea__wrapper:focus,
.c__input__wrapper,
.c__input__wrapper:hover,
.c__input__wrapper:focus {
border-radius: 4px !important;
}
.c__input__wrapper .labelled-box__children {
display: flex;
height: 40px !important;
padding: 0;
align-items: center;
gap: var(--xxs, 6px);
flex: 1 0 0;
}
.c__input,
.c__textarea {
line-height: 1.25rem;
}
.c__textarea {
padding: 6px !important;
}
.c__input::placeholder,
.c__textarea::placeholder {
line-height: 1.25rem;
opacity: 1;
}
.c__button--feedback {
margin-left: 16px;
@@ -11,7 +11,7 @@
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"jsx": "preserve",
"incremental": true,
"plugins": [
{
+6 -2
View File
@@ -12,10 +12,14 @@
"test:ui::chromium": "yarn test:ui --project=chromium"
},
"devDependencies": {
"@playwright/test": "1.56.0",
"@playwright/test": "1.52.0",
"@types/node": "*",
"@types/pdf-parse": "1.1.5",
"eslint-config-conversations": "*",
"typescript": "*"
},
"dependencies": {}
"dependencies": {
"convert-stream": "1.0.2",
"pdf-parse": "1.1.1"
}
}
+5
View File
@@ -0,0 +1,5 @@
declare module 'convert-stream' {
export function toBuffer(
readableStream: NodeJS.ReadableStream,
): Promise<Buffer>;
}
+5 -8
View File
@@ -27,17 +27,14 @@
},
"resolutions": {
"@types/node": "22.15.29",
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
"@types/react": "19.1.6",
"@types/react-dom": "19.1.6",
"@typescript-eslint/eslint-plugin": "8.33.1",
"@typescript-eslint/parser": "8.33.1",
"eslint": "^9.0.0",
"react": "19.2.4",
"react-dom": "19.2.4",
"react": "19.2.1",
"react-dom": "19.2.1",
"typescript": "5.8.3",
"minimatch": ">=10.2.1",
"flatted": ">=3.4.0",
"rollup": ">=4.59.0",
"undici": ">=7.24.0"
"minimatch": ">=10.2.1"
}
}
+1182 -548
View File
File diff suppressed because it is too large Load Diff