├── .ai-agents └── memory-bank │ ├── activeContext.md │ ├── productContext.md │ ├── progress.md │ ├── projectbrief.md │ ├── systemPatterns.md │ └── techContext.md ├── .changeset ├── README.md ├── changelog.cjs └── config.json ├── .claude └── commands │ └── create-pull-request.md ├── .clineignore ├── .clinerules ├── general.md └── memory-bank.md ├── .cursorrules ├── .env.template ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── 1_bug_report.yml │ ├── 2_doc_issue.yml │ ├── 3_create_a_chore.md │ └── config.yml ├── actions │ └── pnpm-setup │ │ └── action.yml ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── add_assignee_to_pr.yml │ ├── codeql.yml │ ├── database-ci.yml │ ├── dependency_review.yml │ ├── discussion-comment-to-slack.yml │ ├── e2e_tests.yml │ ├── figma-to-css-variables.yml │ ├── frontend-ci.yml │ ├── license-report-update.yml │ ├── license.yml │ ├── notify_supabase_failure.yml │ ├── prompt-test.yml │ ├── release.yml │ ├── released_package_test.yml │ ├── stale.yml │ ├── trigger_dev_production.yml │ └── trigger_dev_staging.yml ├── .gitignore ├── .liam └── schema-override.yml ├── .node-version ├── .pr_agent.toml ├── .syncpackrc ├── .vscode ├── extensions.json └── settings.json ├── CODE_OF_CONDUCT.md ├── CODE_OF_CONDUCT_ja.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── assets ├── demo.gif ├── jack.gif ├── logo-dark.png └── logo-light.png ├── biome.jsonc ├── config ├── dependency_decisions.yml └── license_finder.yml ├── docs ├── liam-migration-v1 │ └── product-required-document.md ├── migrationOpsContext.md ├── migrationPatterns.md ├── packages-license.md └── schemaPatterns.md ├── frontend ├── .gitignore ├── apps │ ├── app │ │ ├── .env │ │ ├── .env.local │ │ ├── .env.production │ │ ├── .gitignore │ │ ├── app │ │ │ ├── (app) │ │ │ │ └── app │ │ │ │ │ ├── (root) │ │ │ │ │ ├── invitations │ │ │ │ │ │ └── tokens │ │ │ │ │ │ │ └── [token] │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── organizations │ │ │ │ │ │ ├── new │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── page.tsx │ │ │ │ │ ├── projects │ │ │ │ │ │ ├── new │ │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ └── settings │ │ │ │ │ │ ├── billing │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ └── SettingsHeader │ │ │ │ │ │ │ ├── SettingsHeader.module.css │ │ │ │ │ │ │ ├── SettingsHeader.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── general │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── layout.module.css │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ ├── members │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ └── projects │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── (with-project) │ │ │ │ │ └── projects │ │ │ │ │ │ └── [projectId] │ │ │ │ │ │ ├── branches │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── (with-project-and-branch) │ │ │ │ │ └── projects │ │ │ │ │ │ └── [projectId] │ │ │ │ │ │ └── ref │ │ │ │ │ │ └── [branchOrCommit] │ │ │ │ │ │ ├── build │ │ │ │ │ │ └── page.tsx │ │ │ │ │ │ ├── layout.module.css │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ ├── page.tsx │ │ │ │ │ │ └── schema │ │ │ │ │ │ └── [...schemaFilePath] │ │ │ │ │ │ └── page.tsx │ │ │ │ │ ├── auth │ │ │ │ │ └── callback │ │ │ │ │ │ └── [provider] │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── confirm │ │ │ │ │ └── route.ts │ │ │ ├── .well-known │ │ │ │ └── vercel │ │ │ │ │ └── flags │ │ │ │ │ └── route.ts │ │ │ ├── api │ │ │ │ ├── buildingSchemas │ │ │ │ │ └── versions │ │ │ │ │ │ └── route.ts │ │ │ │ ├── chat │ │ │ │ │ └── route.ts │ │ │ │ ├── projects │ │ │ │ │ ├── [projectId] │ │ │ │ │ │ └── route.ts │ │ │ │ │ ├── route.ts │ │ │ │ │ └── search │ │ │ │ │ │ └── route.ts │ │ │ │ ├── schema │ │ │ │ │ └── override │ │ │ │ │ │ └── route.ts │ │ │ │ └── webhook │ │ │ │ │ ├── github │ │ │ │ │ ├── route.ts │ │ │ │ │ └── utils │ │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ └── checkSchemaChanges.test.ts │ │ │ │ │ │ └── checkSchemaChanges.ts │ │ │ │ │ └── helloworld │ │ │ │ │ └── route.ts │ │ │ ├── app │ │ │ │ └── login │ │ │ │ │ └── page.tsx │ │ │ ├── erd │ │ │ │ └── p │ │ │ │ │ └── [...slug] │ │ │ │ │ ├── erdViewer.tsx │ │ │ │ │ └── page.tsx │ │ │ ├── error │ │ │ │ └── page.tsx │ │ │ ├── favicon.ico │ │ │ ├── global-error.tsx │ │ │ ├── globals.css │ │ │ ├── layout.tsx │ │ │ ├── lib │ │ │ │ ├── schema │ │ │ │ │ └── convertSchemaToText.ts │ │ │ │ └── vectorstore │ │ │ │ │ ├── supabaseVectorStore.ts │ │ │ │ │ └── syncSchemaVectorStore.ts │ │ │ ├── page.tsx │ │ │ └── types.ts │ │ ├── biome.jsonc │ │ ├── components │ │ │ ├── BranchDetailPage │ │ │ │ ├── BranchDetailPage.module.css │ │ │ │ ├── BranchDetailPage.tsx │ │ │ │ └── index.ts │ │ │ ├── BuildPage │ │ │ │ ├── BuildPage.tsx │ │ │ │ ├── Panel │ │ │ │ │ ├── Panel.module.css │ │ │ │ │ ├── Panel.tsx │ │ │ │ │ ├── SchemaEditor │ │ │ │ │ │ ├── SchemaEditor.module.css │ │ │ │ │ │ ├── SchemaEditor.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── useMergeEditor.tsx │ │ │ │ │ ├── TablesList │ │ │ │ │ │ ├── DiffView │ │ │ │ │ │ │ ├── DiffView.module.css │ │ │ │ │ │ │ ├── DiffView.tsx │ │ │ │ │ │ │ ├── TableDiffBlock │ │ │ │ │ │ │ │ ├── TableDiffBlock.module.css │ │ │ │ │ │ │ │ ├── TableDiffBlock.tsx │ │ │ │ │ │ │ │ ├── TableItem │ │ │ │ │ │ │ │ │ ├── ColumnItem │ │ │ │ │ │ │ │ │ │ ├── ColumnItem.module.css │ │ │ │ │ │ │ │ │ │ ├── ColumnItem.tsx │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ ├── ConstraintList │ │ │ │ │ │ │ │ │ │ ├── ConstraintItem │ │ │ │ │ │ │ │ │ │ │ ├── CheckConstraintItem.tsx │ │ │ │ │ │ │ │ │ │ │ ├── ConstraintItem.module.css │ │ │ │ │ │ │ │ │ │ │ ├── ForeignConstraintItem.tsx │ │ │ │ │ │ │ │ │ │ │ ├── PrimaryConstraintItem.tsx │ │ │ │ │ │ │ │ │ │ │ ├── UniqueConstraintItem.tsx │ │ │ │ │ │ │ │ │ │ │ ├── getChangeStatusStyle.ts │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ ├── ConstraintList.module.css │ │ │ │ │ │ │ │ │ │ ├── ConstraintList.tsx │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ ├── Diff.module.css │ │ │ │ │ │ │ │ │ ├── IndexItem │ │ │ │ │ │ │ │ │ │ ├── IndexItem.module.css │ │ │ │ │ │ │ │ │ │ ├── IndexItem.tsx │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ ├── TableItem.module.css │ │ │ │ │ │ │ │ │ ├── TableItem.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── SingleView │ │ │ │ │ │ │ ├── SingleView.module.css │ │ │ │ │ │ │ ├── SingleView.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── TablesList.module.css │ │ │ │ │ │ ├── TablesList.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── after.ts │ │ │ │ │ ├── before.ts │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── Chat │ │ │ │ ├── AgentAvatar │ │ │ │ │ ├── AskAgent.stories.tsx │ │ │ │ │ ├── AskAgent.tsx │ │ │ │ │ ├── BuildAgent.stories.tsx │ │ │ │ │ └── BuildAgent.tsx │ │ │ │ ├── AgentMessage │ │ │ │ │ ├── AgentMessage.module.css │ │ │ │ │ ├── AgentMessage.stories.tsx │ │ │ │ │ ├── AgentMessage.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── Chat.module.css │ │ │ │ ├── Chat.tsx │ │ │ │ ├── MessageOptionButton.module.css │ │ │ │ ├── MessageOptionButton.stories.tsx │ │ │ │ ├── MessageOptionButton.tsx │ │ │ │ ├── MessageOptionButtons.tsx │ │ │ │ ├── NewThreadButton │ │ │ │ │ ├── NewThreadButton.stories.tsx │ │ │ │ │ └── NewThreadButton.tsx │ │ │ │ ├── ProcessIndicator │ │ │ │ │ ├── ProcessIndicator.module.css │ │ │ │ │ ├── ProcessIndicator.stories.tsx │ │ │ │ │ ├── ProcessIndicator.tsx │ │ │ │ │ ├── ProcessIndicatorAnimation.stories.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ThreadListButton │ │ │ │ │ ├── ThreadListButton.stories.tsx │ │ │ │ │ └── ThreadListButton.tsx │ │ │ │ ├── UserMessage │ │ │ │ │ ├── UserMessage.module.css │ │ │ │ │ ├── UserMessage.stories.tsx │ │ │ │ │ ├── UserMessage.tsx │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── ChatInput │ │ │ │ ├── ChatInput.module.css │ │ │ │ ├── ChatInput.stories.tsx │ │ │ │ ├── ChatInput.tsx │ │ │ │ ├── components │ │ │ │ │ ├── CancelButton │ │ │ │ │ │ ├── CancelButton.module.css │ │ │ │ │ │ ├── CancelButton.stories.tsx │ │ │ │ │ │ ├── CancelButton.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── MentionSuggestor │ │ │ │ │ │ ├── MentionSuggestor.module.css │ │ │ │ │ │ ├── MentionSuggestor.stories.tsx │ │ │ │ │ │ ├── MentionSuggestor.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── HighlightedLabel │ │ │ │ │ │ │ │ ├── HighlightedLabel.module.css │ │ │ │ │ │ │ │ ├── HighlightedLabel.tsx │ │ │ │ │ │ │ │ ├── getHighlightedParts.ts │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ └── MentionIcon.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ ├── extractActiveMention.ts │ │ │ │ │ │ │ ├── getAllMentionCandidates.ts │ │ │ │ │ │ │ └── matchSchemaCandidates.ts │ │ │ │ │ ├── ModeToggleSwitch │ │ │ │ │ │ ├── ModeToggleSwitch.module.css │ │ │ │ │ │ ├── ModeToggleSwitch.stories.tsx │ │ │ │ │ │ ├── ModeToggleSwitch.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── SendButton │ │ │ │ │ │ ├── SendButton.module.css │ │ │ │ │ │ ├── SendButton.stories.tsx │ │ │ │ │ │ ├── SendButton.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils │ │ │ │ │ ├── handleNormalKey.ts │ │ │ │ │ ├── insertMention.ts │ │ │ │ │ └── isRegularKey.ts │ │ │ ├── ChatMessage │ │ │ │ ├── ChatMessage.module.css │ │ │ │ ├── ChatMessage.tsx │ │ │ │ └── index.ts │ │ │ ├── ChatbotButton │ │ │ │ ├── ChatbotButton.module.css │ │ │ │ ├── ChatbotButton.tsx │ │ │ │ ├── components │ │ │ │ │ └── ChatbotDialog │ │ │ │ │ │ ├── ChatbotDialog.module.css │ │ │ │ │ │ ├── ChatbotDialog.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── CommonLayout │ │ │ │ ├── AppBar │ │ │ │ │ ├── AppBar.module.css │ │ │ │ │ ├── AppBar.tsx │ │ │ │ │ ├── BranchDropdownMenu │ │ │ │ │ │ ├── BranchDropdownMenu.module.css │ │ │ │ │ │ ├── BranchDropdownMenu.tsx │ │ │ │ │ │ ├── Content.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── services │ │ │ │ │ │ │ └── getBranches.ts │ │ │ │ │ ├── ProjectsDropdownMenu │ │ │ │ │ │ ├── Content.tsx │ │ │ │ │ │ ├── ProjectsDropdownMenu.module.css │ │ │ │ │ │ ├── ProjectsDropdownMenu.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── services │ │ │ │ │ │ │ ├── getProject.ts │ │ │ │ │ │ │ └── getProjects.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── services │ │ │ │ │ │ └── getAuthUser.ts │ │ │ │ ├── CommonLayout.module.css │ │ │ │ ├── CommonLayout.tsx │ │ │ │ ├── GlobalNav │ │ │ │ │ ├── GlobalNav.module.css │ │ │ │ │ ├── GlobalNav.tsx │ │ │ │ │ ├── Item.module.css │ │ │ │ │ ├── LinkItem │ │ │ │ │ │ ├── LinkItem.module.css │ │ │ │ │ │ ├── LinkItem.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── OrganizationItem │ │ │ │ │ │ ├── OrganizationDropdownContent │ │ │ │ │ │ │ ├── OrganizationDropdownContent.module.css │ │ │ │ │ │ │ ├── OrganizationDropdownContent.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── OrganizationItem.module.css │ │ │ │ │ │ ├── OrganizationItem.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── OrgCookie.tsx │ │ │ │ ├── index.ts │ │ │ │ └── services │ │ │ │ │ ├── getAuthUser.ts │ │ │ │ │ ├── getOrganization.ts │ │ │ │ │ └── getOrganizationsByUserId.ts │ │ │ ├── CookieConsent │ │ │ │ ├── CookieConsent.module.css │ │ │ │ ├── CookieConsent.tsx │ │ │ │ └── index.ts │ │ │ ├── DiffCount │ │ │ │ ├── DiffCount.module.css │ │ │ │ ├── DiffCount.tsx │ │ │ │ ├── DiffCounts.module.css │ │ │ │ ├── DiffCounts.tsx │ │ │ │ └── index.ts │ │ │ ├── FormatIcon │ │ │ │ ├── FormatIcon.module.css │ │ │ │ ├── FormatIcon.tsx │ │ │ │ ├── icons │ │ │ │ │ ├── PostgresIcon.tsx │ │ │ │ │ ├── PrismaIcon.tsx │ │ │ │ │ ├── SchemaRbIcon.tsx │ │ │ │ │ ├── TblsIcon.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── types.ts │ │ │ │ └── index.ts │ │ │ ├── GeneralPage │ │ │ │ ├── GeneralPage.module.css │ │ │ │ ├── GeneralPage.tsx │ │ │ │ ├── components │ │ │ │ │ └── GeneralPageClient │ │ │ │ │ │ ├── GeneralPageClient.tsx │ │ │ │ │ │ ├── actions │ │ │ │ │ │ ├── deleteOrganization.ts │ │ │ │ │ │ ├── organizationClientActions.ts │ │ │ │ │ │ └── updateOrganizationName.ts │ │ │ │ │ │ ├── components │ │ │ │ │ │ └── DeleteOrganizationButtonClient │ │ │ │ │ │ │ ├── DeleteConfirmationModal │ │ │ │ │ │ │ ├── DeleteConfirmationModal.module.css │ │ │ │ │ │ │ ├── DeleteConfirmationModal.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── DeleteOrganizationButtonClient.module.css │ │ │ │ │ │ │ ├── DeleteOrganizationButtonClient.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ └── services │ │ │ │ │ └── getOrganizationDetails.ts │ │ │ ├── InvitationPage │ │ │ │ ├── InvitationPage.tsx │ │ │ │ ├── components │ │ │ │ │ └── InvitationCard │ │ │ │ │ │ ├── InvitationCard.module.css │ │ │ │ │ │ ├── InvitationCard.tsx │ │ │ │ │ │ ├── actions │ │ │ │ │ │ └── acceptInvitation.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ └── services │ │ │ │ │ └── getInvitationData.ts │ │ │ ├── LoginPage │ │ │ │ ├── EmailForm.tsx │ │ │ │ ├── LoginPage.module.css │ │ │ │ ├── LoginPage.tsx │ │ │ │ ├── SignInGithubButton.tsx │ │ │ │ ├── index.ts │ │ │ │ └── services │ │ │ │ │ ├── loginByEmail.ts │ │ │ │ │ └── loginByGithub.ts │ │ │ ├── OrganizationMembersPage │ │ │ │ ├── OrganizationMembersPage.tsx │ │ │ │ ├── components │ │ │ │ │ ├── ClientSearchWrapper │ │ │ │ │ │ ├── ClientSearchWrapper.module.css │ │ │ │ │ │ ├── ClientSearchWrapper.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── DeleteInvitationModal │ │ │ │ │ │ ├── DeleteInvitationModal.tsx │ │ │ │ │ │ ├── actions │ │ │ │ │ │ │ └── removeInvitation.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── DeleteMemberModal │ │ │ │ │ │ ├── DeleteMemberModal.tsx │ │ │ │ │ │ ├── actions │ │ │ │ │ │ │ └── removeMember.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── InvitationItem │ │ │ │ │ │ ├── InvitationItem.module.css │ │ │ │ │ │ ├── InvitationItem.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── InviteMemberModal │ │ │ │ │ │ ├── InviteMemberModal.module.css │ │ │ │ │ │ ├── InviteMemberModal.tsx │ │ │ │ │ │ ├── actions │ │ │ │ │ │ │ ├── inviteMember.ts │ │ │ │ │ │ │ └── sendInvitationEmail.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── MemberItem │ │ │ │ │ │ ├── MemberItem.module.css │ │ │ │ │ │ ├── MemberItem.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── SearchInput │ │ │ │ │ │ ├── SearchInput.module.css │ │ │ │ │ │ ├── SearchInput.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ └── services │ │ │ │ │ └── getMembersAndInvites.ts │ │ │ ├── OrganizationNewPage │ │ │ │ ├── OrganizationNewPage.module.css │ │ │ │ ├── OrganizationNewPage.tsx │ │ │ │ ├── actions │ │ │ │ │ └── createOrganizations.ts │ │ │ │ └── index.ts │ │ │ ├── OrganizationsPage │ │ │ │ ├── OrganizationsPage.module.css │ │ │ │ ├── OrganizationsPage.tsx │ │ │ │ ├── OrganizationsPageClient.tsx │ │ │ │ ├── getOrganizations.ts │ │ │ │ └── index.ts │ │ │ ├── ProjectBranchesListPage │ │ │ │ ├── ProjectBranchesListPage.module.css │ │ │ │ ├── ProjectBranchesListPage.tsx │ │ │ │ └── index.ts │ │ │ ├── ProjectLayout │ │ │ │ ├── ProjectHeader │ │ │ │ │ ├── ProjectHeader.module.css │ │ │ │ │ ├── ProjectHeader.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── projectConstants.ts │ │ │ │ ├── ProjectLayout.module.css │ │ │ │ ├── ProjectLayout.tsx │ │ │ │ └── index.ts │ │ │ ├── ProjectNewPage │ │ │ │ ├── ProjectNewPage.module.css │ │ │ │ ├── ProjectNewPage.tsx │ │ │ │ ├── components │ │ │ │ │ ├── InstallationSelector │ │ │ │ │ │ ├── InstallationSelector.module.css │ │ │ │ │ │ ├── InstallationSelector.tsx │ │ │ │ │ │ ├── actions │ │ │ │ │ │ │ └── addProject.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── RepositoryItem │ │ │ │ │ │ ├── RepositoryItem.module.css │ │ │ │ │ │ ├── RepositoryItem.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── ProjectsPage │ │ │ │ ├── ProjectsPage.module.css │ │ │ │ ├── ProjectsPage.tsx │ │ │ │ ├── ServerProjectsDataProvider.tsx │ │ │ │ ├── components │ │ │ │ │ ├── EmptyProjectsState │ │ │ │ │ │ ├── EmptyProjectsState.module.css │ │ │ │ │ │ ├── EmptyProjectsState.tsx │ │ │ │ │ │ ├── JackInBox.tsx │ │ │ │ │ │ ├── JackNoResult.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── ProjectsListView │ │ │ │ │ │ ├── ProjectsListView.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ ├── ProjectItem │ │ │ │ │ │ │ ├── LastCommitDataWrapper.tsx │ │ │ │ │ │ │ ├── OrganizationData.tsx │ │ │ │ │ │ │ ├── OrganizationDataWrapper.tsx │ │ │ │ │ │ │ ├── OrganizationIcon.tsx │ │ │ │ │ │ │ ├── ProjectIcon.tsx │ │ │ │ │ │ │ ├── ProjectItem.module.css │ │ │ │ │ │ │ ├── ProjectItem.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── SearchInput │ │ │ │ │ │ │ ├── SearchInput.module.css │ │ │ │ │ │ │ ├── SearchInput.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── SortDropdown │ │ │ │ │ │ │ ├── SortDropdown.module.css │ │ │ │ │ │ │ ├── SortDropdown.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── hooks │ │ │ │ │ │ └── useProjectSearch.ts │ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── services │ │ │ │ │ ├── fetchLastCommitData.ts │ │ │ │ │ ├── getCurrentOrganization.ts │ │ │ │ │ ├── getProjects.test.ts │ │ │ │ │ └── getProjects.ts │ │ │ │ └── types.ts │ │ │ ├── SchemaLink │ │ │ │ ├── SchemaLink.module.css │ │ │ │ ├── SchemaLink.tsx │ │ │ │ └── index.ts │ │ │ └── SchemaPage │ │ │ │ ├── SchemaPage.module.css │ │ │ │ ├── SchemaPage.tsx │ │ │ │ ├── components │ │ │ │ ├── ERDEditor │ │ │ │ │ ├── ERDEditor.module.css │ │ │ │ │ ├── ERDEditor.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── OverrideEditor │ │ │ │ │ ├── OverrideEditor.module.css │ │ │ │ │ ├── OverrideEditor.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── useYamlEditor.tsx │ │ │ │ └── SchemaHeader │ │ │ │ │ ├── SchemaHeader.module.css │ │ │ │ │ ├── SchemaHeader.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── index.ts │ │ │ │ └── utils │ │ │ │ └── safeApplySchemaOverride.ts │ │ ├── eslint.config.mjs │ │ ├── features │ │ │ ├── organizations │ │ │ │ ├── constants.ts │ │ │ │ └── services │ │ │ │ │ ├── getOrganizationId.ts │ │ │ │ │ ├── getOrganizationIdFromCookie.ts │ │ │ │ │ └── setOrganizationIdCookie.ts │ │ │ ├── projects │ │ │ │ └── services │ │ │ │ │ ├── getProjectRepository.test.ts │ │ │ │ │ └── getProjectRepository.ts │ │ │ └── schemas │ │ │ │ └── constants.ts │ │ ├── instrumentation-client.ts │ │ ├── instrumentation.ts │ │ ├── lib │ │ │ ├── chat │ │ │ │ └── chatProcessor.ts │ │ │ └── mastra │ │ │ │ ├── agents │ │ │ │ ├── databaseSchemaAskAgent.ts │ │ │ │ ├── databaseSchemaBuildAgent.ts │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ ├── libs │ │ │ ├── db │ │ │ │ ├── client.ts │ │ │ │ └── server.ts │ │ │ ├── flags │ │ │ │ └── index.ts │ │ │ ├── gtm │ │ │ │ ├── GTMConsent.tsx │ │ │ │ ├── GtagScript.tsx │ │ │ │ ├── constants.ts │ │ │ │ ├── index.ts │ │ │ │ └── updateConsent.ts │ │ │ ├── routes │ │ │ │ ├── index.ts │ │ │ │ ├── paramsSchema.ts │ │ │ │ ├── routeDefinitions.ts │ │ │ │ └── urlgen.ts │ │ │ └── schema │ │ │ │ ├── __tests__ │ │ │ │ └── applyPatchOperations.test.ts │ │ │ │ ├── applyPatchOperations.ts │ │ │ │ ├── createNewVersion.ts │ │ │ │ ├── index.ts │ │ │ │ └── operationsSchema.ts │ │ ├── middleware.ts │ │ ├── next.config.ts │ │ ├── package.json │ │ ├── public │ │ │ ├── assets │ │ │ │ ├── liam_erd.png │ │ │ │ └── schema-rb-icon.png │ │ │ └── robots.txt │ │ ├── scripts │ │ │ └── install-prisma-internals.mjs │ │ ├── sentry.edge.config.ts │ │ ├── sentry.server.config.ts │ │ ├── tsconfig.json │ │ ├── types │ │ │ └── storybook.d.ts │ │ ├── vitest.config.ts │ │ └── vitest.setup.ts │ ├── docs │ │ ├── .env.development │ │ ├── .env.production │ │ ├── .gitignore │ │ ├── README.md │ │ ├── app │ │ │ ├── docs │ │ │ │ ├── [[...slug]] │ │ │ │ │ └── page.tsx │ │ │ │ ├── api │ │ │ │ │ └── search │ │ │ │ │ │ └── route.ts │ │ │ │ ├── layout.tsx │ │ │ │ ├── llms-full.txt │ │ │ │ │ └── route.ts │ │ │ │ ├── llms.txt │ │ │ │ │ └── route.ts │ │ │ │ └── sitemap.ts │ │ │ ├── global-error.tsx │ │ │ ├── global.css │ │ │ ├── layout.config.tsx │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ ├── biome.jsonc │ │ ├── components │ │ │ ├── Banner │ │ │ │ ├── Banner.style.ts │ │ │ │ ├── Banner.tsx │ │ │ │ ├── JackAnimationForDark.tsx │ │ │ │ ├── JackAnimationForLight.tsx │ │ │ │ └── index.ts │ │ │ ├── Breadcrumb │ │ │ │ ├── Breadcrumb.style.ts │ │ │ │ ├── Breadcrumb.tsx │ │ │ │ └── index.ts │ │ │ ├── Callout │ │ │ │ ├── Callout.style.ts │ │ │ │ ├── Callout.tsx │ │ │ │ └── index.ts │ │ │ ├── CopyButton │ │ │ │ ├── CopyButton.tsx │ │ │ │ └── index.ts │ │ │ ├── FooterNavi │ │ │ │ ├── FooterNavi.style.ts │ │ │ │ ├── FooterNavi.tsx │ │ │ │ └── index.ts │ │ │ ├── Heading │ │ │ │ ├── Heading.style.ts │ │ │ │ ├── Heading.tsx │ │ │ │ └── index.ts │ │ │ ├── LiamLogo │ │ │ │ ├── LiamLogo.tsx │ │ │ │ └── index.ts │ │ │ ├── Tabs │ │ │ │ ├── Tabs.tsx │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ ├── content │ │ │ └── docs │ │ │ │ ├── cli │ │ │ │ ├── ci-cd.mdx │ │ │ │ └── index.mdx │ │ │ │ ├── community-resources.mdx │ │ │ │ ├── contributing │ │ │ │ ├── adr │ │ │ │ │ ├── 20241003-use-css-modules-for-styling.mdx │ │ │ │ │ ├── 20241112-use-react-flow-for-erd-visualization.mdx │ │ │ │ │ ├── 20241128-use-fumadocs-for-documentation-site.mdx │ │ │ │ │ ├── 20241128-use-libpg-query-for-postgresql-sql-parsing.mdx │ │ │ │ │ ├── 20241203-use-prism-for-schema-rb-parsing.mdx │ │ │ │ │ ├── 20241206-node-js-based-unified-db-schema-parsing.mdx │ │ │ │ │ ├── 20250116-use-dmmf-for-prisma-schema-parsing.mdx │ │ │ │ │ ├── 20250205-use-fuse-js.mdx │ │ │ │ │ ├── 20250421-apply-rls-to-all-tables-with-organization-based-policies.mdx │ │ │ │ │ ├── index.mdx │ │ │ │ │ └── template.mdx │ │ │ │ ├── index.mdx │ │ │ │ └── repository-architecture.mdx │ │ │ │ ├── index.mdx │ │ │ │ ├── meta.json │ │ │ │ ├── parser │ │ │ │ ├── index.mdx │ │ │ │ ├── meta.json │ │ │ │ ├── supported-formats │ │ │ │ │ ├── bigquery.mdx │ │ │ │ │ ├── django.mdx │ │ │ │ │ ├── drizzle.mdx │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── mssql.mdx │ │ │ │ │ ├── mysql.mdx │ │ │ │ │ ├── postgresql.mdx │ │ │ │ │ ├── prisma.mdx │ │ │ │ │ ├── rails.mdx │ │ │ │ │ ├── sqlite.mdx │ │ │ │ │ └── tbls.mdx │ │ │ │ └── troubleshooting.mdx │ │ │ │ ├── ui-features │ │ │ │ ├── browsing-your-schema.mdx │ │ │ │ ├── index.mdx │ │ │ │ └── sharing-and-query-params.mdx │ │ │ │ └── web │ │ │ │ ├── index.mdx │ │ │ │ ├── meta.json │ │ │ │ └── troubleshooting.mdx │ │ ├── eslint.config.mjs │ │ ├── instrumentation-client.ts │ │ ├── instrumentation.ts │ │ ├── lib │ │ │ ├── gtm │ │ │ │ ├── GTMConsent.tsx │ │ │ │ ├── GtagScript.tsx │ │ │ │ ├── constants.ts │ │ │ │ ├── index.ts │ │ │ │ └── updateConsent.ts │ │ │ └── source.ts │ │ ├── next.config.mjs │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── public │ │ │ ├── images │ │ │ │ ├── banner_bg.png │ │ │ │ ├── content │ │ │ │ │ └── docs │ │ │ │ │ │ ├── ui-features │ │ │ │ │ │ └── sharing-and-query-params │ │ │ │ │ │ │ └── share.gif │ │ │ │ │ │ └── web.gif │ │ │ │ ├── default.png │ │ │ │ └── liam_erd.png │ │ │ ├── rivs │ │ │ │ ├── jack_animation_for_dark.riv │ │ │ │ └── jack_animation_for_light.riv │ │ │ └── robots.txt │ │ ├── sentry.edge.config.ts │ │ ├── sentry.server.config.ts │ │ ├── source.config.ts │ │ ├── tailwind.config.js │ │ └── tsconfig.json │ ├── erd-sample │ │ ├── .gitignore │ │ ├── package.json │ │ ├── schema.rb │ │ └── scripts │ │ │ └── update_dist_content.mjs │ └── erd-web │ │ └── .next │ │ └── trace ├── internal-packages │ ├── figma-to-css-variables │ │ ├── .env.local.example │ │ ├── .gitignore │ │ ├── README.md │ │ ├── bin │ │ │ ├── fetchFigmaLocalVariables.mjs │ │ │ ├── index.mjs │ │ │ ├── runStyleDictionary.mjs │ │ │ └── transformVariablesForStyleDictionary.mjs │ │ ├── biome.jsonc │ │ └── package.json │ ├── mcp-server │ │ ├── README.md │ │ ├── biome.jsonc │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ └── tsconfig.json │ └── storybook │ │ ├── .gitignore │ │ ├── .storybook │ │ ├── README.md │ │ ├── langfuseWeb.mock.ts │ │ ├── main.ts │ │ ├── preview-head.html │ │ ├── preview.ts │ │ └── public │ │ │ └── .gitkeep │ │ ├── README.md │ │ ├── package.json │ │ ├── public │ │ └── .gitkeep │ │ └── vercel.json ├── packages │ ├── __mocks__ │ │ └── node-gtts │ │ │ └── package.json │ ├── cli │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── bin │ │ │ └── cli.ts │ │ ├── biome.jsonc │ │ ├── eslint.config.mjs │ │ ├── fixtures │ │ │ ├── input.schema.rb │ │ │ └── input.sql │ │ ├── index.html │ │ ├── package.json │ │ ├── public │ │ │ ├── .keep │ │ │ ├── assets │ │ │ │ └── liam_erd.png │ │ │ └── favicon.ico │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── App.tsx │ │ │ ├── cli │ │ │ │ ├── actionRunner.ts │ │ │ │ ├── erdCommand │ │ │ │ │ ├── buildCommand │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── getInputContent.test.ts │ │ │ │ │ ├── getInputContent.ts │ │ │ │ │ ├── index.test.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── runPreprocess.test.ts │ │ │ │ │ └── runPreprocess.ts │ │ │ │ ├── errors.ts │ │ │ │ ├── index.test.ts │ │ │ │ ├── index.ts │ │ │ │ ├── initCommand │ │ │ │ │ └── index.ts │ │ │ │ ├── smoke.test.ts │ │ │ │ └── urls.ts │ │ │ ├── globals.css │ │ │ ├── index.ts │ │ │ ├── main.tsx │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ ├── vite-plugins │ │ │ ├── index.ts │ │ │ ├── remove-import-wasi.ts │ │ │ └── set-env.ts │ │ └── vite.config.ts │ ├── configs │ │ ├── biome.jsonc │ │ ├── eslint │ │ │ ├── base.js │ │ │ └── index.js │ │ ├── package.json │ │ └── tsconfig │ │ │ └── base.json │ ├── db-structure │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── biome.jsonc │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── scripts │ │ │ └── tblsJsonSchemaToZod.mjs │ │ ├── src │ │ │ ├── diff │ │ │ │ ├── buildSchemaDiff.ts │ │ │ │ ├── columns │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ ├── buildColumnCheckDiffItem.test.ts │ │ │ │ │ │ ├── buildColumnCommentDiffItem.test.ts │ │ │ │ │ │ ├── buildColumnDefaultDiffItem.test.ts │ │ │ │ │ │ ├── buildColumnDiffItem.test.ts │ │ │ │ │ │ ├── buildColumnNameDiffItem.test.ts │ │ │ │ │ │ ├── buildColumnNotNullDiffItem.test.ts │ │ │ │ │ │ ├── buildColumnPrimaryDiffItem.test.ts │ │ │ │ │ │ └── buildColumnUniqueDiffItem.test.ts │ │ │ │ │ ├── buildColumnCheckDiffItem.ts │ │ │ │ │ ├── buildColumnCommentDiffItem.ts │ │ │ │ │ ├── buildColumnDefaultDiffItem.ts │ │ │ │ │ ├── buildColumnDiffItem.ts │ │ │ │ │ ├── buildColumnNameDiffItem.ts │ │ │ │ │ ├── buildColumnNotNullDiffItem.ts │ │ │ │ │ ├── buildColumnPrimaryDiffItem.ts │ │ │ │ │ └── buildColumnUniqueDiffItem.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── constraints │ │ │ │ │ ├── buildConstraintColumnNameDiffItem.ts │ │ │ │ │ ├── buildConstraintDeleteConstraintDiffItem.ts │ │ │ │ │ ├── buildConstraintDetailDiffItem.ts │ │ │ │ │ ├── buildConstraintDiffItem.ts │ │ │ │ │ ├── buildConstraintNameDiffItem.ts │ │ │ │ │ ├── buildConstraintTargetColumnNameDiffItem.ts │ │ │ │ │ ├── buildConstraintTargetTableNameDiffItem.ts │ │ │ │ │ └── buildConstraintUpdateConstraintDiffItem.ts │ │ │ │ ├── index.ts │ │ │ │ ├── indexes │ │ │ │ │ ├── buildIndexColumnsDiffItem.ts │ │ │ │ │ ├── buildIndexDiffItem.ts │ │ │ │ │ ├── buildIndexNameDiffItem.ts │ │ │ │ │ ├── buildIndexTypeDiffItem.ts │ │ │ │ │ └── buildIndexUniqueDiffItem.ts │ │ │ │ ├── tables │ │ │ │ │ ├── __tests__ │ │ │ │ │ │ ├── buildTableCommentDiffItem.test.ts │ │ │ │ │ │ ├── buildTableDiffItem.test.ts │ │ │ │ │ │ └── buildTableNameDiffItem.test.ts │ │ │ │ │ ├── buildTableCommentDiffItem.ts │ │ │ │ │ ├── buildTableDiffItem.ts │ │ │ │ │ └── buildTableNameDiffItem.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils │ │ │ │ │ ├── __tests__ │ │ │ │ │ └── getChangeStatus.test.ts │ │ │ │ │ └── getChangeStatus.ts │ │ │ ├── index.ts │ │ │ ├── parser.ts │ │ │ ├── parser │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── index.test.ts.snap │ │ │ │ ├── __tests__ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── testcase.ts │ │ │ │ ├── errors.ts │ │ │ │ ├── index.test.ts │ │ │ │ ├── index.ts │ │ │ │ ├── prisma │ │ │ │ │ ├── convertToPostgresColumnType.ts │ │ │ │ │ ├── index.test.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── parser.ts │ │ │ │ ├── schemarb │ │ │ │ │ ├── convertColumnType.ts │ │ │ │ │ ├── index.test.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── input │ │ │ │ │ │ └── schema1.in.rb │ │ │ │ │ ├── loadPrism.ts │ │ │ │ │ ├── parser.ts │ │ │ │ │ ├── singularize.test.ts │ │ │ │ │ └── singularize.ts │ │ │ │ ├── sql │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── input │ │ │ │ │ │ └── postgresql_schema1.in.sql │ │ │ │ │ └── postgresql │ │ │ │ │ │ ├── converter.ts │ │ │ │ │ │ ├── index.test.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── mergeSchemas.ts │ │ │ │ │ │ ├── parser.ts │ │ │ │ │ │ ├── processSQLInChunks.test.ts │ │ │ │ │ │ └── processSQLInChunks.ts │ │ │ │ ├── supportedFormat │ │ │ │ │ ├── detectFormat.test.ts │ │ │ │ │ ├── detectFormat.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── schema.ts │ │ │ │ ├── tbls │ │ │ │ │ ├── index.test.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── input │ │ │ │ │ │ ├── mysql │ │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ │ └── schema.json │ │ │ │ │ │ └── postgresql │ │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ │ └── schema.json │ │ │ │ │ ├── parser.ts │ │ │ │ │ └── schema.generated.test.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils │ │ │ │ │ ├── defaultRelationshipName.ts │ │ │ │ │ ├── handleOneToOneRelationships.ts │ │ │ │ │ └── index.ts │ │ │ └── schema │ │ │ │ ├── factories.ts │ │ │ │ ├── index.ts │ │ │ │ ├── overrideSchema.test.ts │ │ │ │ ├── overrideSchema.ts │ │ │ │ └── schema.ts │ │ └── tsconfig.json │ ├── db │ │ ├── .env │ │ ├── .gitignore │ │ ├── biome.jsonc │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── schema │ │ │ └── schema.sql │ │ ├── src │ │ │ ├── index.ts │ │ │ └── types │ │ │ │ ├── index.ts │ │ │ │ └── supabase-overrides │ │ │ │ ├── building_schemas.ts │ │ │ │ ├── design_sessions.ts │ │ │ │ ├── doc_file_paths.ts │ │ │ │ ├── github_pull_request_comments.ts │ │ │ │ ├── github_pull_requests.ts │ │ │ │ ├── index.ts │ │ │ │ ├── knowledge_suggestion_doc_mappings.ts │ │ │ │ ├── knowledge_suggestions.ts │ │ │ │ ├── messages.ts │ │ │ │ ├── migration_pull_request_mappings.ts │ │ │ │ ├── migrations.ts │ │ │ │ ├── overall_review_knowledge_suggestion_mappings.ts │ │ │ │ ├── overall_reviews.ts │ │ │ │ ├── project_repository_mappings.ts │ │ │ │ ├── review_feedback_comments.ts │ │ │ │ ├── review_feedback_knowledge_suggestion_mappings.ts │ │ │ │ ├── review_feedbacks.ts │ │ │ │ ├── review_suggestion_snippets.ts │ │ │ │ └── schema_file_paths.ts │ │ ├── supabase │ │ │ ├── .gitignore │ │ │ ├── config.toml │ │ │ ├── database.types.ts │ │ │ ├── migrations │ │ │ │ ├── 20250416105745_initial_squash.sql │ │ │ │ ├── 20250416155760_create_review_feedback_knowledge_suggestion_mapping.sql │ │ │ │ ├── 20250418082113_rename_membership_invites_to_invitations.sql │ │ │ │ ├── 20250421081804_rename_github_tables.sql │ │ │ │ ├── 20250422034040_modify_github_repositories.sql │ │ │ │ ├── 20250422051514_refactor_github_pull_requests.sql │ │ │ │ ├── 20250423040522_users_table_policy.sql │ │ │ │ ├── 20250423064420_update_migrations_table.sql │ │ │ │ ├── 20250423115340_rename_github_schema_file_paths.sql │ │ │ │ ├── 20250423115903_add_organization_id_to_knowledge_suggestions.sql │ │ │ │ ├── 20250423123330_add_token_to_invitations.sql │ │ │ │ ├── 20250423123348_invite_organization_member.sql │ │ │ │ ├── 20250423123350_refine_invite_organization_member.sql │ │ │ │ ├── 20250423124731_rename_github_doc_file_paths.sql │ │ │ │ ├── 20250424000000_add_organization_id_to_review_feedback_knowledge_suggestion_mappings.sql │ │ │ │ ├── 20250424102300_add_organization_id_to_overall_review_knowledge_suggestion_mappings.sql │ │ │ │ ├── 20250424113759_add_organization_id_to_project_repository_mappings.sql │ │ │ │ ├── 20250424113807_add_organization_id_to_migrations.sql │ │ │ │ ├── 20250424113811_add_organization_id_to_github_pull_requests.sql │ │ │ │ ├── 20250424113905_add_organization_id_to_schema_file_paths.sql │ │ │ │ ├── 20250424122906_update_overall_reviews_table.sql │ │ │ │ ├── 20250424123000_add_organization_id_to_migration_pull_request_mappings.sql │ │ │ │ ├── 20250424124724_add_organization_id_to_github_pull_request_comments.sql │ │ │ │ ├── 20250424163100_get_invitation_data.sql │ │ │ │ ├── 20250424163200_accept_invitation.sql │ │ │ │ ├── 20250425090250_add_token_to_invite_organization_member.sql │ │ │ │ ├── 20250425122500_add_organization_id_to_knowledge_suggestion_doc_mappings.sql │ │ │ │ ├── 20250425122820_add_organization_id_to_doc_file_paths.sql │ │ │ │ ├── 20250425122828_add_organization_id_to_overall_reviews.sql │ │ │ │ ├── 20250425123357_add_rls_to_github_repositories.sql │ │ │ │ ├── 20250425123413_add_rls_to_invitations.sql │ │ │ │ ├── 20250425123428_add_rls_to_organization_members.sql │ │ │ │ ├── 20250425123516_add_rls_to_organizations_table.sql │ │ │ │ ├── 20250425124607_add_organization_id_to_review_feedbacks.sql │ │ │ │ ├── 20250425125741_add_organization_id_to_review_feedback_comments.sql │ │ │ │ ├── 20250426000000_add_organization_id_to_review_suggestion_snippets.sql │ │ │ │ ├── 20250428034646_prevent_delete_last_organization_member.sql │ │ │ │ ├── 20250507101500_improve_organization_members_rls.sql │ │ │ │ ├── 20250515100643_add_new_chat_workspace_tables.sql │ │ │ │ ├── 20250519120603_add_vector_support.sql │ │ │ │ ├── 20250519182900_add_organization_id_and_rls_to_documents.sql │ │ │ │ ├── 20250520100200_add_schemas_tables.sql │ │ │ │ ├── 20250521190001_add_unique_constraint_to_building_schemas.sql │ │ │ │ ├── 20250521190230_add_update_building_schema.sql │ │ │ │ └── 20250523152300_move_columns_to_building_schemas.sql │ │ │ ├── seed.sql │ │ │ ├── setup-testing.sql │ │ │ └── tests │ │ │ │ ├── database │ │ │ │ ├── 01-invite_organization_member.test.sql │ │ │ │ ├── 02-prevent_delete_last_organization_member.test.sql │ │ │ │ ├── 03-organization_members_rls.test.sql │ │ │ │ └── 04-update_building_schema.test.sql │ │ │ │ └── run-tests.sh │ │ └── tsconfig.json │ ├── e2e │ │ ├── .gitignore │ │ ├── README.md │ │ ├── biome.jsonc │ │ ├── eslint.config.mjs │ │ ├── global-setup.ts │ │ ├── package.json │ │ ├── playwright.config.ts │ │ ├── tests │ │ │ ├── e2e │ │ │ │ ├── navigation.test.ts │ │ │ │ ├── page.test.ts │ │ │ │ └── toolbar.test.ts │ │ │ └── vrt │ │ │ │ ├── vrt.test.ts │ │ │ │ └── vrt.test.ts-snapshots │ │ │ │ ├── top-1-Mobile-Safari-linux.png │ │ │ │ └── top-1-chromium-linux.png │ │ └── tsconfig.json │ ├── erd-core │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── biome.jsonc │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── src │ │ │ ├── features │ │ │ │ ├── erd │ │ │ │ │ ├── components │ │ │ │ │ │ ├── ERDContent │ │ │ │ │ │ │ ├── ERDContent.module.css │ │ │ │ │ │ │ ├── ERDContent.tsx │ │ │ │ │ │ │ ├── ERDContentContext.tsx │ │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ │ ├── NonRelatedTableGroupNode │ │ │ │ │ │ │ │ │ ├── NonRelatedTableGroupNode.module.css │ │ │ │ │ │ │ │ │ ├── NonRelatedTableGroupNode.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── RelationshipEdge │ │ │ │ │ │ │ │ │ ├── RelationshipEdge.module.css │ │ │ │ │ │ │ │ │ ├── RelationshipEdge.tsx │ │ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ │ │ └── type.ts │ │ │ │ │ │ │ │ ├── Spinner │ │ │ │ │ │ │ │ │ ├── Spinner.module.css │ │ │ │ │ │ │ │ │ ├── Spinner.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── TableGroupBoundingBox │ │ │ │ │ │ │ │ │ ├── TableGroupBoundingBox.module.css │ │ │ │ │ │ │ │ │ ├── TableGroupBoundingBox.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── TableGroupNode │ │ │ │ │ │ │ │ │ ├── TableGroupNode.module.css │ │ │ │ │ │ │ │ │ ├── TableGroupNode.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── TableNode │ │ │ │ │ │ │ │ │ ├── TableColumnList │ │ │ │ │ │ │ │ │ │ ├── TableColumn │ │ │ │ │ │ │ │ │ │ │ ├── TableColumn.module.css │ │ │ │ │ │ │ │ │ │ │ ├── TableColumn.tsx │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ ├── TableColumnList.tsx │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ ├── TableDetail │ │ │ │ │ │ │ │ │ │ ├── CollapsibleHeader │ │ │ │ │ │ │ │ │ │ │ ├── CollapsibleHeader.module.css │ │ │ │ │ │ │ │ │ │ │ ├── CollapsibleHeader.tsx │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ ├── Columns │ │ │ │ │ │ │ │ │ │ │ ├── Columns.module.css │ │ │ │ │ │ │ │ │ │ │ ├── Columns.tsx │ │ │ │ │ │ │ │ │ │ │ ├── ColumnsItem │ │ │ │ │ │ │ │ │ │ │ │ ├── ColumnsItem.module.css │ │ │ │ │ │ │ │ │ │ │ │ ├── ColumnsItem.tsx │ │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ ├── Comment │ │ │ │ │ │ │ │ │ │ │ ├── Comment.module.css │ │ │ │ │ │ │ │ │ │ │ ├── Comment.tsx │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ ├── Constraints │ │ │ │ │ │ │ │ │ │ │ ├── CheckConstraintsItem │ │ │ │ │ │ │ │ │ │ │ │ ├── CheckConstraintsItem.tsx │ │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ │ ├── Constraints.module.css │ │ │ │ │ │ │ │ │ │ │ ├── Constraints.tsx │ │ │ │ │ │ │ │ │ │ │ ├── ForeignKeyConstraintsItem │ │ │ │ │ │ │ │ │ │ │ │ ├── ForeignKeyConstraintsItem.module.css │ │ │ │ │ │ │ │ │ │ │ │ ├── ForeignKeyConstraintsItem.tsx │ │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ │ ├── PrimaryKeyConstraintsItem │ │ │ │ │ │ │ │ │ │ │ │ ├── PrimaryKeyConstraintsItem.tsx │ │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ │ ├── Unique │ │ │ │ │ │ │ │ │ │ │ │ ├── UniqueConstraintsItem.tsx │ │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ ├── Indexes │ │ │ │ │ │ │ │ │ │ │ ├── Indexes.tsx │ │ │ │ │ │ │ │ │ │ │ ├── IndexesItem │ │ │ │ │ │ │ │ │ │ │ │ ├── IndexesItem.module.css │ │ │ │ │ │ │ │ │ │ │ │ ├── IndexesItem.tsx │ │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ │ ├── RelatedTables │ │ │ │ │ │ │ │ │ │ │ ├── RelatedTables.module.css │ │ │ │ │ │ │ │ │ │ │ ├── RelatedTables.tsx │ │ │ │ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ │ │ │ │ └── related-table-ex.png │ │ │ │ │ │ │ │ │ │ ├── TableDetail.module.css │ │ │ │ │ │ │ │ │ │ ├── TableDetail.tsx │ │ │ │ │ │ │ │ │ │ ├── extractSchemaForTable.test.ts │ │ │ │ │ │ │ │ │ │ ├── extractSchemaForTable.ts │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ ├── TableHeader │ │ │ │ │ │ │ │ │ │ ├── TableHeader.module.css │ │ │ │ │ │ │ │ │ │ ├── TableHeader.tsx │ │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ │ ├── TableNode.module.css │ │ │ │ │ │ │ │ │ ├── TableNode.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── hooks │ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ │ ├── useInitialAutoLayout.ts │ │ │ │ │ │ │ │ ├── usePopStateListener.ts │ │ │ │ │ │ │ │ └── useTableGroupBoundingBox.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ │ ├── hasNonRelatedChildNodes.ts │ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ │ └── updateNodesHiddenState.ts │ │ │ │ │ │ ├── ERDRenderer │ │ │ │ │ │ │ ├── AppBar │ │ │ │ │ │ │ │ ├── AppBar.module.css │ │ │ │ │ │ │ │ ├── AppBar.tsx │ │ │ │ │ │ │ │ ├── CopyLinkButton │ │ │ │ │ │ │ │ │ ├── CopyLinkButton.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── ExportButton │ │ │ │ │ │ │ │ │ └── ExportButton.module.css │ │ │ │ │ │ │ │ ├── GithubButton │ │ │ │ │ │ │ │ │ ├── GithubButton.module.css │ │ │ │ │ │ │ │ │ ├── GithubButton.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── HelpButton │ │ │ │ │ │ │ │ │ ├── HelpButton.module.css │ │ │ │ │ │ │ │ │ ├── HelpButton.tsx │ │ │ │ │ │ │ │ │ ├── ReleaseVersion.module.css │ │ │ │ │ │ │ │ │ ├── ReleaseVersion.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── MenuButton │ │ │ │ │ │ │ │ │ ├── MenuButton.module.css │ │ │ │ │ │ │ │ │ ├── MenuButton.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── ReleaseNoteButton │ │ │ │ │ │ │ │ │ ├── ReleaseNoteButton.module.css │ │ │ │ │ │ │ │ │ ├── ReleaseNoteButton.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── CardinalityMarkers │ │ │ │ │ │ │ │ ├── CardinalityMarkers.module.css │ │ │ │ │ │ │ │ ├── CardinalityMarkers.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── ERDRenderer.module.css │ │ │ │ │ │ │ ├── ERDRenderer.tsx │ │ │ │ │ │ │ ├── ErrorDisplay │ │ │ │ │ │ │ │ ├── ErrorDisplay.module.css │ │ │ │ │ │ │ │ ├── ErrorDisplay.tsx │ │ │ │ │ │ │ │ ├── MrJack.tsx │ │ │ │ │ │ │ │ ├── NetworkErrorDisplay.module.css │ │ │ │ │ │ │ │ ├── NetworkErrorDisplay.tsx │ │ │ │ │ │ │ │ ├── ParseErrorDisplay.module.css │ │ │ │ │ │ │ │ ├── ParseErrorDisplay.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── LeftPane │ │ │ │ │ │ │ │ ├── CopyLinkButton │ │ │ │ │ │ │ │ │ ├── CopyLinkButton.module.css │ │ │ │ │ │ │ │ │ ├── CopyLinkButton.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── LeftPane.module.css │ │ │ │ │ │ │ │ ├── LeftPane.tsx │ │ │ │ │ │ │ │ ├── MenuItemLink │ │ │ │ │ │ │ │ │ ├── MenuItemLink.module.css │ │ │ │ │ │ │ │ │ ├── MenuItemLink.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── TableNameMenuButton │ │ │ │ │ │ │ │ │ ├── TableNameMenuButton.module.css │ │ │ │ │ │ │ │ │ ├── TableNameMenuButton.tsx │ │ │ │ │ │ │ │ │ ├── VisibilityButton.module.css │ │ │ │ │ │ │ │ │ ├── VisibilityButton.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── RelationshipEdgeParticleMarker │ │ │ │ │ │ │ │ ├── RelationshipEdgeParticleMarker.module.css │ │ │ │ │ │ │ │ ├── RelationshipEdgeParticleMarker.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── TableDetailDrawer │ │ │ │ │ │ │ │ ├── TableDetailDrawer.module.css │ │ │ │ │ │ │ │ ├── TableDetailDrawer.tsx │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── Toolbar │ │ │ │ │ │ │ │ ├── DesktopToolbar.module.css │ │ │ │ │ │ │ │ ├── DesktopToolbar.tsx │ │ │ │ │ │ │ │ ├── FitviewButton │ │ │ │ │ │ │ │ │ ├── FitviewButton.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── GroupButton │ │ │ │ │ │ │ │ │ ├── GroupButton.module.css │ │ │ │ │ │ │ │ │ ├── GroupButton.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── MobileToolbar │ │ │ │ │ │ │ │ │ ├── MobileToolbar.module.css │ │ │ │ │ │ │ │ │ ├── MobileToolbar.tsx │ │ │ │ │ │ │ │ │ ├── OpenedMobileToolbar.module.css │ │ │ │ │ │ │ │ │ ├── OpenedMobileToolbar.tsx │ │ │ │ │ │ │ │ │ ├── ShowModeMenu.module.css │ │ │ │ │ │ │ │ │ ├── ShowModeMenu.tsx │ │ │ │ │ │ │ │ │ ├── ShowModeMenuRadioGroup.module.css │ │ │ │ │ │ │ │ │ ├── ShowModeMenuRadioGroup.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── ShowModeMenu │ │ │ │ │ │ │ │ │ ├── ShowModeMenu.module.css │ │ │ │ │ │ │ │ │ ├── ShowModeMenu.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── TidyUpButton │ │ │ │ │ │ │ │ │ ├── TidyUpButton.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── Toolbar.tsx │ │ │ │ │ │ │ │ ├── ToolbarIconButton │ │ │ │ │ │ │ │ │ ├── ToolbarIconButton.module.css │ │ │ │ │ │ │ │ │ ├── ToolbarIconButton.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ ├── ZoomControls │ │ │ │ │ │ │ │ │ ├── ZoomControls.module.css │ │ │ │ │ │ │ │ │ ├── ZoomControls.tsx │ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── hooks │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── useTableSelection │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── useTableSelection.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── utils │ │ │ │ │ │ ├── columnHandleId.ts │ │ │ │ │ │ ├── computeAutoLayout │ │ │ │ │ │ ├── computeAutoLayout.ts │ │ │ │ │ │ ├── convertElkNodesToNodes.ts │ │ │ │ │ │ ├── convertNodesToElkNodes.ts │ │ │ │ │ │ ├── getElkLayout.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── convertSchemaToNodes.ts │ │ │ │ │ │ ├── highlightNodesAndEdges.test.ts │ │ │ │ │ │ ├── highlightNodesAndEdges.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── isTableNode.ts │ │ │ │ ├── gtm │ │ │ │ │ └── utils │ │ │ │ │ │ ├── clickLogEvent.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── openRelatedTablesLogEvent.ts │ │ │ │ │ │ ├── pushToDataLayer.ts │ │ │ │ │ │ ├── repositionTableLogEvent.ts │ │ │ │ │ │ ├── selectTableLogEvent.ts │ │ │ │ │ │ ├── toggleLogEvent.ts │ │ │ │ │ │ ├── toolbarActionLogEvent.ts │ │ │ │ │ │ └── types.ts │ │ │ │ ├── index.ts │ │ │ │ └── reactflow │ │ │ │ │ ├── constants.ts │ │ │ │ │ └── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ └── useCustomReactflow.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── useIsTouchDevice.ts │ │ │ │ └── useTableGroups.ts │ │ │ ├── images.d.ts │ │ │ ├── index.ts │ │ │ ├── providers │ │ │ │ ├── index.ts │ │ │ │ └── versionProvider.tsx │ │ │ ├── schemas │ │ │ │ ├── index.ts │ │ │ │ ├── queryParam │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schemas.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── showMode │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schemas.ts │ │ │ │ │ └── types.ts │ │ │ │ └── version │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schemas.ts │ │ │ │ │ └── types.ts │ │ │ ├── stores │ │ │ │ ├── index.ts │ │ │ │ ├── schema │ │ │ │ │ ├── actions.ts │ │ │ │ │ ├── hooks.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── schema.ts │ │ │ │ │ └── store.ts │ │ │ │ └── userEditing │ │ │ │ │ ├── actions.ts │ │ │ │ │ ├── hooks.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── store.ts │ │ │ ├── styles │ │ │ │ ├── globals.css │ │ │ │ └── variables.css │ │ │ ├── types │ │ │ │ └── css.d.ts │ │ │ └── utils │ │ │ │ ├── compressionString.test.ts │ │ │ │ ├── compressionString.ts │ │ │ │ ├── index.ts │ │ │ │ └── urlParams.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── github │ │ ├── .gitignore │ │ ├── biome.jsonc │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── src │ │ │ ├── api.browser.ts │ │ │ ├── api.server.test.ts │ │ │ ├── api.server.ts │ │ │ ├── config.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── tsconfig.json │ ├── jobs │ │ ├── .env │ │ ├── .env.local │ │ ├── .gitignore │ │ ├── biome.jsonc │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── src │ │ │ ├── constants.ts │ │ │ ├── functions │ │ │ │ ├── getInstallationIdFromRepositoryId.ts │ │ │ │ ├── langfuseLangchainHandler.ts │ │ │ │ ├── processCreateKnowledgeSuggestion.ts │ │ │ │ ├── processGenerateDocsSuggestion.ts │ │ │ │ ├── processGenerateSchemaOverride.ts │ │ │ │ └── processRepositoryAnalysis.ts │ │ │ ├── index.ts │ │ │ ├── libs │ │ │ │ └── supabase.ts │ │ │ ├── prompts │ │ │ │ ├── generateDocsSuggestion │ │ │ │ │ ├── docsSuggestionSchema.ts │ │ │ │ │ └── generateDocsSuggestion.ts │ │ │ │ ├── generateReview │ │ │ │ │ ├── generateReview.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── reviewSchema.ts │ │ │ │ ├── generateSchemaOverride │ │ │ │ │ └── generateSchemaOverride.ts │ │ │ │ └── index.ts │ │ │ ├── tasks │ │ │ │ └── review │ │ │ │ │ ├── generateReview.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── postComment.ts │ │ │ │ │ ├── savePullRequest.ts │ │ │ │ │ └── saveReview.ts │ │ │ ├── trigger │ │ │ │ ├── flow.md │ │ │ │ ├── helloworld.ts │ │ │ │ └── jobs.ts │ │ │ ├── types │ │ │ │ └── index.ts │ │ │ └── utils │ │ │ │ ├── categoryUtils.ts │ │ │ │ ├── githubFileUtils.ts │ │ │ │ └── schemaUtils.ts │ │ ├── trigger.config.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ ├── prompt-test │ │ ├── .env │ │ ├── .env.local │ │ ├── .gitignore │ │ ├── README.md │ │ ├── biome.jsonc │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── src │ │ │ ├── fixtures │ │ │ │ └── github.com │ │ │ │ │ └── liam-hq │ │ │ │ │ └── liam │ │ │ │ │ └── pull │ │ │ │ │ ├── 1033 │ │ │ │ │ └── fixture.yaml │ │ │ │ │ ├── 1055 │ │ │ │ │ └── fixture.yaml │ │ │ │ │ └── 1105 │ │ │ │ │ └── fixture.yaml │ │ │ └── index.ts │ │ └── tsconfig.json │ └── ui │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── biome.jsonc │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── src │ │ ├── components │ │ │ ├── Avatar │ │ │ │ ├── Avatar.module.css │ │ │ │ ├── Avatar.tsx │ │ │ │ ├── AvatarWithImage.tsx │ │ │ │ ├── UserAvatarIcon.tsx │ │ │ │ └── index.ts │ │ │ ├── Button │ │ │ │ ├── Button.module.css │ │ │ │ ├── Button.stories.tsx │ │ │ │ ├── Button.tsx │ │ │ │ └── index.ts │ │ │ ├── Callout │ │ │ │ ├── Callout.module.css │ │ │ │ ├── Callout.tsx │ │ │ │ └── index.ts │ │ │ ├── Collapsible │ │ │ │ ├── Collapsible.tsx │ │ │ │ └── index.ts │ │ │ ├── ContextMenu │ │ │ │ ├── ContextMenu.module.css │ │ │ │ ├── ContextMenu.tsx │ │ │ │ └── index.ts │ │ │ ├── CookieConsent │ │ │ │ ├── CookieConsent.module.css │ │ │ │ ├── CookieConsent.tsx │ │ │ │ └── index.ts │ │ │ ├── Drawer │ │ │ │ ├── Drawer.module.css │ │ │ │ ├── Drawer.tsx │ │ │ │ └── index.ts │ │ │ ├── DropdownMenu │ │ │ │ ├── DropdownMenu.module.css │ │ │ │ ├── DropdownMenu.tsx │ │ │ │ └── index.ts │ │ │ ├── GridTable │ │ │ │ ├── GridTable.module.css │ │ │ │ ├── GridTable.tsx │ │ │ │ └── index.ts │ │ │ ├── IconButton │ │ │ │ ├── IconButton.module.css │ │ │ │ ├── IconButton.stories.tsx │ │ │ │ ├── IconButton.tsx │ │ │ │ └── index.ts │ │ │ ├── Input │ │ │ │ ├── Input.module.css │ │ │ │ ├── Input.tsx │ │ │ │ └── index.ts │ │ │ ├── Modal │ │ │ │ ├── Modal.module.css │ │ │ │ ├── Modal.tsx │ │ │ │ └── index.ts │ │ │ ├── Popover │ │ │ │ ├── Popover.module.css │ │ │ │ ├── Popover.tsx │ │ │ │ └── index.ts │ │ │ ├── RadioGroup │ │ │ │ ├── RadioGroup.module.css │ │ │ │ ├── RadioGroup.tsx │ │ │ │ └── index.ts │ │ │ ├── Resizable │ │ │ │ ├── Resizable.module.css │ │ │ │ ├── Resizable.tsx │ │ │ │ └── index.ts │ │ │ ├── RoundBadge │ │ │ │ ├── RoundBadge.module.css │ │ │ │ ├── RoundBadge.tsx │ │ │ │ └── index.ts │ │ │ ├── Sidebar │ │ │ │ ├── Sidebar.module.css │ │ │ │ ├── Sidebar.tsx │ │ │ │ └── index.ts │ │ │ ├── Spinner │ │ │ │ ├── Spinner.module.css │ │ │ │ ├── Spinner.tsx │ │ │ │ └── index.ts │ │ │ ├── Switch │ │ │ │ ├── Switch.tsx │ │ │ │ └── index.ts │ │ │ ├── Tabs │ │ │ │ ├── Tabs.tsx │ │ │ │ └── index.ts │ │ │ ├── Toast │ │ │ │ ├── Toast.module.css │ │ │ │ ├── Toast.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── types.ts │ │ │ │ └── useToast.tsx │ │ │ ├── Tooltip │ │ │ │ ├── Tooltip.module.css │ │ │ │ ├── Tooltip.stories.tsx │ │ │ │ ├── Tooltip.tsx │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ ├── icons │ │ │ ├── CardinalityZeroOrManyLeftIcon.tsx │ │ │ ├── CardinalityZeroOrOneLeftIcon.tsx │ │ │ ├── CardinalityZeroOrOneRightIcon.tsx │ │ │ ├── DiamondFillIcon.tsx │ │ │ ├── DiamondIcon.tsx │ │ │ ├── ErdIcon.tsx │ │ │ ├── FacebookIcon.tsx │ │ │ ├── GotoIcon.tsx │ │ │ ├── InfoIcon.tsx │ │ │ ├── TidyUpIcon.tsx │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── logos │ │ │ ├── GithubLogo.tsx │ │ │ ├── LiamLogo.tsx │ │ │ ├── LiamLogoMark.tsx │ │ │ ├── LiamMigrationLogo.tsx │ │ │ ├── LinkedInLogo.tsx │ │ │ ├── XLogo.tsx │ │ │ └── index.ts │ │ ├── markers │ │ │ ├── CardinalityZeroOrManyLeftMarker.tsx │ │ │ ├── CardinalityZeroOrOneLeftMarker.tsx │ │ │ ├── CardinalityZeroOrOneRightMarker.tsx │ │ │ └── index.ts │ │ └── styles │ │ │ ├── Dark │ │ │ └── variables.css │ │ │ ├── Mode 1 │ │ │ └── variables.css │ │ │ ├── fonts.css │ │ │ ├── globals.css │ │ │ ├── icons │ │ │ └── lucide.css │ │ │ ├── index.ts │ │ │ ├── syntax-highlight.css │ │ │ ├── syntax-theme.ts │ │ │ └── variables.css │ │ └── tsconfig.json └── turbo │ └── generators │ ├── config.ts │ └── templates │ ├── component.tsx.hbs │ ├── index.ts.hbs │ └── module.css.hbs ├── knip.jsonc ├── package.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── renovate.json ├── scripts ├── extract-supabase-anon-key.sh └── extract-supabase-service-key.sh └── turbo.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.4/schema.json", 3 | "changelog": [ 4 | "./changelog.cjs", 5 | { 6 | "repo": "liam-hq/liam" 7 | } 8 | ], 9 | "commit": false, 10 | "fixed": [], 11 | "linked": [], 12 | "access": "restricted", 13 | "baseBranch": "main", 14 | "updateInternalDependencies": "patch", 15 | "ignore": [ 16 | "@liam-hq/app", 17 | "@liam-hq/docs", 18 | "@liam-hq/figma-to-css-variables", 19 | "@liam-hq/db", 20 | "@liam-hq/jobs", 21 | "@liam-hq/prompt-test", 22 | "@liam-hq/storybook", 23 | "node-gtts" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.clineignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | 4 | # Build outputs 5 | build/ 6 | dist/ 7 | .next/ 8 | out/ 9 | .trigger/ 10 | 11 | # Environment variables 12 | .env 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | # Large data files 19 | *.csv 20 | *.xlsx -------------------------------------------------------------------------------- /.env.template: -------------------------------------------------------------------------------- 1 | FLAGS_SECRET="" 2 | GITHUB_APP_ID="" 3 | GITHUB_CLIENT_ID="" 4 | GITHUB_CLIENT_SECRET="" 5 | GITHUB_PRIVATE_KEY="" 6 | LANGFUSE_BASE_URL="https://cloud.langfuse.com" 7 | LANGFUSE_PUBLIC_KEY="" 8 | LANGFUSE_SECRET_KEY="" 9 | MIGRATION_ENABLED="" 10 | NEXT_PUBLIC_BASE_URL="" 11 | NEXT_PUBLIC_ENV_NAME="" 12 | NEXT_PUBLIC_GITHUB_APP_URL="" 13 | NEXT_PUBLIC_SUPABASE_ANON_KEY="" 14 | NEXT_PUBLIC_SUPABASE_URL="http://localhost:54321" 15 | OPENAI_API_KEY="" 16 | POSTGRES_URL="" 17 | POSTGRES_URL_NON_POOLING="" 18 | RESEND_API_KEY="" 19 | RESEND_EMAIL_FROM_ADDRESS="" 20 | SENTRY_AUTH_TOKEN="" 21 | SENTRY_DSN="" 22 | SENTRY_ORG="" 23 | SENTRY_PROJECT="" 24 | TRIGGER_PROJECT_ID="" 25 | TRIGGER_SECRET_KEY="" 26 | SUPABASE_SERVICE_ROLE_KEY="" 27 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @liam-hq/liam-dev 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3_create_a_chore.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Create a chore 3 | about: General chores or maintenance tasks. 4 | --- 5 | 6 | ## Task description 7 | 11 | 12 | 13 | ## Background 14 | 18 | 19 | 20 | ## TODO (Optional) 21 | 22 | 23 | - [ ] 24 | - [ ] 25 | - [ ] 26 | 27 | ## Additional notes (Optional) 28 | 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Feature request 4 | url: https://github.com/liam-hq/liam/discussions/categories/ideas 5 | about: Share ideas for new features 6 | - name: Ask a question 7 | url: https://github.com/liam-hq/liam/discussions/categories/q-a 8 | about: Ask questions and discuss with other community members 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/code-security/dependabot/working-with-dependabot/dependabot-options-reference 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: "github-actions" 6 | directory: "/" 7 | schedule: 8 | interval: "monthly" 9 | time: "10:00" 10 | timezone: "Asia/Tokyo" 11 | -------------------------------------------------------------------------------- /.github/workflows/add_assignee_to_pr.yml: -------------------------------------------------------------------------------- 1 | name: Add assignee to PR 2 | 3 | on: 4 | pull_request: 5 | types: [opened] 6 | 7 | jobs: 8 | add-assignee-to-pr: 9 | permissions: 10 | pull-requests: write 11 | uses: route06/actions/.github/workflows/add_assignee_to_pr.yml@155715656c4cd9079f1213d08d058e78dd00cae7 # v2.6.0 12 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL 2 | 3 | on: 4 | push: 5 | 6 | permissions: 7 | actions: read 8 | checks: read 9 | contents: read 10 | security-events: write 11 | 12 | jobs: 13 | codeql: 14 | uses: route06/actions/.github/workflows/codeql.yml@155715656c4cd9079f1213d08d058e78dd00cae7 # v2.6.0 15 | -------------------------------------------------------------------------------- /.github/workflows/dependency_review.yml: -------------------------------------------------------------------------------- 1 | name: Dependency Review 2 | 3 | on: 4 | merge_group: 5 | pull_request: 6 | 7 | permissions: 8 | contents: read 9 | pull-requests: write 10 | 11 | jobs: 12 | dependency_review: 13 | uses: route06/actions/.github/workflows/dependency_review.yml@155715656c4cd9079f1213d08d058e78dd00cae7 # v2.6.0 14 | -------------------------------------------------------------------------------- /.github/workflows/discussion-comment-to-slack.yml: -------------------------------------------------------------------------------- 1 | on: 2 | discussion_comment: 3 | types: [created] 4 | 5 | jobs: 6 | discussion_commented: 7 | if: github.event.discussion && github.event.comment 8 | uses: route06/actions/.github/workflows/gh_discussion_comment_to_slack.yml@155715656c4cd9079f1213d08d058e78dd00cae7 # v2.6.0 9 | secrets: 10 | slack-webhook-url: ${{ secrets.SLACK_GHD_WEBHOOK_URL }} 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .turbo 3 | /.env 4 | .vercel 5 | .env*.local 6 | prism.wasm 7 | .cursor/mcp.json 8 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 22.15.0 2 | -------------------------------------------------------------------------------- /.pr_agent.toml: -------------------------------------------------------------------------------- 1 | [pr_description] 2 | use_description_markers = true 3 | include_generated_by_header = true 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["bierner.comment-tagged-templates", "biomejs.biome"] 3 | } 4 | -------------------------------------------------------------------------------- /assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/assets/demo.gif -------------------------------------------------------------------------------- /assets/jack.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/assets/jack.gif -------------------------------------------------------------------------------- /assets/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/assets/logo-dark.png -------------------------------------------------------------------------------- /assets/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/assets/logo-light.png -------------------------------------------------------------------------------- /biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["./frontend/packages/configs/biome.jsonc"], 3 | "linter": { 4 | "rules": { 5 | "correctness": { 6 | "noUndeclaredDependencies": "off" 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /config/license_finder.yml: -------------------------------------------------------------------------------- 1 | --- 2 | decisions_file: 'config/dependency_decisions.yml' 3 | enabled_package_managers: 4 | - pnpm 5 | -------------------------------------------------------------------------------- /docs/migrationPatterns.md: -------------------------------------------------------------------------------- 1 | # Safe and Consistent Migration Strategies 2 | 3 | - Migrations should be designed to be atomic and reversible, with comprehensive transaction handling. 4 | - Implement robust error handling and validation checks in migration scripts to ensure data integrity. 5 | - Review each migration against existing patterns to ensure compliance with project standards. -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # misc 13 | .DS_Store 14 | *.pem 15 | 16 | # debug 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | 21 | # local env files 22 | .env*.local 23 | 24 | # typescript 25 | *.tsbuildinfo 26 | next-env.d.ts 27 | 28 | # turborepo 29 | .turbo 30 | -------------------------------------------------------------------------------- /frontend/apps/app/.env: -------------------------------------------------------------------------------- 1 | ../../../.env -------------------------------------------------------------------------------- /frontend/apps/app/.env.local: -------------------------------------------------------------------------------- 1 | ../../../.env.local -------------------------------------------------------------------------------- /frontend/apps/app/.env.production: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_ENV_NAME=production 2 | ASSET_PREFIX="https://liam-erd-web.vercel.app" 3 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(root)/invitations/tokens/[token]/page.tsx: -------------------------------------------------------------------------------- 1 | import type { PageProps } from '@/app/types' 2 | import { InvitationPage } from '@/components/InvitationPage' 3 | 4 | import * as v from 'valibot' 5 | 6 | const paramsSchema = v.object({ 7 | token: v.string(), 8 | }) 9 | 10 | export default async function Page({ params }: PageProps) { 11 | const parsedParams = v.safeParse(paramsSchema, await params) 12 | if (!parsedParams.success) throw new Error('Invalid token parameters') 13 | 14 | const { token } = parsedParams.output 15 | 16 | return 17 | } 18 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(root)/layout.tsx: -------------------------------------------------------------------------------- 1 | import { CommonLayout } from '@/components/CommonLayout' 2 | import type { ReactNode } from 'react' 3 | 4 | export default function Layout({ 5 | children, 6 | }: Readonly<{ 7 | children: ReactNode 8 | }>) { 9 | return {children} 10 | } 11 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(root)/organizations/new/page.tsx: -------------------------------------------------------------------------------- 1 | import { OrganizationNewPage } from '@/components/OrganizationNewPage' 2 | 3 | export default function Page() { 4 | return 5 | } 6 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(root)/organizations/page.tsx: -------------------------------------------------------------------------------- 1 | import { OrganizationsPage } from '@/components/OrganizationsPage' 2 | 3 | export default function Page() { 4 | return 5 | } 6 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(root)/settings/billing/page.tsx: -------------------------------------------------------------------------------- 1 | export default async function BillingPage() { 2 | return ( 3 |
4 |

