mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
fix: feature-base-refactoring (#297)
* docs: add AGENTS.md with feature-based architecture conventions Defines the target src/ structure, feature list, naming conventions (kebab-case, file type patterns), import direction rules, and feature boundary guidelines for the planned big-bang refactor. * docs: add features/channel/ to architecture conventions Generic channel UI (card, modal, form) goes to features/channel/. Provider-specific sub-folders: channel/notifications/ and channel/storages/. * refactor: move event emitter to lib/, project service to db/services/, dedup use-mobile hook * fix: remove unused auth import in db/services/project.ts * refactor: migrate wrappers/common to components/common (flat) * fix: remove dead commented-out code from button-with-loading.tsx * refactor: merge features/browser into features/theme, flatten upload/updates, migrate statistics * refactor: migrate wrappers/auth to features/auth Move all auth components and forms from src/components/wrappers/auth/ into src/features/auth/ with flat kebab-case naming. Handle extra reset-password-form.tsx and differing reset-password-schema.ts by copying them as reset-password-page-form.tsx and reset-password-page.schema.ts. * refactor: remove dead auth files and fix zPassword schema Delete reset-password-section.tsx and reset-password-page-form.tsx (zero consumers). Fix reset-password-page.schema.ts to import zPassword from @/lib/zod. * refactor: migrate wrappers/dashboard/common to features/layout, rename Header.tsx to header.tsx * fix: decouple layout from theme/updates cross-feature imports Use slot props (actions, updateNotification) so app/ composes ModeToggle and UpdateNotification into Header and AppSidebar. Delete dead side-bar-logo.tsx (zero consumers). * refactor: merge features/keys into features/agents, flatten sub-dirs, migrate agent wrappers - Merge src/features/keys/keys.action.ts into src/features/agents/ - Flatten src/features/agents/components/ and hooks/ into feature root - Migrate all src/components/wrappers/dashboard/agent/ files into src/features/agents/ - Update all import paths across app/ and src/ accordingly - Fix broken code-snippet import in agent-key-modal.tsx (was pointing to non-existent wrappers path) * fix: move github-releases to lib/, remove dead code and unused imports Move GitHub release fetch logic from features/updates/github.ts to lib/github-releases.ts so both features/updates and features/agents can import it without cross-feature imports. Remove commented-out impersonation block from agent-database-card.tsx. Remove unused imports (CopyButton, Terminal, Key, Info). * refactor: flatten features/projects/components, migrate project wrappers Move project.dialog/form out of sub-dir, migrate project-card, project-database-card, and delete-project button/action from wrappers into features/projects/. Update all import paths across src/ and app/. Leave wrappers/dashboard/projects/database/ untouched for Task 10. * fix: extract DatabaseCard to components/common, remove cross-feature import DatabaseCard was imported by both features/projects and features/agents, violating the no-cross-feature-import rule. Extract to components/common/ database-card.tsx so both features import from the shared layer. Also tighten extendedProps type and remove commented-out maxCount prop. * refactor: migrate all database/backup/restore/health UI to features/database Consolidates ~40 files from 5 source locations (features/dashboard/backup, features/dashboard/restore, wrappers/dashboard/backup, wrappers/dashboard/database, wrappers/dashboard/health, wrappers/dashboard/projects/database) into the new flat features/database directory with kebab-case filenames and updated @/ imports. * fix: remove dead restore-form files and console.log from health-grid Delete restore-form.tsx (186 lines all commented-out, zero consumers) and restore-form.schema.ts (only a commented import). Remove console.log(logs) from getOldestLog helper in health-grid.tsx. Cross-feature imports (database→storages for dispatchStorage/storeBackupFiles) are accepted as known architectural coupling — storage dispatch is called from database server actions at runtime and cannot route through app/ props. * refactor: migrate wrappers/admin/users to features/users, fix table-colums typo * fix: fix relative imports, string interpolation, and console.error in users feature Replace relative imports with @/ aliases in user-actions-cell.tsx and admin-user-edit-modal.tsx. Fix string interpolation bug in dialog title (was regular string, now template literal). Remove console.error from admin-user-change-role-modal.tsx. * refactor: migrate wrappers/profile to features/profile, fix profile-apperance typo * fix: remove console.error calls and ts-ignore in profile feature Remove console.error from profile-account.tsx, 2fa-form.tsx (x2). Replace @ts-ignore on fileInput.onchange with typed cast in avatar-with-upload.tsx. * refactor: rename features/organization to features/organizations, migrate all org wrappers Moves 37 org-related files from features/organization/, features/dashboard/, hooks/, wrappers/admin/organizations/, wrappers/admin/channels/organization/, and wrappers/dashboard/organization/ into a flat features/organizations/ feature directory. Updates all import paths codebase-wide. Fixes @ts-ignore and removes unused @better-fetch/fetch import in admin-organization-form. * fix: remove console.error, @ts-ignore, and unused destructures in features/organizations * refactor: migrate wrappers/organization/migration to features/migration Move all 5 migration files to src/features/migration/, update internal imports to @/features/migration/ absolute paths, remove console.log, and delete src/components/wrappers/dashboard/organization/ entirely. * refactor: migrate wrappers/admin/settings to features/settings Move all 14 settings files (email, notification, storage, s3) from wrappers/dashboard/admin/settings/ into features/settings/, rewriting imports, replacing @ts-ignore with @ts-expect-error, and renaming error params to _error where applicable. * refactor: rename notifications files to kebab convention, migrate notification logs - Rename dispatch.ts/helpers.ts/types.ts to notifications.*.ts - Migrate notification logs components from wrappers/dashboard/admin/notifications/logs/ to features/notifications/ - Fix all import paths across codebase and in providers/ - Remove unused useRouter import, replace @ts-ignore with @ts-expect-error - Delete src/components/wrappers/dashboard/admin/notifications/ * refactor: rename storages dispatch/helpers/types to kebab convention - Rename dispatch.ts/helpers.ts/types.ts to storages.*.ts - Fix all import paths across codebase and in providers/ - Fix relative ../types and ../../types imports in all storage providers to absolute @/ paths - Replace @ts-ignore with @ts-expect-error, remove console.debug/console.error * refactor: create features/channel with generic UI and notifications/storages provider sub-folders Consolidates 4 source locations into src/features/channel/: - components/wrappers/dashboard/admin/channels/ → features/channel/ (11 generic UI files) - features/notifications/providers/ → features/channel/notifications/ (9 backend + 18 form files) - features/storages/providers/ → features/channel/storages/ (backend + forms) The two conflicting google-drive/helpers.ts files (client helpers vs OAuth action) are kept separate: helpers.ts and google-drive-refresh.action.ts. Rewrites all imports codebase-wide to point to new locations. Removes console.log/console.error calls, upgrades @ts-ignore to @ts-expect-error. * fix: remove console.error from local storage provider * fix: multi-select.tsx scroll issue * fix: multi-select.tsx scroll issue
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { CardContent, CardHeader } from "@/components/ui/card";
|
||||
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { ForgotPasswordForm } from "@/components/wrappers/auth/login/forgot-password-form/forgot-password-form";
|
||||
import { ForgotPasswordForm } from "@/features/auth/forgot-password-form";
|
||||
import { env } from "@/env.mjs";
|
||||
import { CardAuth } from "@/features/layout/card-auth";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {CardContent, CardHeader} from "@/components/ui/card";
|
||||
import {TooltipProvider} from "@/components/ui/tooltip";
|
||||
import {GuardForm} from "@/components/wrappers/auth/guard/guard-form";
|
||||
import {GuardForm} from "@/features/auth/guard-form";
|
||||
import {cookies} from "next/headers";
|
||||
import {redirect} from "next/navigation";
|
||||
import {CardAuth} from "@/features/layout/card-auth";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { redirect } from "next/navigation";
|
||||
import { currentUser } from "@/lib/auth/current-user";
|
||||
import { AuthLogoSection } from "@/components/wrappers/auth/auth-logo-section";
|
||||
import { AuthLogoSection } from "@/features/auth/auth-logo-section";
|
||||
import { Heart } from "lucide-react";
|
||||
|
||||
export default async function Layout({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { LoginForm } from "@/components/wrappers/auth/login/login-form/login-form";
|
||||
import { LoginForm } from "@/features/auth/login-form";
|
||||
import { Metadata } from "next";
|
||||
import { SUPPORTED_PROVIDERS } from "@/lib/auth/config";
|
||||
import { SocialAuthButtons } from "@/components/wrappers/auth/social-buttons";
|
||||
import { SocialAuthButtons } from "@/features/auth/social-buttons";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { CardContent, CardHeader } from "@/components/ui/card";
|
||||
import Link from "next/link";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PageParams } from "@/types/next";
|
||||
import { RegisterForm } from "@/components/wrappers/auth/register/register-form/register-form";
|
||||
import { RegisterForm } from "@/features/auth/register-form";
|
||||
import { Metadata } from "next";
|
||||
import { redirect } from "next/navigation";
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { ResetPasswordForm } from "@/components/wrappers/auth/login/reset-password-form/reset-password-form";
|
||||
import { ResetPasswordForm } from "@/features/auth/reset-password-form";
|
||||
import { redirect } from "next/navigation";
|
||||
import { auth } from "@/lib/auth/auth";
|
||||
import { Avatar, AvatarImage, AvatarFallback } from "@radix-ui/react-avatar";
|
||||
|
||||
@@ -4,7 +4,7 @@ import {db} from "@/db";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {PageParams} from "@/types/next";
|
||||
import {Page} from "@/features/layout/page";
|
||||
import {OrganizationManagement} from "@/components/wrappers/dashboard/admin/organizations/organization/organization-management";
|
||||
import {OrganizationManagement} from "@/features/organizations/admin-organization-management";
|
||||
import {buildOrganizationWithMembers} from "@/utils/common";
|
||||
import {isUUID} from "@/utils/text";
|
||||
import {user} from "@/db/schema/02_user";
|
||||
|
||||
@@ -3,8 +3,8 @@ import {Page, PageActions, PageContent, PageHeader, PageTitle} from "@/features/
|
||||
import {db} from "@/db";
|
||||
import {
|
||||
AdminOrganizationAddModal
|
||||
} from "@/components/wrappers/dashboard/admin/organizations/organization/admin-organization-add-modal";
|
||||
import {AdminOrganizationList} from "@/components/wrappers/dashboard/admin/organizations/organization/admin-orgnization-list";
|
||||
} from "@/features/organizations/admin-organization-add-modal";
|
||||
import {AdminOrganizationList} from "@/features/organizations/admin-organization-list";
|
||||
import {isNull} from "drizzle-orm";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{}>) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {db} from "@/db";
|
||||
import {logger} from "@/lib/logger";
|
||||
import {notFound} from "next/navigation";
|
||||
import {SettingsTabs} from "@/components/wrappers/dashboard/admin/settings/settings-tabs";
|
||||
import {SettingsTabs} from "@/features/settings/settings-tabs";
|
||||
import {desc, isNull} from "drizzle-orm";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {StorageChannelWith} from "@/db/schema/12_storage-channel";
|
||||
|
||||
@@ -2,8 +2,8 @@ import {PageParams} from "@/types/next";
|
||||
import {Page, PageActions, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {db} from "@/db";
|
||||
import {desc, isNull} from "drizzle-orm";
|
||||
import {AdminUserList} from "@/components/wrappers/dashboard/admin/users/admin-user-list";
|
||||
import {AdminUserAddModal} from "@/components/wrappers/dashboard/admin/users/admin-user-add-modal";
|
||||
import {AdminUserList} from "@/features/users/admin-user-list";
|
||||
import {AdminUserAddModal} from "@/features/users/admin-user-add-modal";
|
||||
import {SUPPORTED_PROVIDERS} from "@/lib/auth/config";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{}>) {
|
||||
|
||||
@@ -9,12 +9,12 @@ import { db } from "@/db";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {eq, isNull} from "drizzle-orm";
|
||||
import { notFound } from "next/navigation";
|
||||
import { ButtonDeleteAgent } from "@/components/wrappers/dashboard/agent/button-delete-agent/button-delete-agent";
|
||||
import { ButtonDeleteAgent } from "@/features/agents/agent-delete-button";
|
||||
import { capitalizeFirstLetter } from "@/utils/text";
|
||||
import { generateEdgeKey } from "@/utils/edge_key";
|
||||
import { getServerUrl } from "@/utils/get-server-url";
|
||||
import { AgentContentPage } from "@/components/wrappers/dashboard/agent/agent-content";
|
||||
import { AgentDialog } from "@/features/agents/components/agent.dialog";
|
||||
import { AgentContentPage } from "@/features/agents/agent-content";
|
||||
import { AgentDialog } from "@/features/agents/agent-dialog";
|
||||
|
||||
|
||||
export default async function RoutePage(
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {PageParams} from "@/types/next";
|
||||
import {AgentCard} from "@/components/wrappers/dashboard/agent/agent-card/agent-card";
|
||||
import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination";
|
||||
import {AgentCard} from "@/features/agents/agent-card";
|
||||
import {CardsWithPagination} from "@/components/common/cards-with-pagination";
|
||||
import {Page, PageActions, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {notFound} from "next/navigation";
|
||||
import {db} from "@/db";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {and, desc, eq, isNull, not} from "drizzle-orm";
|
||||
import {Metadata} from "next";
|
||||
import {AgentDialog} from "@/features/agents/components/agent.dialog";
|
||||
import {AgentDialog} from "@/features/agents/agent-dialog";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Agents",
|
||||
|
||||
@@ -4,8 +4,8 @@ import {Metadata} from "next";
|
||||
import {db} from "@/db";
|
||||
import {notificationChannel, NotificationChannelWith} from "@/db/schema/09_notification-channel";
|
||||
import {desc, isNull} from "drizzle-orm";
|
||||
import {ChannelsSection} from "@/components/wrappers/dashboard/admin/channels/channels-section";
|
||||
import {ChannelAddEditModal} from "@/components/wrappers/dashboard/admin/channels/channel/channel-add-edit-modal";
|
||||
import {ChannelsSection} from "@/features/channel/channels-section";
|
||||
import {ChannelAddEditModal} from "@/features/channel/channel-add-edit-modal";
|
||||
import * as drizzleDb from "@/db";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {PageParams} from "@/types/next";
|
||||
import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {Metadata} from "next";
|
||||
import {NotificationLogsList} from "@/components/wrappers/dashboard/admin/notifications/logs/notification-logs-list";
|
||||
import {NotificationLogsList} from "@/features/notifications/notification-logs-list";
|
||||
import {notFound} from "next/navigation";
|
||||
import {getNotificationHistory} from "@/db/services/notification-log";
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {PageParams} from "@/types/next";
|
||||
import {Page, PageActions, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {Metadata} from "next";
|
||||
import {ChannelsSection} from "@/components/wrappers/dashboard/admin/channels/channels-section";
|
||||
import {ChannelsSection} from "@/features/channel/channels-section";
|
||||
import {db} from "@/db";
|
||||
import {desc, eq, isNull} from "drizzle-orm";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {StorageChannelWith} from "@/db/schema/12_storage-channel";
|
||||
import {ChannelAddEditModal} from "@/components/wrappers/dashboard/admin/channels/channel/channel-add-edit-modal";
|
||||
import {ChannelAddEditModal} from "@/features/channel/channel-add-edit-modal";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Storage Channels",
|
||||
|
||||
@@ -4,7 +4,7 @@ import {notFound} from "next/navigation";
|
||||
import {getOrganization} from "@/lib/auth/auth";
|
||||
import {Metadata} from "next";
|
||||
import {db} from "@/db";
|
||||
import {MigrationTool} from "@/components/wrappers/dashboard/organization/migration/migration-tool";
|
||||
import {MigrationTool} from "@/features/migration/migration-tool";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Projects",
|
||||
|
||||
+3
-3
@@ -4,10 +4,10 @@ import {Page} from "@/features/layout/page";
|
||||
import {db} from "@/db";
|
||||
import {eq, and, inArray} from "drizzle-orm";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {getOrganizationProjectDatabases} from "@/lib/services";
|
||||
import {getOrganizationProjectDatabases} from "@/db/services/project";
|
||||
import {getActiveMember, getOrganization} from "@/lib/auth/auth";
|
||||
import {BackupModalProvider} from "@/components/wrappers/dashboard/database/backup/backup-modal-context";
|
||||
import {DatabaseContent} from "@/components/wrappers/dashboard/projects/database/database-content";
|
||||
import {BackupModalProvider} from "@/features/database/backup-modal-context";
|
||||
import {DatabaseContent} from "@/features/database/database-content";
|
||||
import {getHealthLast12hLogs} from "@/db/services/healthcheck";
|
||||
|
||||
export default async function RoutePage(props: PageParams<{
|
||||
|
||||
@@ -2,16 +2,16 @@ import {PageParams} from "@/types/next";
|
||||
import {Page, PageContent, PageTitle} from "@/features/layout/page";
|
||||
import {
|
||||
ButtonDeleteProject
|
||||
} from "@/components/wrappers/dashboard/projects/button-delete-project/button-delete-project";
|
||||
import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination";
|
||||
import {ProjectDatabaseCard} from "@/components/wrappers/dashboard/projects/project-card/project-database-card";
|
||||
} from "@/features/projects/project-delete-button";
|
||||
import {CardsWithPagination} from "@/components/common/cards-with-pagination";
|
||||
import {ProjectDatabaseCard} from "@/features/projects/project-database-card";
|
||||
import {notFound, redirect} from "next/navigation";
|
||||
import {db} from "@/db";
|
||||
import {eq} from "drizzle-orm";
|
||||
import {getActiveMember, getOrganization} from "@/lib/auth/auth";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {capitalizeFirstLetter} from "@/utils/text";
|
||||
import {ProjectDialog} from "@/features/projects/components/project.dialog";
|
||||
import {ProjectDialog} from "@/features/projects/project-dialog";
|
||||
import {ProjectWith} from "@/db/schema/06_project";
|
||||
import {isUuidv4} from "@/utils/verify-uuid";
|
||||
import {getOrganizationAvailableDatabases} from "@/db/services/database";
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {PageParams} from "@/types/next";
|
||||
import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination";
|
||||
import {CardsWithPagination} from "@/components/common/cards-with-pagination";
|
||||
import {Page, PageActions, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {ProjectCard} from "@/components/wrappers/dashboard/projects/project-card/project-card";
|
||||
import {ProjectCard} from "@/features/projects/project-card";
|
||||
import {db} from "@/db";
|
||||
import {notFound} from "next/navigation";
|
||||
import {getActiveMember, getOrganization} from "@/lib/auth/auth";
|
||||
import {EmptyStatePlaceholder} from "@/components/wrappers/common/empty-state-placeholder";
|
||||
import {EmptyStatePlaceholder} from "@/components/common/empty-state-placeholder";
|
||||
import {Metadata} from "next";
|
||||
import {ProjectDialog} from "@/features/projects/components/project.dialog";
|
||||
import {ProjectDialog} from "@/features/projects/project-dialog";
|
||||
import {DatabaseWith} from "@/db/schema/07_database";
|
||||
import {getOrganizationAvailableDatabases} from "@/db/services/database";
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ import {db} from "@/db";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {eq} from "drizzle-orm";
|
||||
import {notFound} from "next/navigation";
|
||||
import {ButtonDeleteAgent} from "@/components/wrappers/dashboard/agent/button-delete-agent/button-delete-agent";
|
||||
import {ButtonDeleteAgent} from "@/features/agents/agent-delete-button";
|
||||
import {capitalizeFirstLetter} from "@/utils/text";
|
||||
import {generateEdgeKey} from "@/utils/edge_key";
|
||||
import {getServerUrl} from "@/utils/get-server-url";
|
||||
import {AgentContentPage} from "@/components/wrappers/dashboard/agent/agent-content";
|
||||
import {AgentDialog} from "@/features/agents/components/agent.dialog";
|
||||
import {AgentContentPage} from "@/features/agents/agent-content";
|
||||
import {AgentDialog} from "@/features/agents/agent-dialog";
|
||||
import {getActiveMember, getOrganization} from "@/lib/auth/auth";
|
||||
import {currentUser} from "@/lib/auth/current-user";
|
||||
import {computeOrganizationPermissions} from "@/lib/acl/organization-acl";
|
||||
|
||||
@@ -9,12 +9,12 @@ import {currentUser} from "@/lib/auth/current-user";
|
||||
import {getActiveMember, getOrganization} from "@/lib/auth/auth";
|
||||
import {notFound} from "next/navigation";
|
||||
import {Metadata} from "next";
|
||||
import {OrganizationTabs} from "@/components/wrappers/dashboard/organization/tabs/organization-tabs";
|
||||
import {OrganizationTabs} from "@/features/organizations/organization-tabs";
|
||||
import {getOrganizationChannels} from "@/db/services/notification-channel";
|
||||
import {computeOrganizationPermissions} from "@/lib/acl/organization-acl";
|
||||
import {getOrganizationStorageChannels} from "@/db/services/storage-channel";
|
||||
import {DeleteOrganizationButton} from "@/components/wrappers/dashboard/organization/delete-organization-button";
|
||||
import {EditOrganizationDialog} from "@/features/organization/components/edit-organization.dialog";
|
||||
import {DeleteOrganizationButton} from "@/features/organizations/organization-delete-button";
|
||||
import {EditOrganizationDialog} from "@/features/organizations/organization-edit-dialog";
|
||||
import {db} from "@/db";
|
||||
import {isNull} from "drizzle-orm";
|
||||
import * as drizzleDb from "@/db";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {PageParams} from "@/types/next";
|
||||
import {Page, PageContent, PageHeader, PageTitle} from "@/features/layout/page";
|
||||
import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card";
|
||||
import {EvolutionLineChart} from "@/components/wrappers/dashboard/statistics/charts/evolution-line-chart";
|
||||
import {PercentageLineChart} from "@/components/wrappers/dashboard/statistics/charts/percentage-line-chart";
|
||||
import {EvolutionLineChart} from "@/features/statistics/evolution-line-chart";
|
||||
import {PercentageLineChart} from "@/features/statistics/percentage-line-chart";
|
||||
import {notFound} from "next/navigation";
|
||||
import {db} from "@/db";
|
||||
import {and, asc, count, eq, inArray} from "drizzle-orm";
|
||||
|
||||
@@ -2,10 +2,12 @@ import { ReactNode } from "react";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
|
||||
import { AppSidebar } from "@/components/wrappers/dashboard/common/sidebar/app-sidebar";
|
||||
import { Header } from "@/features/layout/Header";
|
||||
import { AppSidebar } from "@/features/layout/app-sidebar";
|
||||
import { Header } from "@/features/layout/header";
|
||||
import { currentUser } from "@/lib/auth/current-user";
|
||||
import { ThemeMetaUpdater } from "@/features/browser/theme-meta-updater";
|
||||
import { ThemeMetaUpdater } from "@/features/theme/theme-meta-updater";
|
||||
import { ModeToggle } from "@/features/theme/mode-toggle";
|
||||
import { UpdateNotification } from "@/features/updates/update-notification";
|
||||
|
||||
export default async function Layout({ children }: { children: ReactNode }) {
|
||||
const user = await currentUser();
|
||||
@@ -15,9 +17,9 @@ export default async function Layout({ children }: { children: ReactNode }) {
|
||||
<SidebarProvider>
|
||||
<div className="flex flex-col lg:flex-row w-full">
|
||||
<ThemeMetaUpdater />
|
||||
<AppSidebar />
|
||||
<AppSidebar updateNotification={<UpdateNotification />} />
|
||||
<SidebarInset>
|
||||
<Header />
|
||||
<Header actions={<ModeToggle />} />
|
||||
<main className="h-full">{children}</main>
|
||||
</SidebarInset>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { LoadingSpinner } from "@/components/wrappers/common/loading/loading-spinner";
|
||||
import { LoadingSpinner } from "@/components/common/loading-spinner";
|
||||
|
||||
export default function Loading() {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { getCurrentOrganizationSlug } from "@/features/dashboard/organization-cookie";
|
||||
import { getCurrentOrganizationSlug } from "@/features/organizations/organization-cookie";
|
||||
import { currentUser } from "@/lib/auth/current-user";
|
||||
|
||||
export default async function Index() {
|
||||
|
||||
@@ -5,9 +5,9 @@ import {db as dbClient, db} from "@/db";
|
||||
import {getDatabaseOrThrow, withAgentCheck} from "./helpers";
|
||||
import {Backup} from "@/db/schema/07_database";
|
||||
import {withUpdatedAt} from "@/db/utils";
|
||||
import {eventEmitter} from "@/features/shared/event";
|
||||
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
||||
import {EventKind} from "@/features/notifications/types";
|
||||
import {eventEmitter} from "@/lib/event";
|
||||
import {sendNotificationsBackupRestore} from "@/features/notifications/notifications.helpers";
|
||||
import {EventKind} from "@/features/notifications/notifications.types";
|
||||
import {logger} from "@/lib/logger";
|
||||
|
||||
const log = logger.child({module: "api/agent/backup/route"});
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as drizzleDb from "@/db";
|
||||
import {db} from "@/db";
|
||||
import {getDatabaseOrThrow, withAgentCheck} from "../../helpers";
|
||||
import {isUuidv4} from "@/utils/verify-uuid";
|
||||
import {eventEmitter} from "@/features/shared/event";
|
||||
import {eventEmitter} from "@/lib/event";
|
||||
import {logger} from "@/lib/logger";
|
||||
|
||||
const log = logger.child({module: "api/agent/backup/upload/init"});
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as drizzleDb from "@/db";
|
||||
import {db as dbClient, db} from "@/db";
|
||||
import {withUpdatedAt} from "@/db/utils";
|
||||
import {getDatabaseOrThrow, withAgentCheck} from "../../helpers";
|
||||
import {eventEmitter} from "@/features/shared/event";
|
||||
import {eventEmitter} from "@/lib/event";
|
||||
import {logger} from "@/lib/logger";
|
||||
|
||||
const log = logger.child({module: "api/agent/backup/upload/status"});
|
||||
|
||||
@@ -3,7 +3,7 @@ import {isUuidv4} from "@/utils/verify-uuid";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {db} from "@/db";
|
||||
import {and, eq} from "drizzle-orm";
|
||||
import {sendNotificationsBackupRestore} from "@/features/notifications/helpers";
|
||||
import {sendNotificationsBackupRestore} from "@/features/notifications/notifications.helpers";
|
||||
import {logger} from "@/lib/logger";
|
||||
import {withUpdatedAt} from "@/db/utils";
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import {db, db as dbClient} from "@/db";
|
||||
import {and, eq, inArray} from "drizzle-orm";
|
||||
import {dbmsEnumSchema, EDbmsSchema} from "@/db/schema/types";
|
||||
import {withUpdatedAt} from "@/db/utils";
|
||||
import type {StorageInput} from "@/features/storages/types";
|
||||
import {dispatchStorage} from "@/features/storages/dispatch";
|
||||
import type {StorageInput} from "@/features/storages/storages.types";
|
||||
import {dispatchStorage} from "@/features/storages/storages.dispatch";
|
||||
import {Setting} from "@/db/schema/01_setting";
|
||||
import {logger} from "@/lib/logger";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {auth} from "@/lib/auth/auth";
|
||||
import {headers} from "next/headers";
|
||||
import {NextResponse} from "next/server";
|
||||
import {eventEmitter} from "@/features/shared/event";
|
||||
import {eventEmitter} from "@/lib/event";
|
||||
import {logger} from "@/lib/logger";
|
||||
|
||||
const log = logger.child({module: "api/events"});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {NextResponse} from "next/server";
|
||||
import path from "path";
|
||||
import type {StorageInput} from "@/features/storages/types";
|
||||
import {dispatchStorage} from "@/features/storages/dispatch";
|
||||
import type {StorageInput} from "@/features/storages/storages.types";
|
||||
import {dispatchStorage} from "@/features/storages/storages.dispatch";
|
||||
import {Readable} from "node:stream";
|
||||
import {logger} from "@/lib/logger";
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {NextResponse} from "next/server";
|
||||
import {auth} from "@/lib/auth/auth";
|
||||
import {headers} from "next/headers";
|
||||
import {StorageInput} from "@/features/storages/types";
|
||||
import {dispatchStorage} from "@/features/storages/dispatch";
|
||||
import {StorageInput} from "@/features/storages/storages.types";
|
||||
import {dispatchStorage} from "@/features/storages/storages.dispatch";
|
||||
import {Readable} from "node:stream";
|
||||
import {logger} from "@/lib/logger";
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import type React from "react";
|
||||
import "./globals.css";
|
||||
import { ConsoleSilencer } from "@/components/wrappers/common/console-silencer";
|
||||
import { ConsoleSilencer } from "@/components/common/console-silencer";
|
||||
import { author, geistMono, poppins } from "@/fonts/fonts";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Providers } from "./providers";
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import BackButton from "@/components/wrappers/common/button/back-button";
|
||||
import BackButton from "@/components/common/back-button";
|
||||
|
||||
export default async function NotFound() {
|
||||
return (
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { type PropsWithChildren, Suspense } from "react";
|
||||
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import { ErrorLayout } from "@/components/wrappers/common/error-layout";
|
||||
import { ThemeMetaUpdaterRoot } from "@/features/browser/theme-meta-updater-root";
|
||||
import { ErrorLayout } from "@/components/common/error-layout";
|
||||
import { ThemeMetaUpdaterRoot } from "@/features/theme/theme-meta-updater-root";
|
||||
import { ThemeProvider } from "@/features/theme/theme-provider";
|
||||
|
||||
export type ProviderProps = PropsWithChildren<{}>;
|
||||
|
||||
+1
-59
@@ -1,62 +1,4 @@
|
||||
// "use client";
|
||||
//
|
||||
// import { Button } from "@/components/ui/button";
|
||||
// import { ButtonHTMLAttributes } from "react";
|
||||
// import { Loader2 } from "lucide-react";
|
||||
//
|
||||
// export type VariantButton = {
|
||||
// secondary: string;
|
||||
// default: string;
|
||||
// outline: string;
|
||||
// ghost: string;
|
||||
// link: string;
|
||||
// destructive: string;
|
||||
// };
|
||||
// export type sizeButton = {
|
||||
// default: string;
|
||||
// icon: string;
|
||||
// sm: string;
|
||||
// lg: string;
|
||||
// };
|
||||
//
|
||||
// export type ButtonWithConfirmProps = {
|
||||
// icon?: any;
|
||||
// text: string;
|
||||
// variant?: keyof VariantButton;
|
||||
// className?: string;
|
||||
// onClick: () => void;
|
||||
// isPending?: boolean;
|
||||
// size: keyof sizeButton;
|
||||
// };
|
||||
//
|
||||
// export const ButtonWithLoading = ({
|
||||
// icon,
|
||||
// text,
|
||||
// variant,
|
||||
// className,
|
||||
// onClick,
|
||||
// isPending,
|
||||
// size,
|
||||
// ...props // catch all remaining props
|
||||
// }: ButtonWithConfirmProps & ButtonHTMLAttributes<HTMLButtonElement>) => {
|
||||
// return (
|
||||
// <Button
|
||||
// onClick={() => {
|
||||
// onClick();
|
||||
// }}
|
||||
// variant={variant ? variant : "default"}
|
||||
// className={className}
|
||||
// {...props} // forward the remaining props to the Button component
|
||||
// size={size || "default"}
|
||||
// >
|
||||
// {isPending && <Loader2 className="animate-spin mr-4" size={16} />}
|
||||
// {text}
|
||||
// <>{icon ? icon : null}</>
|
||||
// </Button>
|
||||
// );
|
||||
// };
|
||||
|
||||
'use client'
|
||||
"use client"
|
||||
|
||||
import { ButtonHTMLAttributes, ReactNode } from "react";
|
||||
import { Loader2 } from "lucide-react";
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
import React, { ComponentType, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import { PaginationNavigation } from "@/components/wrappers/common/pagination/pagination-navigation";
|
||||
import { PaginationSize } from "@/components/wrappers/common/pagination/pagination-size";
|
||||
import { PaginationNavigation } from "@/components/common/pagination-navigation";
|
||||
import { PaginationSize } from "@/components/common/pagination-size";
|
||||
|
||||
interface CardsWithPaginationProps<T> {
|
||||
className?: string;
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
import {PropsWithChildren, useState} from "react";
|
||||
import {Button} from "@/components/ui/button";
|
||||
import {Check, Copy, Terminal} from "lucide-react";
|
||||
import {copyToClipboardWithMeta} from "@/components/wrappers/common/button/copy-button";
|
||||
import {copyToClipboardWithMeta} from "@/components/common/copy-button";
|
||||
import {cn} from "@/lib/utils";
|
||||
|
||||
export type CodeSnippetProps = PropsWithChildren<{
|
||||
+3
-21
@@ -4,35 +4,17 @@ import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import {useState} from "react";
|
||||
import {Card} from "@/components/ui/card";
|
||||
import {ConnectionIndicator} from "@/components/wrappers/common/connection-indicator";
|
||||
import {ConnectionIndicator} from "@/components/common/connection-indicator";
|
||||
import {formatDateLastContact} from "@/utils/date-formatting";
|
||||
import {Database} from "@/db/schema/07_database";
|
||||
import {ChevronRight, Activity, Fingerprint, Copy, Check} from "lucide-react";
|
||||
|
||||
export type projectDatabaseCardProps = {
|
||||
data: Database;
|
||||
extendedProps: any;
|
||||
organizationSlug: string;
|
||||
};
|
||||
|
||||
export const ProjectDatabaseCard = (props: projectDatabaseCardProps) => {
|
||||
const {data: database, extendedProps: extendedProps} = props;
|
||||
|
||||
return (
|
||||
<Link
|
||||
className="group block transition-all duration-200 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-xl"
|
||||
href={`/dashboard/projects/${extendedProps.id}/database/${database.id}`}>
|
||||
<DatabaseCard data={database}/>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export type databaseCardProps = {
|
||||
export type DatabaseCardProps = {
|
||||
data: Database;
|
||||
withDetails?: boolean;
|
||||
};
|
||||
|
||||
export const DatabaseCard = (props: databaseCardProps) => {
|
||||
export const DatabaseCard = (props: DatabaseCardProps) => {
|
||||
const {data: database, withDetails = true} = props;
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
|
||||
+67
-35
@@ -1,5 +1,3 @@
|
||||
//https://github.com/sersavan/shadcn-multi-select-component
|
||||
|
||||
import * as React from "react";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { CheckIcon, XCircle, ChevronDown, XIcon, WandSparkles } from "lucide-react";
|
||||
@@ -233,53 +231,87 @@ export const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start" onEscapeKeyDown={() => setIsPopoverOpen(false)}>
|
||||
<PopoverContent
|
||||
className="w-auto p-0"
|
||||
align="start"
|
||||
onEscapeKeyDown={() => setIsPopoverOpen(false)}
|
||||
>
|
||||
<Command>
|
||||
<CommandInput placeholder="Search..." onKeyDown={handleInputKeyDown} />
|
||||
<CommandList>
|
||||
<CommandList className="max-h-none overflow-visible">
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandItem key="all" onSelect={toggleAll} className="cursor-pointer">
|
||||
<div
|
||||
className={cn(
|
||||
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
||||
selectedValues.length === options.length ? "bg-primary text-primary-foreground" : "opacity-50 [&_svg]:invisible"
|
||||
)}
|
||||
>
|
||||
<CheckIcon className="h-4 w-4" />
|
||||
</div>
|
||||
<span>(Select All)</span>
|
||||
</CommandItem>
|
||||
{options.map((option) => {
|
||||
const isSelected = selectedValues.includes(option.value);
|
||||
return (
|
||||
<CommandItem key={option.value} onSelect={() => toggleOption(option.value)} className="cursor-pointer">
|
||||
<div
|
||||
className={cn(
|
||||
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
||||
isSelected ? "bg-primary text-primary-foreground" : "opacity-50 [&_svg]:invisible"
|
||||
)}
|
||||
<div
|
||||
className="max-h-[18rem] overflow-y-auto overflow-x-hidden overscroll-contain touch-pan-y pr-1"
|
||||
style={{ WebkitOverflowScrolling: "touch" }}
|
||||
onWheelCapture={(event) => event.stopPropagation()}
|
||||
onTouchMoveCapture={(event) => event.stopPropagation()}
|
||||
>
|
||||
<CommandGroup>
|
||||
<CommandItem key="all" onSelect={toggleAll} className="cursor-pointer">
|
||||
<div
|
||||
className={cn(
|
||||
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
||||
selectedValues.length === options.length
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "opacity-50 [&_svg]:invisible"
|
||||
)}
|
||||
>
|
||||
<CheckIcon className="h-4 w-4" />
|
||||
</div>
|
||||
<span>(Select All)</span>
|
||||
</CommandItem>
|
||||
|
||||
{options.map((option) => {
|
||||
const isSelected = selectedValues.includes(option.value);
|
||||
|
||||
return (
|
||||
<CommandItem
|
||||
key={option.value}
|
||||
onSelect={() => toggleOption(option.value)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<CheckIcon className="h-4 w-4" />
|
||||
</div>
|
||||
{option.icon && <option.icon className="mr-2 h-4 w-4 text-muted-foreground" />}
|
||||
<span>{option.label}</span>
|
||||
</CommandItem>
|
||||
);
|
||||
})}
|
||||
</CommandGroup>
|
||||
<div
|
||||
className={cn(
|
||||
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
||||
isSelected
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "opacity-50 [&_svg]:invisible"
|
||||
)}
|
||||
>
|
||||
<CheckIcon className="h-4 w-4" />
|
||||
</div>
|
||||
|
||||
{option.icon && (
|
||||
<option.icon className="mr-2 h-4 w-4 text-muted-foreground" />
|
||||
)}
|
||||
|
||||
<span>{option.label}</span>
|
||||
</CommandItem>
|
||||
);
|
||||
})}
|
||||
</CommandGroup>
|
||||
</div>
|
||||
|
||||
<CommandSeparator />
|
||||
|
||||
<CommandGroup>
|
||||
<div className="flex items-center justify-between">
|
||||
{selectedValues.length > 0 && (
|
||||
<>
|
||||
<CommandItem onSelect={handleClear} className="flex-1 justify-center cursor-pointer">
|
||||
<CommandItem
|
||||
onSelect={handleClear}
|
||||
className="flex-1 justify-center cursor-pointer"
|
||||
>
|
||||
Clear
|
||||
</CommandItem>
|
||||
<Separator orientation="vertical" className="flex min-h-6 h-full" />
|
||||
</>
|
||||
)}
|
||||
<CommandItem onSelect={() => setIsPopoverOpen(false)} className="flex-1 justify-center cursor-pointer max-w-full">
|
||||
|
||||
<CommandItem
|
||||
onSelect={() => setIsPopoverOpen(false)}
|
||||
className="flex-1 justify-center cursor-pointer max-w-full"
|
||||
>
|
||||
Close
|
||||
</CommandItem>
|
||||
</div>
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { Pagination, PaginationContent, PaginationItem, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";
|
||||
import { PaginationIndexes } from "@/components/wrappers/common/pagination/pagination-indexes";
|
||||
import { PaginationIndexes } from "@/components/common/pagination-indexes";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export type paginationNavigationProps = {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { PaginationNavigation } from "@/components/wrappers/common/pagination/pagination-navigation";
|
||||
import { PaginationNavigation } from "@/components/common/pagination-navigation";
|
||||
|
||||
export type paginationNavigationProps = {
|
||||
className?: string;
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import {TablePaginationNavigation} from "@/components/wrappers/common/table/table-pagination-navigation";
|
||||
import {TablePaginationSize} from "@/components/wrappers/common/table/table-pagination-size";
|
||||
import {TablePaginationNavigation} from "@/components/common/table-pagination-navigation";
|
||||
import {TablePaginationSize} from "@/components/common/table-pagination-size";
|
||||
import {cn} from "@/lib/utils";
|
||||
|
||||
interface tablePaginationProps {
|
||||
@@ -1,7 +1,7 @@
|
||||
// import * as React from "react";
|
||||
// import EmailLayout from "./email-layout";
|
||||
// import {Text, Section, Button} from "@react-email/components";
|
||||
// import type {EventPayload} from "@/features/notifications/types";
|
||||
// import type {EventPayload} from "@/features/notifications/notifications.types";
|
||||
//
|
||||
// export interface EmailNotificationProps {
|
||||
// payload: EventPayload
|
||||
@@ -48,7 +48,7 @@
|
||||
import * as React from "react";
|
||||
import EmailLayout from "./email-layout";
|
||||
import {Text, Section, Button} from "@react-email/components";
|
||||
import type {EventPayload} from "@/features/notifications/types";
|
||||
import type {EventPayload} from "@/features/notifications/notifications.types";
|
||||
|
||||
export interface EmailNotificationProps {
|
||||
payload: EventPayload;
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import {useRouter} from "next/navigation";
|
||||
import {useMutation} from "@tanstack/react-query";
|
||||
import {Form, FormControl, FormField, FormItem, FormLabel, useZodForm} from "@/components/ui/form";
|
||||
import {PasswordStrengthInput} from "@/components/ui/password-input-indicator";
|
||||
import {ResetPasswordSchema, ResetPasswordType} from "@/components/wrappers/auth/reset-password/reset-password-schema";
|
||||
import {PasswordInput} from "@/components/ui/password-input";
|
||||
import {CardContent, CardHeader} from "@/components/ui/card";
|
||||
import {ButtonWithLoading} from "@/components/wrappers/common/button/button-with-loading";
|
||||
import {authClient} from "@/lib/auth/auth-client";
|
||||
import {toast} from "sonner";
|
||||
import {CardAuth} from "@/features/layout/card-auth";
|
||||
|
||||
type ResetPasswordFormProps = {
|
||||
token: string;
|
||||
};
|
||||
|
||||
export const ResetPasswordForm = ({token}: ResetPasswordFormProps) => {
|
||||
|
||||
const router = useRouter();
|
||||
const form = useZodForm({
|
||||
schema: ResetPasswordSchema,
|
||||
});
|
||||
|
||||
const mutationResetPassword = useMutation({
|
||||
mutationFn: async (data: ResetPasswordType) => {
|
||||
|
||||
await authClient.resetPassword({
|
||||
newPassword: data.password,
|
||||
token,
|
||||
}, {
|
||||
onSuccess: (response) => {
|
||||
toast.success("Password changed successfully.");
|
||||
setTimeout(() => router.push("/"), 1000);
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
toast.error(error.error.message);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<CardAuth>
|
||||
<CardHeader>
|
||||
<div className="grid gap-2 text-center mb-2">
|
||||
<h1 className="text-3xl font-bold">Reset Password</h1>
|
||||
<p className="text-balance text-muted-foreground">Fill information below to change your
|
||||
password</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Form
|
||||
form={form}
|
||||
className="flex flex-col gap-4"
|
||||
onSubmit={async (values) => {
|
||||
await mutationResetPassword.mutateAsync(values);
|
||||
}}
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
defaultValue=""
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<PasswordStrengthInput label={"Enter new password"} field={field}/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="confirmPassword"
|
||||
defaultValue=""
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormLabel>Confirmation Password</FormLabel>
|
||||
<FormControl>
|
||||
<PasswordInput placeholder={"Confirm password"} {...field}
|
||||
value={field.value ?? ""}/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<ButtonWithLoading type="submit" isPending={mutationResetPassword.isPending}>
|
||||
Validate
|
||||
</ButtonWithLoading>
|
||||
</Form>
|
||||
</CardContent>
|
||||
</CardAuth>
|
||||
);
|
||||
};
|
||||
@@ -1,37 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import {useRouter, useSearchParams} from "next/navigation";
|
||||
import {ResetPasswordForm} from "@/components/wrappers/auth/reset-password/reset-password-form";
|
||||
import {toast} from "sonner";
|
||||
import {useEffect} from "react";
|
||||
import {LoadingSpinner} from "@/components/wrappers/common/loading/loading-spinner";
|
||||
|
||||
export const ResetPasswordSection = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const token = searchParams.get("token");
|
||||
const error = searchParams.get("error");
|
||||
|
||||
useEffect(() => {
|
||||
if (error || !token) {
|
||||
if (error == "INVALID_TOKEN") {
|
||||
toast.error("Invalid reset token");
|
||||
} else {
|
||||
toast.error("An error occurred.");
|
||||
}
|
||||
setTimeout(() => router.push("/"), 1000);
|
||||
}
|
||||
}, [error, token, router]);
|
||||
|
||||
|
||||
if (!token) return (
|
||||
<div className="w-full h-full flex flex-col items-center justify-center">
|
||||
<LoadingSpinner size={50}/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<ResetPasswordForm token={token}/>
|
||||
)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import {Database} from "@/db/schema/07_database";
|
||||
import {DatabaseCard} from "@/components/wrappers/dashboard/projects/project-card/project-database-card";
|
||||
|
||||
export type agentDatabaseCardProps = {
|
||||
data: Database;
|
||||
};
|
||||
|
||||
export const AgentDatabaseCard = (props: agentDatabaseCardProps) => {
|
||||
const {data: database} = props;
|
||||
|
||||
return <DatabaseCard withDetails={false} data={database}/>;
|
||||
|
||||
//Todo: Add again when impersonation system will be implemented
|
||||
/* if (!database.projectId) {
|
||||
return <DatabaseCard data={database}/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Link className="group block transition-all duration-200 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-xl"
|
||||
href={`/dashboard/projects/${database.projectId}/database/${database.id}`}>
|
||||
<DatabaseCard data={database}/>
|
||||
</Link>
|
||||
);*/
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
"use client";
|
||||
import {useSidebar} from "@/components/ui/sidebar";
|
||||
import {useTheme} from "next-themes";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export type SideBarLogoProps = {};
|
||||
|
||||
export const SideBarLogo = (props: SideBarLogoProps) => {
|
||||
const {state, isMobile} = useSidebar();
|
||||
const {resolvedTheme} = useTheme();
|
||||
return state === "collapsed" && !isMobile ? (
|
||||
<Link href={"/dashboard"}>
|
||||
|
||||
<div className="flex items-center justify-center">
|
||||
<Image
|
||||
src={"/images/logo/picto.png"}
|
||||
alt="Logo"
|
||||
width={32}
|
||||
height={32}
|
||||
loading="eager"
|
||||
className="object-contain"
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
<Link href={"/dashboard"}>
|
||||
|
||||
<div className="w-full h-auto p-4 flex items-center justify-center">
|
||||
<Image
|
||||
loading="eager"
|
||||
src={"/images/logo/logo.png"}
|
||||
alt="Logo"
|
||||
width={190}
|
||||
height={190}
|
||||
className="object-contain"
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const ImmediateExecutionSchema = z.object({
|
||||
executionMode: z.literal("immediate"),
|
||||
});
|
||||
|
||||
const ScheduledExecutionSchema = z.object({
|
||||
executionMode: z.literal("scheduled"),
|
||||
scheduledDatetime: z.date(),
|
||||
});
|
||||
|
||||
const RemoteImmediateSchema = z
|
||||
.object({
|
||||
backupLocation: z.literal("remote-file"),
|
||||
})
|
||||
.merge(ImmediateExecutionSchema);
|
||||
|
||||
const RemoteScheduledSchema = z
|
||||
.object({
|
||||
backupLocation: z.literal("remote-file"),
|
||||
})
|
||||
.merge(ScheduledExecutionSchema);
|
||||
|
||||
const DesktopImmediateSchema = z
|
||||
.object({
|
||||
backupLocation: z.literal("desktop-file"),
|
||||
uploadedBackupFile: z.instanceof(File),
|
||||
})
|
||||
.merge(ImmediateExecutionSchema);
|
||||
|
||||
const DesktopScheduledSchema = z
|
||||
.object({
|
||||
backupLocation: z.literal("desktop-file"),
|
||||
uploadedBackupFile: z.instanceof(File),
|
||||
})
|
||||
.merge(ScheduledExecutionSchema);
|
||||
|
||||
export const RestoreSchema = z.union([RemoteImmediateSchema, RemoteScheduledSchema, DesktopImmediateSchema, DesktopScheduledSchema]);
|
||||
export type RestoreType = z.infer<typeof RestoreSchema>;
|
||||
@@ -1,186 +0,0 @@
|
||||
// "use client";
|
||||
//
|
||||
// import { useState } from "react";
|
||||
//
|
||||
// import { DateTimePicker } from "@/components/wrappers/common/day-time-picker";
|
||||
// import { Button } from "@/components/ui/button";
|
||||
// import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, useZodForm } from "@/components/ui/form";
|
||||
// import { Input } from "@/components/ui/input";
|
||||
// import { RestoreSchema } from "@/components/wrappers/dashboard/database/restore-form.schema";
|
||||
// import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
// import { ComboBox } from "@/components/wrappers/common/combobox";
|
||||
// import { Label } from "@/components/ui/label";
|
||||
//
|
||||
// export type restoreFormProps = {
|
||||
// databaseToRestore: any;
|
||||
// databases: any[];
|
||||
// backups: any[];
|
||||
// };
|
||||
//
|
||||
// export const RestoreForm = (props: restoreFormProps) => {
|
||||
// const { databaseToRestore, databases, backups } = props;
|
||||
//
|
||||
// const backupLocations = [
|
||||
// {
|
||||
// value: "remote-file",
|
||||
// label: "Remote File",
|
||||
// },
|
||||
// {
|
||||
// value: "desktop-file",
|
||||
// label: "Desktop File",
|
||||
// },
|
||||
// ];
|
||||
//
|
||||
// const executionModes = [
|
||||
// {
|
||||
// value: "immediate",
|
||||
// label: "Immediate",
|
||||
// },
|
||||
// {
|
||||
// value: "scheduled",
|
||||
// label: "Scheduled",
|
||||
// },
|
||||
// ];
|
||||
//
|
||||
// const [selectedDatabaseId, setSelectedDatabaseId] = useState(databaseToRestore.id);
|
||||
//
|
||||
// const filteredBackups = backups.filter((backup) => backup.databaseId == selectedDatabaseId);
|
||||
//
|
||||
// const defaultValues = {
|
||||
// executionMode: "immediate" as const,
|
||||
// backupLocation: "remote-file" as const,
|
||||
// };
|
||||
//
|
||||
// const form = useZodForm({
|
||||
// schema: RestoreSchema,
|
||||
// defaultValues: defaultValues,
|
||||
// });
|
||||
//
|
||||
// const values = form.getValues();
|
||||
//
|
||||
// return (
|
||||
// <div>
|
||||
// <Form
|
||||
// form={form}
|
||||
// onSubmit={async (values) => {
|
||||
// console.log(values);
|
||||
// }}
|
||||
// >
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="backupLocation"
|
||||
// render={({ field }) => (
|
||||
// <FormItem>
|
||||
// <FormLabel>Backup location</FormLabel>
|
||||
// <Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||
// <FormControl>
|
||||
// <SelectTrigger>
|
||||
// <SelectValue />
|
||||
// </SelectTrigger>
|
||||
// </FormControl>
|
||||
// <SelectContent>
|
||||
// {backupLocations.map((backupLocation, key) => (
|
||||
// <SelectItem key={key} value={backupLocation.value}>
|
||||
// {backupLocation.label}
|
||||
// </SelectItem>
|
||||
// ))}
|
||||
// </SelectContent>
|
||||
// </Select>
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
//
|
||||
// {values.backupLocation == "remote-file" ? (
|
||||
// <>
|
||||
// <div className="flex flex-col">
|
||||
// <Label>Database</Label>
|
||||
// <ComboBox
|
||||
// values={databases.map((database) => ({ value: database.id, label: database.name }))}
|
||||
// onValueChange={setSelectedDatabaseId}
|
||||
// defaultValue={selectedDatabaseId}
|
||||
// searchField
|
||||
// />
|
||||
// </div>
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="remoteBackup"
|
||||
// render={({ field }) => (
|
||||
// <FormItem className="flex flex-col">
|
||||
// <FormLabel>Remote backup</FormLabel>
|
||||
// <ComboBoxFormItem
|
||||
// values={filteredBackups.map((backup) => ({
|
||||
// value: backup.id,
|
||||
// label: backup.createdAt.toString(),
|
||||
// }))}
|
||||
// {...field}
|
||||
// />
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
// </>
|
||||
// ) : null}
|
||||
//
|
||||
// {values.backupLocation == "desktop-file" ? (
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="uploadedBackupFile"
|
||||
// render={({ field }) => (
|
||||
// <FormItem>
|
||||
// <FormLabel>File</FormLabel>
|
||||
// <FormControl>
|
||||
// <Input id="uploadedBackupFile" type="file" {...field} />
|
||||
// </FormControl>
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
// ) : null}
|
||||
//
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="executionMode"
|
||||
// render={({ field }) => (
|
||||
// <FormItem>
|
||||
// <FormLabel>Execution mode</FormLabel>
|
||||
// <Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||
// <FormControl>
|
||||
// <SelectTrigger>
|
||||
// <SelectValue />
|
||||
// </SelectTrigger>
|
||||
// </FormControl>
|
||||
// <SelectContent>
|
||||
// {executionModes.map((executionMode, key) => (
|
||||
// <SelectItem key={key} value={executionMode.value}>
|
||||
// {executionMode.label}
|
||||
// </SelectItem>
|
||||
// ))}
|
||||
// </SelectContent>
|
||||
// </Select>
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
//
|
||||
// {values.executionMode == "scheduled" ? (
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="scheduledDatetime"
|
||||
// render={({ field }) => (
|
||||
// <FormItem>
|
||||
// <FormLabel>Scheduled date</FormLabel>
|
||||
// <FormControl>
|
||||
// <DateTimePicker value={field.value} onSelect={field.onChange} />
|
||||
// </FormControl>
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
// ) : null}
|
||||
//
|
||||
// <Button type="submit">Launch restore</Button>
|
||||
// </Form>
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
@@ -1,8 +1,8 @@
|
||||
import {db} from "@/db";
|
||||
import * as drizzleDb from "@/db";
|
||||
import {and, eq, gte, isNotNull, lt} from "drizzle-orm";
|
||||
import {dispatchNotification} from "@/features/notifications/dispatch";
|
||||
import {EventPayload} from "@/features/notifications/types";
|
||||
import {dispatchNotification} from "@/features/notifications/notifications.dispatch";
|
||||
import {EventPayload} from "@/features/notifications/notifications.types";
|
||||
import {logger} from "@/lib/logger";
|
||||
|
||||
const log = logger.child({module: "tasks/healthcheck"});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {auth, getOrganization} from "@/lib/auth/auth";
|
||||
import {getOrganization} from "@/lib/auth/auth";
|
||||
import {db} from "@/db";
|
||||
import {and, eq} from "drizzle-orm";
|
||||
import * as drizzleDb from "@/db";
|
||||
@@ -59,4 +59,3 @@ export const getOrganizationProjectDatabases = async ({organizationSlug, project
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@
|
||||
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Button} from "@/components/ui/button";
|
||||
import {Copy, Check, Eye, EyeOff, Terminal, Key, Info} from "lucide-react";
|
||||
import {Copy, Check, Eye, EyeOff} from "lucide-react";
|
||||
import {useState} from "react";
|
||||
import {copyToClipboardWithMeta} from "@/components/wrappers/common/button/copy-button";
|
||||
import {copyToClipboardWithMeta} from "@/components/common/copy-button";
|
||||
import {Card, CardContent, CardDescription, CardHeader, CardTitle} from "@/components/ui/card";
|
||||
|
||||
export type AgentCardKeyProps = {
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
import {useState} from "react";
|
||||
import Link from "next/link";
|
||||
import {Card} from "@/components/ui/card";
|
||||
import {ConnectionIndicator} from "@/components/wrappers/common/connection-indicator";
|
||||
import {ConnectionIndicator} from "@/components/common/connection-indicator";
|
||||
import {formatDateLastContact} from "@/utils/date-formatting";
|
||||
import {AgentWith} from "@/db/schema/08_agent";
|
||||
import {Activity, ChevronRight, Copy, Check, Fingerprint, Server, Database, AlertCircle} from "lucide-react";
|
||||
@@ -11,7 +11,7 @@ import {Badge} from "@/components/ui/badge";
|
||||
import {truncateWords} from "@/utils/text";
|
||||
import {useIsMobile} from "@/hooks/use-mobile";
|
||||
import {Tooltip, TooltipContent, TooltipTrigger} from "@/components/ui/tooltip";
|
||||
import {useAgentUpdateCheck} from "@/features/agents/hooks/use-agent-update-check";
|
||||
import {useAgentUpdateCheck} from "@/features/agents/use-agent-update-check";
|
||||
|
||||
export type agentCardProps = {
|
||||
data: AgentWith;
|
||||
+4
-4
@@ -3,7 +3,7 @@
|
||||
import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card";
|
||||
import {Server} from "lucide-react";
|
||||
import {formatDateLastContact} from "@/utils/date-formatting";
|
||||
import {AgentCardKey} from "@/components/wrappers/dashboard/agent/agent-card-key/agent-card-key";
|
||||
import {AgentCardKey} from "@/features/agents/agent-card-key";
|
||||
import {AgentWithDatabases} from "@/db/schema/08_agent";
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import {getAgentAction} from "@/features/agents/agents.action";
|
||||
@@ -15,9 +15,9 @@ import {
|
||||
} from "@/components/ui/accordion";
|
||||
import {Separator} from "@/components/ui/separator";
|
||||
import {Badge} from "@/components/ui/badge";
|
||||
import {CardsWithPagination} from "@/components/wrappers/common/cards-with-pagination";
|
||||
import {AgentDatabaseCard} from "@/components/wrappers/dashboard/agent/agent-database-card";
|
||||
import {HealthCheckGraph} from "@/components/wrappers/dashboard/health/heath-grid";
|
||||
import {CardsWithPagination} from "@/components/common/cards-with-pagination";
|
||||
import {AgentDatabaseCard} from "@/features/agents/agent-database-card";
|
||||
import {HealthCheckGraph} from "@/features/database/health-grid";
|
||||
import {HealthcheckLog} from "@/db/schema/15_healthcheck-log";
|
||||
|
||||
type AgentContentPageProps = {
|
||||
@@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import {Database} from "@/db/schema/07_database";
|
||||
import {DatabaseCard} from "@/components/common/database-card";
|
||||
|
||||
export type agentDatabaseCardProps = {
|
||||
data: Database;
|
||||
};
|
||||
|
||||
export const AgentDatabaseCard = (props: agentDatabaseCardProps) => {
|
||||
const {data: database} = props;
|
||||
|
||||
return <DatabaseCard withDetails={false} data={database}/>;
|
||||
};
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
import {ColumnDef} from "@tanstack/react-table"
|
||||
import {Database} from "@/db/schema/07_database"
|
||||
import Image from "next/image"
|
||||
import {ConnectionIndicator} from "@/components/wrappers/common/connection-indicator"
|
||||
import {ConnectionIndicator} from "@/components/common/connection-indicator"
|
||||
import {formatDateLastContact} from "@/utils/date-formatting"
|
||||
import Link from "next/link"
|
||||
import {Button} from "@/components/ui/button"
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import {Trash2} from "lucide-react";
|
||||
import {ButtonWithConfirm} from "@/components/wrappers/common/button/button-with-confirm";
|
||||
import {ButtonWithConfirm} from "@/components/common/button-with-confirm";
|
||||
import {useMutation} from "@tanstack/react-query";
|
||||
import {useRouter} from "next/navigation";
|
||||
import {toast} from "sonner";
|
||||
import {deleteAgentAction} from "@/components/wrappers/dashboard/agent/button-delete-agent/delete-agent.action";
|
||||
import {deleteAgentAction} from "@/features/agents/agent-delete.action";
|
||||
import {useIsMobile} from "@/hooks/use-mobile";
|
||||
|
||||
export type ButtonDeleteAgentProps = {
|
||||
+3
-3
@@ -7,16 +7,16 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import {AgentForm} from "@/features/agents/components/agent.form";
|
||||
import {AgentForm} from "@/features/agents/agent-form";
|
||||
import {Button, buttonVariants} from "@/components/ui/button";
|
||||
import {Plus} from "lucide-react";
|
||||
import {GearIcon} from "@radix-ui/react-icons";
|
||||
import {EmptyStatePlaceholder} from "@/components/wrappers/common/empty-state-placeholder";
|
||||
import {EmptyStatePlaceholder} from "@/components/common/empty-state-placeholder";
|
||||
import {useState} from "react";
|
||||
import {useRouter} from "next/navigation";
|
||||
import {OrganizationWithMembers} from "@/db/schema/03_organization";
|
||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs";
|
||||
import {AgentOrganisationForm} from "@/features/agents/components/agent-organizations.form";
|
||||
import {AgentOrganisationForm} from "@/features/agents/agent-organizations.form";
|
||||
import {AgentWith} from "@/db/schema/08_agent";
|
||||
|
||||
type AgentDialogProps = {
|
||||
+1
-2
@@ -5,9 +5,8 @@ import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogT
|
||||
|
||||
import { generateEdgeKey } from "@/utils/edge_key";
|
||||
import { PropsWithChildren } from "react";
|
||||
import { CopyButton } from "@/components/wrappers/common/button/copy-button";
|
||||
import { getServerUrl } from "@/utils/get-server-url";
|
||||
import { CodeSnippet } from "@/components/wrappers/code-snippet/code-snippet";
|
||||
import { CodeSnippet } from "@/components/common/code-snippet";
|
||||
import {Agent} from "@/db/schema/08_agent";
|
||||
|
||||
export type agentRegistrationDialogProps = PropsWithChildren<{
|
||||
+4
-4
@@ -3,13 +3,13 @@
|
||||
import {useRouter} from "next/navigation";
|
||||
import {useMutation} from "@tanstack/react-query";
|
||||
import {Form, FormControl, FormField, FormItem, useZodForm} from "@/components/ui/form";
|
||||
import {ButtonWithLoading} from "@/components/wrappers/common/button/button-with-loading";
|
||||
import {ButtonWithLoading} from "@/components/common/button-with-loading";
|
||||
import {OrganizationWithMembers} from "@/db/schema/03_organization";
|
||||
import {MultiSelect} from "@/components/wrappers/common/multiselect/multi-select";
|
||||
import {MultiSelect} from "@/components/common/multi-select";
|
||||
import {toast} from "sonner";
|
||||
import {AgentWith} from "@/db/schema/08_agent";
|
||||
import {AgentOrganizationSchema, AgentOrganizationType} from "@/features/agents/components/agent-organizations.schema";
|
||||
import {updateAgentOrganizationsAction} from "@/features/agents/components/agent-organizations.action";
|
||||
import {AgentOrganizationSchema, AgentOrganizationType} from "@/features/agents/agent-organizations.schema";
|
||||
import {updateAgentOrganizationsAction} from "@/features/agents/agent-organizations.action";
|
||||
|
||||
|
||||
type AgentOrganisationFormProps = {
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import {getNewAgentRelease} from "@/features/updates/services/github";
|
||||
import {getNewAgentRelease} from "@/lib/github-releases";
|
||||
|
||||
export const useAgentUpdateCheck = (currentVersion?: string | null) => {
|
||||
const {data: newRelease, isLoading} = useQuery({
|
||||
+1
-1
@@ -7,7 +7,7 @@ import { FormControl, FormField, FormItem, FormLabel, FormMessage, useZodForm }
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Form } from "@/components/ui/form";
|
||||
import { requestPasswordReset } from "@/lib/auth/auth-client";
|
||||
import { ButtonWithLoading } from "@/components/wrappers/common/button/button-with-loading";
|
||||
import { ButtonWithLoading } from "@/components/common/button-with-loading";
|
||||
import Link from "next/link";
|
||||
import { ForgotPasswordSchema, ForgotPasswordType } from "./forgot-password-form.schema";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
import { toast } from "sonner";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import TwoFactorForm from "@/components/wrappers/dashboard/profile/form/2fa-form";
|
||||
import TwoFactorForm from "@/features/profile/2fa-form";
|
||||
|
||||
export const GuardForm = () => {
|
||||
const router = useRouter();
|
||||
+2
-2
@@ -19,8 +19,8 @@ import { PasswordInput } from "@/components/ui/password-input";
|
||||
import {
|
||||
LoginSchema,
|
||||
type LoginType,
|
||||
} from "@/components/wrappers/auth/login/login-form/login-form.schema";
|
||||
import { ButtonWithLoading } from "@/components/wrappers/common/button/button-with-loading";
|
||||
} from "@/features/auth/login-form.schema";
|
||||
import { ButtonWithLoading } from "@/components/common/button-with-loading";
|
||||
import { signIn } from "@/lib/auth/auth-client";
|
||||
|
||||
export type loginFormProps = {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user