Repository navigation
feat: RSS-SE-27 create about page - #33
Conversation
- Add AuthForm feature component with login/register variants - Implement SignIn and SignUp pages - Add localization (ru/en) for auth forms
- Add strict Zod validation schemas for login and registration - Integrate react-hook-form with zodResolver into AuthForm - Configure dynamic mode validation on field change - Add validation error translations for en and ru locales
- install supabase
- Added @uiw/react-codemirror with JSON/YAML support - Created reusable CodeEditor in shared/ui with readonly and transparent props - Applied custom dark theme and syntax highlighting via SCSS and JS - Integrated CodeEditor into SwaggerEditor widget
- add auth-provider, get-current-user - add AuthProvider to layout - add checks in middleware
- Create format-converter feature to detect and convert between JSON and YAML - Implement FormatToggle UI component with unknown state handling - Integrate format converter logic and toggle into SwaggerEditor widget - Add i18n support for the format converter UI
- Integrate `@stoplight/spectral-core` to parse and validate OpenAPI schemas in both JSON and YAML formats. - Add `CodeMirror Linter` adapter to display validation errors directly in the editor with inline tooltips. - Customize the Spectral `oas` ruleset to ignore annoying stylistic rules and focus only on structural errors. - Add comprehensive unit tests for the schema validation utility.
- Implemented `ValidationStatus` and `ValidationFeedback` UI components to visualize schema validity and error counts. - Added `next-intl` localization support for all new validation UI elements. - Integrated CodeMirror's `onUpdate` listener to efficiently extract real-time lint diagnostics without causing redundant validation runs. - Created a responsive split-view layout for the `HomePage` using Flexbox and aspect-ratio media queries. - Assembled the main page by integrating the `SwaggerEditor` into the primary pane and adding a placeholder stub for the `SwaggerViewer`.
- Refactor SwaggerEditor to operate as a fully controlled component by removing its internal local state. - Implement a custom useDebounce hook to optimize performance during user input. - Lift state management up to the HomePage to track raw text and validation status.
- Create header and footer. - Add conditional rendering for auth buttons: Sign In / Sign Up vs History / Sign Out. - Add links to the About page. - Integrate the language switcher (i18n) into the Header.
- Replace 'unknown' magic string with null in DetectedFormat type - Extract parseToObject helper to shared/lib to eliminate duplicated yaml parsing - Replace nested ternary with getStatus function in ValidationFeedback - Split validation object state into separate errorsCount/warningsCount states - Derive currentFormat via useMemo with debounce instead of useState + useEffect - Sync package-lock.json
* Integrate code editor for OpenAPI/Swagger specifications * Implement auto-detection for JSON and YAML formats * Add seamless JSON ↔ YAML format conversion * Add real-time OpenAPI schema validation with UI feedback * Create responsive split view (horizontal/vertical) for Editor and Viewer * Synchronize parsed schema state between Editor and Viewer
- add translations for errors - add submit form and database errors
- add styles and edits to app router - delete try catch
- add sign out
* chore: change name of env * refactor: add edits * chore: change package-lock.json * chore: change package-lock * chore: change package-lock * fix: fix package-lock --------- Co-authored-by: dilmun1101 <dilmun94@gmail.com>
- add auth - add connection to supabase
…maSavingToSupabase - implement schema saving to supabase
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughДобавлены Supabase-аутентификация и хранение схем, OpenAPI-редактор с JSON/YAML-конвертацией и Spectral-валидацией, страницы About, навигация, локализация, UI-компоненты и конфигурация приложения. ChangesПлатформа приложения
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant AuthForm
participant ServerActions
participant Supabase
participant HomePage
participant EditorSchemaAPI
participant SwaggerEditor
User->>AuthForm: отправляет данные формы
AuthForm->>ServerActions: вызывает signInWithPassword или signUp
ServerActions->>Supabase: выполняет auth-запрос
Supabase-->>ServerActions: возвращает результат
ServerActions-->>User: перенаправляет после успеха
HomePage->>EditorSchemaAPI: загружает схему по userId
EditorSchemaAPI->>Supabase: выполняет select
HomePage->>SwaggerEditor: передаёт текст схемы
SwaggerEditor->>EditorSchemaAPI: сохраняет debouncedText
EditorSchemaAPI->>Supabase: выполняет upsert
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (19)
src/features/auth-form/ui/auth-form.module.scss-1-10 (1)
1-10: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winПустые строки перед объявлениями ломают stylelint.
Правило
declaration-empty-line-beforeзапрещает пустую строку перед объявлением внутри блока — это приведёт к падению lint-проверки в CI.🔧 Предлагаемый фикс
.card { border-radius: var(--radius-card); padding: 2.5rem; max-width: 440px; - display: flex; flex-direction: column; align-items: center; gap: 24px; }.button { font-size: 1rem; padding-top: 0.875rem; padding-bottom: 0.875rem; - display: flex; gap: 6px; }.switchContainer { color: var(--text-secondary); font-size: 0.875rem; line-height: 1.25rem; - display: flex; gap: 8px; }Also applies to: 40-47, 54-61
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/auth-form/ui/auth-form.module.scss` around lines 1 - 10, Remove the empty line before the display declaration in the .card rule, and apply the same change to the corresponding declaration blocks at the other affected locations. Keep all declarations and styling values unchanged.Source: Linters/SAST tools
src/pages/about-page/ui/about-hero-section/about-hero-section.module.scss-85-85 (1)
85-85: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winРегистр значения
currentColor.Stylelint требует нижний регистр для ключевого слова.
🔧 Фикс
.arrow { width: 10px; aspect-ratio: 1/1; - color: currentColor; + color: currentcolor; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/about-page/ui/about-hero-section/about-hero-section.module.scss` at line 85, Update the color declaration in the about hero section stylesheet to use the lowercase CSS keyword required by Stylelint, changing currentColor to currentcolor while preserving the existing styling.Source: Linters/SAST tools
src/widgets/swagger-editor/ui/swagger-editor.tsx-27-33 (1)
27-33: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winНе сообщайте о валидности до завершения первой проверки.
errorsCountначинается с0, поэтому любой непустой текст с распознанным форматом сразу даётisValid === true, пока асинхронный линтер ещё не завершил проверку. В результате UI иonValidationChangeмогут сообщить о валидной схеме, которая затем окажется ошибочной. Храните состояниеpending/validatedдля текущей версии текста и выставляйтеtrueтолько после завершения соответствующей валидации.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/widgets/swagger-editor/ui/swagger-editor.tsx` around lines 27 - 33, Update the validation state used by isValid and onValidationChange so the initial and text-changed states remain pending until the asynchronous linter completes for the current value. In the component’s validation flow, track whether the current text version has been validated, reset that state when value or format changes, and mark it validated only when the corresponding check finishes; allow isValid to be true only for completed validation with zero errors.src/widgets/swagger-editor/ui/swagger-editor.module.scss-9-20 (1)
9-20: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winУдалите дублирующиеся декларации в
.toolbar.
displayиalign-itemsобъявлены дважды; Stylelint уже сообщает об этом как об ошибке. Оставьте каждое свойство только один раз и уберите пустую строку перед повторным блоком.Предлагаемое исправление
.toolbar { - display: flex; - align-items: center; padding: 0.75rem 1.5rem; background-color: var(--bg-surface-1); border-bottom: 1px solid var(--bg-surface-2); - display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/widgets/swagger-editor/ui/swagger-editor.module.scss` around lines 9 - 20, Remove the duplicate display and align-items declarations from the .toolbar rule, keeping each property only once with the existing layout behavior. Also remove the empty line separating the repeated declarations.Source: Linters/SAST tools
src/pages/about-page/ui/useful-link-item/useful-link-item.module.scss-17-23 (1)
17-23: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winЗадайте полную границу для
.iconWrapper.
border-colorбезborder-styleиborder-widthне отображает границу. Используйте, например,border: 1px solid rgba(255, 255, 255, 0.5).Предлагаемое исправление
.iconWrapper { min-width: 30px; padding: 10px 5px; border-radius: 15px; - border-color: rgba(255, 255, 255, 0.5); + border: 1px solid rgba(255, 255, 255, 0.5); background: rgba(255, 255, 255, 0.06); transition: 1.5s; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/about-page/ui/useful-link-item/useful-link-item.module.scss` around lines 17 - 23, Update the .iconWrapper styles to define a complete border, including width and style, while preserving the existing semi-transparent border color and other properties.src/features/schema-validator/ui/validation-status/validation-status.module.scss-7-7 (1)
7-7: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winУберите пустую строку перед
display.Stylelint сообщает об ошибке
declaration-empty-line-before; удаление пустой строки междуpaddingиdisplayустранит её.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/schema-validator/ui/validation-status/validation-status.module.scss` at line 7, Remove the empty line between the padding declaration and display: flex in the validation-status style block so declarations are adjacent and satisfy Stylelint’s declaration-empty-line-before rule.Source: Linters/SAST tools
src/shared/ui/button/button.module.scss-61-64 (1)
61-64: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winУберите пустые строки перед декларациями.
Stylelint сообщает об ошибках
declaration-empty-line-beforeпередborderиpadding. Удалите эти пустые строки внутри.tertiary.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/ui/button/button.module.scss` around lines 61 - 64, Remove the empty lines before the border and padding declarations in the .tertiary style block, leaving the declarations contiguous and preserving their existing values.Source: Linters/SAST tools
app/app.module.scss-11-11 (1)
11-11: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winИсправьте нарушение Stylelint в Line 11.
Перед декларацией
paddingнаходится лишняя пустая строка, из-за чего Stylelint выдаётdeclaration-empty-line-before.Предлагаемое исправление
flex: 1; - padding: 0 3rem;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/app.module.scss` at line 11, Remove the extra empty line immediately before the padding declaration in the affected style block so the declaration-empty-line-before Stylelint violation is resolved, while preserving the existing padding value.Source: Linters/SAST tools
src/pages/about-page/ui/card/card.tsx-33-35 (1)
33-35: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winДобавьте
aria-labelссылке GitHub. Сейчас внутри толькоaria-hidden-иконка, поэтому у ссылки нет доступного имени. Используйтеnameдля label, напримерПрофиль GitHub {name}.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/about-page/ui/card/card.tsx` around lines 33 - 35, Добавьте доступное имя в ссылку GitHub в компоненте карточки, используя aria-label со значением «Профиль GitHub» и именем из переменной name. Сохраните текущую иконку и остальные атрибуты ссылки без изменений.src/shared/api/supabase/get-current-user.ts-5-15 (1)
5-15: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winНе приводить
claimsкUserвsrc/shared/api/supabase/get-current-user.ts:5-14
supabase.auth.getClaims()возвращает JWT claims (JwtPayload), а неUser.as unknown as Userскрывает это расхождение и делает сигнатуру функции ложной. Если нужен именно пользователь Supabase — используйтеgetUser(), иначе верните отдельный тип claims.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/api/supabase/get-current-user.ts` around lines 5 - 15, Update getCurrentUser to use supabase.auth.getUser() when the function must return the Supabase User type, preserving the existing null result for errors or missing users. Remove the unsafe claims-to-User cast and adjust the response access to the getUser result.src/pages/about-page/ui/technology-item/technology-item.module.scss-1-15 (1)
1-15: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winДобавьте отсутствующие CSS-классы.
TechnologyItemобращается кstyles.iconиstyles.name, но здесь объявлен только.item. В результате классы изображения и названия не применятся. Добавьте соответствующие селекторы либо удалите эти обращения из компонента.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/about-page/ui/technology-item/technology-item.module.scss` around lines 1 - 15, Add the missing .icon and .name selectors in the technology-item stylesheet so the styles.icon and styles.name references used by TechnologyItem resolve correctly; keep the existing .item styles unchanged.src/pages/about-page/ui/powered-by-section/powered-by-section.module.scss-1-20 (1)
1-20: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winДобавьте отсутствующие селекторы CSS-модуля.
Компонент использует
styles.section,styles.containerиstyles.heading, но в этом файле определены только.gridи.title. В результате секция потеряет ожидаемые стили контейнера и заголовка.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/about-page/ui/powered-by-section/powered-by-section.module.scss` around lines 1 - 20, Добавьте в CSS-модуль селекторы .section, .container и .heading, которые используются компонентом powered-by-section. Перенесите соответствующие стили контейнера и заголовка из текущих .grid и .title либо сохраните их поведение под ожидаемыми именами, чтобы компонент корректно применял стили секции, контейнера и заголовка.src/features/format-converter/ui/format-toggle.tsx-29-32 (1)
29-32: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winОтсутствует класс
.badgeв SCSS-модуле.
styles.badgeиспользуется здесь, но вformat-toggle.module.scssопределены только.wrapper,.text,.format,.button,.convertIcon— класса.badgeтам нет. В результатеclassNameбудетundefined, и задуманные стили дляBadgeне применятся.🎨 Добавить класс badge в SCSS-модуль
+.badge { + // стили для бейджа формата +}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/format-converter/ui/format-toggle.tsx` around lines 29 - 32, Добавьте класс .badge в SCSS-модуль format-toggle.module.scss и определите для него необходимые стили Badge, чтобы styles.badge в компоненте формата-тоггла разрешался и применялся. Сохраните существующие классы .wrapper, .text, .format, .button и .convertIcon без изменений.src/shared/ui/button-link/button-link.module.scss-7-7 (1)
7-7: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winУберите пустые строки перед декларациями.
Stylelint уже отмечает строки 7 и 14 как ошибки
declaration-empty-line-before; без исправления CI может завершиться с ошибкой.Предлагаемое исправление
gap: 12px; - font-size: 0.875rem; @@ transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); - border-radius: var(--radius-card);Also applies to: 14-14
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/ui/button-link/button-link.module.scss` at line 7, Remove the empty lines immediately before the declarations at the referenced locations in the button-link stylesheet, including the declarations around font-size and the second flagged location, so they comply with Stylelint’s declaration-empty-line-before rule.Source: Linters/SAST tools
src/shared/ui/input/input.module.scss-51-56 (1)
51-56: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winНе фиксируйте высоту
.errorContainer
height: 13pxне оставляет места для длинных сообщений с переносом: текст может налезать на следующий блок, особенно в локализациях и на узких экранах. Лучшеmin-height: 13px.Предлагаемое исправление
.errorContainer { margin-top: 6px; - height: 13px; + min-height: 13px; display: flex;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/ui/input/input.module.scss` around lines 51 - 56, Update the .errorContainer style to use min-height: 13px instead of a fixed height, preserving the existing spacing and flex alignment while allowing long, wrapped error messages to expand without overlapping subsequent content.src/pages/about-page/ui/card/card.module.scss-9-13 (1)
9-13: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winПеренесите
transitionв базовый селектор карточки.Сейчас анимация применяется только при наведении; при уходе курсора карточка возвращается в исходное состояние без плавного перехода.
Предлагаемое исправление
.card { border: 1px solid transparent; + transition: border-color 1s, transform 1s; &:hover { border: 1px solid rgba(255, 255, 255, 0.5); - transition: 1s; transform: translateY(-3px);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/about-page/ui/card/card.module.scss` around lines 9 - 13, Перенесите свойство transition из &:hover в базовый селектор карточки, сохранив текущие значения border и transform только в состоянии наведения, чтобы переходы плавно выполнялись и при наведении, и при уходе курсора.src/shared/ui/badge/badge.module.scss-7-17 (1)
7-17: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winУдалите пустые строки перед декларациями.
Stylelint сообщает ошибки
declaration-empty-line-beforeна Lines 7, 12 и 16. Уберите пустые строки передborder-radius,font-familyиfont-size.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/ui/badge/badge.module.scss` around lines 7 - 17, Remove the empty lines before the border-radius, font-family, and font-size declarations in the badge styles so the declaration-empty-line-before Stylelint errors are resolved.Source: Linters/SAST tools
src/shared/ui/arc-background/arc-background.module.scss-22-29 (1)
22-29: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winУдалите пустые строки перед CSS-декларациями.
Stylelint сообщает ошибки
declaration-empty-line-beforeна Lines 22, 25, 27, 29, 39, 41, 43–53 и 62. Удаление этих пустых строк не изменит визуальный эффект, но позволит пройти проверку стилей.Also applies to: 39-53, 62-62
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/ui/arc-background/arc-background.module.scss` around lines 22 - 29, Remove the empty lines immediately before CSS declarations in the arc background stylesheet, including the declarations around transform, opacity, box-shadow, animation, and the additional affected sections through line 62. Preserve all declaration values and ordering while satisfying Stylelint’s declaration-empty-line-before rule.Source: Linters/SAST tools
src/features/schema-validator/ui/validation-feedback/validation-feedback.module.scss-6-6 (1)
6-6: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winУберите пустую строку перед декларацией
display.Stylelint сообщает об ошибке
declaration-empty-line-beforeна Line 6; из-за этого проверка стилей может завершаться ошибкой.Предлагаемое исправление
border-top: 1px solid var(--bg-surface-2); - display: flex;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/schema-validator/ui/validation-feedback/validation-feedback.module.scss` at line 6, Remove the empty line immediately before the display declaration in the validation-feedback style block, leaving display: flex and the surrounding declarations unchanged so the declaration-empty-line-before lint error is resolved.Source: Linters/SAST tools
🧹 Nitpick comments (14)
src/features/auth/model/action.ts (2)
30-64: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winНет серверной валидации входных данных перед вызовом Supabase.
signInWithPassword/signUpберут значения напрямую изFormDataбез повторной проверки схемой (loginSchema/registerSchemaприменяются только на клиенте черезzodResolver). Поскольку server actions — публично вызываемый эндпоинт, клиентские ограничения (например, минимальная длина пароля из zod-схемы) можно обойти, вызвав действие напрямую с произвольными данными.🛡️ Предлагаемый фикс
+import { loginSchema } from '`@/features/auth-form/model/schemas`'; + export async function signInWithPassword(formData: FormData): Promise<AuthActionResult | void> { const email = getFormValue(formData, 'email'); const password = getFormValue(formData, 'password'); + + const parsed = loginSchema.safeParse({ email, password }); + if (!parsed.success) { + return { error: 'unknownError' }; + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/auth/model/action.ts` around lines 30 - 64, Добавьте серверную валидацию входных данных в signInWithPassword и signUp до вызова createClient и Supabase: извлекайте значения из FormData, проверяйте их соответственно через loginSchema и registerSchema, а при ошибке возвращайте результат в формате AuthActionResult вместо обращения к Supabase. Используйте успешно распарсенные значения для последующего вызова signInWithPassword/signUp и сохраните текущую обработку ошибок Supabase и redirect.
14-28: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winМатчинг по тексту сообщения ошибки противоречит рекомендациям Supabase.
Официальная документация Supabase Auth прямо указывает: Always use error.code and error.name to identify errors, not string matching on error messages. Фолбэк на
message.toLowerCase().includes('already registered')(строка 23) хрупок — при смене формулировки сообщения в будущей версии Supabase классификация ошибки сломается.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/auth/model/action.ts` around lines 14 - 28, Update mapAuthError to remove the message-text fallback that checks for “already registered”; classify authentication errors only through the provided structured error code (and error name if available in the surrounding API), preserving the existing mappings and unknownError fallback.src/pages/about-page/ui/about-hero-section/about-hero-section.module.scss (1)
18-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueЗахардкоженный цвет вместо переменной темы.
#d4bd23не согласуется с остальными стилями файла, которые используютvar(--text-primary)/var(--text-secondary). Стоит завести CSS-переменную для сохранения консистентности темизации.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/about-page/ui/about-hero-section/about-hero-section.module.scss` around lines 18 - 27, Replace the hardcoded color in .courseLabel with the appropriate theme CSS variable, reusing the existing --text-primary or --text-secondary token used elsewhere in the stylesheet. If this accent requires a distinct semantic color, define a dedicated CSS variable through the existing theme mechanism and reference it from .courseLabel.src/pages/about-page/ui/card/card.tsx (1)
26-26: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winНе загружайте все аватары eagerly.
ContributorsSectionсоздаёт карточку для каждого участника, поэтомуloading="eager"инициирует загрузку всех изображений сразу. Оставьте стандартную lazy-загрузку и eager/priority только для изображения, действительно находящегося в первом экране.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/about-page/ui/card/card.tsx` at line 26, Remove the loading="eager" setting from the Image in the contributor card component so avatars use the framework’s default lazy loading. Keep eager or priority loading only on the separate image that is actually visible in the initial viewport.src/pages/about-page/model/useful-links.ts (1)
7-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winСинхронизируйте тип
Iconс реальным API компонентов.
ComponentType<SVGProps<SVGSVGElement>>разрешает передавать любые SVG-пропы, но текущие иконки обрабатывают толькоclassName. Либо сузьте тип до поддерживаемых пропов, либо передавайте остальные пропы в<svg>, чтобы избежать тихого игнорирования настроек.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/about-page/model/useful-links.ts` around lines 7 - 10, Synchronize the Icon type in UsefulLinkConfigItem with the actual icon component API: either narrow it to the supported className prop or update the icon components to forward all received SVG props to their underlying <svg> elements. Ensure the chosen approach prevents unsupported props from being silently accepted and ignored.app/[locale]/layout.tsx (1)
54-62: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winНе получайте текущего пользователя дважды за один рендер.
RootLayoutуже вызываетgetCurrentUser()дляAuthProvider, ноHeaderповторно выполняет тот же запрос. Это создаёт лишнюю работу и может привести к рассинхронизации данных пользователя. ПередайтеuserвHeaderчерез props и удалите повторный lookup из него.Предлагаемое изменение
- <Header /> + <Header user={user} />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/layout.tsx around lines 54 - 62, Update RootLayout and Header so the user returned by getCurrentUser() is passed to Header through props and reused for rendering. Remove Header’s duplicate current-user lookup while preserving the existing AuthProvider initialUser behavior and header display for the supplied user.src/widgets/header/ui/header.tsx (1)
11-14: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winПараллелизуйте независимые
await.
getTranslationsиgetCurrentUserне зависят друг от друга — их можно запускать параллельно черезPromise.all, сократив время ожидания.⚡ Предложение
- const t = await getTranslations('Header'); - const user = await getCurrentUser(); + const [t, user] = await Promise.all([getTranslations('Header'), getCurrentUser()]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/widgets/header/ui/header.tsx` around lines 11 - 14, Update Header to start getTranslations('Header') and getCurrentUser concurrently with Promise.all, then destructure their results while preserving the existing values and subsequent behavior.src/shared/api/supabase/get-current-user.ts (1)
5-9: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winРассмотрите мемоизацию через
React.cache().Каждый вызов
getCurrentUser()создаёт новый клиент и заново валидирует JWT. Если функция вызывается из нескольких серверных компонентов в рамках одного запроса (например, изHeader), это приведёт к повторным проверкам. Согласно найденному описанию паттернаgetCachedUser: "getCachedUser() is just getClaims() wrapped in React's cache() meaning it validates the JWT locally (fast, no network call) and only runs once per request no matter how many components need the user."+import { cache } from 'react'; import 'server-only'; import { createClient } from './server'; -export async function getCurrentUser(): Promise<User | null> { +export const getCurrentUser = cache(async (): Promise<User | null> => { const supabase = await createClient(); ... -} +});🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/api/supabase/get-current-user.ts` around lines 5 - 9, Wrap getCurrentUser with React.cache() so repeated calls within the same server request reuse the result instead of recreating the client and validating claims again. Preserve the existing Promise<User | null> behavior and getClaims-based user resolution.src/pages/home-page/ui/home-page.tsx (1)
61-61: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winУберите debug-лог перед релизом.
console.log(parsedSchema)помечен TODO как временный, но выводит содержимое пользовательской схемы в консоль браузера. Хотите, чтобы я подготовил заглушку дляSwaggerViewerбез лога, или предпочитаете отдельный issue для отслеживания?🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/pages/home-page/ui/home-page.tsx` at line 61, Remove the temporary console.log(parsedSchema) statement from the home-page component, while leaving the parsedSchema handling and SwaggerViewer-related TODO context unchanged.src/shared/lib/parse-to-object.ts (1)
6-8: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winПроверка типа пропускает массивы.
Условие
typeof parsed === 'object' && parsed !== nullистинно и для массивов, но функция затем приводит результат кRecord<string, unknown>. Учитывая, что это общая утилита (используется также вdetectFormatиhome-page.tsx), стоит явно исключить массивы, чтобы контракт возвращаемого типа соответствовал реальным данным.♻️ Предлагаемое исправление
- if (typeof parsed === 'object' && parsed !== null) { + if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) { return parsed as Record<string, unknown>; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/lib/parse-to-object.ts` around lines 6 - 8, Update the object validation in the parsing utility to explicitly reject arrays before returning the value as Record<string, unknown>. Preserve acceptance of non-null plain objects and ensure callers such as detectFormat and home-page.tsx receive only object-shaped records.src/widgets/header/ui/logo/logo.tsx (1)
11-11: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winРассмотрите добавление
priorityдля логотипа.Логотип рендерится в шапке сайта и, вероятно, попадает в LCP-область на каждой странице. Без
priorityNext.js применит lazy loading по умолчанию, что может замедлить отображение логотипа.♻️ Предлагаемое изменение
- <Image src="/logo.png" alt="AURA Editor" width={40} height={40} /> + <Image src="/logo.png" alt="AURA Editor" width={40} height={40} priority />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/widgets/header/ui/logo/logo.tsx` at line 11, Update the header logo Image component to mark this above-the-fold asset as high priority, ensuring Next.js loads it eagerly for LCP. Keep the existing src, alt, width, and height attributes unchanged.next.config.ts (1)
20-34: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueЗамена приведения
unknownна типы изwebpack/next.Приведение
config as { resolve?: {...} }черезunknownработает во время выполнения (мутируется тот же объект), но убирает проверку типов для остальной конфигурации webpack и не защищает от опечаток в структуреresolve. Предпочтительнее использовать типConfigurationиз пакетаwebpack(или тип, экспортируемыйNextConfig['webpack']изnext), чтобы сохранить типобезопасность для всей конфигурации.♻️ Предлагаемое изменение
- webpack: (config: unknown, { isServer }: { isServer: boolean }) => { - const webpackConfig = config as { resolve?: { fallback?: Record<string, boolean | string> } }; - if (!isServer) { - if (!webpackConfig.resolve) { - webpackConfig.resolve = {}; - } - webpackConfig.resolve.fallback = { - ...(webpackConfig.resolve.fallback || {}), + webpack: (config: Configuration, { isServer }: { isServer: boolean }) => { + if (!isServer) { + config.resolve ??= {}; + config.resolve.fallback = { + ...(config.resolve.fallback || {}), fs: false, path: false, url: false, }; } - return webpackConfig; + return config; },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@next.config.ts` around lines 20 - 34, Replace the manual unknown cast in the webpack callback with the appropriate Configuration type from webpack or the type derived from NextConfig['webpack']. Type the callback/configuration directly so resolve.fallback and the returned webpack configuration remain fully type-checked, while preserving the existing client-only fallback mutations.src/shared/api/supabase/middleware.ts (2)
38-39: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
startsWithможет ошибочно матчить похожие по префиксу маршруты.
pathname.startsWith(path)совпадёт не только с точным путём, но и с любым путём, начинающимся на эту строку (например, гипотетический/historywhateverсовпадёт с/history). Сейчас коллизий нет, но по мере роста списка маршрутов это легко превратится в скрытую брешь в защите или ложный редирект со страницы логина.🛡️ Предлагаемое изменение
- const isProtected = PROTECTED_PATHS.some((path) => pathname.startsWith(path)); - const isAuthPage = AUTH_PATHS.some((path) => pathname.startsWith(path)); + const isProtected = PROTECTED_PATHS.some((path) => pathname === path || pathname.startsWith(`${path}/`)); + const isAuthPage = AUTH_PATHS.some((path) => pathname === path || pathname.startsWith(`${path}/`));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/api/supabase/middleware.ts` around lines 38 - 39, Update the route checks in the isProtected and isAuthPage calculations so a configured path matches only the exact pathname or a descendant path separated by “/”, not arbitrary strings sharing its prefix. Preserve matching for the configured route itself and its nested routes while preventing cases such as “/historywhatever” from matching “/history”.
10-13: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winСделать
stripLocaleзависимым от списка локалей, а не от позиции сегмента.
Сейчас функция работает только пока URL всегда начинается с локали. Лучше проверятьsegments[1]поrouting.localesи обрезать префикс только при наличии локали, чтобы не сломатьPROTECTED_PATHS/AUTH_PATHSпри сменеlocalePrefix.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/api/supabase/middleware.ts` around lines 10 - 13, Update stripLocale to remove the first path segment only when segments[1] matches a locale from routing.locales; otherwise return the original pathname unchanged. Preserve the existing slash/path behavior for localized URLs so PROTECTED_PATHS and AUTH_PATHS continue to work when localePrefix changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/pages/about-page/model/technologies.ts`:
- Around line 1-11: Define PNG module typings via next-env.d.ts or
next/image-types/global, then update TechnologyItem.icon to use StaticImageData
instead of typeof reactIcon. Ensure all imported technology icons satisfy the
typed contract consumed by the UI.
In `@src/pages/home-page/ui/home-page.tsx`:
- Around line 15-19: In HomePage, add a load-completion flag for
loadEditorSchema and gate the autosave effect so it cannot run until loading has
finished. Set the flag only after loadEditorSchema completes, while preserving
the existing autosave behavior for subsequent editor changes.
In `@src/shared/ui/code-editor/ui/code-editor.tsx`:
- Around line 30-36: Стабилизируй массив расширений в компоненте CodeEditor:
оберни формирование baseExtensions и allExtensions в useMemo с зависимостями
format, editorTheme, syntaxTheme, readonly и extensions, чтобы ссылка не
менялась без изменения входных значений. В swagger-editor используй стабильную
ссылку для массива [openapiLinter], например через useMemo, передавая её в
CodeEditor.
---
Minor comments:
In `@app/app.module.scss`:
- Line 11: Remove the extra empty line immediately before the padding
declaration in the affected style block so the declaration-empty-line-before
Stylelint violation is resolved, while preserving the existing padding value.
In `@src/features/auth-form/ui/auth-form.module.scss`:
- Around line 1-10: Remove the empty line before the display declaration in the
.card rule, and apply the same change to the corresponding declaration blocks at
the other affected locations. Keep all declarations and styling values
unchanged.
In `@src/features/format-converter/ui/format-toggle.tsx`:
- Around line 29-32: Добавьте класс .badge в SCSS-модуль
format-toggle.module.scss и определите для него необходимые стили Badge, чтобы
styles.badge в компоненте формата-тоггла разрешался и применялся. Сохраните
существующие классы .wrapper, .text, .format, .button и .convertIcon без
изменений.
In
`@src/features/schema-validator/ui/validation-feedback/validation-feedback.module.scss`:
- Line 6: Remove the empty line immediately before the display declaration in
the validation-feedback style block, leaving display: flex and the surrounding
declarations unchanged so the declaration-empty-line-before lint error is
resolved.
In
`@src/features/schema-validator/ui/validation-status/validation-status.module.scss`:
- Line 7: Remove the empty line between the padding declaration and display:
flex in the validation-status style block so declarations are adjacent and
satisfy Stylelint’s declaration-empty-line-before rule.
In `@src/pages/about-page/ui/about-hero-section/about-hero-section.module.scss`:
- Line 85: Update the color declaration in the about hero section stylesheet to
use the lowercase CSS keyword required by Stylelint, changing currentColor to
currentcolor while preserving the existing styling.
In `@src/pages/about-page/ui/card/card.module.scss`:
- Around line 9-13: Перенесите свойство transition из &:hover в базовый селектор
карточки, сохранив текущие значения border и transform только в состоянии
наведения, чтобы переходы плавно выполнялись и при наведении, и при уходе
курсора.
In `@src/pages/about-page/ui/card/card.tsx`:
- Around line 33-35: Добавьте доступное имя в ссылку GitHub в компоненте
карточки, используя aria-label со значением «Профиль GitHub» и именем из
переменной name. Сохраните текущую иконку и остальные атрибуты ссылки без
изменений.
In `@src/pages/about-page/ui/powered-by-section/powered-by-section.module.scss`:
- Around line 1-20: Добавьте в CSS-модуль селекторы .section, .container и
.heading, которые используются компонентом powered-by-section. Перенесите
соответствующие стили контейнера и заголовка из текущих .grid и .title либо
сохраните их поведение под ожидаемыми именами, чтобы компонент корректно
применял стили секции, контейнера и заголовка.
In `@src/pages/about-page/ui/technology-item/technology-item.module.scss`:
- Around line 1-15: Add the missing .icon and .name selectors in the
technology-item stylesheet so the styles.icon and styles.name references used by
TechnologyItem resolve correctly; keep the existing .item styles unchanged.
In `@src/pages/about-page/ui/useful-link-item/useful-link-item.module.scss`:
- Around line 17-23: Update the .iconWrapper styles to define a complete border,
including width and style, while preserving the existing semi-transparent border
color and other properties.
In `@src/shared/api/supabase/get-current-user.ts`:
- Around line 5-15: Update getCurrentUser to use supabase.auth.getUser() when
the function must return the Supabase User type, preserving the existing null
result for errors or missing users. Remove the unsafe claims-to-User cast and
adjust the response access to the getUser result.
In `@src/shared/ui/arc-background/arc-background.module.scss`:
- Around line 22-29: Remove the empty lines immediately before CSS declarations
in the arc background stylesheet, including the declarations around transform,
opacity, box-shadow, animation, and the additional affected sections through
line 62. Preserve all declaration values and ordering while satisfying
Stylelint’s declaration-empty-line-before rule.
In `@src/shared/ui/badge/badge.module.scss`:
- Around line 7-17: Remove the empty lines before the border-radius,
font-family, and font-size declarations in the badge styles so the
declaration-empty-line-before Stylelint errors are resolved.
In `@src/shared/ui/button-link/button-link.module.scss`:
- Line 7: Remove the empty lines immediately before the declarations at the
referenced locations in the button-link stylesheet, including the declarations
around font-size and the second flagged location, so they comply with
Stylelint’s declaration-empty-line-before rule.
In `@src/shared/ui/button/button.module.scss`:
- Around line 61-64: Remove the empty lines before the border and padding
declarations in the .tertiary style block, leaving the declarations contiguous
and preserving their existing values.
In `@src/shared/ui/input/input.module.scss`:
- Around line 51-56: Update the .errorContainer style to use min-height: 13px
instead of a fixed height, preserving the existing spacing and flex alignment
while allowing long, wrapped error messages to expand without overlapping
subsequent content.
In `@src/widgets/swagger-editor/ui/swagger-editor.module.scss`:
- Around line 9-20: Remove the duplicate display and align-items declarations
from the .toolbar rule, keeping each property only once with the existing layout
behavior. Also remove the empty line separating the repeated declarations.
In `@src/widgets/swagger-editor/ui/swagger-editor.tsx`:
- Around line 27-33: Update the validation state used by isValid and
onValidationChange so the initial and text-changed states remain pending until
the asynchronous linter completes for the current value. In the component’s
validation flow, track whether the current text version has been validated,
reset that state when value or format changes, and mark it validated only when
the corresponding check finishes; allow isValid to be true only for completed
validation with zero errors.
---
Nitpick comments:
In `@app/`[locale]/layout.tsx:
- Around line 54-62: Update RootLayout and Header so the user returned by
getCurrentUser() is passed to Header through props and reused for rendering.
Remove Header’s duplicate current-user lookup while preserving the existing
AuthProvider initialUser behavior and header display for the supplied user.
In `@next.config.ts`:
- Around line 20-34: Replace the manual unknown cast in the webpack callback
with the appropriate Configuration type from webpack or the type derived from
NextConfig['webpack']. Type the callback/configuration directly so
resolve.fallback and the returned webpack configuration remain fully
type-checked, while preserving the existing client-only fallback mutations.
In `@src/features/auth/model/action.ts`:
- Around line 30-64: Добавьте серверную валидацию входных данных в
signInWithPassword и signUp до вызова createClient и Supabase: извлекайте
значения из FormData, проверяйте их соответственно через loginSchema и
registerSchema, а при ошибке возвращайте результат в формате AuthActionResult
вместо обращения к Supabase. Используйте успешно распарсенные значения для
последующего вызова signInWithPassword/signUp и сохраните текущую обработку
ошибок Supabase и redirect.
- Around line 14-28: Update mapAuthError to remove the message-text fallback
that checks for “already registered”; classify authentication errors only
through the provided structured error code (and error name if available in the
surrounding API), preserving the existing mappings and unknownError fallback.
In `@src/pages/about-page/model/useful-links.ts`:
- Around line 7-10: Synchronize the Icon type in UsefulLinkConfigItem with the
actual icon component API: either narrow it to the supported className prop or
update the icon components to forward all received SVG props to their underlying
<svg> elements. Ensure the chosen approach prevents unsupported props from being
silently accepted and ignored.
In `@src/pages/about-page/ui/about-hero-section/about-hero-section.module.scss`:
- Around line 18-27: Replace the hardcoded color in .courseLabel with the
appropriate theme CSS variable, reusing the existing --text-primary or
--text-secondary token used elsewhere in the stylesheet. If this accent requires
a distinct semantic color, define a dedicated CSS variable through the existing
theme mechanism and reference it from .courseLabel.
In `@src/pages/about-page/ui/card/card.tsx`:
- Line 26: Remove the loading="eager" setting from the Image in the contributor
card component so avatars use the framework’s default lazy loading. Keep eager
or priority loading only on the separate image that is actually visible in the
initial viewport.
In `@src/pages/home-page/ui/home-page.tsx`:
- Line 61: Remove the temporary console.log(parsedSchema) statement from the
home-page component, while leaving the parsedSchema handling and
SwaggerViewer-related TODO context unchanged.
In `@src/shared/api/supabase/get-current-user.ts`:
- Around line 5-9: Wrap getCurrentUser with React.cache() so repeated calls
within the same server request reuse the result instead of recreating the client
and validating claims again. Preserve the existing Promise<User | null> behavior
and getClaims-based user resolution.
In `@src/shared/api/supabase/middleware.ts`:
- Around line 38-39: Update the route checks in the isProtected and isAuthPage
calculations so a configured path matches only the exact pathname or a
descendant path separated by “/”, not arbitrary strings sharing its prefix.
Preserve matching for the configured route itself and its nested routes while
preventing cases such as “/historywhatever” from matching “/history”.
- Around line 10-13: Update stripLocale to remove the first path segment only
when segments[1] matches a locale from routing.locales; otherwise return the
original pathname unchanged. Preserve the existing slash/path behavior for
localized URLs so PROTECTED_PATHS and AUTH_PATHS continue to work when
localePrefix changes.
In `@src/shared/lib/parse-to-object.ts`:
- Around line 6-8: Update the object validation in the parsing utility to
explicitly reject arrays before returning the value as Record<string, unknown>.
Preserve acceptance of non-null plain objects and ensure callers such as
detectFormat and home-page.tsx receive only object-shaped records.
In `@src/widgets/header/ui/header.tsx`:
- Around line 11-14: Update Header to start getTranslations('Header') and
getCurrentUser concurrently with Promise.all, then destructure their results
while preserving the existing values and subsequent behavior.
In `@src/widgets/header/ui/logo/logo.tsx`:
- Line 11: Update the header logo Image component to mark this above-the-fold
asset as high priority, ensuring Next.js loads it eagerly for LCP. Keep the
existing src, alt, width, and height attributes unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 767b67a3-ac1d-4d0b-a667-1063a81cc3b2
⛔ Files ignored due to path filters (8)
package-lock.jsonis excluded by!**/package-lock.jsonpublic/logo.pngis excluded by!**/*.pngsrc/pages/about-page/assets/icons/nextjs.pngis excluded by!**/*.pngsrc/pages/about-page/assets/icons/react.pngis excluded by!**/*.pngsrc/pages/about-page/assets/icons/sass.pngis excluded by!**/*.pngsrc/pages/about-page/assets/icons/supabase.pngis excluded by!**/*.pngsrc/pages/about-page/assets/icons/typescript.pngis excluded by!**/*.pngsrc/pages/about-page/assets/icons/vite.pngis excluded by!**/*.png
📒 Files selected for processing (128)
.commitlintrc.json.env.local.example.github/workflows/checks.yml.gitignoreapp/[locale]/about/page.tsxapp/[locale]/history/page.tsxapp/[locale]/home/page.tsxapp/[locale]/layout.tsxapp/[locale]/login/page.tsxapp/[locale]/register/page.tsxapp/app.module.scssmessages/en.jsonmessages/ru.jsonnext.config.tspackage.jsonproxy.tssrc/app/styles/abstract/_constants.scsssrc/app/styles/style.scsssrc/features/.gitkeepsrc/features/auth-form/index.tssrc/features/auth-form/model/schemas.tssrc/features/auth-form/ui/auth-form.module.scsssrc/features/auth-form/ui/auth-form.tsxsrc/features/auth/index.tssrc/features/auth/model/action.tssrc/features/auth/model/auth-provider.tsxsrc/features/format-converter/index.tssrc/features/format-converter/lib/convert-format.test.tssrc/features/format-converter/lib/convert-format.tssrc/features/format-converter/lib/detect-format.test.tssrc/features/format-converter/lib/detect-format.tssrc/features/format-converter/ui/format-toggle.module.scsssrc/features/format-converter/ui/format-toggle.tsxsrc/features/language-switcher/index.tssrc/features/language-switcher/ui/language-switcher.module.scsssrc/features/language-switcher/ui/language-switcher.tsxsrc/features/schema-persistence/api/editor-schema.tssrc/features/schema-validator/index.tssrc/features/schema-validator/lib/codemirror-linter.tssrc/features/schema-validator/lib/validate-schema.test.tssrc/features/schema-validator/lib/validate-schema.tssrc/features/schema-validator/ui/validation-feedback/validation-feedback.module.scsssrc/features/schema-validator/ui/validation-feedback/validation-feedback.tsxsrc/features/schema-validator/ui/validation-status/validation-status.module.scsssrc/features/schema-validator/ui/validation-status/validation-status.tsxsrc/pages/.gitkeepsrc/pages/about-page/index.tssrc/pages/about-page/model/contributors.tssrc/pages/about-page/model/technologies.tssrc/pages/about-page/model/useful-links.tssrc/pages/about-page/ui/about-hero-section/about-hero-section.module.scsssrc/pages/about-page/ui/about-hero-section/about-hero-section.tsxsrc/pages/about-page/ui/about-page.module.scsssrc/pages/about-page/ui/about-page.tsxsrc/pages/about-page/ui/about-project-section/about-project-section.module.scsssrc/pages/about-page/ui/about-project-section/about-project-section.tsxsrc/pages/about-page/ui/card/card.module.scsssrc/pages/about-page/ui/card/card.tsxsrc/pages/about-page/ui/contributors-section/contributors-section.module.scsssrc/pages/about-page/ui/contributors-section/contributors-section.tsxsrc/pages/about-page/ui/powered-by-section/powered-by-section.module.scsssrc/pages/about-page/ui/powered-by-section/powered-by-section.tsxsrc/pages/about-page/ui/technology-item/technology-item.module.scsssrc/pages/about-page/ui/technology-item/technology-item.tsxsrc/pages/about-page/ui/useful-link-item/useful-link-item.module.scsssrc/pages/about-page/ui/useful-link-item/useful-link-item.tsxsrc/pages/about-page/ui/useful-links-section/useful-links-section.module.scsssrc/pages/about-page/ui/useful-links-section/useful-links-section.tsxsrc/pages/home-page/index.tssrc/pages/home-page/ui/home-page.module.scsssrc/pages/home-page/ui/home-page.tsxsrc/pages/login/index.tssrc/pages/login/ui/login.module.scsssrc/pages/login/ui/login.tsxsrc/pages/register/index.tssrc/pages/register/ui/register.module.scsssrc/pages/register/ui/register.tsxsrc/shared/api/supabase/client.tssrc/shared/api/supabase/get-current-user.tssrc/shared/api/supabase/index.tssrc/shared/api/supabase/middleware.tssrc/shared/api/supabase/server.tssrc/shared/api/utils/form.tssrc/shared/config/env.tssrc/shared/config/routes.tssrc/shared/lib/hooks/index.tssrc/shared/lib/hooks/use-debounce.tssrc/shared/lib/parse-to-object.tssrc/shared/types/format.tssrc/shared/ui/arc-background/arc-background.module.scsssrc/shared/ui/arrow-icon/arrow-icon.tsxsrc/shared/ui/arrow-icon/index.tssrc/shared/ui/badge/badge.module.scsssrc/shared/ui/badge/badge.tsxsrc/shared/ui/brackets-icon/brackets-icon.tsxsrc/shared/ui/brackets-icon/index.tssrc/shared/ui/button-link/button-link.module.scsssrc/shared/ui/button-link/button-link.test.tsxsrc/shared/ui/button-link/button-link.tsxsrc/shared/ui/button-link/index.tssrc/shared/ui/button/button.module.scsssrc/shared/ui/button/button.tsxsrc/shared/ui/code-editor/index.tssrc/shared/ui/code-editor/lib/theme.tssrc/shared/ui/code-editor/ui/code-editor.module.scsssrc/shared/ui/code-editor/ui/code-editor.tsxsrc/shared/ui/github-icon/github-icon.tsxsrc/shared/ui/github-icon/index.tssrc/shared/ui/graduation-cap-icon/graduation-cap-icon.tsxsrc/shared/ui/input/input.module.scsssrc/widgets/.gitkeepsrc/widgets/footer/index.tssrc/widgets/footer/ui/footer.module.scsssrc/widgets/footer/ui/footer.tsxsrc/widgets/header/index.tssrc/widgets/header/ui/header.module.scsssrc/widgets/header/ui/header.tsxsrc/widgets/header/ui/logo/index.tssrc/widgets/header/ui/logo/logo.tsxsrc/widgets/header/ui/page-navigation/index.tssrc/widgets/header/ui/page-navigation/page-navigation.tsxsrc/widgets/header/ui/private-navigation/index.tssrc/widgets/header/ui/private-navigation/private-navigation.tsxsrc/widgets/header/ui/public-navigation/index.tssrc/widgets/header/ui/public-navigation/public-navigation.tsxsrc/widgets/swagger-editor/index.tssrc/widgets/swagger-editor/ui/swagger-editor.module.scsssrc/widgets/swagger-editor/ui/swagger-editor.tsx
| import reactIcon from '../assets/icons/react.png'; | ||
| import typescriptIcon from '../assets/icons/typescript.png'; | ||
| import nextjsIcon from '../assets/icons/nextjs.png'; | ||
| import scssIcon from '../assets/icons/sass.png'; | ||
| import viteIcon from '../assets/icons/vite.png'; | ||
| import supabaseIcon from '../assets/icons/supabase.png'; | ||
|
|
||
| export interface TechnologyItem { | ||
| id: 'react' | 'typescript' | 'nextjs' | 'sass' | 'vite' | 'supabase'; | ||
| name: string; | ||
| icon: typeof reactIcon; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## technologies.ts\n'
cat -n src/pages/about-page/model/technologies.ts
printf '\n## search for image type declarations and PNG handling\n'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' "next/image-types/global|StaticImageData|declare module '.*png'|\\.png'" .
printf '\n## related consumer of technology.icon\n'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' "technology\.icon|TechnologyItem|PoweredBySection" srcRepository: FierceSloth/swagger-editor-app
Length of output: 3562
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## next-env / tsconfig / module declarations\n'
git ls-files | rg '^(next-env\.d\.ts|tsconfig.*|.*d\.ts)$' || true
for f in next-env.d.ts tsconfig.json tsconfig.app.json src/**/*.d.ts; do
if [ -f "$f" ]; then
echo
echo "### $f"
cat -n "$f" | sed -n '1,220p'
fi
done
printf '\n## technology-item implementation\n'
cat -n src/pages/about-page/ui/technology-item/technology-item.tsxRepository: FierceSloth/swagger-editor-app
Length of output: 2433
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## tracked files related to Next image typing\n'
git ls-files | rg '(^|/)(next-env\.d\.ts|global\.d\.ts|.*image.*\.d\.ts|.*png.*\.d\.ts)$' || true
printf '\n## filesystem presence of likely declarations\n'
find . -maxdepth 3 \( -name 'next-env.d.ts' -o -name '*.d.ts' \) | sort
printf '\n## all imports of png assets in src/pages/about-page\n'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' "from '.*\.png'|from \".*\.png\"" src/pages/about-pageRepository: FierceSloth/swagger-editor-app
Length of output: 16445
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n## next/image.d.ts\n'
sed -n '1,220p' node_modules/next/image.d.ts
printf '\n## png module declarations in next package\n'
rg -n "declare module '.*\\.(png|jpg|jpeg|gif|webp|avif)'|StaticImageData" node_modules/next -g '*.d.ts'Repository: FierceSloth/swagger-editor-app
Length of output: 2585
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import json, os, subprocess, tempfile, textwrap, pathlib, sys
repo = pathlib.Path('.').resolve()
tsconfig = repo / 'tsconfig.json'
tmp = pathlib.Path(tempfile.mkdtemp(prefix='ts-img-type-'))
probe = tmp / 'probe.ts'
probe.write_text(textwrap.dedent("""
import reactIcon from './src/pages/about-page/assets/icons/react.png';
type T = typeof reactIcon;
const x: T = reactIcon;
""").lstrip())
# Use TypeScript compiler API to inspect the imported PNG type.
script = textwrap.dedent(f"""
const ts = require('typescript');
const fs = require('fs');
const path = require('path');
const configPath = ts.findConfigFile({json.dumps(str(repo))}, ts.sys.fileExists, 'tsconfig.json');
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
const config = ts.parseJsonConfigFileContent(configFile.config, ts.sys, {json.dumps(str(repo))});
config.fileNames = config.fileNames.concat([{json.dumps(str(probe))}]);
const program = ts.createProgram({json.dumps([str(probe)])}, config.options);
const checker = program.getTypeChecker();
const source = program.getSourceFile({json.dumps(str(probe))});
const importDecl = source.statements.find(s => ts.isImportDeclaration(s));
const localName = importDecl.importClause.name;
const symbol = checker.getSymbolAtLocation(localName);
const type = checker.getTypeOfSymbolAtLocation(symbol, localName);
console.log('typeString=' + checker.typeToString(type));
const decls = symbol.getDeclarations() || [];
for (const d of decls) {{
console.log('decl=' + path.relative({json.dumps(str(repo))}, d.getSourceFile().fileName) + ':' + d.pos + '-' + d.end);
}}
""")
p = subprocess.run(['node', '-e', script], cwd=repo, capture_output=True, text=True)
print(p.stdout)
print(p.stderr, file=sys.stderr)
print('exit=', p.returncode)
if p.returncode != 0:
sys.exit(p.returncode)
PYRepository: FierceSloth/swagger-editor-app
Length of output: 246
Добавьте типы для PNG-импортов
react.png и остальные иконки здесь сейчас попадают как any, поэтому icon: typeof reactIcon не дает безопасного контракта. Добавьте next-env.d.ts/подключите next/image-types/global и типизируйте icon как StaticImageData — это уже ожидает TechnologyItem в UI.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/about-page/model/technologies.ts` around lines 1 - 11, Define PNG
module typings via next-env.d.ts or next/image-types/global, then update
TechnologyItem.icon to use StaticImageData instead of typeof reactIcon. Ensure
all imported technology icons satisfy the typed contract consumed by the UI.
Sources: Linters/SAST tools, Pipeline failures
| export function HomePage() { | ||
| const { user } = useAuth(); | ||
| const [rawText, setRawText] = useState(''); | ||
| const [isSchemaValid, setIsSchemaValid] = useState(false); | ||
| const debouncedText = useDebounce(rawText, DEBOUNCE_DELAY_SIZE_MS); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
cat -n src/shared/lib/hooks/use-debounce.tsRepository: FierceSloth/swagger-editor-app
Length of output: 669
🏁 Script executed:
#!/bin/bash
set -e
cat -n src/pages/home-page/ui/home-page.tsx | sed -n '1,220p'Repository: FierceSloth/swagger-editor-app
Length of output: 2766
Автосохранение может перезаписать сохранённую схему пустой строкой
useDebounce инициализируется текущим значением, поэтому при первом рендере debouncedText === ''. Эффект автосохранения запускается до завершения loadEditorSchema и успевает отправить content: '', что может затереть уже сохранённую схему. Добавь флаг завершения загрузки и не запускай autosave до его установки.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/home-page/ui/home-page.tsx` around lines 15 - 19, In HomePage, add
a load-completion flag for loadEditorSchema and gate the autosave effect so it
cannot run until loading has finished. Set the flag only after loadEditorSchema
completes, while preserving the existing autosave behavior for subsequent editor
changes.
| const baseExtensions = [ | ||
| format === 'json' ? json() : yaml(), | ||
| editorTheme, | ||
| syntaxTheme, | ||
| EditorState.readOnly.of(readonly), | ||
| ]; | ||
| const allExtensions = [...(extensions || []), ...baseExtensions]; |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the target file and nearby context.
printf '\n## file list\n'
git ls-files 'src/shared/ui/code-editor/ui/code-editor.tsx' 'package.json' 'pnpm-lock.yaml' 'package-lock.json' 'yarn.lock' 2>/dev/null || true
printf '\n## target file outline\n'
ast-grep outline src/shared/ui/code-editor/ui/code-editor.tsx --view expanded || true
printf '\n## target file snippet\n'
cat -n src/shared/ui/code-editor/ui/code-editor.tsx | sed -n '1,220p'
printf '\n## package references for CodeMirror wrappers\n'
rg -n "`@uiw/react-codemirror`|codemirror|react-codemirror" -S . --glob '!**/node_modules/**' || trueRepository: FierceSloth/swagger-editor-app
Length of output: 10308
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect package manifest for dependency versions and if the wrapper behavior is documented in repo.
for f in package.json pnpm-lock.yaml package-lock.json yarn.lock; do
if [ -f "$f" ]; then
printf '\n## %s\n' "$f"
rg -n "`@uiw/react-codemirror`|codemirror|`@codemirror/state`" "$f" || true
fi
done
# Search for useMemo around similar editor components to infer local conventions.
rg -n "useMemo\\(|EditorState.readOnly|extensions" src --glob '!**/node_modules/**' || trueRepository: FierceSloth/swagger-editor-app
Length of output: 5377
🌐 Web query:
@uiw/react-codemirror extensions prop reconfigure array reference useMemo source code
💡 Result:
The @uiw/react-codemirror library relies on React's dependency tracking to trigger updates when the extensions prop changes [1]. Specifically, the library's internal hook, useCodeMirror.ts, contains a useEffect that monitors the extensions prop [1]. When the reference of the extensions array changes, this effect fires and triggers a state reconfiguration by dispatching a CodeMirror StateEffect.reconfigure effect [2][1]. Because this useEffect re-runs whenever the extensions array reference changes, creating a new array literal directly in the component's render body (e.g., extensions={[myExtension]}) will cause the editor to reconfigure on every render, which can lead to performance issues or unexpected behavior [3][4][5]. To avoid these unnecessary re-renders and reconfigurations, you should stabilize the reference of the extensions array using React.useMemo [3][4]. By wrapping your extensions array in useMemo with the appropriate dependency array, the reference remains stable across renders unless the dependencies change, preventing the library's internal effect from triggering redundant updates [3][6]. Example implementation: const extensions = useMemo( => [javascript,...otherExtensions], [dependencies]); This pattern ensures that the editor is only reconfigured when the actual extension definitions or their dependencies truly change [3][1].
Citations:
- 1: https://github.com/uiwjs/react-codemirror/blob/master/core/src/useCodeMirror.ts
- 2: https://codemirror.net/docs/ref/
- 3: https://uiwjs.github.io/react-codemirror/
- 4: https://github.com/uiwjs/react-codemirror
- 5: Code examples cause lots of re-renders due to redefintions of
extensionsandonChangeuiwjs/react-codemirror#308 - 6: https://www.npmjs.com/package/@uiw/react-codemirror
🌐 Web query:
site:github.com uiwjs/react-codemirror extensions reconfigure useEffect props.extensions
💡 Result:
In uiwjs/react-codemirror, passing a new array reference to the extensions prop during a React re-render will trigger updates within the component [1][2][3]. Because the CodeMirror component re-evaluates the extensions prop, frequently redefining this array inside your component body without memoization can cause unnecessary re-renders or performance issues [1][2]. To handle extensions correctly and avoid performance degradation: 1. Use useMemo: If your extensions depend on state or props, wrap the extensions array in a useMemo hook to ensure the reference only changes when the dependencies actually update [2][4]. import { useMemo } from 'react'; import CodeMirror from '@uiw/react-codemirror'; import { javascript } from '@codemirror/lang-javascript'; function MyEditor({ isJsx }) { const extensions = useMemo( => [javascript({ jsx: isJsx })], [isJsx]); return ; } 2. Static Extensions: If your extensions are constant, define them outside of your component function or wrap them in useMemo with an empty dependency array to maintain a stable reference [1][2]. 3. Reconfiguration Limitations: Note that while the component updates when the extensions prop changes, it does not always perform a granular reconfigure (e.g., calling EditorView.dispatch with StateEffect.reconfigure) for every extension change [5]. Implementing complex dynamic reconfiguration manually may encounter limitations within the current library architecture [5]. Always check the library's GitHub issues for specific constraints on hot-swapping certain types of extensions [5].
Citations:
- 1: Code examples cause lots of re-renders due to redefintions of
extensionsandonChangeuiwjs/react-codemirror#308 - 2: https://github.com/uiwjs/react-codemirror/tree/master/core
- 3: https://github.com/uiwjs/react-codemirror/tree/d320d95f1b2c33ebbc9ccbe14f2def5bd8a57539
- 4: https://github.com/uiwjs/react-codemirror/tree/refs/heads/master
- 5: Merge view - jumping onChange uiwjs/react-codemirror#681
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cat -n src/widgets/swagger-editor/ui/swagger-editor.tsx | sed -n '1,180p'Repository: FierceSloth/swagger-editor-app
Length of output: 3177
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check whether the linter extension itself is memoized/stable.
cat -n src/features/schema-validator/lib/codemirror-linter.ts | sed -n '1,220p'Repository: FierceSloth/swagger-editor-app
Length of output: 1732
Стабилизируй extensions для CodeMirror
allExtensions пересоздаётся на каждом рендере, а в src/widgets/swagger-editor/ui/swagger-editor.tsx массив ещё и передаётся как новый литерал ([openapiLinter]). Из-за этого @uiw/react-codemirror будет лишний раз переинициализировать редактор на частых обновлениях. Вынеси массив в useMemo или константу и передавай стабильную ссылку.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/shared/ui/code-editor/ui/code-editor.tsx` around lines 30 - 36,
Стабилизируй массив расширений в компоненте CodeEditor: оберни формирование
baseExtensions и allExtensions в useMemo с зависимостями format, editorTheme,
syntaxTheme, readonly и extensions, чтобы ссылка не менялась без изменения
входных значений. В swagger-editor используй стабильную ссылку для массива
[openapiLinter], например через useMemo, передавая её в CodeEditor.
📋 Trello Task ID
⚡️ Summary
Implemented and styled the About page, adding course information, technology stack details, and a dedicated contributors section with team roles and GitHub links.
🛠 Type of change
feat(New feature)fix(Bug fix)refactor(Code improvement / Refactoring without changing logic)style(Formatting, CSS)docs(Documentation)chore(Configs, Build)test(Testing)📷 Screenshots / GIFs
Summary by CodeRabbit
Summary by CodeRabbit