Billing Settings

5 |

Billing and subscription settings will be available here.

6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(root)/settings/components/SettingsHeader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SettingsHeader' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(root)/settings/general/page.tsx: -------------------------------------------------------------------------------- 1 | import { GeneralPage } from '@/components/GeneralPage' 2 | import { getOrganizationId } from '@/features/organizations/services/getOrganizationId' 3 | 4 | export default async function Page() { 5 | const organizationId = await getOrganizationId() 6 | 7 | // TODO: Reconsider what screen should be displayed to the user when organizationId is not available 8 | if (organizationId == null) { 9 | return null 10 | } 11 | 12 | return 13 | } 14 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(root)/settings/layout.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | font-family: var(--main-font); 3 | display: flex; 4 | width: 100%; 5 | height: 100%; 6 | padding: var(--spacing-20) var(--spacing-4); 7 | flex-direction: column; 8 | align-items: center; 9 | gap: var(--spacing-20); 10 | margin: 0 auto; 11 | } 12 | 13 | .heading { 14 | font-size: var(--font-size-8); 15 | font-weight: 500; 16 | color: var(--global-foreground); 17 | line-height: 100%; 18 | } 19 | 20 | .contentContainer { 21 | display: flex; 22 | flex-direction: column; 23 | gap: var(--spacing-7); 24 | width: 100%; 25 | height: 100%; 26 | max-width: 1080px; 27 | } 28 | 29 | .tabContent { 30 | width: 100%; 31 | padding-top: var(--spacing-7); 32 | } 33 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(root)/settings/projects/page.tsx: -------------------------------------------------------------------------------- 1 | export default async function ProjectsPage() { 2 | return ( 3 |
4 |

Projects Settings

5 |

Organization projects settings will be available here.

6 |
7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(with-project)/projects/[projectId]/branches/page.tsx: -------------------------------------------------------------------------------- 1 | import type { PageProps } from '@/app/types' 2 | import { ProjectBranchesListPage } from '@/components/ProjectBranchesListPage' 3 | 4 | import * as v from 'valibot' 5 | 6 | const paramsSchema = v.object({ 7 | projectId: v.string(), 8 | }) 9 | 10 | export default async function BranchesPage({ params }: PageProps) { 11 | const parsedParams = v.safeParse(paramsSchema, await params) 12 | if (!parsedParams.success) throw new Error('Invalid parameters') 13 | return 14 | } 15 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(with-project)/projects/[projectId]/page.tsx: -------------------------------------------------------------------------------- 1 | import type { PageProps } from '@/app/types' 2 | import { redirect } from 'next/navigation' 3 | import * as v from 'valibot' 4 | 5 | const paramsSchema = v.object({ 6 | projectId: v.string(), 7 | }) 8 | 9 | export default async function Page({ params }: PageProps) { 10 | const parsedParams = v.safeParse(paramsSchema, await params) 11 | if (!parsedParams.success) throw new Error('Invalid project parameters') 12 | 13 | const { projectId } = parsedParams.output 14 | 15 | // Redirect to the branch detail page with 'main' as the default branch 16 | return redirect(`/app/projects/${projectId}/ref/main`) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/apps/app/app/(app)/app/(with-project-and-branch)/projects/[projectId]/ref/[branchOrCommit]/layout.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | display: grid; 3 | grid-template-rows: auto 1fr; 4 | width: 100%; 5 | height: 100%; 6 | } 7 | 8 | .tabContent { 9 | width: 100%; 10 | min-height: 0; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/apps/app/app/.well-known/vercel/flags/route.ts: -------------------------------------------------------------------------------- 1 | import * as flags from '@/libs/flags' 2 | import { createFlagsDiscoveryEndpoint, getProviderData } from 'flags/next' 3 | 4 | // @see: https://vercel.com/docs/feature-flags/implement-flags-in-toolbar 5 | export const GET = createFlagsDiscoveryEndpoint(async () => { 6 | const providerData = getProviderData(flags) 7 | return providerData 8 | }) 9 | -------------------------------------------------------------------------------- /frontend/apps/app/app/api/webhook/helloworld/route.ts: -------------------------------------------------------------------------------- 1 | import { helloWorld } from '@liam-hq/jobs' 2 | import { type NextRequest, NextResponse } from 'next/server' 3 | 4 | export const GET = async (request: NextRequest): Promise => { 5 | const name = request.nextUrl.searchParams.get('name') ?? 'World' 6 | 7 | let result = 'hello world task processing initiated' 8 | try { 9 | await helloWorld(name) 10 | } catch (error) { 11 | console.error(error) 12 | result = error instanceof Error ? error.message : 'unknown error' 13 | } 14 | 15 | return NextResponse.json( 16 | { message: result }, 17 | { status: 404 }, // NOTE: always 404 for crawler 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /frontend/apps/app/app/app/login/page.tsx: -------------------------------------------------------------------------------- 1 | import { LoginPage } from '@/components/LoginPage' 2 | 3 | export default async function Page() { 4 | return 5 | } 6 | -------------------------------------------------------------------------------- /frontend/apps/app/app/error/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | export default function ErrorPage() { 4 | return

Sorry, something went wrong

5 | } 6 | -------------------------------------------------------------------------------- /frontend/apps/app/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/frontend/apps/app/app/favicon.ico -------------------------------------------------------------------------------- /frontend/apps/app/app/globals.css: -------------------------------------------------------------------------------- 1 | @import url('@liam-hq/ui/src/styles/globals.css'); 2 | -------------------------------------------------------------------------------- /frontend/apps/app/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from 'next/navigation' 2 | 3 | export default function Page() { 4 | redirect( 5 | '/erd/p/github.com/mastodon/mastodon/blob/1bc28709ccde4106ab7d654ad5888a14c6bb1724/db/schema.rb', 6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /frontend/apps/app/app/types.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react' 2 | 3 | // https://nextjs.org/docs/app/api-reference/file-conventions/page 4 | export type PageProps = { 5 | params: Promise<{ [key: string]: string | string[] | undefined }> 6 | searchParams: Promise<{ [key: string]: string | string[] | undefined }> 7 | } 8 | 9 | //https://nextjs.org/docs/app/api-reference/file-conventions/layout 10 | export type LayoutProps = { 11 | children?: ReactNode 12 | params: Promise<{ [key: string]: string | string[] | undefined }> 13 | } 14 | -------------------------------------------------------------------------------- /frontend/apps/app/biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../packages/configs/biome.jsonc"] 3 | } 4 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BranchDetailPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BranchDetailPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/SchemaEditor/SchemaEditor.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | height: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/SchemaEditor/SchemaEditor.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { type FC, useState } from 'react' 4 | import { BEFORE } from '../before' 5 | import styles from './SchemaEditor.module.css' 6 | import { useMergeEditor } from './useMergeEditor' 7 | 8 | type Props = { 9 | initialDoc: string 10 | } 11 | 12 | export const SchemaEditor: FC = ({ initialDoc }) => { 13 | const [doc, setDoc] = useState(initialDoc) 14 | 15 | const { ref } = useMergeEditor({ 16 | original: JSON.stringify(BEFORE, null, 2), 17 | modified: doc, 18 | setModified: setDoc, 19 | mode: 'unified', 20 | }) 21 | 22 | return
23 | } 24 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/SchemaEditor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SchemaEditor' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/DiffView/TableDiffBlock/TableDiffBlock.module.css: -------------------------------------------------------------------------------- 1 | .beforeAndAfter { 2 | display: grid; 3 | grid-template-columns: 1fr 1fr; 4 | grid-template-areas: 'before after'; 5 | align-items: start; 6 | } 7 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/DiffView/TableDiffBlock/TableItem/ColumnItem/index.ts: -------------------------------------------------------------------------------- 1 | export { ColumnItem } from './ColumnItem' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/DiffView/TableDiffBlock/TableItem/ConstraintList/ConstraintItem/ConstraintItem.module.css: -------------------------------------------------------------------------------- 1 | .icon { 2 | width: 0.75rem; 3 | height: 0.75rem; 4 | color: var(--primary-accent); 5 | } 6 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/DiffView/TableDiffBlock/TableItem/ConstraintList/ConstraintItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './PrimaryConstraintItem' 2 | export * from './ForeignConstraintItem' 3 | export * from './CheckConstraintItem' 4 | export * from './UniqueConstraintItem' 5 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/DiffView/TableDiffBlock/TableItem/ConstraintList/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ConstraintList' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/DiffView/TableDiffBlock/TableItem/Diff.module.css: -------------------------------------------------------------------------------- 1 | .added { 2 | background-color: var(--color-green-alpha-20) !important; 3 | } 4 | 5 | .removed { 6 | background-color: var(--color-red-alpha-20) !important; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/DiffView/TableDiffBlock/TableItem/IndexItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IndexItem' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/DiffView/TableDiffBlock/TableItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableItem' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/DiffView/TableDiffBlock/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableDiffBlock' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/DiffView/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DiffView' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/SingleView/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SingleView' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/TablesList/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TablesList' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/Panel/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Panel' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/BuildPage/index.ts: -------------------------------------------------------------------------------- 1 | export { BuildPage } from './BuildPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/Chat/AgentAvatar/AskAgent.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/react' 2 | import type { ComponentProps } from 'react' 3 | import { AskAgent } from './AskAgent' 4 | 5 | type AskAgentProps = ComponentProps 6 | 7 | const meta = { 8 | component: AskAgent, 9 | title: 'Components/Chat/AgentAvatar/AskAgent', 10 | } satisfies Meta 11 | 12 | export default meta 13 | type Story = StoryObj 14 | 15 | export const Default: Story = { 16 | args: {}, 17 | } 18 | 19 | export const CustomSize: Story = { 20 | args: { 21 | width: 48, 22 | height: 48, 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /frontend/apps/app/components/Chat/AgentAvatar/BuildAgent.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/react' 2 | import type { ComponentProps } from 'react' 3 | import { BuildAgent } from './BuildAgent' 4 | 5 | type BuildAgentProps = ComponentProps 6 | 7 | const meta = { 8 | component: BuildAgent, 9 | title: 'Components/Chat/AgentAvatar/BuildAgent', 10 | } satisfies Meta 11 | 12 | export default meta 13 | type Story = StoryObj 14 | 15 | export const Default: Story = { 16 | args: {}, 17 | } 18 | 19 | export const CustomSize: Story = { 20 | args: { 21 | width: 48, 22 | height: 48, 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /frontend/apps/app/components/Chat/AgentMessage/index.ts: -------------------------------------------------------------------------------- 1 | export { AgentMessage } from './AgentMessage' 2 | export type { AgentType } from './AgentMessage' 3 | -------------------------------------------------------------------------------- /frontend/apps/app/components/Chat/NewThreadButton/NewThreadButton.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { IconButton, Plus } from '@liam-hq/ui' 4 | import type { ComponentProps, FC } from 'react' 5 | 6 | type Props = Omit< 7 | ComponentProps, 8 | 'icon' | 'tooltipContent' 9 | > & { 10 | tooltipContent?: string 11 | variant?: ComponentProps['variant'] 12 | } 13 | 14 | export const NewThreadButton: FC = ({ 15 | tooltipContent = 'New Thread', 16 | className, 17 | variant = 'hoverBackground', 18 | ...props 19 | }) => { 20 | return ( 21 | } 23 | tooltipContent={tooltipContent} 24 | variant={variant} 25 | {...props} 26 | /> 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /frontend/apps/app/components/Chat/ProcessIndicator/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProcessIndicator' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/Chat/ThreadListButton/ThreadListButton.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { IconButton, List } from '@liam-hq/ui' 4 | import type { ComponentProps, FC } from 'react' 5 | 6 | type Props = Omit< 7 | ComponentProps, 8 | 'icon' | 'tooltipContent' 9 | > & { 10 | tooltipContent?: string 11 | variant?: ComponentProps['variant'] 12 | } 13 | 14 | export const ThreadListButton: FC = ({ 15 | tooltipContent = 'Thread List', 16 | className, 17 | variant = 'hoverBackground', 18 | ...props 19 | }) => { 20 | return ( 21 | } 23 | tooltipContent={tooltipContent} 24 | variant={variant} 25 | {...props} 26 | /> 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /frontend/apps/app/components/Chat/UserMessage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './UserMessage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/Chat/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Chat' 2 | export * from './ProcessIndicator' 3 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/components/CancelButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CancelButton' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/components/MentionSuggestor/components/HighlightedLabel/HighlightedLabel.module.css: -------------------------------------------------------------------------------- 1 | .highlight { 2 | color: var(--primary-accent); 3 | } 4 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/components/MentionSuggestor/components/HighlightedLabel/HighlightedLabel.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react' 2 | import styles from './HighlightedLabel.module.css' 3 | import { getHighlightedParts } from './getHighlightedParts' 4 | 5 | type Props = { 6 | label: string 7 | query: string 8 | } 9 | 10 | export const HighlightedLabel: FC = ({ label, query }) => { 11 | const { before, match, after } = getHighlightedParts(label, query) 12 | 13 | return ( 14 | <> 15 | {before} 16 | {match && {match}} 17 | {after} 18 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/components/MentionSuggestor/components/HighlightedLabel/index.ts: -------------------------------------------------------------------------------- 1 | export * from './HighlightedLabel' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/components/MentionSuggestor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './MentionSuggestor' 2 | export * from '../../types' 3 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/components/MentionSuggestor/utils/extractActiveMention.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_TRIGGER } from '../../../constants' 2 | 3 | export function extractActiveMention(text: string, cursorPos: number): string { 4 | const before = text.slice(0, cursorPos) 5 | const match = new RegExp(`\\${DEFAULT_TRIGGER}([\\w-]*)$`).exec(before) 6 | return match ? match[1] : '' 7 | } 8 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/components/ModeToggleSwitch/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ModeToggleSwitch' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/components/SendButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SendButton' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/constants.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_TRIGGER = '@' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ChatInput' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/types.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react' 2 | 3 | export type MentionItem = { 4 | id: string 5 | label: string 6 | type?: 'group' | 'table' | 'column' | 'relation' 7 | icon?: ReactNode 8 | columnType?: 'primary' | 'foreign' | 'notNull' | 'nullable' 9 | } 10 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/utils/handleNormalKey.ts: -------------------------------------------------------------------------------- 1 | import type { KeyboardEvent } from 'react' 2 | 3 | type NormalKeyHandlerOptions = { 4 | isImeComposing: boolean 5 | hasContent: boolean 6 | onSubmit: () => void 7 | } 8 | 9 | export const handleNormalKey = ( 10 | e: KeyboardEvent, 11 | { isImeComposing, hasContent, onSubmit }: NormalKeyHandlerOptions, 12 | ): void => { 13 | if (e.nativeEvent.isComposing || isImeComposing) return 14 | 15 | if (e.key === 'Enter' && !e.shiftKey) { 16 | e.preventDefault() 17 | 18 | if (hasContent) { 19 | onSubmit() 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/utils/insertMention.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_TRIGGER } from '../constants' 2 | import type { MentionItem } from '../types' 3 | 4 | export const insertMentionAtCursor = ( 5 | text: string, 6 | cursorPos: number, 7 | mention: MentionItem, 8 | ): string => { 9 | const before = text.slice(0, cursorPos) 10 | const match = new RegExp(`\\${DEFAULT_TRIGGER}([\\w-]*)$`).exec(before) 11 | if (!match) return text 12 | 13 | const start = cursorPos - match[0].length 14 | const after = text.slice(cursorPos) 15 | 16 | return `${text.slice(0, start)}${DEFAULT_TRIGGER}${mention.label} ${after}` 17 | } 18 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatInput/utils/isRegularKey.ts: -------------------------------------------------------------------------------- 1 | export function isRegularKey(key: string): boolean { 2 | return /^[a-zA-Z0-9-_]$/.test(key) 3 | } 4 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatMessage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ChatMessage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatbotButton/ChatbotButton.module.css: -------------------------------------------------------------------------------- 1 | .chatButton { 2 | position: fixed; 3 | bottom: 20px; 4 | right: 20px; 5 | display: flex; 6 | align-items: center; 7 | gap: 8px; 8 | padding: 10px 16px; 9 | border-radius: 24px; 10 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); 11 | z-index: 100; 12 | } 13 | 14 | .buttonText { 15 | font-size: var(--font-size-3); 16 | } 17 | 18 | @media (max-width: 768px) { 19 | .buttonText { 20 | display: none; 21 | } 22 | 23 | .chatButton { 24 | width: 48px; 25 | height: 48px; 26 | padding: 0; 27 | justify-content: center; 28 | border-radius: 50%; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatbotButton/components/ChatbotDialog/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ChatbotDialog' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ChatbotButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ChatbotButton' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/AppBar/BranchDropdownMenu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BranchDropdownMenu' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/AppBar/ProjectsDropdownMenu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProjectsDropdownMenu' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/AppBar/ProjectsDropdownMenu/services/getProject.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from '@/libs/db/server' 2 | import type { QueryData } from '@liam-hq/db' 3 | 4 | export async function getProject(projectId: string) { 5 | const supabase = await createClient() 6 | 7 | return await supabase 8 | .from('projects') 9 | .select('id, name') 10 | .eq('id', projectId) 11 | .single() 12 | } 13 | 14 | export type Project = QueryData> 15 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/AppBar/ProjectsDropdownMenu/services/getProjects.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from '@/libs/db/server' 2 | import type { QueryData } from '@liam-hq/db' 3 | 4 | async function query(organizationId: string) { 5 | const supabase = await createClient() 6 | 7 | return await supabase 8 | .from('projects') 9 | .select('id, name') 10 | .eq('organization_id', organizationId) 11 | } 12 | 13 | export async function getProjects(organizationId: string | null) { 14 | if (!organizationId) { 15 | return { data: null, error: null } 16 | } 17 | 18 | return query(organizationId) 19 | } 20 | 21 | export type Projects = QueryData> 22 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/AppBar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AppBar' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/AppBar/services/getAuthUser.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from '@/libs/db/server' 2 | 3 | export async function getAuthUser() { 4 | const supabase = await createClient() 5 | 6 | return await supabase.auth.getUser() 7 | } 8 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/GlobalNav/LinkItem/LinkItem.module.css: -------------------------------------------------------------------------------- 1 | .active { 2 | background-color: var(--pane-background-active); 3 | } 4 | 5 | .activeIcon > svg { 6 | color: var(--global-foreground); 7 | } 8 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/GlobalNav/LinkItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LinkItem' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/GlobalNav/OrganizationItem/OrganizationDropdownContent/OrganizationDropdownContent.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | width: 15rem; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/GlobalNav/OrganizationItem/OrganizationDropdownContent/index.ts: -------------------------------------------------------------------------------- 1 | export * from './OrganizationDropdownContent' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/GlobalNav/OrganizationItem/OrganizationItem.module.css: -------------------------------------------------------------------------------- 1 | .badgeContainer { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | padding: var(--spacing-1); 6 | background-color: var(--overlay-20); 7 | border-radius: var(--borderRadius-base, 0.25rem); 8 | font-size: var(--font-size-2, 0.6875rem); 9 | font-weight: 500; 10 | line-height: 1; 11 | color: var(--global-foreground, #fff); 12 | font-family: 'IBM Plex Mono', monospace; 13 | } 14 | 15 | .chevronIcon { 16 | width: 0.75rem; 17 | height: 0.75rem; 18 | color: var(--overlay-70); 19 | } 20 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/GlobalNav/OrganizationItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './OrganizationItem' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/GlobalNav/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GlobalNav' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/OrgCookie.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { setOrganizationIdCookie } from '@/features/organizations/services/setOrganizationIdCookie' 4 | import { type FC, useEffect } from 'react' 5 | 6 | type Props = { 7 | orgId: string 8 | } 9 | 10 | export const OrgCookie: FC = ({ orgId }) => { 11 | useEffect(() => { 12 | setOrganizationIdCookie(orgId) 13 | }, [orgId]) 14 | 15 | return null 16 | } 17 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CommonLayout' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/services/getAuthUser.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from '@/libs/db/server' 2 | 3 | export async function getAuthUser() { 4 | const supabase = await createClient() 5 | 6 | return await supabase.auth.getUser() 7 | } 8 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/services/getOrganization.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from '@/libs/db/server' 2 | import type { QueryData } from '@liam-hq/db' 3 | 4 | async function query(organizationId: string) { 5 | const supabase = await createClient() 6 | 7 | return await supabase 8 | .from('organizations') 9 | .select('id, name') 10 | .eq('id', organizationId) 11 | .single() 12 | } 13 | 14 | export async function getOrganization(organizationId: string | null) { 15 | if (!organizationId) { 16 | return { data: null, error: null } 17 | } 18 | 19 | return query(organizationId) 20 | } 21 | 22 | export type Organization = QueryData> 23 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CommonLayout/services/getOrganizationsByUserId.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from '@/libs/db/server' 2 | import type { QueryData } from '@liam-hq/db' 3 | 4 | export async function getOrganizationsByUserId(userId: string) { 5 | const supabase = await createClient() 6 | 7 | return await supabase 8 | .from('organization_members') 9 | .select('organizations:organization_id(id, name)') 10 | .eq('user_id', userId) 11 | } 12 | 13 | export type OrganizationsByUserId = QueryData< 14 | ReturnType 15 | > 16 | -------------------------------------------------------------------------------- /frontend/apps/app/components/CookieConsent/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CookieConsent' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/DiffCount/DiffCount.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | font-family: var(--code-font); 6 | font-size: var(--font-size-2); 7 | font-weight: 400; 8 | line-height: 1em; 9 | } 10 | 11 | .new { 12 | color: var(--success-accent); 13 | } 14 | 15 | .delete { 16 | color: var(--error-accent); 17 | } 18 | -------------------------------------------------------------------------------- /frontend/apps/app/components/DiffCount/DiffCount.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react' 2 | import styles from './DiffCount.module.css' 3 | 4 | type DiffCountVariant = 'new' | 'delete' 5 | 6 | interface DiffCountProps { 7 | count: number 8 | variant: DiffCountVariant 9 | } 10 | 11 | export const DiffCount: FC = ({ count, variant }) => { 12 | const prefix = variant === 'new' ? '+' : '-' 13 | const absoluteCount = Math.abs(count) 14 | 15 | return ( 16 |
17 | {`${prefix}${absoluteCount}`} 18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /frontend/apps/app/components/DiffCount/DiffCounts.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | gap: var(--spacing-1, 0.25rem); 6 | } 7 | -------------------------------------------------------------------------------- /frontend/apps/app/components/DiffCount/DiffCounts.tsx: -------------------------------------------------------------------------------- 1 | import { DiffCount } from '@/components/DiffCount' 2 | import type { FC } from 'react' 3 | import styles from './DiffCounts.module.css' 4 | 5 | interface DiffCountsProps { 6 | additions: number 7 | deletions: number 8 | } 9 | 10 | export const DiffCounts: FC = ({ additions, deletions }) => { 11 | return ( 12 |
13 | {additions > 0 && } 14 | {deletions > 0 && } 15 |
16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/apps/app/components/DiffCount/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DiffCount' 2 | export * from './DiffCounts' 3 | -------------------------------------------------------------------------------- /frontend/apps/app/components/FormatIcon/FormatIcon.module.css: -------------------------------------------------------------------------------- 1 | .formatIcon { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | width: 16px; 6 | height: 16px; 7 | color: var(--color-white-alpha-70, rgba(255, 255, 255, 0.7)); 8 | } 9 | -------------------------------------------------------------------------------- /frontend/apps/app/components/FormatIcon/icons/SchemaRbIcon.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react' 2 | import type { IconProps } from './types' 3 | 4 | export const SchemaRbIcon: FC = ({ size = 16 }) => { 5 | return ( 6 | SchemaRbIcon 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /frontend/apps/app/components/FormatIcon/icons/index.ts: -------------------------------------------------------------------------------- 1 | export * from './PostgresIcon' 2 | export * from './PrismaIcon' 3 | export * from './SchemaRbIcon' 4 | export * from './TblsIcon' 5 | export * from './types' 6 | -------------------------------------------------------------------------------- /frontend/apps/app/components/FormatIcon/icons/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Common props interface for all icon components 3 | */ 4 | export interface IconProps { 5 | /** The size of the icon in pixels (default: 16) */ 6 | size?: number 7 | } 8 | -------------------------------------------------------------------------------- /frontend/apps/app/components/FormatIcon/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FormatIcon' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/GeneralPage/GeneralPage.tsx: -------------------------------------------------------------------------------- 1 | import { GeneralPageClient } from './components/GeneralPageClient' 2 | import { getOrganizationDetails } from './services/getOrganizationDetails' 3 | 4 | export async function GeneralPage({ 5 | organizationId, 6 | }: { 7 | organizationId: string 8 | }) { 9 | // Fetch organization details using the existing function 10 | const organization = await getOrganizationDetails(organizationId) 11 | 12 | if (!organization) { 13 | throw new Error('Organization not found') 14 | } 15 | 16 | // Use the client component with useActionState for toast notifications 17 | return 18 | } 19 | -------------------------------------------------------------------------------- /frontend/apps/app/components/GeneralPage/components/GeneralPageClient/actions/deleteOrganization.ts: -------------------------------------------------------------------------------- 1 | 'use server' 2 | 3 | import { createClient } from '@/libs/db/server' 4 | 5 | /** 6 | * Delete organization 7 | */ 8 | export async function deleteOrganization( 9 | organizationId: string, 10 | ): Promise<{ success: boolean; error?: string }> { 11 | const supabase = await createClient() 12 | const { error } = await supabase 13 | .from('organizations') 14 | .delete() 15 | .eq('id', organizationId) 16 | 17 | if (error) { 18 | console.error('Error deleting organization:', error) 19 | return { success: false, error: 'Failed to delete organization' } 20 | } 21 | 22 | return { success: true } 23 | } 24 | -------------------------------------------------------------------------------- /frontend/apps/app/components/GeneralPage/components/GeneralPageClient/components/DeleteOrganizationButtonClient/DeleteConfirmationModal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DeleteConfirmationModal' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/GeneralPage/components/GeneralPageClient/components/DeleteOrganizationButtonClient/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DeleteOrganizationButtonClient' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/GeneralPage/components/GeneralPageClient/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GeneralPageClient' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/GeneralPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GeneralPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/InvitationPage/InvitationPage.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react' 2 | import { InvitationCard } from './components/InvitationCard' 3 | import { getInvitationData } from './services/getInvitationData' 4 | 5 | type Props = { 6 | token: string 7 | } 8 | 9 | export const InvitationPage: FC = async ({ token }) => { 10 | const { organizationName, currentUser } = await getInvitationData(token) 11 | 12 | return ( 13 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /frontend/apps/app/components/InvitationPage/components/InvitationCard/index.ts: -------------------------------------------------------------------------------- 1 | export * from './InvitationCard' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/InvitationPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './InvitationPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/LoginPage/SignInGithubButton.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { GithubLogo } from '@liam-hq/ui' 4 | import styles from './LoginPage.module.css' 5 | import { loginByGithub } from './services/loginByGithub' 6 | 7 | type Props = { 8 | returnTo: string 9 | } 10 | 11 | export const SignInGithubButton = ({ returnTo }: Props) => { 12 | return ( 13 |
14 | 15 | 23 |
24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /frontend/apps/app/components/LoginPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LoginPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/OrganizationMembersPage/components/ClientSearchWrapper/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ClientSearchWrapper' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/OrganizationMembersPage/components/DeleteInvitationModal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DeleteInvitationModal' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/OrganizationMembersPage/components/DeleteMemberModal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DeleteMemberModal' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/OrganizationMembersPage/components/InvitationItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './InvitationItem' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/OrganizationMembersPage/components/InviteMemberModal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './InviteMemberModal' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/OrganizationMembersPage/components/MemberItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './MemberItem' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/OrganizationMembersPage/components/SearchInput/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SearchInput' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/OrganizationMembersPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './OrganizationMembersPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/OrganizationNewPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './OrganizationNewPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/OrganizationsPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './OrganizationsPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectBranchesListPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProjectBranchesListPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectLayout/ProjectHeader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProjectHeader' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectLayout/ProjectLayout.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | display: grid; 3 | grid-template-rows: auto 1fr; 4 | width: 100%; 5 | height: 100%; 6 | } 7 | 8 | .tabContent { 9 | width: 100%; 10 | min-height: 0; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectLayout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProjectLayout' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectNewPage/ProjectNewPage.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | flex-direction: column; 4 | padding: 20px; 5 | } 6 | 7 | .title { 8 | font-size: 24px; 9 | font-weight: bold; 10 | margin-bottom: 20px; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectNewPage/ProjectNewPage.tsx: -------------------------------------------------------------------------------- 1 | import type { Installation } from '@liam-hq/github' 2 | import type { FC } from 'react' 3 | import styles from './ProjectNewPage.module.css' 4 | import { InstallationSelector } from './components/InstallationSelector' 5 | 6 | type Props = { 7 | installations: Installation[] 8 | organizationId: string 9 | } 10 | 11 | export const ProjectNewPage: FC = ({ 12 | installations, 13 | organizationId, 14 | }) => { 15 | return ( 16 |
17 |

Add a Project

18 | 22 |
23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/InstallationSelector.module.css: -------------------------------------------------------------------------------- 1 | .installationSelector { 2 | margin: 20px 0; 3 | width: 100%; 4 | max-width: 400px; 5 | } 6 | 7 | .repositoriesList { 8 | display: grid; 9 | gap: var(--spacing-3); 10 | width: 100%; 11 | max-width: 400px; 12 | margin-top: 20px; 13 | } 14 | 15 | .repositoryItem { 16 | padding: 10px; 17 | border: 1px solid #ccc; 18 | border-radius: 4px; 19 | margin-bottom: 10px; 20 | } 21 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectNewPage/components/InstallationSelector/index.ts: -------------------------------------------------------------------------------- 1 | export * from './InstallationSelector' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectNewPage/components/RepositoryItem/RepositoryItem.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: flex; 3 | padding: var(--spacing-3, 0.75rem); 4 | align-items: center; 5 | gap: var(--spacing-3, 0.75rem); 6 | border: solid 1px white; 7 | border-radius: var(--border-radius-base); 8 | } 9 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectNewPage/components/RepositoryItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RepositoryItem' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectNewPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProjectNewPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectsPage/components/EmptyProjectsState/index.ts: -------------------------------------------------------------------------------- 1 | export * from './EmptyProjectsState' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectsPage/components/ProjectsListView/components/ProjectItem/OrganizationData.tsx: -------------------------------------------------------------------------------- 1 | 'use server' 2 | 3 | import { getOrganizationInfo } from '@liam-hq/github' 4 | 5 | // Separating data fetching function as a server action 6 | export async function fetchOrganizationData( 7 | installationId: number, 8 | owner: string, 9 | repo: string, 10 | ) { 11 | if (!installationId || !owner || !repo) { 12 | return null 13 | } 14 | const orgInfo = await getOrganizationInfo(installationId, owner, repo) 15 | return orgInfo?.avatar_url || null 16 | } 17 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectsPage/components/ProjectsListView/components/ProjectItem/index.ts: -------------------------------------------------------------------------------- 1 | export { ProjectItem } from './ProjectItem' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectsPage/components/ProjectsListView/components/SearchInput/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SearchInput' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectsPage/components/ProjectsListView/components/SortDropdown/SortDropdown.module.css: -------------------------------------------------------------------------------- 1 | .sortSelect { 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | gap: var(--spacing-1); 6 | padding: var(--spacing-2) var(--spacing-3); 7 | background-color: var(--global-background); 8 | border: var(--border-width-base) solid var(--global-border); 9 | border-radius: var(--border-radius-md); 10 | color: var(--global-foreground); 11 | font-size: var(--font-size-4); 12 | width: 282px; 13 | height: 36px; 14 | cursor: pointer; 15 | } 16 | 17 | .sortSelectIcon { 18 | margin-left: auto; 19 | color: var(--global-foreground); 20 | width: 1rem; 21 | height: 1rem; 22 | } 23 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectsPage/components/ProjectsListView/components/SortDropdown/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SortDropdown' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectsPage/components/ProjectsListView/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProjectsListView' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectsPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProjectsPage' 2 | export * from './ServerProjectsDataProvider' 3 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectsPage/services/fetchLastCommitData.ts: -------------------------------------------------------------------------------- 1 | 'use server' 2 | 3 | import { getLastCommit } from '@liam-hq/github' 4 | 5 | // define the data fetching function as a server action 6 | export async function fetchLastCommitData( 7 | installationId: number, 8 | owner: string, 9 | repo: string, 10 | ) { 11 | if (!installationId || !owner || !repo) { 12 | return null 13 | } 14 | 15 | const commitInfo = await getLastCommit(installationId, owner, repo) 16 | 17 | if (commitInfo) { 18 | return { 19 | author: commitInfo.author, 20 | date: commitInfo.date, 21 | } 22 | } 23 | 24 | return null 25 | } 26 | -------------------------------------------------------------------------------- /frontend/apps/app/components/ProjectsPage/types.ts: -------------------------------------------------------------------------------- 1 | import type { Tables } from '@liam-hq/db' 2 | 3 | /** 4 | * Extended project type with last commit date 5 | */ 6 | export type ProjectWithLastCommit = Tables<'projects'> & { 7 | lastCommitDate?: string 8 | project_repository_mappings?: Array<{ 9 | repository: Tables<'github_repositories'> 10 | }> 11 | } 12 | -------------------------------------------------------------------------------- /frontend/apps/app/components/SchemaLink/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SchemaLink' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/SchemaPage/SchemaPage.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: grid; 3 | grid-template-rows: auto 1fr; 4 | height: 100%; 5 | } 6 | 7 | .tabsContent { 8 | min-height: 0; 9 | } 10 | -------------------------------------------------------------------------------- /frontend/apps/app/components/SchemaPage/components/ERDEditor/ERDEditor.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | position: relative; 3 | height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /frontend/apps/app/components/SchemaPage/components/ERDEditor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ERDEditor' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/SchemaPage/components/OverrideEditor/OverrideEditor.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | height: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/apps/app/components/SchemaPage/components/OverrideEditor/OverrideEditor.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { type FC, useState } from 'react' 4 | import styles from './OverrideEditor.module.css' 5 | import { useYamlEditor } from './useYamlEditor' 6 | 7 | export const OverrideEditor: FC = () => { 8 | const [doc, setDoc] = useState(undefined) 9 | 10 | const { editor } = useYamlEditor({ doc, setDoc }) 11 | 12 | return
13 | } 14 | -------------------------------------------------------------------------------- /frontend/apps/app/components/SchemaPage/components/OverrideEditor/index.ts: -------------------------------------------------------------------------------- 1 | export * from './OverrideEditor' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/SchemaPage/components/SchemaHeader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SchemaHeader' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/components/SchemaPage/constants.ts: -------------------------------------------------------------------------------- 1 | export const SCHEMA_TAB = { 2 | ERD: 'erd', 3 | EDITOR: 'editor', 4 | } as const 5 | 6 | type SchemaTabValue = (typeof SCHEMA_TAB)[keyof typeof SCHEMA_TAB] 7 | 8 | interface SchemaTab { 9 | value: SchemaTabValue 10 | label: string 11 | } 12 | 13 | export const SCHEMA_TABS: SchemaTab[] = [ 14 | { value: SCHEMA_TAB.ERD, label: 'ERD' }, 15 | { value: SCHEMA_TAB.EDITOR, label: 'Override' }, 16 | ] 17 | 18 | export const DEFAULT_SCHEMA_TAB = SCHEMA_TAB.ERD 19 | -------------------------------------------------------------------------------- /frontend/apps/app/components/SchemaPage/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SchemaPage' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { createBaseConfig } from '../../packages/configs/eslint/index.js' 3 | 4 | const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url)) 5 | 6 | export default [ 7 | ...createBaseConfig({ 8 | tsconfigPath: './tsconfig.json', 9 | gitignorePath, 10 | }), 11 | ] 12 | -------------------------------------------------------------------------------- /frontend/apps/app/features/organizations/constants.ts: -------------------------------------------------------------------------------- 1 | export const ORGANIZATION_ID_KEY = 'organizationId' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/features/organizations/services/getOrganizationIdFromCookie.ts: -------------------------------------------------------------------------------- 1 | import { cookies } from 'next/headers' 2 | import { ORGANIZATION_ID_KEY } from '../constants' 3 | 4 | export async function getOrganizationIdFromCookie(): Promise { 5 | const cookirStore = await cookies() 6 | const cookie = cookirStore.get(ORGANIZATION_ID_KEY) 7 | 8 | return cookie?.value ?? null 9 | } 10 | -------------------------------------------------------------------------------- /frontend/apps/app/features/organizations/services/setOrganizationIdCookie.ts: -------------------------------------------------------------------------------- 1 | 'use server' 2 | 3 | import { cookies } from 'next/headers' 4 | import { ORGANIZATION_ID_KEY } from '../constants' 5 | 6 | export async function setOrganizationIdCookie( 7 | organizationId: string, 8 | ): Promise { 9 | const cookieStore = await cookies() 10 | cookieStore.set(ORGANIZATION_ID_KEY, organizationId) 11 | } 12 | -------------------------------------------------------------------------------- /frontend/apps/app/features/schemas/constants.ts: -------------------------------------------------------------------------------- 1 | export const SCHEMA_OVERRIDE_FILE_PATH = '.liam/schema-override.yml' 2 | -------------------------------------------------------------------------------- /frontend/apps/app/instrumentation-client.ts: -------------------------------------------------------------------------------- 1 | import * as Sentry from '@sentry/nextjs' 2 | 3 | Sentry.init({ 4 | dsn: process.env.SENTRY_DSN, 5 | 6 | integrations: [Sentry.replayIntegration()], 7 | 8 | tracesSampleRate: 1, 9 | 10 | replaysSessionSampleRate: 0.1, 11 | 12 | replaysOnErrorSampleRate: 1.0, 13 | 14 | debug: false, 15 | 16 | environment: process.env.NEXT_PUBLIC_ENV_NAME, 17 | }) 18 | 19 | export const onRouterTransitionStart = Sentry.captureRouterTransitionStart 20 | -------------------------------------------------------------------------------- /frontend/apps/app/lib/mastra/agents/index.ts: -------------------------------------------------------------------------------- 1 | export { databaseSchemaAskAgent } from './databaseSchemaAskAgent' 2 | export { databaseSchemaBuildAgent } from './databaseSchemaBuildAgent' 3 | -------------------------------------------------------------------------------- /frontend/apps/app/libs/db/client.ts: -------------------------------------------------------------------------------- 1 | import { createBrowserClient } from '@liam-hq/db' 2 | 3 | export function createClient() { 4 | return createBrowserClient( 5 | process.env.NEXT_PUBLIC_SUPABASE_URL ?? '', 6 | process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ?? '', 7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /frontend/apps/app/libs/flags/index.ts: -------------------------------------------------------------------------------- 1 | import { flag } from 'flags/next' 2 | 3 | function takeLocalEnv(localEnvironemntKey: string) { 4 | if (process.env.NODE_ENV !== 'development') { 5 | return false 6 | } 7 | if ( 8 | process.env[localEnvironemntKey] === undefined || 9 | process.env[localEnvironemntKey] === 'false' 10 | ) { 11 | return false 12 | } 13 | return true 14 | } 15 | 16 | export const migrationFlag = flag({ 17 | key: 'migration', 18 | decide() { 19 | return takeLocalEnv('MIGRATION_ENABLED') 20 | }, 21 | }) 22 | -------------------------------------------------------------------------------- /frontend/apps/app/libs/gtm/GTMConsent.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { type FC, useEffect } from 'react' 4 | import { GTM_CONSENT_MODE_KEY } from './constants' 5 | 6 | export const GTMConsent: FC = () => { 7 | useEffect(() => { 8 | const consentMode = localStorage.getItem(GTM_CONSENT_MODE_KEY) 9 | if (consentMode === null) { 10 | window.gtag('consent', 'default', { 11 | ad_storage: 'denied', 12 | analytics_storage: 'denied', 13 | personalization_storage: 'denied', 14 | functionality_storage: 'denied', 15 | security_storage: 'denied', 16 | }) 17 | } else { 18 | window.gtag('consent', 'default', JSON.parse(consentMode)) 19 | } 20 | }, []) 21 | 22 | return null 23 | } 24 | -------------------------------------------------------------------------------- /frontend/apps/app/libs/gtm/GtagScript.tsx: -------------------------------------------------------------------------------- 1 | import Script from 'next/script' 2 | import type { FC } from 'react' 3 | 4 | export const GtagScript: FC = () => { 5 | return ( 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /frontend/packages/cli/public/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/frontend/packages/cli/public/.keep -------------------------------------------------------------------------------- /frontend/packages/cli/public/assets/liam_erd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/frontend/packages/cli/public/assets/liam_erd.png -------------------------------------------------------------------------------- /frontend/packages/cli/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/frontend/packages/cli/public/favicon.ico -------------------------------------------------------------------------------- /frontend/packages/cli/src/cli/index.ts: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'node:module' 2 | import { Command } from 'commander' 3 | import { erdCommand } from './erdCommand/index.js' 4 | import { initCommand } from './initCommand/index.js' 5 | 6 | const program = new Command() 7 | 8 | const require = createRequire(import.meta.url) 9 | const { version } = require('../../package.json') 10 | 11 | program.name('liam').description('CLI tool for Liam').version(version) 12 | program.addCommand(erdCommand) 13 | program.addCommand(initCommand) 14 | export { program } 15 | -------------------------------------------------------------------------------- /frontend/packages/cli/src/cli/urls.ts: -------------------------------------------------------------------------------- 1 | // liambx.com 2 | export const DocsUrl = 'https://liambx.com/docs' 3 | export const TroubleshootingUrl = 4 | 'https://liambx.com/docs/parser/troubleshooting' 5 | 6 | // github.com 7 | export const RepositoryUrl = 'https://github.com/liam-hq/liam' 8 | export const DiscussionUrl = 'https://github.com/liam-hq/liam/discussions' 9 | export const DbOrmDiscussionUrl = 10 | 'https://github.com/liam-hq/liam/discussions/364' 11 | -------------------------------------------------------------------------------- /frontend/packages/cli/src/globals.css: -------------------------------------------------------------------------------- 1 | #root { 2 | display: flex; 3 | flex-direction: column; 4 | height: 100dvh; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/packages/cli/src/index.ts: -------------------------------------------------------------------------------- 1 | export { program } from './cli/index.js' 2 | -------------------------------------------------------------------------------- /frontend/packages/cli/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './globals.css' 5 | 6 | const rootElement = document.getElementById('root') 7 | if (rootElement) { 8 | createRoot(rootElement).render( 9 | 10 | 11 | , 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /frontend/packages/cli/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontend/packages/cli/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /frontend/packages/cli/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "incremental": true, 5 | "target": "ES2022", 6 | "lib": ["ES2023"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | "moduleResolution": "Bundler", 10 | "isolatedModules": true, 11 | "moduleDetection": "force", 12 | "noEmit": false, 13 | "strict": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "noUncheckedSideEffectImports": true 18 | }, 19 | "include": ["vite.config.ts", "bin"] 20 | } 21 | -------------------------------------------------------------------------------- /frontend/packages/cli/vite-plugins/index.ts: -------------------------------------------------------------------------------- 1 | export * from './remove-import-wasi.js' 2 | export * from './set-env.js' 3 | -------------------------------------------------------------------------------- /frontend/packages/cli/vite-plugins/remove-import-wasi.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | import type { Plugin } from 'vite' 3 | 4 | // The `import 'wasi'` statement is dynamically imported within the db-structure package. 5 | // However, `import 'wasi';` gets included in the build output. 6 | // To address this, the buildEnd hook removes it from the build artifact. 7 | export function removeImportWasi(): Plugin { 8 | return { 9 | name: 'remove-import-wasi', 10 | buildEnd() { 11 | const filePath = 'dist-cli/bin/cli.js' 12 | const originalContent = fs.readFileSync(filePath, 'utf8') 13 | const content = originalContent.replace(/import 'wasi';\s*/g, '') 14 | fs.writeFileSync(filePath, content, 'utf8') 15 | }, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/packages/configs/eslint/index.js: -------------------------------------------------------------------------------- 1 | export { createBaseConfig } from './base.js' 2 | -------------------------------------------------------------------------------- /frontend/packages/configs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@liam-hq/configs", 3 | "private": true, 4 | "version": "0.0.1", 5 | "type": "module", 6 | "exports": { 7 | "./eslint/index.js": "./eslint/index.js", 8 | "./eslint/base.js": "./eslint/base.js", 9 | "./tsconfig/base.json": "./tsconfig/base.json", 10 | "./tsconfig": "./tsconfig" 11 | }, 12 | "devDependencies": { 13 | "@biomejs/biome": "1.9.4", 14 | "@eslint/compat": "1.2.9", 15 | "@tsconfig/strictest": "2.0.5", 16 | "@typescript-eslint/eslint-plugin": "8.32.1", 17 | "@typescript-eslint/parser": "8.32.1", 18 | "eslint": "9.27.0" 19 | }, 20 | "files": [ 21 | "eslint", 22 | "tsconfig" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /frontend/packages/configs/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@tsconfig/strictest/tsconfig.json", 4 | "compilerOptions": { 5 | "jsx": "preserve", 6 | "lib": ["dom", "es2019"], 7 | "resolveJsonModule": true, 8 | "erasableSyntaxOnly": true 9 | }, 10 | "include": ["**/*.ts", "**/*.tsx"] 11 | } 12 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | src/parser/schemarb/prism.wasm 3 | src/parser/tbls/schema.generated.ts 4 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // biome-ignore lint/correctness/noNodejsModules: This is a config file 2 | import { fileURLToPath } from 'node:url' 3 | import { createBaseConfig } from '../../packages/configs/eslint/index.js' 4 | 5 | const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url)) 6 | 7 | export default createBaseConfig({ 8 | tsconfigPath: './tsconfig.json', 9 | gitignorePath, 10 | }) 11 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/diff/index.ts: -------------------------------------------------------------------------------- 1 | export { buildSchemaDiff } from './buildSchemaDiff.js' 2 | export { schemaDiffItemsSchema } from './types.js' 3 | export type { 4 | SchemaDiffItem, 5 | TableRelatedDiffItem, 6 | ColumnRelatedDiffItem, 7 | IndexRelatedDiffItem, 8 | ConstraintRelatedDiffItem, 9 | } from './types.js' 10 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser.ts: -------------------------------------------------------------------------------- 1 | export { 2 | parse, 3 | type SupportedFormat, 4 | supportedFormatSchema, 5 | detectFormat, 6 | setPrismWasmUrl, 7 | ProcessError, 8 | } from './parser/index.js' 9 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/__tests__/index.ts: -------------------------------------------------------------------------------- 1 | export * from './testcase.js' 2 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/errors.ts: -------------------------------------------------------------------------------- 1 | export class ProcessError extends Error { 2 | constructor(message: string) { 3 | super(message) 4 | this.name = 'ParseError' 5 | } 6 | } 7 | 8 | export class WarningError extends ProcessError { 9 | constructor(message: string) { 10 | super(message) 11 | this.name = 'WarningError' 12 | } 13 | } 14 | 15 | export class UnexpectedTokenWarningError extends WarningError { 16 | constructor(message: string) { 17 | super(message) 18 | this.name = 'UnexpectedTokenWarningError' 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/prisma/index.ts: -------------------------------------------------------------------------------- 1 | export { processor } from './parser.js' 2 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/schemarb/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | processor, 3 | UnsupportedTokenError, 4 | } from './parser.js' 5 | export { setPrismWasmUrl } from './loadPrism.js' 6 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/sql/index.ts: -------------------------------------------------------------------------------- 1 | export { processor } from './postgresql/index.js' 2 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/sql/input/postgresql_schema1.in.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE users ( 2 | id SERIAL PRIMARY KEY, 3 | username VARCHAR(255) NOT NULL UNIQUE, 4 | email VARCHAR(255) NOT NULL UNIQUE, 5 | created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 6 | ); 7 | 8 | CREATE TABLE posts ( 9 | id SERIAL PRIMARY KEY, 10 | user_id INT REFERENCES users(id) 11 | ); 12 | 13 | CREATE UNIQUE INDEX index_users_on_id_and_email ON public.users USING btree (id, email); 14 | COMMENT ON TABLE users IS 'store our users.'; 15 | COMMENT ON COLUMN users.username IS 'user fullname.'; 16 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/supportedFormat/index.ts: -------------------------------------------------------------------------------- 1 | export * from './schema.js' 2 | export * from './detectFormat.js' 3 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/supportedFormat/schema.ts: -------------------------------------------------------------------------------- 1 | import * as v from 'valibot' 2 | 3 | export const supportedFormatSchema = v.picklist([ 4 | 'schemarb', 5 | 'postgres', 6 | 'prisma', 7 | 'tbls', 8 | ]) 9 | 10 | export type SupportedFormat = v.InferOutput 11 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/tbls/index.ts: -------------------------------------------------------------------------------- 1 | export { processor } from './parser.js' 2 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/tbls/input/mysql/README.md: -------------------------------------------------------------------------------- 1 | # MySQL Schema Sample 2 | 3 | This `schema.json` is copied from: 4 | https://github.com/k1LoW/tbls/blob/v1.81.0/sample/mysql/schema.json 5 | 6 | ## License 7 | The original file is part of [tbls](https://github.com/k1LoW/tbls) project, licensed under MIT License. 8 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/tbls/input/postgresql/README.md: -------------------------------------------------------------------------------- 1 | # PostgreSQL Schema Sample 2 | 3 | This `schema.json` is copied from: 4 | https://github.com/k1LoW/tbls/blob/v1.81.0/sample/postgres/schema.json 5 | 6 | ## License 7 | The original file is part of [tbls](https://github.com/k1LoW/tbls) project, licensed under MIT License. 8 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/types.ts: -------------------------------------------------------------------------------- 1 | import type { Schema } from '../schema/index.js' 2 | import type { ProcessError } from './errors.js' 3 | 4 | export type ProcessResult = { 5 | value: Schema 6 | errors: ProcessError[] 7 | } 8 | 9 | export type Processor = (str: string) => Promise 10 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/utils/defaultRelationshipName.ts: -------------------------------------------------------------------------------- 1 | // relationshipName example: "users_id_to_posts_user_id" 2 | export const defaultRelationshipName = ( 3 | primaryTableName: string, 4 | primaryColumnName: string, 5 | foreignTableName: string, 6 | foreignColumnName: string, 7 | ) => 8 | `${primaryTableName}_${primaryColumnName}_to_${foreignTableName}_${foreignColumnName}` 9 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/utils/handleOneToOneRelationships.ts: -------------------------------------------------------------------------------- 1 | import type { Relationships, Tables } from '../../schema/index.js' 2 | 3 | // If there is a unique index for a column in relationships, make it `ONE_TO_ONE` cardinality. 4 | export const handleOneToOneRelationships = ( 5 | tables: Tables, 6 | relationships: Relationships, 7 | ) => { 8 | for (const relationship of Object.values(relationships)) { 9 | const foreignTable = tables[relationship.foreignTableName] 10 | const foreignColumn = foreignTable?.columns[relationship.foreignColumnName] 11 | 12 | if (foreignColumn?.unique) { 13 | relationship.cardinality = 'ONE_TO_ONE' 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/src/parser/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { handleOneToOneRelationships } from './handleOneToOneRelationships.js' 2 | export { defaultRelationshipName } from './defaultRelationshipName.js' 3 | -------------------------------------------------------------------------------- /frontend/packages/db-structure/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@liam-hq/configs/tsconfig/base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "outDir": "dist", 6 | "declaration": true, 7 | "esModuleInterop": true, 8 | "module": "ESNext", 9 | "target": "ES2022", 10 | "moduleResolution": "bundler" 11 | }, 12 | "include": ["src/**/*"], 13 | "exclude": ["node_modules", "dist"] 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/.env: -------------------------------------------------------------------------------- 1 | ../../../.env -------------------------------------------------------------------------------- /frontend/packages/db/.gitignore: -------------------------------------------------------------------------------- 1 | # env 2 | .env 3 | .env.local 4 | 5 | # build 6 | dist -------------------------------------------------------------------------------- /frontend/packages/db/biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../packages/configs/biome.jsonc"] 3 | } 4 | -------------------------------------------------------------------------------- /frontend/packages/db/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { createBaseConfig } from '../../packages/configs/eslint/index.js' 3 | 4 | const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url)) 5 | 6 | export default createBaseConfig({ 7 | tsconfigPath: './tsconfig.json', 8 | gitignorePath, 9 | }) 10 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type { AppDatabaseOverrides } from './supabase-overrides' 2 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/building_schemas.ts: -------------------------------------------------------------------------------- 1 | export interface BuildingSchemasOverride { 2 | public: { 3 | Tables: { 4 | building_schemas: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/design_sessions.ts: -------------------------------------------------------------------------------- 1 | export interface DesignSessionsOverride { 2 | public: { 3 | Tables: { 4 | design_sessions: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/doc_file_paths.ts: -------------------------------------------------------------------------------- 1 | export interface DocFilePathsOverride { 2 | public: { 3 | Tables: { 4 | doc_file_paths: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/github_pull_request_comments.ts: -------------------------------------------------------------------------------- 1 | export interface GithubPullRequestCommentsOverride { 2 | public: { 3 | Tables: { 4 | github_pull_request_comments: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/github_pull_requests.ts: -------------------------------------------------------------------------------- 1 | export interface GithubPullRequestsOverride { 2 | public: { 3 | Tables: { 4 | github_pull_requests: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/knowledge_suggestion_doc_mappings.ts: -------------------------------------------------------------------------------- 1 | export interface KnowledgeSuggestionDocMappingsOverride { 2 | public: { 3 | Tables: { 4 | knowledge_suggestion_doc_mappings: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/knowledge_suggestions.ts: -------------------------------------------------------------------------------- 1 | export interface KnowledgeSuggestionsOverride { 2 | public: { 3 | Tables: { 4 | knowledge_suggestions: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/messages.ts: -------------------------------------------------------------------------------- 1 | export interface MessagesOverride { 2 | public: { 3 | Tables: { 4 | messages: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/migration_pull_request_mappings.ts: -------------------------------------------------------------------------------- 1 | export interface MigrationPullRequestMappingsOverride { 2 | public: { 3 | Tables: { 4 | migration_pull_request_mappings: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/migrations.ts: -------------------------------------------------------------------------------- 1 | export interface MigrationsOverride { 2 | public: { 3 | Tables: { 4 | migrations: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/overall_review_knowledge_suggestion_mappings.ts: -------------------------------------------------------------------------------- 1 | export interface OverallReviewKnowledgeSuggestionMappingsOverride { 2 | public: { 3 | Tables: { 4 | overall_review_knowledge_suggestion_mappings: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/overall_reviews.ts: -------------------------------------------------------------------------------- 1 | export interface OverallReviewsOverride { 2 | public: { 3 | Tables: { 4 | overall_reviews: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/project_repository_mappings.ts: -------------------------------------------------------------------------------- 1 | export interface ProjectRepositoryMappingsOverride { 2 | public: { 3 | Tables: { 4 | project_repository_mappings: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/review_feedback_comments.ts: -------------------------------------------------------------------------------- 1 | export interface ReviewFeedbackCommentsOverride { 2 | public: { 3 | Tables: { 4 | review_feedback_comments: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/review_feedback_knowledge_suggestion_mappings.ts: -------------------------------------------------------------------------------- 1 | export interface ReviewFeedbackKnowledgeSuggestionMappingsOverride { 2 | public: { 3 | Tables: { 4 | review_feedback_knowledge_suggestion_mappings: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/review_feedbacks.ts: -------------------------------------------------------------------------------- 1 | export interface ReviewFeedbacksOverride { 2 | public: { 3 | Tables: { 4 | review_feedbacks: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/review_suggestion_snippets.ts: -------------------------------------------------------------------------------- 1 | export interface ReviewSuggestionSnippetsOverride { 2 | public: { 3 | Tables: { 4 | review_suggestion_snippets: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/src/types/supabase-overrides/schema_file_paths.ts: -------------------------------------------------------------------------------- 1 | export interface SchemaFilePathsOverride { 2 | public: { 3 | Tables: { 4 | schema_file_paths: { 5 | Insert: { 6 | organization_id?: string | null 7 | } 8 | Update: { 9 | organization_id?: string | null 10 | } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/db/supabase/.gitignore: -------------------------------------------------------------------------------- 1 | # Supabase 2 | .branches 3 | .temp 4 | 5 | # dotenvx 6 | .env.keys 7 | .env.local 8 | .env.*.local 9 | -------------------------------------------------------------------------------- /frontend/packages/db/supabase/migrations/20250423123330_add_token_to_invitations.sql: -------------------------------------------------------------------------------- 1 | alter table "public"."invitations" 2 | add column "token" uuid not null default gen_random_uuid(), 3 | add column "expired_at" timestamp(3) with time zone not null default current_timestamp, 4 | add unique ("token"); 5 | -------------------------------------------------------------------------------- /frontend/packages/db/supabase/migrations/20250423123348_invite_organization_member.sql: -------------------------------------------------------------------------------- 1 | -- This empty .sql file is required because a migration with this filename was already applied in production. 2 | -- It will no longer be needed if the production database is ever reset. 3 | -------------------------------------------------------------------------------- /frontend/packages/db/supabase/migrations/20250423123350_refine_invite_organization_member.sql: -------------------------------------------------------------------------------- 1 | -- This empty .sql file is required because a migration with this filename was already applied in production. 2 | -- It will no longer be needed if the production database is ever reset. 3 | -------------------------------------------------------------------------------- /frontend/packages/db/supabase/migrations/20250521190001_add_unique_constraint_to_building_schemas.sql: -------------------------------------------------------------------------------- 1 | begin; 2 | 3 | alter table public.building_schemas add constraint building_schemas_design_session_id_key unique (design_session_id); 4 | 5 | commit; 6 | -------------------------------------------------------------------------------- /frontend/packages/db/supabase/migrations/20250523152300_move_columns_to_building_schemas.sql: -------------------------------------------------------------------------------- 1 | begin; 2 | 3 | -- add columns to building_schemas table 4 | alter table "public"."building_schemas" 5 | add column "git_sha" "text", 6 | add column "initial_schema_snapshot" "jsonb", 7 | add column "schema_file_path" "text"; 8 | 9 | -- remove columns from design_sessions table 10 | alter table "public"."design_sessions" 11 | drop column "git_sha", 12 | drop column "initial_schema_snapshot", 13 | drop column "schema_file_path"; 14 | 15 | commit; 16 | -------------------------------------------------------------------------------- /frontend/packages/db/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@liam-hq/configs/tsconfig/base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "outDir": "dist", 6 | "declaration": true, 7 | "esModuleInterop": true, 8 | "module": "ESNext", 9 | "target": "ES2022", 10 | "moduleResolution": "node" 11 | }, 12 | "include": ["src/**/*"], 13 | "exclude": ["node_modules", "dist"] 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/e2e/.gitignore: -------------------------------------------------------------------------------- 1 | # playwright 2 | /test-results/ 3 | /playwright-report/ 4 | /blob-report/ 5 | /playwright/.cache/ 6 | # Files created when tests are run locally 7 | /tests/vrt/vrt.test.ts-snapshots/*.png 8 | !/tests/vrt/vrt.test.ts-snapshots/top-1-chromium-linux.png 9 | !/tests/vrt/vrt.test.ts-snapshots/top-1-Mobile-Safari-linux.png 10 | 11 | storageState.json 12 | -------------------------------------------------------------------------------- /frontend/packages/e2e/biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../packages/configs/biome.jsonc"], 3 | "files": { 4 | "ignore": ["test-results"] 5 | }, 6 | "linter": { 7 | "rules": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /frontend/packages/e2e/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { createBaseConfig } from '../../packages/configs/eslint/index.js' 3 | 4 | const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url)) 5 | 6 | export default createBaseConfig({ 7 | tsconfigPath: './tsconfig.json', 8 | gitignorePath, 9 | }) 10 | -------------------------------------------------------------------------------- /frontend/packages/e2e/global-setup.ts: -------------------------------------------------------------------------------- 1 | import { type FullConfig, chromium } from '@playwright/test' 2 | 3 | async function globalSetup(config: FullConfig) { 4 | const { baseURL, storageState } = config.projects[0].use 5 | const browser = await chromium.launch() 6 | const page = await browser.newPage() 7 | await page.goto(`${baseURL}/`) 8 | 9 | const cookieButton = page.getByRole('button', { 10 | name: 'Accept All Cookies', 11 | }) 12 | await cookieButton.click({ timeout: 3000, force: true }).catch(() => {}) 13 | await page.context().storageState({ path: storageState as string }) 14 | 15 | await browser.close() 16 | } 17 | 18 | export default globalSetup 19 | -------------------------------------------------------------------------------- /frontend/packages/e2e/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@liam-hq/e2e", 3 | "private": true, 4 | "version": "0.0.0", 5 | "devDependencies": { 6 | "@biomejs/biome": "1.9.4", 7 | "@liam-hq/configs": "workspace:*", 8 | "@playwright/test": "1.52.0", 9 | "@types/node": "22.15.17", 10 | "eslint": "9.27.0", 11 | "typescript": "5.8.3" 12 | }, 13 | "scripts": { 14 | "fmt": "concurrently \"pnpm:fmt:*\"", 15 | "fmt:biome": "biome check --write --unsafe .", 16 | "fmt:eslint": "eslint --fix .", 17 | "lint": "concurrently \"pnpm:lint:*\"", 18 | "lint:biome": "biome check .", 19 | "lint:eslint": "eslint .", 20 | "test:e2e": "playwright test" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /frontend/packages/e2e/tests/vrt/vrt.test.ts-snapshots/top-1-Mobile-Safari-linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/frontend/packages/e2e/tests/vrt/vrt.test.ts-snapshots/top-1-Mobile-Safari-linux.png -------------------------------------------------------------------------------- /frontend/packages/e2e/tests/vrt/vrt.test.ts-snapshots/top-1-chromium-linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/frontend/packages/e2e/tests/vrt/vrt.test.ts-snapshots/top-1-chromium-linux.png -------------------------------------------------------------------------------- /frontend/packages/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@liam-hq/configs/tsconfig/base.json", 3 | "compilerOptions": { 4 | "baseUrl": "." 5 | }, 6 | "include": ["tests/**/*", "playwright.config.ts", "global-setup.ts"] 7 | } 8 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/.gitignore: -------------------------------------------------------------------------------- 1 | # typed-css-modules 2 | *.css.d.ts 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../packages/configs/biome.jsonc"], 3 | "linter": { 4 | "rules": { 5 | "correctness": { 6 | "noNodejsModules": "error" 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // biome-ignore lint/correctness/noNodejsModules: This is a config file 2 | import { fileURLToPath } from 'node:url' 3 | import { createBaseConfig } from '../../packages/configs/eslint/index.js' 4 | 5 | const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url)) 6 | 7 | export default createBaseConfig({ 8 | tsconfigPath: './tsconfig.json', 9 | gitignorePath, 10 | }) 11 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/ERDContent.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | background-color: var(--global-background); 6 | } 7 | 8 | .loading { 9 | position: absolute; 10 | top: 50%; 11 | left: 50%; 12 | transform: translate(-50%, -50%); 13 | } 14 | 15 | .groupEditMode :global(.react-flow__pane) { 16 | cursor: crosshair; 17 | } 18 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/NonRelatedTableGroupNode/NonRelatedTableGroupNode.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | width: 100%; 3 | height: 100%; 4 | opacity: 1; 5 | } 6 | 7 | :global([data-loading='true']) .wrapper { 8 | opacity: 0; 9 | } 10 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/NonRelatedTableGroupNode/NonRelatedTableGroupNode.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react' 2 | import styles from './NonRelatedTableGroupNode.module.css' 3 | 4 | export const NonRelatedTableGroupNode: FC = () => { 5 | return
6 | } 7 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/NonRelatedTableGroupNode/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NonRelatedTableGroupNode' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/RelationshipEdge/RelationshipEdge.module.css: -------------------------------------------------------------------------------- 1 | .edge { 2 | stroke: var(--pane-border-hover); 3 | stroke-width: 1px; 4 | transition: stroke 0.3s var(--default-timing-function); 5 | } 6 | 7 | :global([data-loading='true']) .edge { 8 | stroke: transparent; 9 | opacity: 0; 10 | } 11 | 12 | .hovered { 13 | stroke: var(--node-layout); 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/RelationshipEdge/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RelationshipEdge' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/RelationshipEdge/type.ts: -------------------------------------------------------------------------------- 1 | import type { Cardinality } from '@liam-hq/db-structure' 2 | import type { Edge } from '@xyflow/react' 3 | 4 | type Data = { 5 | isHighlighted: boolean 6 | cardinality: Cardinality 7 | } 8 | 9 | export type RelationshipEdgeType = Edge 10 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/Spinner/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Spinner' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableGroupBoundingBox/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableGroupBoundingBox' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableGroupNode/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableGroupNode' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableColumnList/TableColumn/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableColumn' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableColumnList/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableColumnList' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/CollapsibleHeader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CollapsibleHeader' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Columns/Columns.module.css: -------------------------------------------------------------------------------- 1 | .itemWrapper { 2 | border-bottom: 1px solid var(--global-border); 3 | } 4 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Columns/ColumnsItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ColumnsItem' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Columns/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Columns' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Comment/Comment.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | padding: var(--spacing-4); 3 | border-bottom: 1px solid var(--global-border); 4 | } 5 | 6 | .text { 7 | padding: var(--spacing-2); 8 | border-radius: var(--border-radius-base); 9 | background: var(--pane-muted-background); 10 | color: var(--color-white-alpha-70); 11 | font-size: var(--font-size-3); 12 | font-style: normal; 13 | font-weight: 400; 14 | line-height: 150%; 15 | } 16 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Comment/Comment.tsx: -------------------------------------------------------------------------------- 1 | import { DrawerDescription } from '@liam-hq/ui' 2 | import type { FC } from 'react' 3 | import styles from './Comment.module.css' 4 | 5 | type Props = { 6 | comment: string 7 | } 8 | 9 | export const Comment: FC = ({ comment }) => { 10 | return ( 11 |
12 | {comment} 13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Comment/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Comment' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Constraints/CheckConstraintsItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CheckConstraintsItem' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Constraints/ForeignKeyConstraintsItem/ForeignKeyConstraintsItem.module.css: -------------------------------------------------------------------------------- 1 | .tableKeyIcon { 2 | width: 0.75rem; 3 | height: 0.75rem; 4 | color: var(--primary-accent); 5 | } 6 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Constraints/ForeignKeyConstraintsItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ForeignKeyConstraintsItem' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Constraints/PrimaryKeyConstraintsItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './PrimaryKeyConstraintsItem' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Constraints/Unique/index.ts: -------------------------------------------------------------------------------- 1 | export * from './UniqueConstraintsItem' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Constraints/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Constraints' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Indexes/IndexesItem/IndexesItem.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: grid; 3 | gap: var(--spacing-2); 4 | padding: var(--spacing-4); 5 | } 6 | 7 | .list { 8 | list-style-type: decimal; 9 | padding-left: 1rem; 10 | margin: 0; 11 | width: 100%; 12 | } 13 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Indexes/IndexesItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IndexesItem' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/Indexes/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Indexes' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/RelatedTables/RelatedTables.module.css: -------------------------------------------------------------------------------- 1 | .outerWrapper { 2 | border-bottom: 1px solid var(--global-border); 3 | } 4 | 5 | .contentWrapper { 6 | border-radius: var(--border-radius-smbase); 7 | border: 1px solid var(--pane-border); 8 | background: var(--global-background); 9 | width: 92%; 10 | height: 333px; 11 | margin: var(--spacing-3); 12 | } 13 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/RelatedTables/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RelatedTables' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/RelatedTables/related-table-ex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liam-hq/liam/881026dc397226c4ee86e3beb1eb3e7003a362ce/frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/RelatedTables/related-table-ex.png -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableDetail/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableDetail' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/TableHeader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableHeader' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/TableNode/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableNode' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NonRelatedTableGroupNode' 2 | export * from './RelationshipEdge' 3 | export * from './Spinner' 4 | export * from './TableGroupBoundingBox' 5 | export * from './TableNode' 6 | export * from './TableGroupNode' 7 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useInitialAutoLayout' 2 | export * from './usePopStateListener' 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ERDContent' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/utils/hasNonRelatedChildNodes.ts: -------------------------------------------------------------------------------- 1 | import { NON_RELATED_TABLE_GROUP_NODE_ID } from '@/features/erd/constants' 2 | import type { Node } from '@xyflow/react' 3 | 4 | export const hasNonRelatedChildNodes = (nodes: Node[]): boolean => { 5 | return nodes.some((node) => node.parentId === NON_RELATED_TABLE_GROUP_NODE_ID) 6 | } 7 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hasNonRelatedChildNodes' 2 | export * from './updateNodesHiddenState' 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDContent/utils/updateNodesHiddenState.ts: -------------------------------------------------------------------------------- 1 | import { NON_RELATED_TABLE_GROUP_NODE_ID } from '@/features/erd/constants' 2 | import type { Node } from '@xyflow/react' 3 | 4 | type Params = { 5 | nodes: Node[] 6 | hiddenNodeIds: string[] 7 | shouldHideGroupNodeId: boolean 8 | } 9 | 10 | export function updateNodesHiddenState({ 11 | nodes, 12 | hiddenNodeIds, 13 | shouldHideGroupNodeId, 14 | }: Params): Node[] { 15 | return nodes.map((node) => ({ 16 | ...node, 17 | hidden: 18 | hiddenNodeIds.includes(node.id) || 19 | (shouldHideGroupNodeId && node.id === NON_RELATED_TABLE_GROUP_NODE_ID), 20 | })) 21 | } 22 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/AppBar/CopyLinkButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CopyLinkButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/AppBar/ExportButton/ExportButton.module.css: -------------------------------------------------------------------------------- 1 | .menuContent { 2 | min-width: 9.75rem; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/AppBar/GithubButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GithubButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/AppBar/HelpButton/ReleaseVersion.module.css: -------------------------------------------------------------------------------- 1 | .version { 2 | margin: var(--spacing-2); 3 | border-radius: var(--border-radius-full); 4 | background: var(--pane-muted-background); 5 | padding: var(--spacing-1) var(--spacing-2); 6 | color: var(--global-mute-text); 7 | font-family: var(--code-font); 8 | font-size: var(--font-size-1); 9 | } 10 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/AppBar/HelpButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './HelpButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/AppBar/MenuButton/MenuButton.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: grid; 3 | align-items: center; 4 | justify-content: center; 5 | padding: var(--spacing-1); 6 | margin: 0 var(--spacing-2); 7 | border-radius: var(--border-radius-base); 8 | &:hover .icon { 9 | color: var(--global-foreground); 10 | } 11 | } 12 | 13 | .wrapper:focus-visible { 14 | outline: 1px solid var(--primary-color); 15 | } 16 | 17 | .icon { 18 | width: 1.25rem; 19 | height: 1.25rem; 20 | color: var(--link-default); 21 | transition: color var(--default-hover-animation-duration) 22 | var(--default-timing-function); 23 | } 24 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/AppBar/MenuButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './MenuButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/AppBar/ReleaseNoteButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ReleaseNoteButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/AppBar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AppBar' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/CardinalityMarkers/CardinalityMarkers.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/CardinalityMarkers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CardinalityMarkers' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/ErrorDisplay/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ErrorDisplay' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/LeftPane/CopyLinkButton/CopyLinkButton.module.css: -------------------------------------------------------------------------------- 1 | .button { 2 | display: grid; 3 | grid-auto-flow: column; 4 | gap: var(--spacing-2); 5 | align-items: center; 6 | justify-content: flex-start; 7 | } 8 | 9 | .icon { 10 | width: 0.75rem; 11 | height: 0.75rem; 12 | color: var(--overlay-70); 13 | } 14 | 15 | .label { 16 | color: var(--global-foreground); 17 | font-family: var(--main-font); 18 | font-size: var(--font-size-2); 19 | } 20 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/LeftPane/CopyLinkButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CopyLinkButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/LeftPane/MenuItemLink/MenuItemLink.module.css: -------------------------------------------------------------------------------- 1 | .link { 2 | display: grid; 3 | grid-auto-flow: column; 4 | gap: var(--spacing-2); 5 | align-items: center; 6 | justify-content: flex-start; 7 | } 8 | 9 | .label { 10 | color: var(--global-foreground); 11 | font-family: var(--main-font); 12 | font-size: var(--font-size-2); 13 | } 14 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/LeftPane/MenuItemLink/index.ts: -------------------------------------------------------------------------------- 1 | export * from './MenuItemLink' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/LeftPane/TableNameMenuButton/VisibilityButton.module.css: -------------------------------------------------------------------------------- 1 | .icon { 2 | width: 12px; 3 | height: 12px; 4 | } 5 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/LeftPane/TableNameMenuButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableNameMenuButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/LeftPane/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LeftPane' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/RelationshipEdgeParticleMarker/RelationshipEdgeParticleMarker.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | opacity: 0; 6 | overflow: hidden; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/RelationshipEdgeParticleMarker/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RelationshipEdgeParticleMarker' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/TableDetailDrawer/TableDetailDrawer.module.css: -------------------------------------------------------------------------------- 1 | .content { 2 | top: var(--default-header-height); 3 | right: 0; 4 | bottom: 0; 5 | } 6 | 7 | .content[data-vaul-drawer] { 8 | transition-duration: 165ms; 9 | animation-duration: 165ms; 10 | user-select: auto; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/TableDetailDrawer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableDetailDrawer' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/FitviewButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FitviewButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/GroupButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GroupButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/MobileToolbar/ShowModeMenuRadioGroup.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: center; 5 | align-items: flex-start; 6 | align-self: stretch; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/MobileToolbar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './MobileToolbar' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/ShowModeMenu/ShowModeMenu.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: grid; 3 | grid-auto-flow: column; 4 | gap: var(--spacing-1); 5 | align-items: center; 6 | } 7 | 8 | .label { 9 | color: var(--overlay-60); 10 | font-size: var(--font-size-3); 11 | font-style: normal; 12 | font-weight: 400; 13 | line-height: normal; 14 | } 15 | 16 | .content { 17 | width: 9.75rem; 18 | } 19 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/ShowModeMenu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ShowModeMenu' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/TidyUpButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TidyUpButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/Toolbar.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react' 2 | import { DesktopToolbar } from './DesktopToolbar' 3 | import { MobileToolbar } from './MobileToolbar' 4 | 5 | type ToolbarProps = { 6 | withGroupButton?: boolean 7 | } 8 | 9 | export const Toolbar: FC = ({ withGroupButton = false }) => { 10 | return ( 11 | <> 12 | 13 | 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/ToolbarIconButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ToolbarIconButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/ZoomControls/ZoomControls.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: grid; 3 | grid-auto-flow: column; 4 | align-items: center; 5 | gap: var(--spacing-1); 6 | } 7 | 8 | .zoomLevelText { 9 | color: var(--global-foreground); 10 | text-align: center; 11 | font-family: var(--code-font); 12 | font-size: var(--font-size-3); 13 | font-style: normal; 14 | font-weight: 400; 15 | line-height: 100%; 16 | } 17 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/ZoomControls/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ZoomControls' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/Toolbar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Toolbar' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/ERDRenderer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ERDRenderer' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ERDRenderer' 2 | export * from './ERDContent' 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/constants.ts: -------------------------------------------------------------------------------- 1 | export const zIndex = { 2 | nodeDefault: 2, 3 | edgeHighlighted: 1, 4 | edgeDefault: 0, 5 | } 6 | 7 | export const NON_RELATED_TABLE_GROUP_NODE_ID = 'non-related-table-group' 8 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useTableSelection' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/hooks/useTableSelection/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useTableSelection' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/utils/columnHandleId.ts: -------------------------------------------------------------------------------- 1 | export const columnHandleId = (tableName: string, columnName: string) => 2 | `${tableName}-${columnName}` 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/utils/computeAutoLayout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './computeAutoLayout' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './computeAutoLayout' 2 | export * from './columnHandleId' 3 | export * from './convertSchemaToNodes' 4 | export * from './highlightNodesAndEdges' 5 | export * from './isTableNode' 6 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/erd/utils/isTableNode.ts: -------------------------------------------------------------------------------- 1 | import type { Node } from '@xyflow/react' 2 | import type { TableNodeType } from '../types' 3 | 4 | export const isTableNode = (node: Node): node is TableNodeType => 5 | node.type === 'table' 6 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/gtm/utils/clickLogEvent.ts: -------------------------------------------------------------------------------- 1 | import { pushToDataLayer } from './pushToDataLayer' 2 | import type { CommonLogEvent } from './types' 3 | 4 | type ClickLogEvent = CommonLogEvent & { 5 | element: string 6 | } 7 | 8 | export const clickLogEvent = (params: ClickLogEvent) => { 9 | pushToDataLayer({ 10 | event: 'click', 11 | ...params, 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/gtm/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './clickLogEvent' 2 | export * from './selectTableLogEvent' 3 | export * from './toggleLogEvent' 4 | export * from './openRelatedTablesLogEvent' 5 | export * from './toolbarActionLogEvent' 6 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/gtm/utils/openRelatedTablesLogEvent.ts: -------------------------------------------------------------------------------- 1 | import { pushToDataLayer } from './pushToDataLayer' 2 | import type { CommonLogEvent } from './types' 3 | 4 | type OpenRelatedTablesLogEvent = CommonLogEvent & { 5 | tableId: string 6 | } 7 | 8 | export const openRelatedTablesLogEvent = ( 9 | params: OpenRelatedTablesLogEvent, 10 | ) => { 11 | pushToDataLayer({ 12 | event: 'openRelatedTables', 13 | ...params, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/gtm/utils/pushToDataLayer.ts: -------------------------------------------------------------------------------- 1 | type WindowWithDataLayer = Window & { 2 | dataLayer: Record[] 3 | } 4 | 5 | declare const window: WindowWithDataLayer 6 | 7 | export const pushToDataLayer = (obj: Record) => { 8 | window.dataLayer = window.dataLayer || [] 9 | window.dataLayer.push(obj) 10 | } 11 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/gtm/utils/repositionTableLogEvent.ts: -------------------------------------------------------------------------------- 1 | import { pushToDataLayer } from './pushToDataLayer' 2 | import type { CommonLogEvent } from './types' 3 | 4 | type RepositionTable = CommonLogEvent & { 5 | tableId: string 6 | operationId: string 7 | } 8 | 9 | export const repositionTableLogEvent = (params: RepositionTable) => { 10 | pushToDataLayer({ 11 | event: 'repositionTable', 12 | ...params, 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/gtm/utils/selectTableLogEvent.ts: -------------------------------------------------------------------------------- 1 | import { pushToDataLayer } from './pushToDataLayer' 2 | import type { CommonLogEvent } from './types' 3 | 4 | type SelectTable = CommonLogEvent & { 5 | ref: 'leftPane' | 'mainArea' 6 | tableId: string 7 | } 8 | 9 | export const selectTableLogEvent = ({ 10 | ref, 11 | tableId, 12 | platform, 13 | ver, 14 | gitHash, 15 | appEnv, 16 | }: SelectTable) => { 17 | pushToDataLayer({ 18 | event: 'selectTable', 19 | ref, 20 | tableId, 21 | platform, 22 | ver, 23 | gitHash, 24 | appEnv, 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/gtm/utils/toggleLogEvent.ts: -------------------------------------------------------------------------------- 1 | import { pushToDataLayer } from './pushToDataLayer' 2 | import type { CommonLogEvent } from './types' 3 | 4 | type ToggleLogEvent = CommonLogEvent & { 5 | element: string 6 | isShow: boolean 7 | tableId?: string 8 | } 9 | 10 | export const toggleLogEvent = (params: ToggleLogEvent) => { 11 | pushToDataLayer({ 12 | event: 'toggle', 13 | ...params, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/gtm/utils/toolbarActionLogEvent.ts: -------------------------------------------------------------------------------- 1 | import { pushToDataLayer } from './pushToDataLayer' 2 | import type { CommonLogEvent } from './types' 3 | 4 | type ToolbarActionLogEvent = CommonLogEvent & { 5 | element: string 6 | zoomLevel?: string 7 | showMode?: string 8 | } 9 | 10 | export const toolbarActionLogEvent = (params: ToolbarActionLogEvent) => { 11 | pushToDataLayer({ 12 | event: 'toolbarAction', 13 | ...params, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/gtm/utils/types.ts: -------------------------------------------------------------------------------- 1 | export type CommonLogEvent = { 2 | platform: string 3 | ver: string 4 | gitHash: string 5 | appEnv: string 6 | } 7 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/index.ts: -------------------------------------------------------------------------------- 1 | export * from './erd' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/reactflow/constants.ts: -------------------------------------------------------------------------------- 1 | export const MIN_ZOOM = 0.1 2 | export const MAX_ZOOM = 2 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/features/reactflow/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useCustomReactflow' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useIsTouchDevice' 2 | export * from './useTableGroups' 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/hooks/useIsTouchDevice.ts: -------------------------------------------------------------------------------- 1 | import { useSyncExternalStore } from 'react' 2 | 3 | const isTouchDevice = (): boolean => { 4 | return ( 5 | typeof window !== 'undefined' && 6 | ('ontouchstart' in window || navigator.maxTouchPoints > 0) 7 | ) 8 | } 9 | 10 | export const useIsTouchDevice = () => 11 | useSyncExternalStore( 12 | () => () => {}, 13 | isTouchDevice, 14 | () => false, 15 | ) 16 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/hooks/useTableGroups.ts: -------------------------------------------------------------------------------- 1 | import type { TableGroup } from '@liam-hq/db-structure' 2 | import { useCallback, useState } from 'react' 3 | 4 | export function useTableGroups(initialGroups: Record = {}) { 5 | const [tableGroups, setTableGroups] = 6 | useState>(initialGroups) 7 | 8 | const addTableGroup = useCallback(({ name, tables, comment }: TableGroup) => { 9 | setTableGroups((prev) => ({ 10 | ...prev, 11 | [name]: { name, tables, comment }, 12 | })) 13 | 14 | return { name, tables, comment } 15 | }, []) 16 | 17 | return { 18 | tableGroups, 19 | addTableGroup, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.png' { 2 | const value: string 3 | export default value 4 | } 5 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './features' 2 | export * from './hooks' 3 | export * from './providers' 4 | export * from './schemas' 5 | export * from './stores' 6 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/providers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './versionProvider' 2 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/schemas/index.ts: -------------------------------------------------------------------------------- 1 | export * from './version' 2 | export * from './queryParam' 3 | export * from './showMode' 4 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/schemas/queryParam/index.ts: -------------------------------------------------------------------------------- 1 | export * from './schemas' 2 | export * from './types' 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/schemas/queryParam/schemas.ts: -------------------------------------------------------------------------------- 1 | import { picklist } from 'valibot' 2 | 3 | export const queryParamSchema = picklist(['active', 'hidden', 'showMode']) 4 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/schemas/queryParam/types.ts: -------------------------------------------------------------------------------- 1 | import type { InferOutput } from 'valibot' 2 | import type { queryParamSchema } from './schemas' 3 | 4 | export type QueryParam = InferOutput 5 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/schemas/showMode/index.ts: -------------------------------------------------------------------------------- 1 | export * from './schemas' 2 | export * from './types' 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/schemas/showMode/schemas.ts: -------------------------------------------------------------------------------- 1 | import { picklist } from 'valibot' 2 | 3 | export const showModeSchema = picklist(['ALL_FIELDS', 'TABLE_NAME', 'KEY_ONLY']) 4 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/schemas/showMode/types.ts: -------------------------------------------------------------------------------- 1 | import type { InferOutput } from 'valibot' 2 | import type { showModeSchema } from './schemas' 3 | 4 | export type ShowMode = InferOutput 5 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/schemas/version/index.ts: -------------------------------------------------------------------------------- 1 | export * from './schemas' 2 | export * from './types' 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/schemas/version/schemas.ts: -------------------------------------------------------------------------------- 1 | import * as v from 'valibot' 2 | 3 | const webVersionSchema = v.object({ 4 | version: v.string(), 5 | gitHash: v.string(), 6 | envName: v.string(), 7 | date: v.string(), 8 | displayedOn: v.literal('web'), 9 | }) 10 | 11 | const cliVersionSchema = v.object({ 12 | version: v.string(), 13 | gitHash: v.string(), 14 | envName: v.string(), 15 | isReleasedGitHash: v.boolean(), 16 | date: v.string(), 17 | displayedOn: v.literal('cli'), 18 | }) 19 | 20 | export const versionSchema = v.union([webVersionSchema, cliVersionSchema]) 21 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/schemas/version/types.ts: -------------------------------------------------------------------------------- 1 | import type { InferOutput } from 'valibot' 2 | import type { versionSchema } from './schemas' 3 | 4 | export type Version = InferOutput 5 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/stores/index.ts: -------------------------------------------------------------------------------- 1 | export * from './schema' 2 | export * from './userEditing' 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/stores/schema/hooks.ts: -------------------------------------------------------------------------------- 1 | import { safeParse } from 'valibot' 2 | import { useSnapshot } from 'valtio' 3 | import { schemaStoreSchema } from './schema' 4 | import { schemaStore } from './store' 5 | 6 | export const useSchemaStore = () => { 7 | const snapshot = useSnapshot(schemaStore) 8 | 9 | const result = safeParse(schemaStoreSchema, snapshot) 10 | 11 | if (!result.success) { 12 | throw new Error('Invalid schema store') 13 | } 14 | 15 | return result.output 16 | } 17 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/stores/schema/index.ts: -------------------------------------------------------------------------------- 1 | export * from './store' 2 | export * from './hooks' 3 | export * from './actions' 4 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/stores/schema/schema.ts: -------------------------------------------------------------------------------- 1 | import { schemaDiffItemsSchema, schemaSchema } from '@liam-hq/db-structure' 2 | import * as v from 'valibot' 3 | 4 | export const schemaStoreSchema = v.object({ 5 | current: schemaSchema, 6 | previous: v.optional(schemaSchema), 7 | diffItems: v.optional(schemaDiffItemsSchema), 8 | }) 9 | 10 | export type SchemaStore = v.InferOutput 11 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/stores/schema/store.ts: -------------------------------------------------------------------------------- 1 | import { proxy } from 'valtio' 2 | import type { SchemaStore } from './schema' 3 | 4 | export const schemaStore = proxy({ 5 | current: { 6 | tables: {}, 7 | relationships: {}, 8 | tableGroups: {}, 9 | }, 10 | previous: { 11 | tables: {}, 12 | relationships: {}, 13 | tableGroups: {}, 14 | }, 15 | diffItems: [], 16 | }) 17 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/stores/userEditing/hooks.ts: -------------------------------------------------------------------------------- 1 | import { useSnapshot } from 'valtio' 2 | import { userEditingStore } from './store' 3 | 4 | export const useUserEditingStore = () => useSnapshot(userEditingStore) 5 | export const useUserEditingActiveStore = () => 6 | useSnapshot(userEditingStore.active) 7 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/stores/userEditing/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hooks' 2 | export * from './actions' 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/styles/globals.css: -------------------------------------------------------------------------------- 1 | @import url('@liam-hq/ui/src/styles/globals.css'); 2 | @import './variables.css'; 3 | 4 | /* https://github.com/radix-ui/primitives/issues/2908 */ 5 | [data-radix-popper-content-wrapper] { 6 | font-family: var(--main-font); 7 | } 8 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/styles/variables.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --default-header-height: 52px; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/types/css.d.ts: -------------------------------------------------------------------------------- 1 | import 'react' 2 | 3 | // NOTE: React.CSSProperties does not accept CSS Variables by default, so override them here 4 | // @see: https://stackoverflow.com/questions/52005083/how-to-define-css-variables-in-style-attribute-in-react-and-typescript 5 | // @see: https://github.com/frenic/csstype#what-should-i-do-when-i-get-type-errors 6 | declare module 'react' { 7 | interface CSSProperties { 8 | [key: `--${string}`]: string 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './compressionString' 2 | export * from './urlParams' 3 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@liam-hq/configs/tsconfig/base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": ["./src/*"] 7 | } 8 | }, 9 | "include": ["src/**/*"] 10 | } 11 | -------------------------------------------------------------------------------- /frontend/packages/erd-core/vitest.config.ts: -------------------------------------------------------------------------------- 1 | // biome-ignore lint/correctness/noNodejsModules: Because this file is a config file 2 | import * as path from 'node:path' 3 | import { defineConfig } from 'vitest/config' 4 | 5 | export default defineConfig({ 6 | test: { 7 | alias: { 8 | '@': path.resolve(__dirname, './src'), 9 | }, 10 | }, 11 | }) 12 | -------------------------------------------------------------------------------- /frontend/packages/github/.gitignore: -------------------------------------------------------------------------------- 1 | # env 2 | .env 3 | .env.local 4 | 5 | # build 6 | dist 7 | -------------------------------------------------------------------------------- /frontend/packages/github/biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../packages/configs/biome.jsonc"] 3 | } 4 | -------------------------------------------------------------------------------- /frontend/packages/github/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { createBaseConfig } from '../../packages/configs/eslint/index.js' 3 | 4 | const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url)) 5 | 6 | export default createBaseConfig({ 7 | tsconfigPath: './tsconfig.json', 8 | gitignorePath, 9 | }) 10 | -------------------------------------------------------------------------------- /frontend/packages/github/src/config.ts: -------------------------------------------------------------------------------- 1 | export const validateConfig = (): { valid: boolean; missing: string[] } => { 2 | const requiredEnvVars = [ 3 | 'GITHUB_APP_ID', 4 | 'GITHUB_PRIVATE_KEY', 5 | 'GITHUB_WEBHOOK_SECRET', 6 | ] 7 | 8 | const missing = requiredEnvVars.filter((envVar) => !process.env[envVar]) 9 | 10 | return { 11 | valid: missing.length === 0, 12 | missing, 13 | } 14 | } 15 | 16 | export const supportedEvents = [ 17 | 'pull_request.opened', 18 | 'pull_request.synchronize', 19 | 'pull_request.reopened', 20 | ] 21 | -------------------------------------------------------------------------------- /frontend/packages/github/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './api.browser' 2 | export * from './api.server' 3 | export * from './config' 4 | export * from './types' 5 | -------------------------------------------------------------------------------- /frontend/packages/github/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@liam-hq/configs/tsconfig/base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "outDir": "dist", 6 | "declaration": true, 7 | "esModuleInterop": true, 8 | "module": "ESNext", 9 | "target": "ES2022", 10 | "moduleResolution": "node" 11 | }, 12 | "include": ["src/**/*"], 13 | "exclude": ["node_modules", "dist"] 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/jobs/.env: -------------------------------------------------------------------------------- 1 | ../../../.env -------------------------------------------------------------------------------- /frontend/packages/jobs/.env.local: -------------------------------------------------------------------------------- 1 | ../../../.env.local -------------------------------------------------------------------------------- /frontend/packages/jobs/.gitignore: -------------------------------------------------------------------------------- 1 | # env 2 | .env 3 | .env.local 4 | 5 | # build 6 | dist 7 | 8 | # trigger.dev 9 | .trigger 10 | -------------------------------------------------------------------------------- /frontend/packages/jobs/biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../packages/configs/biome.jsonc"] 3 | } 4 | -------------------------------------------------------------------------------- /frontend/packages/jobs/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { createBaseConfig } from '../../packages/configs/eslint/index.js' 3 | 4 | const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url)) 5 | 6 | export default createBaseConfig({ 7 | tsconfigPath: './tsconfig.json', 8 | gitignorePath, 9 | }) 10 | -------------------------------------------------------------------------------- /frontend/packages/jobs/src/constants.ts: -------------------------------------------------------------------------------- 1 | // FIXME: This should be imported from the app package once we have proper package structure 2 | export const SCHEMA_OVERRIDE_FILE_PATH = '.liam/schema-override.yml' 3 | -------------------------------------------------------------------------------- /frontend/packages/jobs/src/functions/getInstallationIdFromRepositoryId.ts: -------------------------------------------------------------------------------- 1 | import { createClient } from '../libs/supabase' 2 | 3 | export const getInstallationIdFromRepositoryId = async ( 4 | repositoryId: string, 5 | ): Promise => { 6 | const supabase = createClient() 7 | const { data: repository, error } = await supabase 8 | .from('github_repositories') 9 | .select('github_installation_identifier') 10 | .eq('id', repositoryId) 11 | .single() 12 | 13 | if (error || !repository) { 14 | throw new Error( 15 | `Repository with ID ${repositoryId} not found: ${JSON.stringify(error)}`, 16 | ) 17 | } 18 | 19 | return repository.github_installation_identifier 20 | } 21 | -------------------------------------------------------------------------------- /frontend/packages/jobs/src/functions/langfuseLangchainHandler.ts: -------------------------------------------------------------------------------- 1 | import { CallbackHandler } from 'langfuse-langchain' 2 | 3 | export const langfuseLangchainHandler = new CallbackHandler({ 4 | publicKey: process.env['LANGFUSE_PUBLIC_KEY'] ?? '', 5 | secretKey: process.env['LANGFUSE_SECRET_KEY'] ?? '', 6 | baseUrl: process.env['LANGFUSE_BASE_URL'] ?? 'https://cloud.langfuse.com', 7 | // Setting flushAt to 1 sends events immediately without batching 8 | flushAt: 1, 9 | // Set environment name for Langfuse to track different environments 10 | environment: process.env['NEXT_PUBLIC_ENV_NAME'] ?? '', 11 | }) 12 | -------------------------------------------------------------------------------- /frontend/packages/jobs/src/libs/supabase.ts: -------------------------------------------------------------------------------- 1 | import { createClient as _createClient } from '@liam-hq/db' 2 | 3 | export type SupabaseClient = ReturnType 4 | 5 | export function createClient(): SupabaseClient { 6 | const supabaseUrl = process.env['NEXT_PUBLIC_SUPABASE_URL'] 7 | const supabaseKey = process.env['SUPABASE_SERVICE_ROLE_KEY'] 8 | 9 | if (!supabaseUrl || !supabaseKey) { 10 | throw new Error('Missing Supabase environment variables') 11 | } 12 | 13 | return _createClient(supabaseUrl, supabaseKey) 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/jobs/src/prompts/generateReview/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | SYSTEM_PROMPT, 3 | USER_PROMPT, 4 | reviewJsonSchema, 5 | chain, 6 | } from './generateReview' 7 | -------------------------------------------------------------------------------- /frontend/packages/jobs/src/prompts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './generateReview' 2 | -------------------------------------------------------------------------------- /frontend/packages/jobs/src/tasks/review/index.ts: -------------------------------------------------------------------------------- 1 | export { savePullRequestTask } from './savePullRequest' 2 | export { generateReviewTask } from './generateReview' 3 | export { saveReviewTask } from './saveReview' 4 | export { postCommentTask } from './postComment' 5 | -------------------------------------------------------------------------------- /frontend/packages/jobs/src/trigger/helloworld.ts: -------------------------------------------------------------------------------- 1 | import { logger, task } from '@trigger.dev/sdk/v3' 2 | 3 | export const helloWorldTask = task({ 4 | id: 'helloworld', 5 | run: async (payload: { name: string }) => { 6 | logger.log('Executing Hello World task:', { payload }) 7 | return `Hello ${payload.name}` 8 | }, 9 | }) 10 | -------------------------------------------------------------------------------- /frontend/packages/jobs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@liam-hq/configs/tsconfig/base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "outDir": "dist", 6 | "declaration": true, 7 | "esModuleInterop": true, 8 | "module": "ESNext", 9 | "target": "ES2022", 10 | "moduleResolution": "bundler" 11 | }, 12 | "include": ["src/**/*"], 13 | "exclude": ["node_modules", "dist"] 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/jobs/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv' 2 | import { defineConfig } from 'vitest/config' 3 | 4 | export default defineConfig({ 5 | test: { 6 | env: dotenv.config({ path: '.env' }).parsed, 7 | }, 8 | }) 9 | -------------------------------------------------------------------------------- /frontend/packages/prompt-test/.env: -------------------------------------------------------------------------------- 1 | ../../../.env -------------------------------------------------------------------------------- /frontend/packages/prompt-test/.env.local: -------------------------------------------------------------------------------- 1 | ../../../.env.local -------------------------------------------------------------------------------- /frontend/packages/prompt-test/.gitignore: -------------------------------------------------------------------------------- 1 | .env.local 2 | result.json 3 | -------------------------------------------------------------------------------- /frontend/packages/prompt-test/biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../packages/configs/biome.jsonc"] 3 | } 4 | -------------------------------------------------------------------------------- /frontend/packages/prompt-test/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { createBaseConfig } from '../../packages/configs/eslint/index.js' 3 | 4 | const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url)) 5 | 6 | export default createBaseConfig({ 7 | tsconfigPath: './tsconfig.json', 8 | gitignorePath, 9 | }) 10 | -------------------------------------------------------------------------------- /frontend/packages/prompt-test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@liam-hq/configs/tsconfig/base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "declaration": true, 6 | "esModuleInterop": true, 7 | "module": "ESNext", 8 | "target": "ES2022", 9 | "moduleResolution": "node" 10 | }, 11 | "include": ["src/**/*"], 12 | "exclude": ["node_modules"] 13 | } 14 | -------------------------------------------------------------------------------- /frontend/packages/ui/.gitignore: -------------------------------------------------------------------------------- 1 | # typed-css-modules 2 | *.css.d.ts 3 | -------------------------------------------------------------------------------- /frontend/packages/ui/biome.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../packages/configs/biome.jsonc"] 3 | } 4 | -------------------------------------------------------------------------------- /frontend/packages/ui/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { createBaseConfig } from '../../packages/configs/eslint/index.js' 3 | 4 | const gitignorePath = fileURLToPath(new URL('.gitignore', import.meta.url)) 5 | 6 | export default createBaseConfig({ 7 | tsconfigPath: './tsconfig.json', 8 | gitignorePath, 9 | }) 10 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Avatar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Avatar' 2 | export * from './AvatarWithImage' 3 | export * from './UserAvatarIcon' 4 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Button' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Callout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Callout' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Collapsible/Collapsible.tsx: -------------------------------------------------------------------------------- 1 | import { Content, Root, Trigger } from '@radix-ui/react-collapsible' 2 | 3 | export const CollapsibleRoot = Root 4 | 5 | export const CollapsibleTrigger = Trigger 6 | 7 | export const CollapsibleContent = Content 8 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Collapsible/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Collapsible' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/ContextMenu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ContextMenu' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/CookieConsent/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CookieConsent' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Drawer/Drawer.module.css: -------------------------------------------------------------------------------- 1 | .content { 2 | position: fixed; 3 | z-index: var(--z-index-drawer); 4 | } 5 | 6 | /* 7 | * Override Vaul's default animation settings 8 | * Note: Specificity is tied to the [data-vaul-drawer] attribute 9 | */ 10 | .content[data-vaul-drawer] { 11 | transition: transform var(--default-animation-duration) 12 | var(--default-timing-function); 13 | animation-duration: var(--default-animation-duration); 14 | animation-timing-function: var(--default-timing-function); 15 | } 16 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Drawer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Drawer' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/DropdownMenu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DropdownMenu' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/GridTable/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GridTable' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/IconButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IconButton' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Input/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Input' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Modal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Modal' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Popover/Popover.module.css: -------------------------------------------------------------------------------- 1 | .content { 2 | /* Basic popover content styles */ 3 | background: var(--global-background, #141616); 4 | border: var(--border-width-base) solid 5 | var(--global-border, rgba(255, 255, 255, 0.05)); 6 | border-radius: var(--border-radius-md); 7 | padding: var(--spacing-1); 8 | box-shadow: 0 4px 20px 0 var(--shadow-context-menu-shadow); 9 | z-index: var(--z-index-popover); 10 | } 11 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Popover/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Popover' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/RadioGroup/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RadioGroup' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Resizable/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Resizable' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/RoundBadge/index.ts: -------------------------------------------------------------------------------- 1 | export * from './RoundBadge' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Sidebar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Sidebar' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Spinner/Spinner.module.css: -------------------------------------------------------------------------------- 1 | @keyframes rotate { 2 | 0% { 3 | transform: rotate(0deg); 4 | } 5 | 6 | 100% { 7 | transform: rotate(360deg); 8 | } 9 | } 10 | 11 | .svg { 12 | color: var(--overlay-100); 13 | animation: rotate 1s linear infinite; 14 | } 15 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Spinner/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Spinner' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Switch/Switch.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Root, Thumb } from '@radix-ui/react-switch' 4 | 5 | export const SwitchRoot = Root 6 | export const SwitchThumb = Thumb 7 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Switch/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Switch' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Tabs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Tabs' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Toast/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Toast' 2 | export * from './useToast' 3 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Toast/types.ts: -------------------------------------------------------------------------------- 1 | export type ToastId = string 2 | 3 | type ToastStatus = 'success' | 'error' | 'warning' | 'info' 4 | 5 | export type ToastOptions = { 6 | title: string 7 | description?: string 8 | status: ToastStatus 9 | } 10 | 11 | export type ToastItem = ToastOptions & { id: ToastId; isOpen: boolean } 12 | 13 | export type ToastFn = (options: ToastOptions) => ToastId 14 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Toast/useToast.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import { ToastContext } from './Toast' 3 | 4 | export const useToast = () => useContext(ToastContext) 5 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Tooltip/Tooltip.module.css: -------------------------------------------------------------------------------- 1 | .content { 2 | z-index: var(--z-index-tooltip); 3 | padding: var(--spacing-1half) var(--spacing-1); 4 | font-size: var(--font-size-1); 5 | color: var(--tooltip-foreground); 6 | background-color: var(--tooltip-background); 7 | border: 1px solid var(--tooltip-border); 8 | border-radius: var(--border-radius-sm); 9 | animation-duration: 150ms; 10 | animation-timing-function: var(--default-timing-function); 11 | } 12 | 13 | .content[data-state='delayed-open'] { 14 | animation-name: fadeIn; 15 | } 16 | 17 | @keyframes fadeIn { 18 | from { 19 | opacity: 0; 20 | } 21 | 22 | to { 23 | opacity: 1; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/components/Tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Tooltip' 2 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components' 2 | export * from './icons' 3 | export * from './logos' 4 | export * from './markers' 5 | export * from './styles' 6 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/logos/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GithubLogo' 2 | export * from './LiamLogo' 3 | export * from './LiamLogoMark' 4 | export * from './LinkedInLogo' 5 | export * from './LiamMigrationLogo' 6 | export * from './XLogo' 7 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/markers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CardinalityZeroOrManyLeftMarker' 2 | export * from './CardinalityZeroOrOneLeftMarker' 3 | export * from './CardinalityZeroOrOneRightMarker' 4 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/styles/fonts.css: -------------------------------------------------------------------------------- 1 | /* https://fonts.google.com/specimen/IBM+Plex+Mono */ 2 | /* https://fonts.google.com/specimen/Inter */ 3 | @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'); 4 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/styles/globals.css: -------------------------------------------------------------------------------- 1 | @import './fonts.css'; 2 | @import url('destyle.css'); 3 | @import './Dark/variables.css'; 4 | @import './Mode 1/variables.css'; 5 | @import './variables.css'; 6 | @import './icons/lucide.css'; 7 | @import './syntax-highlight.css'; 8 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/styles/icons/lucide.css: -------------------------------------------------------------------------------- 1 | .lucide { 2 | stroke-width: 1.5; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/styles/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Export all styles from the UI package 3 | */ 4 | 5 | // Export syntax highlighting theme 6 | export * from './syntax-theme' 7 | -------------------------------------------------------------------------------- /frontend/packages/ui/src/styles/variables.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --default-timing-function: ease-out; 3 | --default-animation-duration: 300ms; 4 | --default-hover-animation-duration: 100ms; 5 | 6 | --code-font: 'ui-monospace', 'IBM Plex Mono', SF Mono, Menlo, Monaco, Consolas, 7 | monospace; 8 | 9 | --z-index-toolbar-closed: 800; 10 | --z-index-sidebar: 900; 11 | --z-index-drawer: 900; 12 | --z-index-header: 1000; 13 | --z-index-dropdown-menu: 1100; 14 | --z-index-popover: 1500; 15 | --z-index-tooltip: 2000; 16 | --z-index-toast: 3000; 17 | --z-index-overlay: 3100; 18 | --z-index-toolbar-opened: 3200; 19 | --z-index-cookie-consent: 4000; 20 | } 21 | -------------------------------------------------------------------------------- /frontend/packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@liam-hq/configs/tsconfig/base.json", 3 | "compilerOptions": { 4 | "baseUrl": "." 5 | }, 6 | "include": ["src/**/*"] 7 | } 8 | -------------------------------------------------------------------------------- /frontend/turbo/generators/templates/component.tsx.hbs: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react' 2 | import styles from './{{ pascalCase name }}.module.css' 3 | 4 | type Props = {} 5 | 6 | export const {{ pascalCase name }}: FC = ({ ...props }) => { 7 | return ( 8 |
9 |

{{ pascalCase name }} Component

10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /frontend/turbo/generators/templates/index.ts.hbs: -------------------------------------------------------------------------------- 1 | export * from './{{pascalCase name}}' 2 | -------------------------------------------------------------------------------- /frontend/turbo/generators/templates/module.css.hbs: -------------------------------------------------------------------------------- 1 | /* 2 | Please delete this comment after starting the implementation. 3 | - We use .wrapper as the class for the root node of the component. For more details, please refer to: [If you are confused about naming in CSS Modules](https://zenn.dev/takepepe/articles/cssmodules-naming-convention) 4 | - If the component does not have any styles, you can delete this file. 5 | */ 6 | 7 | .wrapper { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "frontend/apps/*" 3 | - "frontend/packages/*" 4 | - "frontend/packages/__mocks__/*" 5 | - "frontend/internal-packages/*" 6 | --------------------------------------------------------------------------------