├── .dockerignore
├── .editorconfig
├── .firebaserc
├── .github
└── workflows
│ ├── build_and_deploy.yaml
│ ├── check.yaml
│ ├── main_push.yaml
│ ├── pull_request.yaml
│ └── tags_push.yaml
├── .gitignore
├── .prettierignore
├── .tool-versions
├── .vscode
├── .user-settings.sample.json
├── extensions.json
├── launch.json
└── settings.json
├── Dockerfile
├── Dockerfile_local
├── LICENSE
├── README.md
├── firebase.json
├── lefthook.yml
├── package.json
├── packages-licenses.json
├── packages
├── app-builder
│ ├── .env.example
│ ├── .gitignore
│ ├── README.md
│ ├── eslint.config.mjs
│ ├── package.json
│ ├── postcss.config.js
│ ├── public
│ │ ├── favicon.ico
│ │ ├── favicons
│ │ │ ├── android-chrome-192x192.png
│ │ │ ├── android-chrome-512x512.png
│ │ │ ├── apple-touch-icon.png
│ │ │ ├── favicon-16x16.png
│ │ │ └── favicon-32x32.png
│ │ ├── fonts
│ │ │ └── Inter
│ │ │ │ ├── Inter-Black.woff
│ │ │ │ ├── Inter-Black.woff2
│ │ │ │ ├── Inter-BlackItalic.woff
│ │ │ │ ├── Inter-BlackItalic.woff2
│ │ │ │ ├── Inter-Bold.woff
│ │ │ │ ├── Inter-Bold.woff2
│ │ │ │ ├── Inter-BoldItalic.woff
│ │ │ │ ├── Inter-BoldItalic.woff2
│ │ │ │ ├── Inter-ExtraBold.woff
│ │ │ │ ├── Inter-ExtraBold.woff2
│ │ │ │ ├── Inter-ExtraBoldItalic.woff
│ │ │ │ ├── Inter-ExtraBoldItalic.woff2
│ │ │ │ ├── Inter-ExtraLight.woff
│ │ │ │ ├── Inter-ExtraLight.woff2
│ │ │ │ ├── Inter-ExtraLightItalic.woff
│ │ │ │ ├── Inter-ExtraLightItalic.woff2
│ │ │ │ ├── Inter-Italic.woff
│ │ │ │ ├── Inter-Italic.woff2
│ │ │ │ ├── Inter-Light.woff
│ │ │ │ ├── Inter-Light.woff2
│ │ │ │ ├── Inter-LightItalic.woff
│ │ │ │ ├── Inter-LightItalic.woff2
│ │ │ │ ├── Inter-Medium.woff
│ │ │ │ ├── Inter-Medium.woff2
│ │ │ │ ├── Inter-MediumItalic.woff
│ │ │ │ ├── Inter-MediumItalic.woff2
│ │ │ │ ├── Inter-Regular.woff
│ │ │ │ ├── Inter-Regular.woff2
│ │ │ │ ├── Inter-SemiBold.woff
│ │ │ │ ├── Inter-SemiBold.woff2
│ │ │ │ ├── Inter-SemiBoldItalic.woff
│ │ │ │ ├── Inter-SemiBoldItalic.woff2
│ │ │ │ ├── Inter-Thin.woff
│ │ │ │ ├── Inter-Thin.woff2
│ │ │ │ ├── Inter-ThinItalic.woff
│ │ │ │ ├── Inter-ThinItalic.woff2
│ │ │ │ ├── Inter-italic.var.woff2
│ │ │ │ ├── Inter-roman.var.woff2
│ │ │ │ ├── Inter.var.woff2
│ │ │ │ ├── LICENSE.txt
│ │ │ │ └── inter.css
│ │ ├── img
│ │ │ ├── home
│ │ │ │ ├── api.png
│ │ │ │ ├── scenario-guide.png
│ │ │ │ ├── testrun.png
│ │ │ │ └── workflow.png
│ │ │ └── lottie
│ │ │ │ └── login_hero.json
│ │ └── site.webmanifest
│ ├── scripts
│ │ ├── generateRoutes.sh
│ │ └── generateRoutes.ts
│ ├── src
│ │ ├── components
│ │ │ ├── Annotations
│ │ │ │ ├── ClientDocumentsList.tsx
│ │ │ │ ├── ClientTagsList.tsx
│ │ │ │ └── FileDownload.tsx
│ │ │ ├── AstBuilder
│ │ │ │ ├── Operand.tsx
│ │ │ │ ├── OperandInfos.tsx
│ │ │ │ ├── OperandTypeInfos.tsx
│ │ │ │ ├── Provider.tsx
│ │ │ │ ├── Root.tsx
│ │ │ │ ├── edition
│ │ │ │ │ ├── EditModal
│ │ │ │ │ │ ├── Container.tsx
│ │ │ │ │ │ ├── EditModal.tsx
│ │ │ │ │ │ └── modals
│ │ │ │ │ │ │ ├── Aggregation
│ │ │ │ │ │ │ ├── Aggregation.tsx
│ │ │ │ │ │ │ ├── EditDataModelField.tsx
│ │ │ │ │ │ │ └── EditFilters.tsx
│ │ │ │ │ │ │ ├── FuzzyMatchComparator
│ │ │ │ │ │ │ ├── EditAlgorithm.tsx
│ │ │ │ │ │ │ ├── EditLevel.tsx
│ │ │ │ │ │ │ ├── EditThreshold.tsx
│ │ │ │ │ │ │ ├── Examples.tsx
│ │ │ │ │ │ │ ├── FuzzyMatchAggregation.tsx
│ │ │ │ │ │ │ ├── FuzzyMatchComparator.tsx
│ │ │ │ │ │ │ ├── InnerFuzzyMatchModal.tsx
│ │ │ │ │ │ │ └── helpers.ts
│ │ │ │ │ │ │ ├── IsMultipleOf
│ │ │ │ │ │ │ ├── Examples.tsx
│ │ │ │ │ │ │ └── IsMultipleOf.tsx
│ │ │ │ │ │ │ ├── StringTemplate
│ │ │ │ │ │ │ ├── StringTemplate.tsx
│ │ │ │ │ │ │ ├── StringTemplateForm.tsx
│ │ │ │ │ │ │ └── helpers.ts
│ │ │ │ │ │ │ ├── TimeAdd
│ │ │ │ │ │ │ ├── DurationUnitSelect.tsx
│ │ │ │ │ │ │ ├── TimeAdd.tsx
│ │ │ │ │ │ │ └── helpers.ts
│ │ │ │ │ │ │ └── TimestampExtract
│ │ │ │ │ │ │ ├── TimestampExtract.tsx
│ │ │ │ │ │ │ └── helpers.tsx
│ │ │ │ │ ├── EditionAndRoot.tsx
│ │ │ │ │ ├── EditionAnyRoot.tsx
│ │ │ │ │ ├── EditionNode.tsx
│ │ │ │ │ ├── EditionOperand.tsx
│ │ │ │ │ ├── EditionOrWithAndRoot.tsx
│ │ │ │ │ ├── EvaluationErrors.tsx
│ │ │ │ │ ├── OperandMenu
│ │ │ │ │ │ ├── DiscoveryList.tsx
│ │ │ │ │ │ ├── MenuOption.tsx
│ │ │ │ │ │ ├── SearchResults.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── OperatorSelect.tsx
│ │ │ │ │ ├── base-options.ts
│ │ │ │ │ ├── coerceToConstantAstNode.spec.ts
│ │ │ │ │ ├── coerceToConstantAstNode.ts
│ │ │ │ │ ├── helpers.ts
│ │ │ │ │ ├── hooks
│ │ │ │ │ │ └── useRoot.ts
│ │ │ │ │ └── node-store.ts
│ │ │ │ ├── index.tsx
│ │ │ │ ├── styles
│ │ │ │ │ ├── AddLogicalOperatorButton.tsx
│ │ │ │ │ ├── LogicalOperatorLabel.tsx
│ │ │ │ │ ├── NodeTypeError.tsx
│ │ │ │ │ ├── OperandDisplayName.tsx
│ │ │ │ │ └── RemoveButton.tsx
│ │ │ │ ├── types.ts
│ │ │ │ └── viewing
│ │ │ │ │ ├── ViewingAndRoot.tsx
│ │ │ │ │ ├── ViewingAnyRoot.tsx
│ │ │ │ │ ├── ViewingEvaluationErrors.tsx
│ │ │ │ │ ├── ViewingNode.tsx
│ │ │ │ │ ├── ViewingOperand.tsx
│ │ │ │ │ ├── ViewingOperator.tsx
│ │ │ │ │ ├── ViewingOrWithAndRoot.tsx
│ │ │ │ │ └── helpers.ts
│ │ │ ├── Auth
│ │ │ │ ├── AuthError.tsx
│ │ │ │ ├── PopupBlockedError.tsx
│ │ │ │ ├── ResetPassword.tsx
│ │ │ │ ├── SendEmailVerification.tsx
│ │ │ │ ├── SignInWithEmailAndPassword.tsx
│ │ │ │ ├── SignInWithGoogle.tsx
│ │ │ │ ├── SignInWithMicrosoft.tsx
│ │ │ │ ├── SignUpWithEmailAndPassword.tsx
│ │ │ │ └── auth-i18n.ts
│ │ │ ├── Breadcrumbs.tsx
│ │ │ ├── Callout.tsx
│ │ │ ├── CaseManager
│ │ │ │ ├── DecisionPanel
│ │ │ │ │ └── DecisionPanel.tsx
│ │ │ │ ├── Drawer
│ │ │ │ │ ├── Drawer.tsx
│ │ │ │ │ └── DrawerIcon.tsx
│ │ │ │ ├── PivotsPanel
│ │ │ │ │ ├── DataCard.tsx
│ │ │ │ │ ├── PivotAnnotations.tsx
│ │ │ │ │ ├── PivotNavigationOptions.tsx
│ │ │ │ │ ├── PivotsPanel.tsx
│ │ │ │ │ └── PivotsPanelContent.tsx
│ │ │ │ └── SnoozePanel
│ │ │ │ │ └── SnoozePanel.tsx
│ │ │ ├── Cases
│ │ │ │ ├── CaseAlerts.tsx
│ │ │ │ ├── CaseAssignedTo.tsx
│ │ │ │ ├── CaseContributors.tsx
│ │ │ │ ├── CaseDetails.tsx
│ │ │ │ ├── CaseEvents.tsx
│ │ │ │ ├── CaseFile.tsx
│ │ │ │ ├── CasePivotValues.tsx
│ │ │ │ ├── CaseRightPanel.tsx
│ │ │ │ ├── CaseStatus.tsx
│ │ │ │ ├── CaseTags.tsx
│ │ │ │ ├── CasesList.tsx
│ │ │ │ ├── Events
│ │ │ │ │ ├── CaseAssignedDetail.tsx
│ │ │ │ │ ├── CaseCreated.tsx
│ │ │ │ │ ├── CaseSnoozed.tsx
│ │ │ │ │ ├── CaseUnsnoozed.tsx
│ │ │ │ │ ├── CommentAdded.tsx
│ │ │ │ │ ├── DecisionAdded.tsx
│ │ │ │ │ ├── DecisionReviewed.tsx
│ │ │ │ │ ├── FileAdded.tsx
│ │ │ │ │ ├── Filters
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── InboxChanged.tsx
│ │ │ │ │ ├── NameUpdated.tsx
│ │ │ │ │ ├── OutcomeUpdated.tsx
│ │ │ │ │ ├── RuleSnoozed.tsx
│ │ │ │ │ ├── SarCreated.tsx
│ │ │ │ │ ├── SarDeleted.tsx
│ │ │ │ │ ├── SarFileUploaded.tsx
│ │ │ │ │ ├── SarStatusChanged.tsx
│ │ │ │ │ ├── StatusUpdated.tsx
│ │ │ │ │ ├── TagsUpdated.tsx
│ │ │ │ │ └── Time.tsx
│ │ │ │ ├── Filters
│ │ │ │ │ ├── CasesFiltersBar.tsx
│ │ │ │ │ ├── CasesFiltersContext.tsx
│ │ │ │ │ ├── CasesFiltersMenu.tsx
│ │ │ │ │ ├── FilterDetail
│ │ │ │ │ │ ├── CasesDateRangeFilter.tsx
│ │ │ │ │ │ ├── CasesExcludeAssignedFilter.tsx
│ │ │ │ │ │ ├── CasesSnoozedFilter.tsx
│ │ │ │ │ │ ├── ClosedCasesFilter.tsx
│ │ │ │ │ │ ├── FilterDetail.tsx
│ │ │ │ │ │ ├── NameFilter.tsx
│ │ │ │ │ │ ├── StatusesFilter.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── filters.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── RequiredActions.tsx
│ │ │ │ ├── cases-i18n.ts
│ │ │ │ └── index.ts
│ │ │ ├── CopyToClipboardButton.tsx
│ │ │ ├── Data
│ │ │ │ ├── DataModelFlow.tsx
│ │ │ │ ├── IngestedObjectDetail.tsx
│ │ │ │ ├── IngestedObjectDetailModal.tsx
│ │ │ │ ├── LinkToSingleEdge.tsx
│ │ │ │ ├── PivotDetails.tsx
│ │ │ │ ├── PivotType.tsx
│ │ │ │ ├── SelectedPivot.tsx
│ │ │ │ ├── TableDetails.tsx
│ │ │ │ ├── TableModelNode.tsx
│ │ │ │ └── data-i18n.ts
│ │ │ ├── DataModelExplorer
│ │ │ │ ├── ClientObjectAnnotationPopover.tsx
│ │ │ │ ├── ClientObjectComments.tsx
│ │ │ │ ├── ClientObjectDataList.tsx
│ │ │ │ ├── DataModelExplorer.tsx
│ │ │ │ ├── DataTableRender.tsx
│ │ │ │ ├── Provider.tsx
│ │ │ │ └── types.ts
│ │ │ ├── Decisions
│ │ │ │ ├── DecisionDetail.tsx
│ │ │ │ ├── DecisionRightPanel.tsx
│ │ │ │ ├── DecisionsList.tsx
│ │ │ │ ├── Filters
│ │ │ │ │ ├── DecisionFiltersBar.tsx
│ │ │ │ │ ├── DecisionFiltersContext.tsx
│ │ │ │ │ ├── DecisionFiltersMenu.tsx
│ │ │ │ │ ├── FilterDetail
│ │ │ │ │ │ ├── CaseInboxFilter.tsx
│ │ │ │ │ │ ├── DecisionsDateRangeFilter.tsx
│ │ │ │ │ │ ├── FilterDetail.tsx
│ │ │ │ │ │ ├── HasCaseFilter.tsx
│ │ │ │ │ │ ├── OutcomeAndReviewStatusFilter.tsx
│ │ │ │ │ │ ├── PivotValueFilter.tsx
│ │ │ │ │ │ ├── ScenarioFilter.tsx
│ │ │ │ │ │ ├── ScheduledExecutionFilter.tsx
│ │ │ │ │ │ ├── TriggerObjectFilter.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── filters.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── OutcomeTag.tsx
│ │ │ │ ├── PivotDetail.tsx
│ │ │ │ ├── ReviewStatusTag.tsx
│ │ │ │ ├── RulesDetail.tsx
│ │ │ │ ├── RulesExecutions
│ │ │ │ │ ├── RuleExecutionStatus.tsx
│ │ │ │ │ └── RulesExecutions.tsx
│ │ │ │ ├── SanctionCheckDetail.tsx
│ │ │ │ ├── Score.tsx
│ │ │ │ ├── ScoreOutcomeThresholds.tsx
│ │ │ │ ├── TriggerObjectDetail.tsx
│ │ │ │ ├── decisions-i18n.ts
│ │ │ │ └── index.ts
│ │ │ ├── ErrorComponent.tsx
│ │ │ ├── ExternalLink.tsx
│ │ │ ├── Files
│ │ │ │ ├── AddYourFirstFile.tsx
│ │ │ │ └── FilesList.tsx
│ │ │ ├── Filters
│ │ │ │ ├── AddNewFilterButton.tsx
│ │ │ │ ├── ClearAllFilters.tsx
│ │ │ │ ├── DateRangeFilter.tsx
│ │ │ │ ├── FilterPopover.tsx
│ │ │ │ ├── FiltersButton.tsx
│ │ │ │ ├── FiltersDropdownMenu.tsx
│ │ │ │ ├── SimpleFilter.tsx
│ │ │ │ ├── filters-i18n.ts
│ │ │ │ └── index.ts
│ │ │ ├── Form
│ │ │ │ ├── AutoWidthInput.tsx
│ │ │ │ ├── DateSelector.tsx
│ │ │ │ └── Tanstack
│ │ │ │ │ ├── FormErrorOrDescription.tsx
│ │ │ │ │ ├── FormInput.tsx
│ │ │ │ │ ├── FormLabel.tsx
│ │ │ │ │ └── FormTextArea.tsx
│ │ │ ├── FormatData.tsx
│ │ │ ├── GithubBanner.tsx
│ │ │ ├── HelpCenter.tsx
│ │ │ ├── Highlight.tsx
│ │ │ ├── Layout
│ │ │ │ └── LeftSidebar.tsx
│ │ │ ├── LottiePlayer.client.tsx
│ │ │ ├── MarbleToaster.tsx
│ │ │ ├── Navigation.tsx
│ │ │ ├── Nudge.tsx
│ │ │ ├── Page.tsx
│ │ │ ├── PaginationButtons.tsx
│ │ │ ├── Paper.tsx
│ │ │ ├── Ping
│ │ │ │ ├── CornerPing.tsx
│ │ │ │ ├── Ping.tsx
│ │ │ │ └── index.ts
│ │ │ ├── ReactFlow.tsx
│ │ │ ├── RightPanel.tsx
│ │ │ ├── Sanctions
│ │ │ │ ├── DatasetFresshnessBanner.tsx
│ │ │ │ ├── DatasetTag.tsx
│ │ │ │ ├── DatasetTagSelect.tsx
│ │ │ │ ├── EntityProperties.tsx
│ │ │ │ ├── MatchCard.tsx
│ │ │ │ ├── MatchDetails.tsx
│ │ │ │ ├── MatchResult.tsx
│ │ │ │ ├── RefineSearchModal.tsx
│ │ │ │ ├── SanctionCheckErrors.tsx
│ │ │ │ ├── SanctionReview.tsx
│ │ │ │ ├── SanctionStatusTag.tsx
│ │ │ │ ├── SearchInput.tsx
│ │ │ │ ├── StatusRadioGroup.tsx
│ │ │ │ ├── StatusTag.tsx
│ │ │ │ └── sanctions-i18n.ts
│ │ │ ├── Scenario
│ │ │ │ ├── Iteration
│ │ │ │ │ └── ScenarioIterationMenu.tsx
│ │ │ │ ├── Rules
│ │ │ │ │ ├── Filters
│ │ │ │ │ │ ├── FilterDetail
│ │ │ │ │ │ │ ├── FilterDetail.tsx
│ │ │ │ │ │ │ └── RuleGroupFilter.tsx
│ │ │ │ │ │ ├── RulesFiltersBar.tsx
│ │ │ │ │ │ ├── RulesFiltersContext.tsx
│ │ │ │ │ │ ├── RulesFiltersMenu.tsx
│ │ │ │ │ │ └── filters.ts
│ │ │ │ │ ├── RuleGroup.tsx
│ │ │ │ │ └── ScoreModifier.tsx
│ │ │ │ ├── Sanction
│ │ │ │ │ ├── FieldAstFormula.tsx
│ │ │ │ │ ├── FieldDataset.tsx
│ │ │ │ │ ├── FieldDatasetFilters.tsx
│ │ │ │ │ ├── FieldNode.tsx
│ │ │ │ │ ├── FieldNodeConcat.tsx
│ │ │ │ │ ├── FieldOutcomes.tsx
│ │ │ │ │ ├── FieldRuleGroup.tsx
│ │ │ │ │ ├── FieldToolTip.tsx
│ │ │ │ │ └── MatchOperand.tsx
│ │ │ │ ├── ScenarioValidationError.tsx
│ │ │ │ ├── ScheduledExecutionsList.tsx
│ │ │ │ ├── TestRun
│ │ │ │ │ ├── Filters
│ │ │ │ │ │ ├── FilterDetail
│ │ │ │ │ │ │ ├── CreatorsFilter.tsx
│ │ │ │ │ │ │ ├── FilterDetail.tsx
│ │ │ │ │ │ │ ├── StartedAfterFilter.tsx
│ │ │ │ │ │ │ ├── StatusesFilter.tsx
│ │ │ │ │ │ │ ├── VersionsFilter.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── TestRunsFiltersBar.tsx
│ │ │ │ │ │ ├── TestRunsFiltersContext.tsx
│ │ │ │ │ │ ├── TestRunsFiltersMenu.tsx
│ │ │ │ │ │ ├── filters.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── Graphs
│ │ │ │ │ │ ├── DistributionOfDecisionChart.tsx
│ │ │ │ │ │ ├── FilterTransactionByDecision.tsx
│ │ │ │ │ │ └── HamburgerGraph.tsx
│ │ │ │ │ ├── Skeletons
│ │ │ │ │ │ ├── DistributionOfDecicionSkeleton.tsx
│ │ │ │ │ │ └── FilterTransactionByDecicionSkeleton.tsx
│ │ │ │ │ ├── TestRunDetails.tsx
│ │ │ │ │ ├── TestRunNudge.tsx
│ │ │ │ │ ├── TestRunPeriod.tsx
│ │ │ │ │ ├── TestRunSelector.tsx
│ │ │ │ │ ├── TestRunStatus.tsx
│ │ │ │ │ └── TestRunVersions.tsx
│ │ │ │ ├── Trigger
│ │ │ │ │ ├── ScheduleOption
│ │ │ │ │ │ ├── ScheduleOption.tsx
│ │ │ │ │ │ ├── ScheduleOptionEditor.tsx
│ │ │ │ │ │ ├── ScheduleOptionViewer.tsx
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── models.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TriggerObjectTag.tsx
│ │ │ │ ├── Workflow
│ │ │ │ │ ├── DetailPanel
│ │ │ │ │ │ ├── AddToCaseIfPossibleNode.tsx
│ │ │ │ │ │ ├── CaseNameEditor.hook.ts
│ │ │ │ │ │ ├── CaseNameEditor.tsx
│ │ │ │ │ │ ├── Checklist.tsx
│ │ │ │ │ │ ├── CreateCaseNode.tsx
│ │ │ │ │ │ ├── DecisionCreatedNode.tsx
│ │ │ │ │ │ ├── DetailPanel.tsx
│ │ │ │ │ │ ├── SelectInbox.tsx
│ │ │ │ │ │ └── shared.ts
│ │ │ │ │ ├── Nodes
│ │ │ │ │ │ ├── Action.tsx
│ │ │ │ │ │ ├── AddToCaseIfPossibleActionContent.tsx
│ │ │ │ │ │ ├── CreateCaseActionContent.tsx
│ │ │ │ │ │ ├── DecisionCreatedTriggerContent.tsx
│ │ │ │ │ │ ├── EmptyNode.tsx
│ │ │ │ │ │ ├── Trigger.tsx
│ │ │ │ │ │ └── shared.tsx
│ │ │ │ │ ├── WorkflowFlow.tsx
│ │ │ │ │ ├── WorkflowNudge.tsx
│ │ │ │ │ ├── WorkflowProvider.tsx
│ │ │ │ │ ├── models
│ │ │ │ │ │ ├── nodes.ts
│ │ │ │ │ │ └── validation.ts
│ │ │ │ │ ├── validate.tsx
│ │ │ │ │ └── workflow-i18n.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── scenario-i18n.ts
│ │ │ ├── Schema
│ │ │ │ └── SchemaMenu.tsx
│ │ │ ├── SecretValue.tsx
│ │ │ ├── Settings
│ │ │ │ └── FormSelectTimezone.tsx
│ │ │ ├── Spinner.tsx
│ │ │ ├── Tags
│ │ │ │ ├── ColorPreview.tsx
│ │ │ │ └── ColorSelect.tsx
│ │ │ ├── TransferAlerts
│ │ │ │ ├── AlertData.tsx
│ │ │ │ ├── AlertStatus.tsx
│ │ │ │ ├── AlertsList.tsx
│ │ │ │ ├── Filters
│ │ │ │ │ ├── AlertsFiltersBar.tsx
│ │ │ │ │ ├── AlertsFiltersContext.tsx
│ │ │ │ │ ├── AlertsFiltersMenu.tsx
│ │ │ │ │ ├── FilterDetail
│ │ │ │ │ │ ├── AlertsDateRangeFilter.tsx
│ │ │ │ │ │ ├── FilterDetail.tsx
│ │ │ │ │ │ ├── MessageFilter.tsx
│ │ │ │ │ │ ├── StatusesFilter.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── filters.ts
│ │ │ │ │ └── index.ts
│ │ │ │ └── alerts-i18n.ts
│ │ │ ├── Transfers
│ │ │ │ ├── TransferData.tsx
│ │ │ │ ├── TransferStatus.tsx
│ │ │ │ ├── TransfersList.tsx
│ │ │ │ └── transfers-i18n.ts
│ │ │ ├── UserInfo.tsx
│ │ │ ├── Webhooks
│ │ │ │ └── EventTypes.tsx
│ │ │ └── index.ts
│ │ ├── constants
│ │ │ └── sanction-check-entity.tsx
│ │ ├── entry.client.tsx
│ │ ├── entry.server.tsx
│ │ ├── hooks
│ │ │ ├── decisions
│ │ │ │ └── usePivotValues.ts
│ │ │ ├── useCursorPaginatedFetcher.ts
│ │ │ ├── useCursorPagination.ts
│ │ │ ├── useFormDropzone.ts
│ │ │ └── useIntersection.ts
│ │ ├── infra
│ │ │ ├── feature-access-api.ts
│ │ │ ├── firebase.ts
│ │ │ ├── marblecore-api.ts
│ │ │ └── transfercheck-api.ts
│ │ ├── locales
│ │ │ ├── ar
│ │ │ │ ├── api.json
│ │ │ │ ├── auth.json
│ │ │ │ ├── cases.json
│ │ │ │ ├── common.json
│ │ │ │ ├── data.json
│ │ │ │ ├── decisions.json
│ │ │ │ ├── filters.json
│ │ │ │ ├── lists.json
│ │ │ │ ├── navigation.json
│ │ │ │ ├── sanctions.json
│ │ │ │ ├── scenarios.json
│ │ │ │ ├── settings.json
│ │ │ │ ├── transfercheck.json
│ │ │ │ ├── upload.json
│ │ │ │ └── workflows.json
│ │ │ ├── en
│ │ │ │ ├── api.json
│ │ │ │ ├── auth.json
│ │ │ │ ├── cases.json
│ │ │ │ ├── common.json
│ │ │ │ ├── data.json
│ │ │ │ ├── decisions.json
│ │ │ │ ├── filters.json
│ │ │ │ ├── lists.json
│ │ │ │ ├── navigation.json
│ │ │ │ ├── sanctions.json
│ │ │ │ ├── scenarios.json
│ │ │ │ ├── settings.json
│ │ │ │ ├── transfercheck.json
│ │ │ │ ├── upload.json
│ │ │ │ └── workflows.json
│ │ │ └── fr
│ │ │ │ ├── api.json
│ │ │ │ ├── auth.json
│ │ │ │ ├── cases.json
│ │ │ │ ├── common.json
│ │ │ │ ├── data.json
│ │ │ │ ├── decisions.json
│ │ │ │ ├── filters.json
│ │ │ │ ├── lists.json
│ │ │ │ ├── navigation.json
│ │ │ │ ├── sanctions.json
│ │ │ │ ├── scenarios.json
│ │ │ │ ├── settings.json
│ │ │ │ ├── transfercheck.json
│ │ │ │ ├── upload.json
│ │ │ │ └── workflows.json
│ │ ├── models
│ │ │ ├── analytics.ts
│ │ │ ├── api-keys.ts
│ │ │ ├── ast-validation.ts
│ │ │ ├── astNode
│ │ │ │ ├── aggregation.ts
│ │ │ │ ├── ast-node.ts
│ │ │ │ ├── builder-ast-node-node-operator.ts
│ │ │ │ ├── builder-ast-node.ts
│ │ │ │ ├── constant.ts
│ │ │ │ ├── custom-list.ts
│ │ │ │ ├── data-accessor.ts
│ │ │ │ ├── multiple-of.ts
│ │ │ │ ├── strings.ts
│ │ │ │ └── time.ts
│ │ │ ├── auth-errors.ts
│ │ │ ├── cases.ts
│ │ │ ├── custom-list.ts
│ │ │ ├── data-model.ts
│ │ │ ├── decision.ts
│ │ │ ├── duration.ts
│ │ │ ├── feature-access.ts
│ │ │ ├── fuzzy-match.ts
│ │ │ ├── fuzzy-match
│ │ │ │ ├── aggregationFuzzyMatchConfig.ts
│ │ │ │ ├── baseFuzzyMatchConfig.ts
│ │ │ │ └── comparatorFuzzyMatchConfig.ts
│ │ │ ├── get-operator-name.ts
│ │ │ ├── http-errors.ts
│ │ │ ├── inbox.ts
│ │ │ ├── index.ts
│ │ │ ├── marble-session.ts
│ │ │ ├── modale-operators.ts
│ │ │ ├── node-evaluation.ts
│ │ │ ├── operand-type.ts
│ │ │ ├── operator-options.ts
│ │ │ ├── organization.ts
│ │ │ ├── outcome.ts
│ │ │ ├── pagination.ts
│ │ │ ├── partner.ts
│ │ │ ├── rule-snooze.ts
│ │ │ ├── sanction-check-config.ts
│ │ │ ├── sanction-check-dataset.ts
│ │ │ ├── sanction-check.ts
│ │ │ ├── scenario-iteration-rule.ts
│ │ │ ├── scenario-iteration.ts
│ │ │ ├── scenario-publication.ts
│ │ │ ├── scenario-validation.ts
│ │ │ ├── scenario.ts
│ │ │ ├── signup-status.ts
│ │ │ ├── tags.ts
│ │ │ ├── testrun.ts
│ │ │ ├── toast-session.ts
│ │ │ ├── transfer-alert.ts
│ │ │ ├── transfer.ts
│ │ │ ├── user.ts
│ │ │ ├── version.ts
│ │ │ └── webhook.ts
│ │ ├── queries
│ │ │ ├── builder-options.ts
│ │ │ ├── client-object-list.ts
│ │ │ ├── opensanctions-dataset-freshness-info.ts
│ │ │ ├── pivot-related-cases.ts
│ │ │ └── validate-ast.ts
│ │ ├── repositories
│ │ │ ├── AnalyticsRepository.ts
│ │ │ ├── ApiKeyRepository.ts
│ │ │ ├── AuthenticationRepository.ts
│ │ │ ├── CaseRepository.ts
│ │ │ ├── CustomListRepository.ts
│ │ │ ├── DataModelRepository.ts
│ │ │ ├── DecisionRepository.ts
│ │ │ ├── EditorRepository.ts
│ │ │ ├── FeatureAccessRepository.ts
│ │ │ ├── InboxRepository.ts
│ │ │ ├── OrganizationRepository.ts
│ │ │ ├── PartnerRepository.ts
│ │ │ ├── RuleSnoozeRepository.ts
│ │ │ ├── SanctionCheckRepository.ts
│ │ │ ├── ScenarioIterationRuleRepository.ts
│ │ │ ├── ScenarioIterationSanctionRepository.ts
│ │ │ ├── ScenarioRepository.ts
│ │ │ ├── SessionStorageRepositories
│ │ │ │ ├── AuthStorageRepository.ts
│ │ │ │ ├── CsrfStorageRepository.ts
│ │ │ │ ├── LngStorageRepository.ts
│ │ │ │ ├── SessionStorageRepository.ts
│ │ │ │ ├── ToastStorageRepository.ts
│ │ │ │ └── index.ts
│ │ │ ├── SignupStatusRepository.ts
│ │ │ ├── TestRunRepository.ts
│ │ │ ├── TransferAlertRepository.ts
│ │ │ ├── TransferRepository.ts
│ │ │ ├── UserRepository.ts
│ │ │ ├── VersionRepository.ts
│ │ │ ├── WebhookRepository.ts
│ │ │ ├── init.client.ts
│ │ │ └── init.server.ts
│ │ ├── root.tsx
│ │ ├── routes
│ │ │ ├── $.tsx
│ │ │ ├── _auth+
│ │ │ │ ├── _layout.tsx
│ │ │ │ ├── email-verification.tsx
│ │ │ │ ├── forgot-password.tsx
│ │ │ │ ├── sign-in.tsx
│ │ │ │ └── sign-up.tsx
│ │ │ ├── _builder+
│ │ │ │ ├── _layout.tsx
│ │ │ │ ├── analytics.tsx
│ │ │ │ ├── api.tsx
│ │ │ │ ├── cases+
│ │ │ │ │ ├── $caseId+
│ │ │ │ │ │ ├── _index.tsx
│ │ │ │ │ │ └── sanctions.$decisionId+
│ │ │ │ │ │ │ ├── _index.tsx
│ │ │ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ │ │ ├── files.tsx
│ │ │ │ │ │ │ └── hits.tsx
│ │ │ │ │ ├── _index.tsx
│ │ │ │ │ ├── inboxes.$inboxId.tsx
│ │ │ │ │ └── inboxes._layout.tsx
│ │ │ │ ├── data+
│ │ │ │ │ ├── _index.tsx
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ ├── list.tsx
│ │ │ │ │ ├── schema.tsx
│ │ │ │ │ ├── view.$tableName.$objectId.tsx
│ │ │ │ │ └── view.tsx
│ │ │ │ ├── decisions+
│ │ │ │ │ ├── $decisionId.tsx
│ │ │ │ │ ├── _index.tsx
│ │ │ │ │ └── _layout.tsx
│ │ │ │ ├── lists+
│ │ │ │ │ ├── $listId.tsx
│ │ │ │ │ ├── _index.tsx
│ │ │ │ │ └── _layout.tsx
│ │ │ │ ├── scenarios+
│ │ │ │ │ ├── $scenarioId+
│ │ │ │ │ │ ├── _index.tsx
│ │ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ │ ├── home.tsx
│ │ │ │ │ │ ├── i+
│ │ │ │ │ │ │ └── $iterationId+
│ │ │ │ │ │ │ │ ├── _edit-view+
│ │ │ │ │ │ │ │ ├── _index.tsx
│ │ │ │ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ │ │ │ ├── decision.tsx
│ │ │ │ │ │ │ │ ├── rules.tsx
│ │ │ │ │ │ │ │ └── trigger.tsx
│ │ │ │ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ │ │ │ ├── rules.$ruleId.tsx
│ │ │ │ │ │ │ │ └── sanction.tsx
│ │ │ │ │ │ ├── scheduled-executions.tsx
│ │ │ │ │ │ ├── test-run+
│ │ │ │ │ │ │ ├── $testRunId+
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── workflow.tsx
│ │ │ │ │ ├── _index.tsx
│ │ │ │ │ └── _layout.tsx
│ │ │ │ ├── settings+
│ │ │ │ │ ├── _index.tsx
│ │ │ │ │ ├── _layout.tsx
│ │ │ │ │ ├── api-keys.tsx
│ │ │ │ │ ├── data-display.tsx
│ │ │ │ │ ├── inboxes.$inboxId.tsx
│ │ │ │ │ ├── inboxes._index.tsx
│ │ │ │ │ ├── scenarios.tsx
│ │ │ │ │ ├── tags.tsx
│ │ │ │ │ ├── users.tsx
│ │ │ │ │ ├── webhooks.tsx
│ │ │ │ │ └── webhooks_.$webhookId.tsx
│ │ │ │ └── upload+
│ │ │ │ │ └── $objectType.tsx
│ │ │ ├── _index.tsx
│ │ │ ├── app-router.tsx
│ │ │ ├── healthcheck.ts
│ │ │ ├── ressources+
│ │ │ │ ├── auth+
│ │ │ │ │ ├── logout.tsx
│ │ │ │ │ └── refresh.tsx
│ │ │ │ ├── cases+
│ │ │ │ │ ├── add-comment.tsx
│ │ │ │ │ ├── add-rule-snooze.tsx
│ │ │ │ │ ├── add-to-case.tsx
│ │ │ │ │ ├── close-case.tsx
│ │ │ │ │ ├── create-case.tsx
│ │ │ │ │ ├── edit-assignee.tsx
│ │ │ │ │ ├── edit-inbox.tsx
│ │ │ │ │ ├── edit-name.tsx
│ │ │ │ │ ├── edit-suspicion.tsx
│ │ │ │ │ ├── edit-tags.tsx
│ │ │ │ │ ├── escalate-case.tsx
│ │ │ │ │ ├── open-case.tsx
│ │ │ │ │ ├── pivot+
│ │ │ │ │ │ └── related+
│ │ │ │ │ │ │ └── $pivotValue._index.tsx
│ │ │ │ │ ├── review-decision.tsx
│ │ │ │ │ ├── review-sanction-match.tsx
│ │ │ │ │ └── snooze-case.tsx
│ │ │ │ ├── data+
│ │ │ │ │ ├── $tableId.createNavigationOption.tsx
│ │ │ │ │ ├── $tableName.list-objects.tsx
│ │ │ │ │ ├── create-annotation.tsx
│ │ │ │ │ ├── create-pivot.tsx
│ │ │ │ │ ├── create-pivot
│ │ │ │ │ │ ├── SelectLinkPath.tsx
│ │ │ │ │ │ ├── SelectTargetEntity.tsx
│ │ │ │ │ │ ├── ValidateSelfPivot.tsx
│ │ │ │ │ │ └── selectField.tsx
│ │ │ │ │ ├── createField.tsx
│ │ │ │ │ ├── createLink.tsx
│ │ │ │ │ ├── createTable.tsx
│ │ │ │ │ ├── delete-annotation.$annotationId.tsx
│ │ │ │ │ ├── editField.tsx
│ │ │ │ │ └── editTable.tsx
│ │ │ │ ├── decisions+
│ │ │ │ │ └── list-scheduled-execution.tsx
│ │ │ │ ├── files+
│ │ │ │ │ └── upload-file.tsx
│ │ │ │ ├── lists+
│ │ │ │ │ ├── create.tsx
│ │ │ │ │ ├── delete.tsx
│ │ │ │ │ ├── edit.tsx
│ │ │ │ │ ├── value_create.tsx
│ │ │ │ │ └── value_delete.tsx
│ │ │ │ ├── locales.ts
│ │ │ │ ├── opensanctions+
│ │ │ │ │ └── dataset-freshness.tsx
│ │ │ │ ├── rule-snoozes+
│ │ │ │ │ └── read.$ruleSnoozeId.tsx
│ │ │ │ ├── sanction-check+
│ │ │ │ │ ├── enrich-match.$matchId.tsx
│ │ │ │ │ ├── refine.tsx
│ │ │ │ │ └── search.tsx
│ │ │ │ ├── scenarios+
│ │ │ │ │ ├── $scenarioId+
│ │ │ │ │ │ ├── $iterationId+
│ │ │ │ │ │ │ ├── activate.tsx
│ │ │ │ │ │ │ ├── commit.tsx
│ │ │ │ │ │ │ ├── create_draft.tsx
│ │ │ │ │ │ │ ├── deactivate.tsx
│ │ │ │ │ │ │ ├── prepare.tsx
│ │ │ │ │ │ │ ├── rules+
│ │ │ │ │ │ │ │ ├── create.tsx
│ │ │ │ │ │ │ │ ├── delete.tsx
│ │ │ │ │ │ │ │ └── duplicate.tsx
│ │ │ │ │ │ │ ├── sanctions+
│ │ │ │ │ │ │ │ ├── create.tsx
│ │ │ │ │ │ │ │ └── delete.tsx
│ │ │ │ │ │ │ └── validate-with-given-trigger-or-rule.tsx
│ │ │ │ │ │ ├── builder-options.tsx
│ │ │ │ │ │ ├── testrun+
│ │ │ │ │ │ │ ├── $testRunId+
│ │ │ │ │ │ │ │ └── cancel.tsx
│ │ │ │ │ │ │ └── create.tsx
│ │ │ │ │ │ └── validate-ast.tsx
│ │ │ │ │ ├── create.tsx
│ │ │ │ │ └── update.tsx
│ │ │ │ ├── settings+
│ │ │ │ │ ├── api-keys+
│ │ │ │ │ │ ├── create.tsx
│ │ │ │ │ │ └── delete.tsx
│ │ │ │ │ ├── inboxes+
│ │ │ │ │ │ ├── create.tsx
│ │ │ │ │ │ ├── delete.tsx
│ │ │ │ │ │ ├── inbox-users.create.tsx
│ │ │ │ │ │ ├── inbox-users.delete.tsx
│ │ │ │ │ │ ├── inbox-users.update.tsx
│ │ │ │ │ │ └── update.tsx
│ │ │ │ │ ├── tags+
│ │ │ │ │ │ ├── create.tsx
│ │ │ │ │ │ ├── delete.tsx
│ │ │ │ │ │ └── update.tsx
│ │ │ │ │ ├── users+
│ │ │ │ │ │ ├── create.tsx
│ │ │ │ │ │ ├── delete.tsx
│ │ │ │ │ │ └── update.tsx
│ │ │ │ │ └── webhooks+
│ │ │ │ │ │ ├── create.tsx
│ │ │ │ │ │ ├── delete.tsx
│ │ │ │ │ │ └── update.tsx
│ │ │ │ └── user+
│ │ │ │ │ └── language.tsx
│ │ │ └── transfercheck+
│ │ │ │ ├── $.tsx
│ │ │ │ ├── _index.tsx
│ │ │ │ ├── _layout.tsx
│ │ │ │ ├── alerts+
│ │ │ │ ├── _.received.$alertId.tsx
│ │ │ │ ├── _.sent.$alertId.tsx
│ │ │ │ ├── _index.tsx
│ │ │ │ ├── _layout.tsx
│ │ │ │ ├── received.tsx
│ │ │ │ └── sent.tsx
│ │ │ │ ├── ressources+
│ │ │ │ ├── alert.create.tsx
│ │ │ │ ├── alert.update.status.tsx
│ │ │ │ └── alert.update.tsx
│ │ │ │ └── transfers+
│ │ │ │ ├── $transferId.tsx
│ │ │ │ └── _index.tsx
│ │ ├── services
│ │ │ ├── DownloadFilesService.ts
│ │ │ ├── ast-node
│ │ │ │ ├── formatConstant.ts
│ │ │ │ ├── getAstNodeDataType.ts
│ │ │ │ ├── getAstNodeDisplayName.ts
│ │ │ │ ├── getAstNodeOperandType.ts
│ │ │ │ ├── getCustomListAccessCustomList.ts
│ │ │ │ └── getDataAccessorAstNodeField.ts
│ │ │ ├── auth
│ │ │ │ ├── auth.client.ts
│ │ │ │ ├── auth.server.ts
│ │ │ │ └── session.server.ts
│ │ │ ├── data
│ │ │ │ ├── data-model.tsx
│ │ │ │ ├── pivot.spec.tsx
│ │ │ │ └── pivot.tsx
│ │ │ ├── documentation-href.ts
│ │ │ ├── editor
│ │ │ │ └── editor-mode.tsx
│ │ │ ├── feature-access.ts
│ │ │ ├── i18n
│ │ │ │ ├── i18n-config.ts
│ │ │ │ ├── i18next.client.ts
│ │ │ │ ├── i18next.d.ts
│ │ │ │ ├── i18next.server.ts
│ │ │ │ ├── resources
│ │ │ │ │ ├── ar.server.ts
│ │ │ │ │ ├── en.server.ts
│ │ │ │ │ ├── fr.server.ts
│ │ │ │ │ └── resources.server.ts
│ │ │ │ └── translation-keys
│ │ │ │ │ └── api-key.ts
│ │ │ ├── init.client.ts
│ │ │ ├── init.server.ts
│ │ │ ├── monitoring.ts
│ │ │ ├── organization
│ │ │ │ ├── organization-detail.tsx
│ │ │ │ ├── organization-object-tags.tsx
│ │ │ │ ├── organization-tags.tsx
│ │ │ │ └── organization-users.tsx
│ │ │ ├── segment
│ │ │ │ ├── SegmentScript.tsx
│ │ │ │ ├── getPageviewNameAndProps.ts
│ │ │ │ ├── index.tsx
│ │ │ │ └── segment.server.ts
│ │ │ ├── user.ts
│ │ │ └── validation
│ │ │ │ ├── ast-node-validation.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── scenario-validation-error-messages.ts
│ │ │ │ └── scenario-validation.ts
│ │ ├── tailwind.css
│ │ ├── tests
│ │ │ └── setup
│ │ │ │ └── i18next.ts
│ │ ├── types
│ │ │ └── operand-options.ts
│ │ └── utils
│ │ │ ├── browser.ts
│ │ │ ├── create-context.tsx
│ │ │ ├── currencies.ts
│ │ │ ├── datetime.ts
│ │ │ ├── download-file.ts
│ │ │ ├── environment.ts
│ │ │ ├── files.ts
│ │ │ ├── form.ts
│ │ │ ├── format.ts
│ │ │ ├── hooks
│ │ │ ├── index.ts
│ │ │ ├── use-async.ts
│ │ │ ├── use-callback-ref.ts
│ │ │ ├── use-compose-refs.ts
│ │ │ ├── use-interval.ts
│ │ │ ├── use-isomorphic-layout-effect.ts
│ │ │ └── use-visibility-change.ts
│ │ │ ├── http
│ │ │ ├── handle-errors.ts
│ │ │ ├── http-responses.ts
│ │ │ └── http-status-codes.ts
│ │ │ ├── input-validation.ts
│ │ │ ├── list.ts
│ │ │ ├── parse.ts
│ │ │ ├── preferences-cookies
│ │ │ ├── config.ts
│ │ │ ├── preferences-cookie-read.server.ts
│ │ │ └── preferences-cookies-write.ts
│ │ │ ├── routes
│ │ │ ├── index.ts
│ │ │ ├── routes.ts
│ │ │ └── types.ts
│ │ │ ├── schema
│ │ │ ├── dataTypeSchema.ts
│ │ │ ├── filterSchema.ts
│ │ │ └── shortUUIDSchema.ts
│ │ │ ├── search
│ │ │ ├── filter.ts
│ │ │ ├── highlight.ts
│ │ │ └── index.ts
│ │ │ ├── short-uuid.ts
│ │ │ ├── sleep.ts
│ │ │ ├── table-filter-fn.ts
│ │ │ ├── tree.spec.ts
│ │ │ ├── tree.ts
│ │ │ ├── types.ts
│ │ │ ├── unknown-error.ts
│ │ │ ├── use-get-copy-to-clipboard.tsx
│ │ │ └── validTimezones.ts
│ ├── tailwind.config.ts
│ ├── tsconfig.json
│ ├── types
│ │ └── global.d.ts
│ └── vite.config.ts
├── eslint-config
│ ├── README.md
│ ├── default.mjs
│ ├── eslint.config.mjs
│ ├── package.json
│ ├── react.mjs
│ ├── storybook.mjs
│ ├── tailwindcss.mjs
│ ├── typescript.mjs
│ └── vitest.mjs
├── marble-api
│ ├── README.md
│ ├── eslint.config.mjs
│ ├── openapis
│ │ ├── feature-access-api.yaml
│ │ ├── marblecore-api.yaml
│ │ ├── marblecore-api
│ │ │ ├── _common.yml
│ │ │ ├── _schemas.yml
│ │ │ ├── admin.yml
│ │ │ ├── annotations.yml
│ │ │ ├── ast.yml
│ │ │ ├── authorization.yml
│ │ │ ├── cases.yml
│ │ │ ├── components.yml
│ │ │ ├── custom-lists.yml
│ │ │ ├── data-model.yml
│ │ │ ├── decisions.yml
│ │ │ ├── inboxes.yml
│ │ │ ├── ingestion.yml
│ │ │ ├── misc.yml
│ │ │ ├── rule-snoozes.yml
│ │ │ ├── sanction-checks.yml
│ │ │ ├── sar.yml
│ │ │ ├── scenario-iteration-rules.yml
│ │ │ ├── scenario-iterations.yml
│ │ │ ├── scenario-publications.yml
│ │ │ ├── scenario-testrun.yml
│ │ │ ├── scenarios.yml
│ │ │ ├── signup-status.yml
│ │ │ ├── tags.yml
│ │ │ ├── version.yml
│ │ │ └── webhooks.yml
│ │ └── transfercheck-api.yaml
│ ├── package.json
│ ├── scripts
│ │ ├── config.ts
│ │ └── generate.ts
│ ├── src
│ │ ├── generated
│ │ │ ├── feature-access-api.ts
│ │ │ ├── marblecore-api.ts
│ │ │ └── transfercheck-api.ts
│ │ ├── helpers
│ │ │ ├── authorization.ts
│ │ │ └── index.ts
│ │ └── index.ts
│ └── tsconfig.json
├── shared
│ ├── eslint.config.mjs
│ ├── package.json
│ ├── src
│ │ ├── component-state.ts
│ │ ├── index.ts
│ │ ├── simple-context.ts
│ │ ├── use-callback-ref.ts
│ │ └── use-ref-fn.ts
│ └── tsconfig.json
├── tailwind-preset
│ ├── README.md
│ ├── eslint.config.mjs
│ ├── package.json
│ ├── src
│ │ └── tailwind.config.ts
│ └── tsconfig.json
├── tests
│ ├── .gitignore
│ ├── README.md
│ ├── auth.json
│ ├── e2e
│ │ ├── 001-user-signin-flow.test.ts
│ │ ├── 002-custom-lists.test.ts
│ │ └── 003-scenario-publication.test.ts
│ ├── eslint.config.mjs
│ ├── fixtures
│ │ ├── authentication.ts
│ │ └── index.ts
│ ├── package.json
│ ├── page-object-models
│ │ ├── auth-pages.ts
│ │ ├── custom-lists.ts
│ │ ├── firebase-auth-emulator.ts
│ │ ├── formula-builder.ts
│ │ ├── scenario-iteration-page.ts
│ │ ├── scenarios-page.ts
│ │ └── utils.ts
│ ├── playwright.config.ts
│ └── tsconfig.json
├── typescript-utils
│ ├── README.md
│ ├── eslint.config.mjs
│ ├── package.json
│ ├── src
│ │ ├── assert-never.ts
│ │ ├── index.ts
│ │ ├── isomorphic-env.ts
│ │ ├── noop.ts
│ │ └── utility-types.ts
│ └── tsconfig.json
├── ui-design-system
│ ├── .gitignore
│ ├── .storybook
│ │ ├── main.ts
│ │ ├── preview.ts
│ │ ├── public
│ │ │ └── fonts
│ │ │ │ └── Inter
│ │ │ │ ├── Inter-Black.woff
│ │ │ │ ├── Inter-Black.woff2
│ │ │ │ ├── Inter-BlackItalic.woff
│ │ │ │ ├── Inter-BlackItalic.woff2
│ │ │ │ ├── Inter-Bold.woff
│ │ │ │ ├── Inter-Bold.woff2
│ │ │ │ ├── Inter-BoldItalic.woff
│ │ │ │ ├── Inter-BoldItalic.woff2
│ │ │ │ ├── Inter-ExtraBold.woff
│ │ │ │ ├── Inter-ExtraBold.woff2
│ │ │ │ ├── Inter-ExtraBoldItalic.woff
│ │ │ │ ├── Inter-ExtraBoldItalic.woff2
│ │ │ │ ├── Inter-ExtraLight.woff
│ │ │ │ ├── Inter-ExtraLight.woff2
│ │ │ │ ├── Inter-ExtraLightItalic.woff
│ │ │ │ ├── Inter-ExtraLightItalic.woff2
│ │ │ │ ├── Inter-Italic.woff
│ │ │ │ ├── Inter-Italic.woff2
│ │ │ │ ├── Inter-Light.woff
│ │ │ │ ├── Inter-Light.woff2
│ │ │ │ ├── Inter-LightItalic.woff
│ │ │ │ ├── Inter-LightItalic.woff2
│ │ │ │ ├── Inter-Medium.woff
│ │ │ │ ├── Inter-Medium.woff2
│ │ │ │ ├── Inter-MediumItalic.woff
│ │ │ │ ├── Inter-MediumItalic.woff2
│ │ │ │ ├── Inter-Regular.woff
│ │ │ │ ├── Inter-Regular.woff2
│ │ │ │ ├── Inter-SemiBold.woff
│ │ │ │ ├── Inter-SemiBold.woff2
│ │ │ │ ├── Inter-SemiBoldItalic.woff
│ │ │ │ ├── Inter-SemiBoldItalic.woff2
│ │ │ │ ├── Inter-Thin.woff
│ │ │ │ ├── Inter-Thin.woff2
│ │ │ │ ├── Inter-ThinItalic.woff
│ │ │ │ ├── Inter-ThinItalic.woff2
│ │ │ │ ├── Inter-italic.var.woff2
│ │ │ │ ├── Inter-roman.var.woff2
│ │ │ │ ├── Inter.var.woff2
│ │ │ │ ├── LICENSE.txt
│ │ │ │ └── inter.css
│ │ └── tailwind-imports.css
│ ├── README.md
│ ├── eslint.config.mjs
│ ├── package.json
│ ├── postcss.config.js
│ ├── src
│ │ ├── Avatar
│ │ │ ├── Avatar.spec.tsx
│ │ │ ├── Avatar.stories.tsx
│ │ │ └── Avatar.tsx
│ │ ├── Button
│ │ │ ├── Button.spec.tsx
│ │ │ ├── Button.stories.tsx
│ │ │ └── Button.tsx
│ │ ├── Calendar
│ │ │ ├── Calendar.stories.tsx
│ │ │ └── Calendar.tsx
│ │ ├── Checkbox
│ │ │ ├── Checkbox.spec.tsx
│ │ │ ├── Checkbox.stories.tsx
│ │ │ └── Checkbox.tsx
│ │ ├── Code
│ │ │ ├── Code.stories.tsx
│ │ │ └── Code.tsx
│ │ ├── Collapsible
│ │ │ ├── Collapsible.spec.tsx
│ │ │ ├── Collapsible.stories.tsx
│ │ │ └── Collapsible.tsx
│ │ ├── Combobox
│ │ │ ├── Combobox.spec.tsx
│ │ │ ├── Combobox.stories.tsx
│ │ │ └── Combobox.tsx
│ │ ├── Command
│ │ │ ├── Command.stories.tsx
│ │ │ └── Command.tsx
│ │ ├── HiddenInputs
│ │ │ ├── HiddenInputs.spec.tsx
│ │ │ ├── HiddenInputs.stories.tsx
│ │ │ └── HiddenInputs.tsx
│ │ ├── Input
│ │ │ ├── Input.constants.tsx
│ │ │ ├── Input.spec.tsx
│ │ │ ├── Input.stories.tsx
│ │ │ └── Input.tsx
│ │ ├── Kbd
│ │ │ ├── Kbd.spec.tsx
│ │ │ ├── Kbd.stories.tsx
│ │ │ └── Kbd.tsx
│ │ ├── Menu
│ │ │ ├── Menu.spec.tsx
│ │ │ ├── Menu.stories.tsx
│ │ │ └── Menu.tsx
│ │ ├── MenuCommand
│ │ │ └── MenuCommand.tsx
│ │ ├── Modal
│ │ │ ├── Modal.spec.tsx
│ │ │ ├── Modal.stories.tsx
│ │ │ └── Modal.tsx
│ │ ├── Popover
│ │ │ └── Popover.tsx
│ │ ├── RadioGroup
│ │ │ ├── RadioGroup.stories.tsx
│ │ │ └── RadioGroup.tsx
│ │ ├── ScrollArea
│ │ │ ├── ScrollArea.spec.tsx
│ │ │ ├── ScrollArea.stories.tsx
│ │ │ └── ScrollArea.tsx
│ │ ├── Select
│ │ │ ├── Select.constants.tsx
│ │ │ ├── Select.spec.tsx
│ │ │ ├── Select.stories.tsx
│ │ │ └── Select.tsx
│ │ ├── SelectWithCombobox
│ │ │ ├── SelectWithCombobox.spec.tsx
│ │ │ ├── SelectWithCombobox.stories.tsx
│ │ │ └── SelectWithCombobox.tsx
│ │ ├── Separator
│ │ │ ├── Separator.spec.tsx
│ │ │ ├── Separator.stories.tsx
│ │ │ └── Separator.tsx
│ │ ├── Switch
│ │ │ ├── Switch.spec.tsx
│ │ │ ├── Switch.stories.tsx
│ │ │ └── Switch.tsx
│ │ ├── Table
│ │ │ ├── Table.spec.tsx
│ │ │ ├── Table.stories.tsx
│ │ │ └── Table.tsx
│ │ ├── Tabs
│ │ │ ├── Tabs.stories.tsx
│ │ │ └── Tabs.tsx
│ │ ├── Tag
│ │ │ ├── Tag.constants.tsx
│ │ │ ├── Tag.spec.tsx
│ │ │ ├── Tag.stories.tsx
│ │ │ └── Tag.tsx
│ │ ├── TextArea
│ │ │ ├── TextArea.spec.tsx
│ │ │ ├── TextArea.stories.tsx
│ │ │ └── TextArea.tsx
│ │ ├── Tooltip
│ │ │ ├── Tooltip.spec.tsx
│ │ │ ├── Tooltip.stories.tsx
│ │ │ └── Tooltip.tsx
│ │ ├── index.ts
│ │ └── utils.ts
│ ├── tailwind.config.ts
│ ├── tsconfig.json
│ ├── types
│ │ └── svg.d.ts
│ ├── vite.config.ts
│ └── vitest-setup.ts
└── ui-icons
│ ├── README.md
│ ├── docs
│ └── extract-svg-figma.png
│ ├── eslint.config.mjs
│ ├── package.json
│ ├── scripts
│ └── generate.ts
│ ├── src
│ ├── Icon.tsx
│ ├── Logo.tsx
│ ├── generated
│ │ ├── icon-names.ts
│ │ ├── icons-svg-sprite.svg
│ │ ├── logo-names.ts
│ │ └── logos-svg-sprite.svg
│ └── index.ts
│ ├── svgs
│ ├── icons
│ │ ├── accepted.svg
│ │ ├── add-alert.svg
│ │ ├── add-circle.svg
│ │ ├── alt-route.svg
│ │ ├── analytics.svg
│ │ ├── arrow-2-down.svg
│ │ ├── arrow-2-up.svg
│ │ ├── arrow-forward.svg
│ │ ├── arrow-left.svg
│ │ ├── arrow-range.svg
│ │ ├── arrow-right.svg
│ │ ├── arrow-top-left.svg
│ │ ├── arrow-up-right.svg
│ │ ├── arrow-up.svg
│ │ ├── attachment.svg
│ │ ├── backtest.svg
│ │ ├── block_and_review.svg
│ │ ├── boolean.svg
│ │ ├── calendar-month.svg
│ │ ├── caret-down.svg
│ │ ├── case-manager.svg
│ │ ├── category.svg
│ │ ├── center-focus.svg
│ │ ├── check-indeterminate-small.svg
│ │ ├── checked.svg
│ │ ├── column.svg
│ │ ├── comment.svg
│ │ ├── commit.svg
│ │ ├── copy.svg
│ │ ├── create-new-folder.svg
│ │ ├── cross.svg
│ │ ├── dash.svg
│ │ ├── decision.svg
│ │ ├── delete.svg
│ │ ├── denied.svg
│ │ ├── dns.svg
│ │ ├── dots-three.svg
│ │ ├── download.svg
│ │ ├── draft.svg
│ │ ├── drag.svg
│ │ ├── drawer-small.svg
│ │ ├── edit-square.svg
│ │ ├── edit.svg
│ │ ├── empty-flag.svg
│ │ ├── enum.svg
│ │ ├── error.svg
│ │ ├── eye-slash.svg
│ │ ├── eye.svg
│ │ ├── field.svg
│ │ ├── filters-off.svg
│ │ ├── filters.svg
│ │ ├── full-flag.svg
│ │ ├── function.svg
│ │ ├── half-flag.svg
│ │ ├── harddrive.svg
│ │ ├── helpcenter.svg
│ │ ├── history.svg
│ │ ├── in-progress.svg
│ │ ├── inbox.svg
│ │ ├── investigating.svg
│ │ ├── left-panel-close.svg
│ │ ├── left-panel-open.svg
│ │ ├── lightbulb.svg
│ │ ├── linked-services.svg
│ │ ├── list.svg
│ │ ├── lists.svg
│ │ ├── lock.svg
│ │ ├── logout.svg
│ │ ├── manage-search.svg
│ │ ├── manually_accepted.svg
│ │ ├── manually_denied.svg
│ │ ├── minus.svg
│ │ ├── modeling.svg
│ │ ├── monitor.svg
│ │ ├── more-menu.svg
│ │ ├── new-inbox.svg
│ │ ├── news.svg
│ │ ├── north-east.svg
│ │ ├── notifications.svg
│ │ ├── number.svg
│ │ ├── openinnew.svg
│ │ ├── parentheses.svg
│ │ ├── paste.svg
│ │ ├── percentage.svg
│ │ ├── person.svg
│ │ ├── play.svg
│ │ ├── plus.svg
│ │ ├── policy.svg
│ │ ├── pushtolive.svg
│ │ ├── queue-list.svg
│ │ ├── radio-selected.svg
│ │ ├── radio-unselected.svg
│ │ ├── report.svg
│ │ ├── resolved.svg
│ │ ├── restart-alt.svg
│ │ ├── rule-settings.svg
│ │ ├── rules.svg
│ │ ├── save.svg
│ │ ├── scenarios.svg
│ │ ├── schedule.svg
│ │ ├── scheduled-execution.svg
│ │ ├── search.svg
│ │ ├── send.svg
│ │ ├── settings.svg
│ │ ├── smallarrow-up.svg
│ │ ├── snooze-on.svg
│ │ ├── snooze.svg
│ │ ├── spinner.svg
│ │ ├── status.svg
│ │ ├── status_snoozed.svg
│ │ ├── stop.svg
│ │ ├── string.svg
│ │ ├── subdirectory-arrow-right.svg
│ │ ├── swap.svg
│ │ ├── tick.svg
│ │ ├── tip.svg
│ │ ├── transfercheck.svg
│ │ ├── tree-schema.svg
│ │ ├── trigger.svg
│ │ ├── uncheck.svg
│ │ ├── unfold_less.svg
│ │ ├── unfold_more.svg
│ │ ├── unlock-right.svg
│ │ ├── upload.svg
│ │ ├── users.svg
│ │ ├── version.svg
│ │ ├── visibility-on.svg
│ │ ├── visibility.svg
│ │ ├── visibility_off.svg
│ │ ├── waiting_for_action.svg
│ │ ├── warning.svg
│ │ └── world.svg
│ └── logos
│ │ ├── google-logo.svg
│ │ ├── logo-favicon.svg
│ │ ├── logo-standard.svg
│ │ ├── logo.svg
│ │ ├── marble.svg
│ │ └── microsoft-logo.svg
│ ├── tsconfig.json
│ └── types
│ └── svg.d.ts
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── prettier.config.js
├── tsconfig.base.json
└── vitest.workspace.ts
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | **/.github
4 | **/.gitignore
5 | **/.vscode
6 | **/coverage
7 | **/.env
8 | **/.aws
9 | **/.ssh
10 | Dockerfile
11 | Dockerfile_local
12 | .dockerignore
13 | README.md
14 | docker-compose.yml
15 | **/.DS_Store
16 | **/venv
17 | **/env
18 | **/dist
19 | **/build
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.firebaserc:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/.github/workflows/pull_request.yaml:
--------------------------------------------------------------------------------
1 | name: Pull request CI
2 |
3 | on: [pull_request]
4 |
5 | concurrency:
6 | group: ${{ github.workflow }}-${{ github.ref }}
7 | cancel-in-progress: true
8 |
9 | jobs:
10 | check:
11 | permissions:
12 | contents: read
13 | actions: read
14 | uses: ./.github/workflows/check.yaml
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | dist
5 | tmp
6 | /out-tsc
7 |
8 | # dependencies
9 | node_modules
10 |
11 | # IDEs and editors
12 | /.idea
13 | .project
14 | .classpath
15 | .c9/
16 | *.launch
17 | .settings/
18 | *.sublime-workspace
19 |
20 | # IDE - VSCode
21 | .vscode/*
22 | !.vscode/settings.json
23 | !.vscode/tasks.json
24 | !.vscode/launch.json
25 | !.vscode/extensions.json
26 | !.vscode/.user-settings.sample.json
27 |
28 | # misc
29 | /.sass-cache
30 | /connect.lock
31 | /coverage
32 | /libpeerconnection.log
33 | npm-debug.log
34 | yarn-error.log
35 | testem.log
36 | /typings
37 |
38 | # System Files
39 | .DS_Store
40 | Thumbs.db
41 |
42 |
43 | # Env files
44 | **/.env
45 |
46 | # Firebase
47 | firebase-debug.log
48 | ui-debug.log
49 | # Sentry Config File
50 | .sentryclirc
51 |
52 | .jj/
53 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # Add files here to ignore them from prettier formatting
2 | /.vscode/
3 | pnpm-lock.yaml
4 | packages-licenses.json
5 |
6 | # app-builder
7 | /packages/app-builder/.cache/
8 | /packages/app-builder/build/
9 | /packages/app-builder/public/build/
10 | /packages/app-builder/public/img/
11 | /packages/app-builder/src/utils/routes/routes.ts
12 |
13 | # marble-api
14 | /packages/marble-api/src/generated
15 |
16 | # ui-design-system
17 | /packages/ui-design-system/storybook-static/
18 |
19 | # tests
20 | /packages/tests/playwright-report
21 | /packages/tests/test-results
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | nodejs 22.9.0
2 | pnpm 9.12.3
3 |
--------------------------------------------------------------------------------
/.vscode/.user-settings.sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "mise.configureExtensionsUseSymLinks": true,
3 | "debug.javascript.defaultRuntimeExecutable": {
4 | "pwa-node": "${workspaceFolder}/.vscode/mise-tools/node"
5 | }
6 | }
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "esbenp.prettier-vscode",
4 | "dbaeumer.vscode-eslint",
5 | "bradlc.vscode-tailwindcss",
6 | "lokalise.i18n-ally",
7 | "developer2006.svg-gallery",
8 | "42crunch.vscode-openapi",
9 | "hverlin.mise-vscode"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "command": "pnpm --filter app-builder run dev",
9 | "name": "Launch app-builder",
10 | "request": "launch",
11 | "type": "node-terminal"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/Dockerfile_local:
--------------------------------------------------------------------------------
1 | FROM node:22-slim AS build
2 | ENV PNPM_HOME="/pnpm"
3 | ENV PATH="$PNPM_HOME:$PATH"
4 | RUN corepack enable
5 |
6 | COPY . /usr/src/app
7 | WORKDIR /usr/src/app
8 | RUN pnpm install --frozen-lockfile
9 | RUN pnpm --filter=app-builder run build
10 | RUN pnpm --filter=app-builder --prod deploy /prod/app-builder
11 |
12 | FROM gcr.io/distroless/nodejs22-debian12 AS app-builder
13 | ENV PORT=${PORT:-8080}
14 | COPY --from=build /prod/app-builder/node_modules /prod/app-builder/node_modules
15 | COPY --from=build /prod/app-builder/build /prod/app-builder/build
16 | WORKDIR /prod/app-builder
17 | USER nonroot
18 | EXPOSE $PORT
19 | CMD ["./node_modules/@remix-run/serve/dist/cli.js", "./build/server/index.js"]
20 |
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "emulators": {
3 | "auth": {
4 | "port": 9099
5 | },
6 | "ui": {
7 | "enabled": true
8 | },
9 | "singleProjectMode": true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/lefthook.yml:
--------------------------------------------------------------------------------
1 | # EXAMPLE USAGE:
2 | #
3 | # Refer for explanation to following link:
4 | # https://lefthook.dev/configuration/
5 | #
6 | pre-push:
7 | jobs:
8 | - run: pnpm run -r type-check
9 |
10 | pre-commit:
11 | parallel: true
12 | commands:
13 | lint:
14 | run: pnpm run -r lint --fix
15 | stage_fixed: true
16 | format:
17 | run: pnpm run format:write
18 | stage_fixed: true
19 |
--------------------------------------------------------------------------------
/packages/app-builder/.gitignore:
--------------------------------------------------------------------------------
1 | .cache
2 | build
3 | public/build
4 | .env
5 |
--------------------------------------------------------------------------------
/packages/app-builder/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import reactConfig from '@marble/eslint-config/react.mjs';
2 | import tailwindcssConfig from '@marble/eslint-config/tailwindcss.mjs';
3 | import vitestConfig from '@marble/eslint-config/vitest.mjs';
4 | import { join } from 'path';
5 |
6 | const tailwindConfigPath = join(import.meta.dirname, 'tailwind.config.ts');
7 |
8 | export default [
9 | ...reactConfig,
10 | ...tailwindcssConfig(tailwindConfigPath),
11 | ...vitestConfig,
12 | { ignores: ['build'] },
13 | ];
14 |
--------------------------------------------------------------------------------
/packages/app-builder/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/packages/app-builder/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/favicon.ico
--------------------------------------------------------------------------------
/packages/app-builder/public/favicons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/favicons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/packages/app-builder/public/favicons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/favicons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/packages/app-builder/public/favicons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/favicons/apple-touch-icon.png
--------------------------------------------------------------------------------
/packages/app-builder/public/favicons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/favicons/favicon-16x16.png
--------------------------------------------------------------------------------
/packages/app-builder/public/favicons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/favicons/favicon-32x32.png
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Black.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Black.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Black.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Black.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-BlackItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-BlackItalic.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-BlackItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-BlackItalic.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Bold.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Bold.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-BoldItalic.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-BoldItalic.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-ExtraBold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-ExtraBold.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-ExtraBold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-ExtraBold.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-ExtraBoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-ExtraBoldItalic.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-ExtraBoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-ExtraBoldItalic.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-ExtraLight.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-ExtraLight.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-ExtraLight.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-ExtraLight.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-ExtraLightItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-ExtraLightItalic.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-ExtraLightItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-ExtraLightItalic.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Italic.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Italic.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Light.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Light.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-LightItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-LightItalic.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-LightItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-LightItalic.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Medium.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Medium.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-MediumItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-MediumItalic.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-MediumItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-MediumItalic.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Regular.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Regular.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-SemiBold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-SemiBold.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-SemiBold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-SemiBold.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-SemiBoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-SemiBoldItalic.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-SemiBoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-SemiBoldItalic.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Thin.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Thin.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-Thin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-Thin.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-ThinItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-ThinItalic.woff
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-ThinItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-ThinItalic.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-italic.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-italic.var.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter-roman.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter-roman.var.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/fonts/Inter/Inter.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/fonts/Inter/Inter.var.woff2
--------------------------------------------------------------------------------
/packages/app-builder/public/img/home/api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/img/home/api.png
--------------------------------------------------------------------------------
/packages/app-builder/public/img/home/scenario-guide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/img/home/scenario-guide.png
--------------------------------------------------------------------------------
/packages/app-builder/public/img/home/testrun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/img/home/testrun.png
--------------------------------------------------------------------------------
/packages/app-builder/public/img/home/workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/public/img/home/workflow.png
--------------------------------------------------------------------------------
/packages/app-builder/public/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Marble",
3 | "short_name": "Marble",
4 | "icons": [
5 | {
6 | "src": "/favicons/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/favicons/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#ffffff",
17 | "background_color": "#ffffff",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/packages/app-builder/scripts/generateRoutes.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Get the routes from the Remix CLI
4 | routes_json=$(pnpm --filter app-builder exec remix routes --json)
5 |
6 | # Write the routes to the file
7 | echo "export const routes = $routes_json as const;" > src/utils/routes/routes.ts
8 |
9 |
10 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/AstBuilder/edition/EditModal/modals/FuzzyMatchComparator/helpers.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type fuzzyMatchAnyOfAstNodeName,
3 | type fuzzyMatchAstNodeName,
4 | } from '@app-builder/models/astNode/strings';
5 | import { type ParseKeys } from 'i18next';
6 |
7 | export const funcNameTKeys = {
8 | FuzzyMatch: 'scenarios:edit_fuzzy_match.fuzzy_match',
9 | FuzzyMatchAnyOf: 'scenarios:edit_fuzzy_match.fuzzy_match_any_of',
10 | } satisfies Record<
11 | typeof fuzzyMatchAnyOfAstNodeName | typeof fuzzyMatchAstNodeName,
12 | ParseKeys<['scenarios']>
13 | >;
14 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/AstBuilder/edition/EditModal/modals/StringTemplate/helpers.ts:
--------------------------------------------------------------------------------
1 | import { STRING_TEMPLATE_VARIABLE_REGEXP } from '@app-builder/models/astNode/strings';
2 |
3 | export const extractVariablesNamesFromTemplate = (template: string) => {
4 | const res = template.matchAll(STRING_TEMPLATE_VARIABLE_REGEXP).toArray();
5 |
6 | return res.reduce((acc, match) => {
7 | return match[1] && !acc.includes(match[1]) ? [...acc, match[1]] : acc;
8 | }, [] as string[]);
9 | };
10 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/AstBuilder/edition/EditionAnyRoot.tsx:
--------------------------------------------------------------------------------
1 | import { type AstBuilderRootProps } from '@ast-builder/types';
2 |
3 | import { EditionAstBuilderNode } from './EditionNode';
4 | import { EditionEvaluationErrors } from './EvaluationErrors';
5 | import { useRoot } from './hooks/useRoot';
6 | import { AstBuilderNodeSharpFactory } from './node-store';
7 |
8 | export function EditionAstBuilderAnyRoot(props: AstBuilderRootProps) {
9 | const nodeStore = useRoot(props);
10 |
11 | return (
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/AstBuilder/edition/OperandMenu/types.ts:
--------------------------------------------------------------------------------
1 | import { type AstNode } from '@app-builder/models';
2 |
3 | export type SmartMenuListProps = {
4 | onSelect: (node: AstNode) => void;
5 | };
6 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/AstBuilder/index.tsx:
--------------------------------------------------------------------------------
1 | import { OperandEditModal } from './edition/EditModal/EditModal';
2 | import { AstBuilderOperand } from './Operand';
3 | import { AstBuilderProvider } from './Provider';
4 | import { AstBuilderRoot } from './Root';
5 |
6 | export const AstBuilder = {
7 | Root: AstBuilderRoot,
8 | Operand: AstBuilderOperand,
9 | Provider: AstBuilderProvider,
10 | EditModal: OperandEditModal,
11 | };
12 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/AstBuilder/styles/NodeTypeError.tsx:
--------------------------------------------------------------------------------
1 | export function NodeTypeError() {
2 | return (
3 |
4 | Wrong node type
5 |
6 | );
7 | }
8 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/AstBuilder/viewing/ViewingAnyRoot.tsx:
--------------------------------------------------------------------------------
1 | import { type AstBuilderRootProps } from '@ast-builder/types';
2 | import { useMemo } from 'react';
3 |
4 | import { ViewingEvaluationErrors } from './ViewingEvaluationErrors';
5 | import { ViewingAstBuilderNode } from './ViewingNode';
6 |
7 | export function EditionAstBuilderAnyRoot(props: AstBuilderRootProps) {
8 | const validation = useMemo(
9 | () => props.validation ?? { errors: [], evaluation: [] },
10 | [props.validation],
11 | );
12 |
13 | return (
14 |
15 |
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Auth/auth-i18n.ts:
--------------------------------------------------------------------------------
1 | import { type Namespace } from 'i18next';
2 |
3 | export const authI18n = ['auth', 'common'] satisfies Namespace;
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Cases/Filters/FilterDetail/CasesExcludeAssignedFilter.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-hooks/exhaustive-deps */
2 | import { useMemo } from 'react';
3 | import { useFormContext } from 'react-hook-form';
4 |
5 | import { type CasesFiltersForm, useCasesFiltersContext } from '../CasesFiltersContext';
6 |
7 | export function CasesExcludeAssignedFilter() {
8 | const { submitCasesFilters } = useCasesFiltersContext();
9 | const { setValue } = useFormContext();
10 |
11 | useMemo(() => {
12 | setValue('excludeAssigned', true);
13 | submitCasesFilters();
14 | }, []);
15 | return null;
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Cases/Filters/FilterDetail/CasesSnoozedFilter.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-hooks/exhaustive-deps */
2 | import { useMemo } from 'react';
3 | import { useFormContext } from 'react-hook-form';
4 |
5 | import { type CasesFiltersForm, useCasesFiltersContext } from '../CasesFiltersContext';
6 |
7 | export function CasesSnoozedFilter() {
8 | const { submitCasesFilters } = useCasesFiltersContext();
9 | const { setValue } = useFormContext();
10 |
11 | useMemo(() => {
12 | setValue('includeSnoozed', true);
13 | submitCasesFilters();
14 | }, []);
15 | return null;
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Cases/Filters/FilterDetail/ClosedCasesFilter.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react-hooks/exhaustive-deps */
2 |
3 | import { useMemo } from 'react';
4 | import { useFormContext } from 'react-hook-form';
5 |
6 | import { type CasesFiltersForm, useCasesFiltersContext } from '../CasesFiltersContext';
7 |
8 | export function ClosedCasesFilter() {
9 | const { submitCasesFilters } = useCasesFiltersContext();
10 | const { setValue } = useFormContext();
11 |
12 | useMemo(() => {
13 | setValue('statuses', ['closed']);
14 | submitCasesFilters();
15 | }, []);
16 |
17 | return null;
18 | }
19 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Cases/Filters/FilterDetail/FilterDetail.tsx:
--------------------------------------------------------------------------------
1 | import { match } from 'ts-pattern';
2 |
3 | import { type CasesFilterName } from '../filters';
4 | import { CasesDateRangeFilter } from './CasesDateRangeFilter';
5 | import { CasesExcludeAssignedFilter } from './CasesExcludeAssignedFilter';
6 | import { CasesSnoozedFilter } from './CasesSnoozedFilter';
7 | import { ClosedCasesFilter } from './ClosedCasesFilter';
8 |
9 | export const FilterDetail = ({ filterName }: { filterName: CasesFilterName }) =>
10 | match(filterName)
11 | .with('dateRange', () => )
12 | .with('statuses', () => )
13 | .with('includeSnoozed', () => )
14 | .with('excludeAssigned', () => )
15 | .exhaustive();
16 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Cases/Filters/FilterDetail/NameFilter.tsx:
--------------------------------------------------------------------------------
1 | import { Input } from 'ui-design-system';
2 |
3 | import { useNameFilter } from '../CasesFiltersContext';
4 |
5 | export function NameFilter() {
6 | const { name, setName } = useNameFilter();
7 |
8 | return (
9 |
10 | {
13 | setName(event.target.value);
14 | }}
15 | autoFocus
16 | />
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Cases/Filters/FilterDetail/index.ts:
--------------------------------------------------------------------------------
1 | export * from './FilterDetail';
2 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Cases/Filters/index.ts:
--------------------------------------------------------------------------------
1 | export * from './CasesFiltersBar';
2 | export * from './CasesFiltersContext';
3 | export * from './CasesFiltersMenu';
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Cases/cases-i18n.ts:
--------------------------------------------------------------------------------
1 | import { type Namespace } from 'i18next';
2 |
3 | import { decisionsI18n } from '../Decisions/decisions-i18n';
4 | import { filtersI18n } from '../Filters/filters-i18n';
5 | import { sanctionsI18n } from '../Sanctions/sanctions-i18n';
6 |
7 | export const casesI18n = [
8 | 'cases',
9 | ...filtersI18n,
10 | ...decisionsI18n,
11 | ...sanctionsI18n,
12 | ] satisfies Namespace;
13 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Cases/index.ts:
--------------------------------------------------------------------------------
1 | export * from './CaseRightPanel';
2 | export * from './cases-i18n';
3 | export * from './CasesList';
4 | export * from './CaseStatus';
5 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Data/PivotType.tsx:
--------------------------------------------------------------------------------
1 | import { Tag } from 'ui-design-system';
2 |
3 | export function PivotType({ type }: { type: 'field' | 'link' }) {
4 | return (
5 |
11 | {type}
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Data/data-i18n.ts:
--------------------------------------------------------------------------------
1 | import { type Namespace } from 'i18next';
2 |
3 | export const dataI18n = ['common', 'data'] satisfies Namespace;
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/DataModelExplorer/types.ts:
--------------------------------------------------------------------------------
1 | import { type ClientObjectDetail } from '@app-builder/models';
2 | import { type PivotObject } from '@app-builder/models/cases';
3 |
4 | export type DataModelExplorerNavigationTab = {
5 | pivotObject: PivotObject;
6 | sourceObject: ClientObjectDetail['data'];
7 | sourceTableName: string;
8 | sourceFieldName: string;
9 | targetTableName: string;
10 | filterFieldName: string;
11 | orderingFieldName: string;
12 | };
13 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Decisions/Filters/FilterDetail/index.ts:
--------------------------------------------------------------------------------
1 | export * from './FilterDetail';
2 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Decisions/Filters/index.ts:
--------------------------------------------------------------------------------
1 | export * from './DecisionFiltersBar';
2 | export * from './DecisionFiltersContext';
3 | export * from './DecisionFiltersMenu';
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Decisions/decisions-i18n.ts:
--------------------------------------------------------------------------------
1 | import { type Namespace } from 'i18next';
2 |
3 | import { filtersI18n } from '../Filters/filters-i18n';
4 |
5 | export const decisionsI18n = [
6 | 'decisions',
7 | 'common',
8 | 'scenarios',
9 | 'cases',
10 | 'sanctions',
11 | ...filtersI18n,
12 | ] satisfies Namespace;
13 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Decisions/index.ts:
--------------------------------------------------------------------------------
1 | export * from './DecisionDetail';
2 | export * from './DecisionRightPanel';
3 | export * from './decisions-i18n';
4 | export * from './DecisionsList';
5 | export * from './Filters';
6 | export * from './OutcomeTag';
7 | export * from './RulesDetail';
8 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/ExternalLink.tsx:
--------------------------------------------------------------------------------
1 | import { forwardRef } from 'react';
2 | import { cn } from 'ui-design-system';
3 |
4 | export const linkClasses =
5 | 'hover:text-purple-60 focus:text-purple-60 font-semibold lowercase text-purple-65 hover:underline focus:underline';
6 |
7 | export const ExternalLink = forwardRef>(
8 | function ExternalLink({ className, children, ...otherProps }, ref) {
9 | return (
10 |
17 | {children}
18 |
19 | );
20 | },
21 | );
22 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Files/AddYourFirstFile.tsx:
--------------------------------------------------------------------------------
1 | import { UploadFile } from '@app-builder/routes/ressources+/files+/upload-file';
2 |
3 | export function AddYourFirstFile({
4 | children,
5 | uploadFileEndpoint,
6 | }: {
7 | children?: React.ReactNode;
8 | uploadFileEndpoint: string;
9 | }) {
10 | return (
11 |
12 |
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Filters/AddNewFilterButton.tsx:
--------------------------------------------------------------------------------
1 | import { forwardRef } from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { Button, type ButtonProps } from 'ui-design-system';
4 | import { Icon } from 'ui-icons';
5 |
6 | import { filtersI18n } from './filters-i18n';
7 |
8 | type AddNewFilterButtonProps = Omit;
9 |
10 | export const AddNewFilterButton = forwardRef(
11 | function AddNewFilterButton(props, ref) {
12 | const { t } = useTranslation(filtersI18n);
13 | return (
14 |
18 | );
19 | },
20 | );
21 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Filters/SimpleFilter.tsx:
--------------------------------------------------------------------------------
1 | import clsx from 'clsx';
2 | import { type ComponentPropsWithoutRef } from 'react';
3 |
4 | export function SimpleFilter({ className, ...props }: ComponentPropsWithoutRef<'div'>) {
5 | return (
6 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Filters/filters-i18n.ts:
--------------------------------------------------------------------------------
1 | import { type Namespace } from 'i18next';
2 |
3 | export const filtersI18n = ['filters'] satisfies Namespace;
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Filters/index.ts:
--------------------------------------------------------------------------------
1 | export * from './AddNewFilterButton';
2 | export * from './ClearAllFilters';
3 | export * from './DateRangeFilter';
4 | export * from './FilterPopover';
5 | export * from './FiltersButton';
6 | export * from './FiltersDropdownMenu';
7 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Form/Tanstack/FormLabel.tsx:
--------------------------------------------------------------------------------
1 | import * as LabelPrimitive from '@radix-ui/react-label';
2 | import * as React from 'react';
3 | import { cn } from 'ui-design-system';
4 |
5 | interface FormLabelProps
6 | extends Omit, 'htmlFor'> {
7 | name: string;
8 | valid?: boolean;
9 | }
10 |
11 | export const FormLabel = React.forwardRef<
12 | React.ElementRef,
13 | FormLabelProps
14 | >(function FormLabel({ className, valid, name, ...props }, ref) {
15 | return (
16 |
24 | );
25 | });
26 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Form/Tanstack/FormTextArea.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { TextArea, type TextAreaProps } from 'ui-design-system';
3 |
4 | interface FormTextAreaProps extends Omit {
5 | valid?: boolean;
6 | }
7 |
8 | export const FormTextArea = React.forwardRef, FormTextAreaProps>(
9 | function FormTextArea(props, ref) {
10 | return (
11 |
17 | );
18 | },
19 | );
20 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/LottiePlayer.client.tsx:
--------------------------------------------------------------------------------
1 | import { Player } from '@lottiefiles/react-lottie-player';
2 |
3 | export const LottiePlayer = Player;
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Ping/Ping.tsx:
--------------------------------------------------------------------------------
1 | import clsx from 'clsx';
2 |
3 | /**
4 | * A ping animation.
5 | * @param className - Use tex-color-* to customize ping color. Use border to make a "white" circle arround the ping.
6 | *
7 | * @example className="border-grey-100 absolute right-0 top-0 h-[10px] w-[10px] border-2 text-red-47"
8 | */
9 | export function Ping({ className }: { className?: string }) {
10 | return (
11 |
12 |
13 |
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Ping/index.ts:
--------------------------------------------------------------------------------
1 | export * from './CornerPing';
2 | export * from './Ping';
3 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Sanctions/sanctions-i18n.ts:
--------------------------------------------------------------------------------
1 | import { type Namespace } from 'i18next';
2 |
3 | export const sanctionsI18n = ['common', 'sanctions'] satisfies Namespace;
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Rules/Filters/FilterDetail/FilterDetail.tsx:
--------------------------------------------------------------------------------
1 | import { assertNever } from 'typescript-utils';
2 |
3 | import { type RulesFilterName } from '../filters';
4 | import { RuleGroupFilter } from './RuleGroupFilter';
5 |
6 | export function FilterDetail({ filterName }: { filterName: RulesFilterName }) {
7 | switch (filterName) {
8 | case 'ruleGroup':
9 | return ;
10 | default:
11 | assertNever('[RulesFilter] unknown filter:', filterName);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Rules/RuleGroup.tsx:
--------------------------------------------------------------------------------
1 | import { type ComponentProps } from 'react';
2 | import { Icon } from 'ui-icons';
3 |
4 | export const RuleGroup = ({
5 | ruleGroup,
6 | onClear,
7 | ...rest
8 | }: ComponentProps<'div'> & { ruleGroup: string; onClear?: () => void }) => (
9 |
13 | {ruleGroup}
14 | {onClear ? (
15 |
20 | ) : null}
21 |
22 | );
23 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Rules/ScoreModifier.tsx:
--------------------------------------------------------------------------------
1 | import { type ComponentProps } from 'react';
2 | import { cn } from 'ui-design-system';
3 |
4 | export const ScoreModifier = ({
5 | score,
6 | className,
7 | ...rest
8 | }: ComponentProps<'span'> & { score: number }) => {
9 | return (
10 |
17 | {score >= 0 ? '+' : '-'}
18 | {Math.abs(score)}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Sanction/FieldToolTip.tsx:
--------------------------------------------------------------------------------
1 | import { Hovercard, HovercardAnchor, HovercardProvider } from '@ariakit/react';
2 | import { Icon } from 'ui-icons';
3 |
4 | export const FieldToolTip = ({ children }: { children: React.ReactNode }) => {
5 | return (
6 |
7 |
11 |
12 |
13 |
18 | {children}
19 |
20 |
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Sanction/MatchOperand.tsx:
--------------------------------------------------------------------------------
1 | import { AstBuilder } from '@app-builder/components/AstBuilder';
2 | import { type AstNode, NewUndefinedAstNode } from '@app-builder/models';
3 | import { type KnownOperandAstNode } from '@app-builder/models/astNode/builder-ast-node';
4 | import { memo } from 'react';
5 |
6 | export const MatchOperand = memo(function MatchOperand({
7 | node,
8 | onSave,
9 | placeholder,
10 | }: {
11 | node?: KnownOperandAstNode;
12 | onSave?: (astNode: AstNode) => void;
13 | placeholder?: string;
14 | }) {
15 | return (
16 |
23 | );
24 | });
25 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/ScenarioValidationError.tsx:
--------------------------------------------------------------------------------
1 | import clsx from 'clsx';
2 |
3 | export function EvaluationErrors({ errors, className }: { errors: string[]; className?: string }) {
4 | if (errors.length === 0) return null;
5 | return (
6 |
7 | {errors.map((error) => (
8 |
15 | {error}
16 |
17 | ))}
18 |
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/TestRun/Filters/FilterDetail/FilterDetail.tsx:
--------------------------------------------------------------------------------
1 | import { match } from 'ts-pattern';
2 |
3 | import { type TestRunFilterName } from '../filters';
4 | import { CreatorsFilter } from './CreatorsFilter';
5 | import { StartedAfterFilter } from './StartedAfterFilter';
6 | import { StatusesFilter } from './StatusesFilter';
7 | import { VersionsFilter } from './VersionsFilter';
8 |
9 | export function FilterDetail({ filterName }: { filterName: TestRunFilterName }) {
10 | return match(filterName)
11 | .with('startedAfter', () => )
12 | .with('statuses', () => )
13 | .with('creators', () => )
14 | .with('ref_versions', () => )
15 | .with('test_versions', () => )
16 | .exhaustive();
17 | }
18 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/TestRun/Filters/FilterDetail/StartedAfterFilter.tsx:
--------------------------------------------------------------------------------
1 | import { getDateFnsLocale } from '@app-builder/services/i18n/i18n-config';
2 | import { useFormatLanguage } from '@app-builder/utils/format';
3 | import { Calendar } from 'ui-design-system';
4 |
5 | import { useStartedAfterFilter } from '../TestRunsFiltersContext';
6 |
7 | export function StartedAfterFilter() {
8 | const { startedAfter, setStartedAfter } = useStartedAfterFilter();
9 | const language = useFormatLanguage();
10 |
11 | return (
12 |
13 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/TestRun/Filters/FilterDetail/index.ts:
--------------------------------------------------------------------------------
1 | export * from './FilterDetail';
2 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/TestRun/Filters/index.ts:
--------------------------------------------------------------------------------
1 | export * from './TestRunsFiltersBar';
2 | export * from './TestRunsFiltersContext';
3 | export * from './TestRunsFiltersMenu';
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Trigger/ScheduleOption/index.ts:
--------------------------------------------------------------------------------
1 | export * from './ScheduleOption';
2 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Trigger/index.ts:
--------------------------------------------------------------------------------
1 | export * from './ScheduleOption';
2 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Workflow/DetailPanel/CaseNameEditor.hook.ts:
--------------------------------------------------------------------------------
1 | import { NewPayloadAstNode } from '@app-builder/models/astNode/data-accessor';
2 | import { NewStringTemplateAstNode } from '@app-builder/models/astNode/strings';
3 | import { useMemo } from 'react';
4 |
5 | import { defaultCaseName } from './shared';
6 |
7 | export const useDefaultCaseName = (triggerObjectType: string) => {
8 | const defaultCaseTemplate = defaultCaseName.replace('%trigger_object_type%', triggerObjectType);
9 | const defaultCaseNameNode = useMemo(() => {
10 | return NewStringTemplateAstNode(defaultCaseTemplate, {
11 | object_id: NewPayloadAstNode('object_id'),
12 | });
13 | }, [defaultCaseTemplate]);
14 |
15 | return {
16 | defaultCaseNameNode,
17 | };
18 | };
19 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Workflow/DetailPanel/shared.ts:
--------------------------------------------------------------------------------
1 | export const defaultCaseName = 'Case for %trigger_object_type%: %object_id%';
2 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Workflow/Nodes/EmptyNode.tsx:
--------------------------------------------------------------------------------
1 | import clsx from 'clsx';
2 | import { Handle, type NodeProps, Position } from 'reactflow';
3 | import { Icon } from 'ui-icons';
4 |
5 | export function EmptyNode({ selected }: NodeProps) {
6 | return (
7 |
13 |
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/Workflow/workflow-i18n.ts:
--------------------------------------------------------------------------------
1 | import { type Namespace } from 'i18next';
2 |
3 | export const workflowI18n = [
4 | 'common',
5 | 'workflows',
6 | 'decisions',
7 | 'settings', // Required by
8 | ] satisfies Namespace;
9 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/index.ts:
--------------------------------------------------------------------------------
1 | export * from './scenario-i18n';
2 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Scenario/scenario-i18n.ts:
--------------------------------------------------------------------------------
1 | import { type Namespace } from 'i18next';
2 |
3 | export const scenarioI18n = ['common', 'scenarios'] satisfies Namespace;
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Tags/ColorPreview.tsx:
--------------------------------------------------------------------------------
1 | import { type TagColor } from '@app-builder/models/tags';
2 |
3 | export const ColorPreview = ({ color }: { color: TagColor }) => {
4 | return (
5 |
6 | );
7 | };
8 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/TransferAlerts/Filters/FilterDetail/FilterDetail.tsx:
--------------------------------------------------------------------------------
1 | import { assertNever } from 'typescript-utils';
2 |
3 | import { type AlertsFilterName } from '../filters';
4 | import { AlertsDateRangeFilter } from './AlertsDateRangeFilter';
5 | import { StatusesFilter } from './StatusesFilter';
6 |
7 | export function FilterDetail({ filterName }: { filterName: AlertsFilterName }) {
8 | switch (filterName) {
9 | case 'dateRange':
10 | return ;
11 | case 'statuses':
12 | return ;
13 | default:
14 | assertNever('[CasesFilter] unknown filter:', filterName);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/TransferAlerts/Filters/FilterDetail/index.ts:
--------------------------------------------------------------------------------
1 | export * from './FilterDetail';
2 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/TransferAlerts/Filters/index.ts:
--------------------------------------------------------------------------------
1 | export * from './AlertsFiltersBar';
2 | export * from './AlertsFiltersContext';
3 | export * from './AlertsFiltersMenu';
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/TransferAlerts/alerts-i18n.ts:
--------------------------------------------------------------------------------
1 | import { type Namespace } from 'i18next';
2 |
3 | export const alertsI18n = ['common', 'transfercheck'] satisfies Namespace;
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/Transfers/transfers-i18n.ts:
--------------------------------------------------------------------------------
1 | import { type Namespace } from 'i18next';
2 |
3 | export const transfersI18n = ['common', 'transfercheck'] satisfies Namespace;
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Callout';
2 | export * from './Cases';
3 | export * from './CopyToClipboardButton';
4 | export * from './Decisions';
5 | export * from './ErrorComponent';
6 | export * from './Navigation';
7 | export * from './Page';
8 | export * from './PaginationButtons';
9 | export * from './Paper';
10 | export * from './RightPanel';
11 | export * from './Scenario';
12 |
--------------------------------------------------------------------------------
/packages/app-builder/src/hooks/decisions/usePivotValues.ts:
--------------------------------------------------------------------------------
1 | import { type Pivot } from '@app-builder/models';
2 | import { type CaseDetail } from '@app-builder/models/cases';
3 | import { useMemo } from 'react';
4 | import * as R from 'remeda';
5 |
6 | type PivotValues = CaseDetail['decisions'][number]['pivotValues'];
7 |
8 | export function usePivotValues(pivotValues: PivotValues, pivots: Pivot[]) {
9 | const value = useMemo(() => {
10 | return R.pipe(
11 | pivotValues,
12 | R.map(({ id, value }) => {
13 | const pivot = pivots.find((p) => p.id === id);
14 | if (!pivot || !value) {
15 | return null;
16 | }
17 |
18 | return { pivot, value };
19 | }),
20 | R.filter(R.isNonNullish),
21 | );
22 | }, [pivotValues, pivots]);
23 |
24 | return value;
25 | }
26 |
--------------------------------------------------------------------------------
/packages/app-builder/src/locales/ar/api.json:
--------------------------------------------------------------------------------
1 | {
2 | "download_openapi_spec": "تنزيل مواصفات OpenAPI"
3 | }
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/locales/ar/filters.json:
--------------------------------------------------------------------------------
1 | {
2 | "filters": "الفلاتر",
3 | "new_filter": "فلتر جدبد",
4 | "clear_filters": "مسح الفلاتر",
5 | "up_to": "حتى {{date}}"
6 | }
7 |
--------------------------------------------------------------------------------
/packages/app-builder/src/locales/en/api.json:
--------------------------------------------------------------------------------
1 | {
2 | "download_openapi_spec": "Download OpenAPI specification"
3 | }
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/locales/en/filters.json:
--------------------------------------------------------------------------------
1 | {
2 | "filters": "filters",
3 | "new_filter": "new filter",
4 | "clear_filters": "clear filters",
5 | "up_to": "up to {{duration}}"
6 | }
7 |
--------------------------------------------------------------------------------
/packages/app-builder/src/locales/fr/api.json:
--------------------------------------------------------------------------------
1 | {
2 | "download_openapi_spec": "Télécharger la spécification OpenAPI"
3 | }
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/locales/fr/filters.json:
--------------------------------------------------------------------------------
1 | {
2 | "clear_filters": "effacer les filtres",
3 | "filters": "filtres",
4 | "new_filter": "nouveau filtre",
5 | "up_to": "jusqu'à {{duration}}"
6 | }
7 |
--------------------------------------------------------------------------------
/packages/app-builder/src/models/analytics.ts:
--------------------------------------------------------------------------------
1 | import { type AnalyticsDto } from 'marble-api';
2 |
3 | export interface Analytics {
4 | embeddingType: 'global_dashboard' | 'unknown_embedding_type';
5 | signedEmbeddingUrl: string;
6 | }
7 |
8 | export function adaptAnalytics(analyticsDto: AnalyticsDto): Analytics {
9 | return {
10 | embeddingType: analyticsDto.embedding_type,
11 | signedEmbeddingUrl: analyticsDto.signed_embedding_url,
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/packages/app-builder/src/models/auth-errors.ts:
--------------------------------------------------------------------------------
1 | import { CSRFError } from 'remix-utils/csrf/server';
2 |
3 | import { isMarbleError, isUnauthorizedHttpError } from './http-errors';
4 |
5 | export type AuthErrors = 'NoAccount' | 'CSRFError' | 'BackendUnavailable' | 'Unknown';
6 |
7 | export function adaptAuthErrors(error: unknown): AuthErrors {
8 | if (error instanceof CSRFError) {
9 | return 'CSRFError';
10 | }
11 | if (isUnauthorizedHttpError(error) && isMarbleError(error)) {
12 | const errorCode = error.data.error_code;
13 | if (errorCode === 'unknown_user') {
14 | return 'NoAccount';
15 | }
16 | }
17 |
18 | return 'Unknown';
19 | }
20 |
--------------------------------------------------------------------------------
/packages/app-builder/src/models/fuzzy-match.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/app-builder/src/models/fuzzy-match.ts
--------------------------------------------------------------------------------
/packages/app-builder/src/models/index.ts:
--------------------------------------------------------------------------------
1 | export * from './astNode/ast-node';
2 | export * from './auth-errors';
3 | export * from './data-model';
4 | export * from './http-errors';
5 | export * from './marble-session';
6 | export * from './scenario-validation';
7 | export * from './user';
8 |
--------------------------------------------------------------------------------
/packages/app-builder/src/models/marble-session.ts:
--------------------------------------------------------------------------------
1 | import { type Session } from '@remix-run/node';
2 | import { type Token } from 'marble-api';
3 |
4 | import { type CreatedApiKey } from './api-keys';
5 | import { type AuthErrors } from './auth-errors';
6 |
7 | export type AuthData = {
8 | authToken: Token;
9 | };
10 | export type AuthFlashData = {
11 | authError: { message: AuthErrors };
12 | createdApiKey: CreatedApiKey;
13 | };
14 | export type AuthSession = Session;
15 |
--------------------------------------------------------------------------------
/packages/app-builder/src/models/outcome.ts:
--------------------------------------------------------------------------------
1 | export const knownOutcomes = ['approve', 'review', 'block_and_review', 'decline'] as const;
2 | export type KnownOutcome = (typeof knownOutcomes)[number];
3 | export type SanctionOutcome = 'review' | 'decline' | 'block_and_review';
4 |
5 | export const outcomes = [...knownOutcomes, 'unknown'] as const;
6 | export type Outcome = (typeof outcomes)[number];
7 |
--------------------------------------------------------------------------------
/packages/app-builder/src/models/partner.ts:
--------------------------------------------------------------------------------
1 | import { type PartnerDto } from 'marble-api/generated/transfercheck-api';
2 |
3 | export interface Partner {
4 | id: string;
5 | createdAt: string;
6 | name: string;
7 | }
8 |
9 | export function adaptPartner(dto: PartnerDto): Partner {
10 | return {
11 | id: dto.id,
12 | createdAt: dto.created_at,
13 | name: dto.name,
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/packages/app-builder/src/models/signup-status.ts:
--------------------------------------------------------------------------------
1 | export type SignupStatus = {
2 | hasAnOrganization: boolean;
3 | hasAUser: boolean;
4 | migrationsRun: boolean;
5 | };
6 |
--------------------------------------------------------------------------------
/packages/app-builder/src/models/tags.ts:
--------------------------------------------------------------------------------
1 | export const tagColors = ['#C8C3FF', '#FDE9AD', '#FFA89A', '#B7DFF5', '#B2E5BA'] as const;
2 |
3 | export type TagColor = (typeof tagColors)[number];
4 |
--------------------------------------------------------------------------------
/packages/app-builder/src/models/version.ts:
--------------------------------------------------------------------------------
1 | export type AppVersions = {
2 | apiVersion: string;
3 | appVersion: string;
4 | };
5 |
--------------------------------------------------------------------------------
/packages/app-builder/src/queries/opensanctions-dataset-freshness-info.ts:
--------------------------------------------------------------------------------
1 | import { type OpenSanctionDatasetFreshnessInfoResource } from '@app-builder/routes/ressources+/opensanctions+/dataset-freshness';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { useQuery } from '@tanstack/react-query';
4 |
5 | const endpoint = () => getRoute('/ressources/opensanctions/dataset-freshness');
6 |
7 | export function useOpenSanctionsDatasetFreshnessInfo() {
8 | const queryKey = ['opensanctions-dataset-freshness-info'] as const;
9 |
10 | return useQuery({
11 | queryKey,
12 | queryFn: async () => {
13 | const response = await fetch(endpoint(), { method: 'GET' });
14 | return response.json() as Promise;
15 | },
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/packages/app-builder/src/queries/pivot-related-cases.ts:
--------------------------------------------------------------------------------
1 | import { type PivotRelatedCasesResource } from '@app-builder/routes/ressources+/cases+/pivot+/related+/$pivotValue._index';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { useQuery } from '@tanstack/react-query';
4 |
5 | const endpoint = (pivotValue: string) =>
6 | getRoute('/ressources/cases/pivot/related/:pivotValue', {
7 | pivotValue,
8 | });
9 |
10 | export function usePivotRelatedCasesQuery(pivotValue: string) {
11 | return useQuery({
12 | queryKey: ['pivot', 'relatedCases', pivotValue],
13 | queryFn: async () => {
14 | return (await fetch(endpoint(pivotValue))).json() as Promise;
15 | },
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/AnalyticsRepository.ts:
--------------------------------------------------------------------------------
1 | import { type MarbleCoreApi } from '@app-builder/infra/marblecore-api';
2 | import { adaptAnalytics, type Analytics } from '@app-builder/models/analytics';
3 |
4 | export interface AnalyticsRepository {
5 | listAnalytics(): Promise;
6 | }
7 |
8 | export function makeGetAnalyticsRepository() {
9 | return (marbleCoreApiClient: MarbleCoreApi): AnalyticsRepository => ({
10 | listAnalytics: async () => {
11 | const { analytics } = await marbleCoreApiClient.listAnalytics();
12 |
13 | return analytics.map(adaptAnalytics);
14 | },
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/FeatureAccessRepository.ts:
--------------------------------------------------------------------------------
1 | import { type FeatureAccessApi } from '@app-builder/infra/feature-access-api';
2 | import { adaptFeatureAccesses, type FeatureAccesses } from '@app-builder/models/feature-access';
3 |
4 | export interface FeatureAccessRepository {
5 | getEntitlements(): Promise;
6 | isSsoEnabled(): Promise;
7 | }
8 |
9 | export const makeGetFeatureAccessRepository =
10 | () =>
11 | (client: FeatureAccessApi): FeatureAccessRepository => ({
12 | isSsoEnabled: async () => (await client.isSsoEnabled()).is_sso_enabled,
13 | getEntitlements: async () =>
14 | adaptFeatureAccesses((await client.getEntitlements()).feature_access),
15 | });
16 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/PartnerRepository.ts:
--------------------------------------------------------------------------------
1 | import { type TransfercheckApi } from '@app-builder/infra/transfercheck-api';
2 | import { adaptPartner, type Partner } from '@app-builder/models/partner';
3 |
4 | export interface PartnerRepository {
5 | getPartner(partnerId: string): Promise;
6 | }
7 |
8 | export function makeGetPartnerRepository() {
9 | return (transfercheckApi: TransfercheckApi): PartnerRepository => ({
10 | getPartner: async (partnerId) => {
11 | const { partner } = await transfercheckApi.getPartner(partnerId);
12 |
13 | return adaptPartner(partner);
14 | },
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/RuleSnoozeRepository.ts:
--------------------------------------------------------------------------------
1 | import { type MarbleCoreApi } from '@app-builder/infra/marblecore-api';
2 | import { adaptRuleSnooze, type RuleSnooze } from '@app-builder/models/rule-snooze';
3 |
4 | export interface RuleSnoozeRepository {
5 | getRuleSnooze(ruleSnoozeId: string): Promise;
6 | }
7 |
8 | export function makeGetRuleSnoozeRepository() {
9 | return (marbleCoreApiClient: MarbleCoreApi): RuleSnoozeRepository => ({
10 | getRuleSnooze: async (ruleSnoozeId) => {
11 | const { snooze } = await marbleCoreApiClient.getRuleSnooze(ruleSnoozeId);
12 | return adaptRuleSnooze(snooze);
13 | },
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/SessionStorageRepositories/CsrfStorageRepository.ts:
--------------------------------------------------------------------------------
1 | import { createCookie } from '@remix-run/node';
2 |
3 | import { type SessionStorageRepositoryOptions } from './SessionStorageRepository';
4 |
5 | export function getCsrfCookie({ maxAge, secrets, secure }: SessionStorageRepositoryOptions) {
6 | return createCookie('csrf', {
7 | maxAge,
8 | sameSite: 'lax', // this helps with CSRF
9 | path: '/', // remember to add this so the cookie will work in all routes
10 | httpOnly: true,
11 | secrets,
12 | secure,
13 | });
14 | }
15 |
16 | export type CsrfCookie = ReturnType;
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/SessionStorageRepositories/SessionStorageRepository.ts:
--------------------------------------------------------------------------------
1 | export interface SessionStorageRepositoryOptions {
2 | maxAge: number;
3 | secrets: string[];
4 | secure: boolean;
5 | }
6 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/SessionStorageRepositories/index.ts:
--------------------------------------------------------------------------------
1 | export * from './AuthStorageRepository';
2 | export * from './CsrfStorageRepository';
3 | export * from './LngStorageRepository';
4 | export * from './SessionStorageRepository';
5 | export * from './ToastStorageRepository';
6 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/SignupStatusRepository.ts:
--------------------------------------------------------------------------------
1 | import { type MarbleCoreApi } from '@app-builder/infra/marblecore-api';
2 | import { type SignupStatus } from '@app-builder/models/signup-status';
3 |
4 | export interface SignupStatusRepository {
5 | getSignupStatus(): Promise;
6 | }
7 |
8 | export function makeGetSignupStatusRepository() {
9 | return (marbleCoreApiClient: MarbleCoreApi): SignupStatusRepository => ({
10 | async getSignupStatus() {
11 | const {
12 | migrations_run: migrationsRun,
13 | has_a_user: hasAUser,
14 | has_an_organization: hasAnOrganization,
15 | } = await marbleCoreApiClient.getSignupStatus();
16 | return { migrationsRun, hasAUser, hasAnOrganization };
17 | },
18 | });
19 | }
20 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/UserRepository.ts:
--------------------------------------------------------------------------------
1 | import { type MarbleCoreApi } from '@app-builder/infra/marblecore-api';
2 | import { adaptCurrentUser, type CurrentUser } from '@app-builder/models/user';
3 |
4 | export interface UserRepository {
5 | getCurrentUser(): Promise;
6 | }
7 |
8 | export function makeGetUserRepository() {
9 | return (marbleCoreApiClient: MarbleCoreApi): UserRepository => ({
10 | getCurrentUser: async () => {
11 | const { credentials } = await marbleCoreApiClient.getCredentials();
12 |
13 | return adaptCurrentUser(credentials);
14 | },
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/VersionRepository.ts:
--------------------------------------------------------------------------------
1 | import { type MarbleCoreApi } from '@app-builder/infra/marblecore-api';
2 | import { type AppVersions } from '@app-builder/models/version';
3 | import { getServerEnv } from '@app-builder/utils/environment';
4 |
5 | export interface VersionRepository {
6 | getBackendVersion(): Promise;
7 | }
8 |
9 | export function makeGetVersionRepository() {
10 | return (marbleCoreApiClient: MarbleCoreApi): VersionRepository => ({
11 | async getBackendVersion() {
12 | const { version: apiVersion } = await marbleCoreApiClient.getBackendVersion();
13 | return {
14 | appVersion: getServerEnv('APP_VERSION') ?? 'dev',
15 | apiVersion,
16 | };
17 | },
18 | });
19 | }
20 |
--------------------------------------------------------------------------------
/packages/app-builder/src/repositories/init.client.ts:
--------------------------------------------------------------------------------
1 | import { type FirebaseClientWrapper } from '@app-builder/infra/firebase';
2 |
3 | import {
4 | type AuthenticationClientRepository,
5 | getAuthenticationClientRepository,
6 | } from './AuthenticationRepository';
7 |
8 | export interface ClientRepositories {
9 | authenticationClientRepository: AuthenticationClientRepository;
10 | }
11 |
12 | interface MakeClientRepositoriesArgs {
13 | firebaseClient: FirebaseClientWrapper;
14 | }
15 |
16 | export function makeClientRepositories({
17 | firebaseClient,
18 | }: MakeClientRepositoriesArgs): ClientRepositories {
19 | return {
20 | authenticationClientRepository: getAuthenticationClientRepository(firebaseClient),
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/$.tsx:
--------------------------------------------------------------------------------
1 | import { initServerServices } from '@app-builder/services/init.server';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { type LoaderFunctionArgs } from '@remix-run/node';
4 |
5 | export async function loader({ request }: LoaderFunctionArgs) {
6 | const { authService } = initServerServices(request);
7 | await authService.isAuthenticated(request, {
8 | successRedirect: getRoute('/app-router'),
9 | failureRedirect: getRoute('/sign-in'),
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/_builder+/data+/_index.tsx:
--------------------------------------------------------------------------------
1 | import { initServerServices } from '@app-builder/services/init.server';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { type LoaderFunctionArgs } from '@remix-run/node';
4 |
5 | export async function loader({ request }: LoaderFunctionArgs) {
6 | const { authService } = initServerServices(request);
7 |
8 | return authService.isAuthenticated(request, {
9 | successRedirect: getRoute('/data/list'),
10 | failureRedirect: getRoute('/sign-in'),
11 | });
12 | }
13 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/_builder+/lists+/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { BreadCrumbLink, type BreadCrumbProps } from '@app-builder/components/Breadcrumbs';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { Outlet } from '@remix-run/react';
4 | import { useTranslation } from 'react-i18next';
5 | import { Icon } from 'ui-icons';
6 |
7 | export const handle = {
8 | BreadCrumbs: [
9 | ({ isLast }: BreadCrumbProps) => {
10 | const { t } = useTranslation(['navigation']);
11 |
12 | return (
13 |
14 |
15 | {t('navigation:lists')}
16 |
17 | );
18 | },
19 | ],
20 | };
21 |
22 | export default function ListsLayout() {
23 | return ;
24 | }
25 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/_builder+/scenarios+/$scenarioId+/i+/$iterationId+/_edit-view+/_index.tsx:
--------------------------------------------------------------------------------
1 | import { initServerServices } from '@app-builder/services/init.server';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { type LoaderFunctionArgs } from '@remix-run/node';
4 |
5 | export async function loader({ request, params }: LoaderFunctionArgs) {
6 | const { authService } = initServerServices(request);
7 | const { scenarioId, iterationId } = params;
8 | if (!scenarioId || !iterationId) {
9 | return {
10 | redirect: getRoute('/scenarios'),
11 | };
12 | }
13 |
14 | return authService.isAuthenticated(request, {
15 | successRedirect: getRoute('/scenarios/:scenarioId/i/:iterationId/trigger', {
16 | scenarioId,
17 | iterationId,
18 | }),
19 | failureRedirect: getRoute('/sign-in'),
20 | });
21 | }
22 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/_builder+/scenarios+/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { BreadCrumbLink, type BreadCrumbProps } from '@app-builder/components/Breadcrumbs';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { Outlet } from '@remix-run/react';
4 | import { useTranslation } from 'react-i18next';
5 | import { Icon } from 'ui-icons';
6 |
7 | export const handle = {
8 | BreadCrumbs: [
9 | ({ isLast }: BreadCrumbProps) => {
10 | const { t } = useTranslation(['navigation']);
11 |
12 | return (
13 |
14 |
15 | {t('navigation:scenarios')}
16 |
17 | );
18 | },
19 | ],
20 | };
21 |
22 | export default function ScenarioLayout() {
23 | return ;
24 | }
25 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/_index.tsx:
--------------------------------------------------------------------------------
1 | import { getRoute } from '@app-builder/utils/routes';
2 | import { redirect } from '@remix-run/node';
3 |
4 | export function loader() {
5 | return redirect(getRoute('/sign-in'));
6 | }
7 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/healthcheck.ts:
--------------------------------------------------------------------------------
1 | export function loader() {
2 | try {
3 | return new Response('OK');
4 | } catch (error: unknown) {
5 | console.log('healthcheck ❌', { error });
6 | return new Response('ERROR', { status: 500 });
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/ressources+/decisions+/list-scheduled-execution.tsx:
--------------------------------------------------------------------------------
1 | import { initServerServices } from '@app-builder/services/init.server';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { json, type LoaderFunctionArgs } from '@remix-run/node';
4 |
5 | export async function loader({ request }: LoaderFunctionArgs) {
6 | const { authService } = initServerServices(request);
7 | const { decision } = await authService.isAuthenticated(request, {
8 | failureRedirect: getRoute('/sign-in'),
9 | });
10 |
11 | const scheduledExecutions = await decision.listScheduledExecutions();
12 |
13 | return json(scheduledExecutions);
14 | }
15 |
16 | export type ScheduledExecutionsLoader = typeof loader;
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/transfercheck+/$.tsx:
--------------------------------------------------------------------------------
1 | import { initServerServices } from '@app-builder/services/init.server';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { type LoaderFunctionArgs } from '@remix-run/node';
4 |
5 | export async function loader({ request }: LoaderFunctionArgs) {
6 | const { authService } = initServerServices(request);
7 | return authService.isAuthenticated(request, {
8 | successRedirect: getRoute('/transfercheck'),
9 | failureRedirect: getRoute('/sign-in'),
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/transfercheck+/_index.tsx:
--------------------------------------------------------------------------------
1 | import { initServerServices } from '@app-builder/services/init.server';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { type LoaderFunctionArgs } from '@remix-run/node';
4 |
5 | export async function loader({ request }: LoaderFunctionArgs) {
6 | const { authService } = initServerServices(request);
7 | return authService.isAuthenticated(request, {
8 | successRedirect: getRoute('/transfercheck/transfers'),
9 | failureRedirect: getRoute('/sign-in'),
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/packages/app-builder/src/routes/transfercheck+/alerts+/_index.tsx:
--------------------------------------------------------------------------------
1 | import { initServerServices } from '@app-builder/services/init.server';
2 | import { getRoute } from '@app-builder/utils/routes';
3 | import { type LoaderFunctionArgs } from '@remix-run/node';
4 |
5 | export async function loader({ request }: LoaderFunctionArgs) {
6 | const { authService } = initServerServices(request);
7 | return authService.isAuthenticated(request, {
8 | successRedirect: getRoute('/transfercheck/alerts/received'),
9 | failureRedirect: getRoute('/sign-in'),
10 | });
11 | }
12 |
--------------------------------------------------------------------------------
/packages/app-builder/src/services/ast-node/getCustomListAccessCustomList.ts:
--------------------------------------------------------------------------------
1 | import { type IdLessAstNode } from '@app-builder/models';
2 | import { type CustomListAccessAstNode } from '@app-builder/models/astNode/custom-list';
3 | import { type CustomList } from '@app-builder/models/custom-list';
4 | import * as R from 'remeda';
5 |
6 | export function getCustomListAccessCustomList(
7 | astNode: IdLessAstNode,
8 | context: {
9 | customLists: CustomList[];
10 | },
11 | ) {
12 | return R.pipe(
13 | context.customLists,
14 | R.find(({ id }) => id === astNode.namedChildren.customListId.constant),
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/services/editor/editor-mode.tsx:
--------------------------------------------------------------------------------
1 | import { createSimpleContext } from '@app-builder/utils/create-context';
2 |
3 | export type EditorMode = 'edit' | 'view';
4 |
5 | const EditorModeContext = createSimpleContext('EditorModeContext');
6 |
7 | export const EditorModeContextProvider = EditorModeContext.Provider;
8 |
9 | export const useEditorMode = EditorModeContext.useValue;
10 |
--------------------------------------------------------------------------------
/packages/app-builder/src/services/i18n/i18next.d.ts:
--------------------------------------------------------------------------------
1 | import { type resources } from './resources/resources.server';
2 |
3 | declare module 'i18next' {
4 | interface CustomTypeOptions {
5 | defaultNS: typeof defaultNS;
6 | resources: (typeof resources)['en'];
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/app-builder/src/services/i18n/resources/resources.server.ts:
--------------------------------------------------------------------------------
1 | import { type supportedLngs } from '../i18n-config';
2 | import { ar } from './ar.server';
3 | import { en } from './en.server';
4 | import { fr } from './fr.server';
5 |
6 | export const resources = {
7 | en,
8 | fr,
9 | ar,
10 | } satisfies Record<(typeof supportedLngs)[number], typeof en>;
11 |
--------------------------------------------------------------------------------
/packages/app-builder/src/services/i18n/translation-keys/api-key.ts:
--------------------------------------------------------------------------------
1 | import { type ApiKey } from '@app-builder/models/api-keys';
2 |
3 | export function tKeyForApiKeyRole(role: ApiKey['role']) {
4 | switch (role) {
5 | case 'API_CLIENT':
6 | return 'settings:api_keys.role.api_client';
7 | default:
8 | return 'settings:api_keys.role.unknown';
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/app-builder/src/services/monitoring.ts:
--------------------------------------------------------------------------------
1 | import {
2 | isForbiddenHttpError,
3 | isNotFoundHttpError,
4 | isUnauthorizedHttpError,
5 | } from '@app-builder/models';
6 | import * as Sentry from '@sentry/remix';
7 |
8 | export function captureUnexpectedRemixError(error: unknown, name: string, request: Request) {
9 | if (isUnauthorizedHttpError(error) || isForbiddenHttpError(error) || isNotFoundHttpError(error)) {
10 | return;
11 | }
12 | if (error instanceof Error) {
13 | void Sentry.captureRemixServerException(error, name, request);
14 | } else {
15 | // Optionally capture non-Error objects
16 | Sentry.captureException(error);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/packages/app-builder/src/services/segment/SegmentScript.tsx:
--------------------------------------------------------------------------------
1 | export function SegmentScript({ script }: { script: string }) {
2 | return (
3 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/packages/app-builder/src/services/segment/segment.server.ts:
--------------------------------------------------------------------------------
1 | import { min } from '@segment/snippet';
2 |
3 | export function getSegmentScript(apiKey: string) {
4 | return min({
5 | apiKey,
6 |
7 | // TODO(GDPR): uncomment to lazy load segment after GDPR consent
8 | // Ressource to implement in house cookie consent banner: https://github.com/remix-run/examples/tree/main/gdpr-cookie-consent
9 | // load: false,
10 |
11 | // page tracking is done manually
12 | page: false,
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/packages/app-builder/src/services/user.ts:
--------------------------------------------------------------------------------
1 | import { filter, isTruthy, join, pipe } from 'remeda';
2 |
3 | export function getFullName(user?: { firstName?: string; lastName?: string }) {
4 | return pipe([user?.firstName, user?.lastName], filter(isTruthy), join(' '));
5 | }
6 |
--------------------------------------------------------------------------------
/packages/app-builder/src/services/validation/index.ts:
--------------------------------------------------------------------------------
1 | export * from './scenario-validation';
2 | export * from './scenario-validation-error-messages';
3 |
--------------------------------------------------------------------------------
/packages/app-builder/src/tailwind.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer utilities {
6 | .form-textarea {
7 | field-sizing: content;
8 | resize: false;
9 | }
10 |
11 | .border-inset {
12 | border-style: inset;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/app-builder/src/tests/setup/i18next.ts:
--------------------------------------------------------------------------------
1 | import { i18nConfig } from '@app-builder/services/i18n/i18n-config';
2 | import { resources } from '@app-builder/services/i18n/resources/resources.server';
3 | import i18next, { type TFunction } from 'i18next';
4 | import { initReactI18next } from 'react-i18next';
5 |
6 | export const i18nextTest = (await i18next.use(initReactI18next).init({
7 | ...i18nConfig,
8 | lng: 'en',
9 | fallbackLng: 'en',
10 | debug: false, // set to true to see more logs
11 | resources,
12 | // cf https://github.com/i18next/react-i18next/issues/1699
13 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
14 | })) as TFunction;
15 |
--------------------------------------------------------------------------------
/packages/app-builder/src/types/operand-options.ts:
--------------------------------------------------------------------------------
1 | import { type AstNode, type DataType } from '@app-builder/models';
2 | import { type OperandType } from '@app-builder/models/operand-type';
3 | import { type IconName } from 'ui-icons';
4 |
5 | export type OperandEditorContext = {
6 | searchValue?: string;
7 | initialAstNode: AstNode;
8 | };
9 |
10 | export type OperandOption = {
11 | createNode: (context: OperandEditorContext) => AstNode;
12 | dataType: DataType;
13 | operandType: OperandType;
14 | displayName: string;
15 | searchShortcut?: string;
16 | icon?: IconName;
17 | };
18 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/browser.ts:
--------------------------------------------------------------------------------
1 | export function getCurrentBrowser(userAgent: string) {
2 | if (userAgent.includes('Chrome')) {
3 | return 'Chrome';
4 | } else if (userAgent.includes('Firefox')) {
5 | return 'Firefox';
6 | } else if (userAgent.includes('Safari')) {
7 | return 'Safari';
8 | } else if (userAgent.includes('Edge')) {
9 | return 'Edge';
10 | } else if (userAgent.includes('Opera')) {
11 | return 'Opera';
12 | } else {
13 | return 'Unknown Browser';
14 | }
15 | }
16 |
17 | export type KnownBrowser = Exclude, 'Unknown Browser'>;
18 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export * from './use-callback-ref';
2 | export * from './use-interval';
3 | export * from './use-isomorphic-layout-effect';
4 | export * from './use-visibility-change';
5 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/hooks/use-callback-ref.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | /**
4 | * A custom hook that converts a callback to a ref to avoid triggering re-renders when passed as a
5 | * prop or avoid re-executing effects when passed as a dependency
6 | *
7 | * Inspired from @radix-ui/react-use-callback-ref
8 | */
9 |
10 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
11 | export function useCallbackRef any>(callback: T | undefined): T {
12 | const callbackRef = React.useRef(callback);
13 |
14 | React.useEffect(() => {
15 | callbackRef.current = callback;
16 | });
17 |
18 | // https://github.com/facebook/react/issues/19240
19 | return React.useMemo(() => ((...args) => callbackRef.current?.(...args)) as T, []);
20 | }
21 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/hooks/use-isomorphic-layout-effect.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useLayoutEffect } from 'react';
2 |
3 | export const useIsomorphicLayoutEffect =
4 | typeof window !== 'undefined' ? useLayoutEffect : useEffect;
5 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/hooks/use-visibility-change.ts:
--------------------------------------------------------------------------------
1 | import { useSyncExternalStore } from 'react';
2 |
3 | function subscribe(listener: (this: Document, ev: DocumentEventMap['visibilitychange']) => void) {
4 | document.addEventListener('visibilitychange', listener);
5 | return () => {
6 | document.removeEventListener('visibilitychange', listener);
7 | };
8 | }
9 |
10 | export function useVisibilityChange() {
11 | return useSyncExternalStore(
12 | subscribe,
13 | () => document.visibilityState,
14 | () => 'visible',
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/http/http-responses.ts:
--------------------------------------------------------------------------------
1 | import { json } from '@remix-run/node';
2 |
3 | import {
4 | BAD_REQUEST,
5 | CONFLICT,
6 | FORBIDDEN,
7 | INTERNAL_SERVER_ERROR,
8 | NOT_FOUND,
9 | UNAUTHORIZED,
10 | } from './http-status-codes';
11 |
12 | function errorResponse(status: number) {
13 | return (data: Data, init?: Omit) => {
14 | throw json(data, { status, ...init });
15 | };
16 | }
17 |
18 | export const badRequest = errorResponse(BAD_REQUEST);
19 | export const unauthorized = errorResponse(UNAUTHORIZED);
20 | export const forbidden = errorResponse(FORBIDDEN);
21 | export const notFound = errorResponse(NOT_FOUND);
22 | export const conflict = errorResponse(CONFLICT);
23 |
24 | export const internalServerError = errorResponse(INTERNAL_SERVER_ERROR);
25 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/list.ts:
--------------------------------------------------------------------------------
1 | export function reorder(list: TItem[], startIndex: number, endIndex: number): TItem[] {
2 | const result = [...list];
3 | const [removed] = result.splice(startIndex, 1);
4 | if (removed) result.splice(endIndex, 0, removed);
5 | return result;
6 | }
7 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/parse.ts:
--------------------------------------------------------------------------------
1 | import { knownDataTypeSchema } from './schema/dataTypeSchema';
2 |
3 | export function parseUnknownData(value: unknown) {
4 | const parseResult = knownDataTypeSchema.safeParse(value);
5 | if (parseResult.success) {
6 | return parseResult.data;
7 | }
8 | return { type: 'unknown' as const, value };
9 | }
10 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/preferences-cookies/config.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod';
2 |
3 | export const COOKIE_NAME = 'u-prefs';
4 |
5 | export type PreferencesCookie = {
6 | menuExpd: boolean;
7 | };
8 | export const PreferencesCookieSchema = z.object({
9 | menuExpd: z.preprocess((val) => val === 1, z.boolean()),
10 | });
11 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/schema/dataTypeSchema.ts:
--------------------------------------------------------------------------------
1 | import * as z from 'zod';
2 |
3 | const protocolWhitelist = ['http:', 'https:'];
4 | export const urlDataTypeSchema = z.string().refine((value) => {
5 | try {
6 | const url = new URL(value);
7 | return protocolWhitelist.includes(url.protocol);
8 | } catch {
9 | return false;
10 | }
11 | });
12 |
13 | export const dateTimeDataTypeSchema = z.string().datetime({ offset: true });
14 |
15 | export const knownDataTypeSchema = z.union([
16 | urlDataTypeSchema.transform((value) => ({
17 | type: 'url' as const,
18 | value,
19 | })),
20 | dateTimeDataTypeSchema.transform((value) => ({
21 | type: 'datetime' as const,
22 | value,
23 | })),
24 | z.number().transform((value) => ({
25 | type: 'number' as const,
26 | value,
27 | })),
28 | ]);
29 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/search/filter.ts:
--------------------------------------------------------------------------------
1 | export { matchSorter } from 'match-sorter';
2 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/search/highlight.ts:
--------------------------------------------------------------------------------
1 | import match from 'autosuggest-highlight/match/index.js';
2 | import parse from 'autosuggest-highlight/parse/index.js';
3 |
4 | const defaultMatchOptions = {
5 | insideWords: true,
6 | findAllOccurrences: false,
7 | requireMatchAll: false,
8 | };
9 |
10 | export function adaptHighlightedParts(text: string, query: string) {
11 | const matches = match(text, query, defaultMatchOptions);
12 | return parse(text, matches);
13 | }
14 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/search/index.ts:
--------------------------------------------------------------------------------
1 | export * from './filter';
2 | export * from './highlight';
3 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/sleep.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Sleep for a given number of milliseconds.
3 | *
4 | * This is a useful utility function for testing.
5 | */
6 | export function sleep(ms: number) {
7 | return new Promise((resolve) => setTimeout(resolve, ms));
8 | }
9 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/types.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
2 | type Contra = T extends any ? (arg: T) => void : never;
3 |
4 | type InferContra = [T] extends [(arg: infer I) => void] ? I : never;
5 |
6 | type PickOne = InferContra>>>;
7 |
8 | export type UnionToArray =
9 | PickOne extends infer U
10 | ? Exclude extends never
11 | ? [T]
12 | : [...UnionToArray>, U]
13 | : never;
14 |
--------------------------------------------------------------------------------
/packages/app-builder/src/utils/unknown-error.ts:
--------------------------------------------------------------------------------
1 | export class UnknownError extends Error {
2 | constructor(error: unknown) {
3 | super(`Internal error: ${error instanceof Error ? error.message : 'unknown error'}`);
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/app-builder/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from 'tailwindcss';
2 |
3 | import sharedTailwindConfig from '../tailwind-preset/src/tailwind.config';
4 |
5 | export default {
6 | presets: [sharedTailwindConfig],
7 | content: ['./src/**/*.{ts,tsx,jsx,js}', '../ui-design-system/src/**/*.{ts,tsx,jsx,js}'],
8 | } satisfies Config;
9 |
--------------------------------------------------------------------------------
/packages/app-builder/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
4 | "compilerOptions": {
5 | "types": ["@remix-run/node", "vite/client", "vitest/globals"],
6 | "jsx": "react-jsx",
7 | "skipLibCheck": true,
8 | "module": "ESNext",
9 | "moduleResolution": "Bundler"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/app-builder/types/global.d.ts:
--------------------------------------------------------------------------------
1 | import { type AnalyticsSnippet } from '@segment/analytics-next';
2 |
3 | declare global {
4 | interface Window {
5 | /**
6 | * Segment
7 | */
8 | analytics?: AnalyticsSnippet;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/packages/eslint-config/README.md:
--------------------------------------------------------------------------------
1 | # eslint-config
2 |
3 | This is configs for [ESLint](https://eslint.org/) that provides a set of opinionated defaults that we use at Marble.
4 |
--------------------------------------------------------------------------------
/packages/eslint-config/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import defaultConfig from './default.mjs';
2 |
3 | export default defaultConfig;
4 |
--------------------------------------------------------------------------------
/packages/eslint-config/storybook.mjs:
--------------------------------------------------------------------------------
1 | import eslintStorybook from 'eslint-plugin-storybook';
2 |
3 | /** @type {import('eslint').Linter.Config} */
4 | export default [
5 | {
6 | files: ['*.stories.{ts,tsx}'],
7 | plugins: {
8 | storybook: eslintStorybook,
9 | },
10 | rules: eslintStorybook.configs.recommended,
11 | },
12 | ];
13 |
--------------------------------------------------------------------------------
/packages/eslint-config/tailwindcss.mjs:
--------------------------------------------------------------------------------
1 | import eslintTailwindcss from 'eslint-plugin-tailwindcss';
2 |
3 | /** @type {(configPath: string) => import('eslint').Linter.Config} */
4 | const config = (configPath) => {
5 | return [
6 | ...eslintTailwindcss.configs['flat/recommended'],
7 | {
8 | settings: {
9 | tailwindcss: {
10 | config: configPath,
11 | },
12 | },
13 | rules: {
14 | 'tailwindcss/classnames-order': 'off',
15 | },
16 | },
17 | ];
18 | };
19 |
20 | export default config;
21 |
--------------------------------------------------------------------------------
/packages/eslint-config/vitest.mjs:
--------------------------------------------------------------------------------
1 | import eslintVitest from '@vitest/eslint-plugin';
2 | import eslintTestingLibrary from 'eslint-plugin-testing-library';
3 |
4 | /** @type {import('eslint').Linter.Config} */
5 | export default [
6 | {
7 | files: ['*.test.{ts,tsx}'],
8 | plugins: {
9 | vitest: eslintVitest,
10 | 'testing-library': eslintTestingLibrary,
11 | },
12 | rules: {
13 | ...eslintVitest.configs.recommended,
14 | ...eslintTestingLibrary.configs['flat/react'],
15 | },
16 | },
17 | ];
18 |
--------------------------------------------------------------------------------
/packages/marble-api/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import typescriptConfig from '@marble/eslint-config/typescript.mjs';
2 |
3 | export default [...typescriptConfig, { ignores: ['src/generated'] }];
4 |
--------------------------------------------------------------------------------
/packages/marble-api/openapis/marblecore-api/version.yml:
--------------------------------------------------------------------------------
1 | /version:
2 | get:
3 | summary: Retrieves the backend version
4 | operationId: getBackendVersion
5 | responses:
6 | '200':
7 | description: The version of the backend
8 | content:
9 | application/json:
10 | schema:
11 | $ref: '#/components/schemas/VersionDto'
12 | components:
13 | schemas:
14 | VersionDto:
15 | type: object
16 | required:
17 | - version
18 | properties:
19 | version:
20 | type: string
21 |
--------------------------------------------------------------------------------
/packages/marble-api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "marble-api",
3 | "version": "1.0.0",
4 | "description": "",
5 | "sideEffect": false,
6 | "type": "module",
7 | "scripts": {
8 | "lint": "eslint .",
9 | "type-check": "pnpm exec tsc --noEmit",
10 | "generate-api": "swagger-cli validate openapis/marblecore-api.yaml && tsx scripts/generate.ts"
11 | },
12 | "devDependencies": {
13 | "@marble/eslint-config": "workspace:*",
14 | "@types/node": "22.13.10",
15 | "oazapfts": "^6.2.1",
16 | "ora": "^8.2.0",
17 | "swagger-cli": "^4.0.4",
18 | "tailwind-preset": "^1.0.8",
19 | "tsx": "^4.19.3"
20 | },
21 | "dependencies": {
22 | "@oazapfts/runtime": "^1.0.4"
23 | },
24 | "author": "",
25 | "license": "ISC"
26 | }
27 |
--------------------------------------------------------------------------------
/packages/marble-api/src/helpers/index.ts:
--------------------------------------------------------------------------------
1 | export * from './authorization';
2 |
--------------------------------------------------------------------------------
/packages/marble-api/src/index.ts:
--------------------------------------------------------------------------------
1 | export * as featureAccessApi from './generated/feature-access-api';
2 | export * as marblecoreApi from './generated/marblecore-api';
3 | export * from './generated/marblecore-api';
4 | export * as transfercheckApi from './generated/transfercheck-api';
5 | export * from './helpers';
6 |
--------------------------------------------------------------------------------
/packages/marble-api/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "types": ["node"]
5 | },
6 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"],
7 | "exclude": []
8 | }
9 |
--------------------------------------------------------------------------------
/packages/shared/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import reactConfig from '@marble/eslint-config/react.mjs';
2 | import tailwindcssConfig from '@marble/eslint-config/tailwindcss.mjs';
3 | import vitestConfig from '@marble/eslint-config/vitest.mjs';
4 | import { join } from 'path';
5 |
6 | const tailwindConfigPath = join(import.meta.dirname, 'tailwind.config.ts');
7 |
8 | export default [
9 | ...reactConfig,
10 | ...tailwindcssConfig(tailwindConfigPath),
11 | ...vitestConfig,
12 | { ignores: ['build'] },
13 | ];
14 |
--------------------------------------------------------------------------------
/packages/shared/src/index.ts:
--------------------------------------------------------------------------------
1 | // export * from './component-state';
2 | export * from './simple-context';
3 | export * from './use-callback-ref';
4 | export * from './use-ref-fn';
5 |
--------------------------------------------------------------------------------
/packages/shared/src/use-callback-ref.ts:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | /**
4 | * A custom hook that converts a callback to a ref to avoid triggering re-renders when passed as a
5 | * prop or avoid re-executing effects when passed as a dependency
6 | *
7 | * Inspired from @radix-ui/react-use-callback-ref
8 | */
9 |
10 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
11 | export function useCallbackRef any>(callback: T | undefined): T {
12 | const callbackRef = React.useRef(callback);
13 |
14 | React.useEffect(() => {
15 | callbackRef.current = callback;
16 | });
17 |
18 | // https://github.com/facebook/react/issues/19240
19 | return React.useMemo(() => ((...args) => callbackRef.current?.(...args)) as T, []);
20 | }
21 |
--------------------------------------------------------------------------------
/packages/shared/src/use-ref-fn.ts:
--------------------------------------------------------------------------------
1 | import { type MutableRefObject, useRef } from 'react';
2 |
3 | const UNINIT_VALUE = Symbol('uninitialized_value');
4 |
5 | /**
6 | * Create a ref with an initializer function which is not re-executed after initialization
7 | *
8 | * @param initializer The initializer function, should return you value
9 | * @returns A React RefObject with your value
10 | */
11 | export function useRefFn(initializer: () => T): MutableRefObject {
12 | const cachedRef = useRef(UNINIT_VALUE);
13 |
14 | let refValue = cachedRef.current;
15 | if (refValue === UNINIT_VALUE) {
16 | refValue = initializer();
17 | cachedRef.current = refValue;
18 | }
19 |
20 | return useRef(refValue);
21 | }
22 |
--------------------------------------------------------------------------------
/packages/shared/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "types": ["vitest/globals"],
5 | "jsx": "react-jsx"
6 | },
7 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/tailwind-preset/README.md:
--------------------------------------------------------------------------------
1 | # tailwind-preset
2 |
3 | This is a preset for [Tailwind CSS](https://tailwindcss.com/) that provides a set of opinionated defaults that we use at Marble.
4 |
5 | This config is shared between all our projects.
6 |
--------------------------------------------------------------------------------
/packages/tailwind-preset/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import typescriptConfig from '@marble/eslint-config/typescript.mjs';
2 |
3 | export default typescriptConfig;
4 |
--------------------------------------------------------------------------------
/packages/tailwind-preset/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tailwind-preset",
3 | "version": "1.0.0",
4 | "description": "Shared config that group all specific design tokens for Marble",
5 | "sideEffect": false,
6 | "type": "module",
7 | "scripts": {
8 | "lint": "eslint .",
9 | "type-check": "pnpm exec tsc --noEmit"
10 | },
11 | "devDependencies": {
12 | "@marble/eslint-config": "workspace:*",
13 | "tailwindcss": "3.4.14",
14 | "tailwindcss-animate": "^1.0.7",
15 | "tailwindcss-radix": "^4.0.2"
16 | },
17 | "license": "ISC"
18 | }
19 |
--------------------------------------------------------------------------------
/packages/tailwind-preset/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {},
4 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"],
5 | "exclude": []
6 | }
7 |
--------------------------------------------------------------------------------
/packages/tests/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | /test-results/
3 | /playwright-report/
4 | /blob-report/
5 | /playwright/.cache/
6 |
--------------------------------------------------------------------------------
/packages/tests/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import typescriptConfig from '@marble/eslint-config/typescript.mjs';
2 |
3 | export default typescriptConfig;
4 |
--------------------------------------------------------------------------------
/packages/tests/fixtures/index.ts:
--------------------------------------------------------------------------------
1 | import { mergeExpects, mergeTests } from '@playwright/test';
2 |
3 | import * as authentication from './authentication';
4 |
5 | export const test = mergeTests(authentication.test);
6 | export const expect = mergeExpects(authentication.expect);
7 |
--------------------------------------------------------------------------------
/packages/tests/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tests",
3 | "version": "1.0.0",
4 | "description": "",
5 | "sideEffect": false,
6 | "type": "module",
7 | "scripts": {
8 | "test": "playwright test",
9 | "test:ui": "playwright test --ui",
10 | "lint": "eslint ."
11 | },
12 | "keywords": [],
13 | "author": "",
14 | "license": "ISC",
15 | "devDependencies": {
16 | "@marble/eslint-config": "workspace:*",
17 | "@playwright/test": "^1.51.1",
18 | "@types/node": "22.13.10"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/tests/page-object-models/utils.ts:
--------------------------------------------------------------------------------
1 | import { test } from '@playwright/test';
2 |
3 | /**
4 | * A decorator that wraps a method in a test.step call, with box: true.
5 | * More info at https://playwright.dev/docs/api/class-test#test-step
6 | */
7 | export function boxedStep(
8 | // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
9 | target: Function,
10 | context: ClassMethodDecoratorContext,
11 | ) {
12 | return function replacementMethod(this: NonNullable, ...args: unknown[]) {
13 | const name = this.constructor.name + '.' + context.name.toString();
14 | return test.step(
15 | name,
16 | async () => {
17 | return await target.call(this, ...args);
18 | },
19 | { box: true },
20 | );
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/packages/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "types": ["node"]
5 | },
6 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/typescript-utils/README.md:
--------------------------------------------------------------------------------
1 | # typescript-utils
2 |
3 | This library regroup some typescript utilities.
4 |
--------------------------------------------------------------------------------
/packages/typescript-utils/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import typescriptConfig from '@marble/eslint-config/typescript.mjs';
2 |
3 | export default typescriptConfig;
4 |
--------------------------------------------------------------------------------
/packages/typescript-utils/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "typescript-utils",
3 | "version": "1.0.0",
4 | "description": "",
5 | "sideEffect": false,
6 | "type": "module",
7 | "devDependencies": {
8 | "@marble/eslint-config": "workspace:*",
9 | "@types/node": "22.13.10"
10 | },
11 | "scripts": {
12 | "lint": "eslint .",
13 | "type-check": "pnpm exec tsc --noEmit"
14 | },
15 | "author": "",
16 | "license": "ISC"
17 | }
18 |
--------------------------------------------------------------------------------
/packages/typescript-utils/src/assert-never.ts:
--------------------------------------------------------------------------------
1 | import { isomorphicGetEnv } from './isomorphic-env';
2 |
3 | /**
4 | * Used to assert that a value is never.
5 | * Particularly useful for exhaustiveness checks (ex: in switch statements default).
6 | */
7 | export function assertNever(
8 | prefix: string,
9 | x: never,
10 | ): // @ts-expect-error assertNever
11 | never {
12 | const env = isomorphicGetEnv('NODE_ENV') ?? isomorphicGetEnv('ENV') ?? 'development';
13 | if (env !== 'production') {
14 | console.error(`[AssertNever]: ${prefix}`, x);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/typescript-utils/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './assert-never';
2 | export * from './noop';
3 | export * from './utility-types';
4 |
--------------------------------------------------------------------------------
/packages/typescript-utils/src/isomorphic-env.ts:
--------------------------------------------------------------------------------
1 | export function isomorphicGetEnv(envVarName: string): string | undefined {
2 | if (typeof window !== 'undefined') {
3 | //@ts-expect-error ENV is a custom global variable injected in browser
4 | const clientEnv = window.ENV;
5 | if (clientEnv === undefined) {
6 | throw new Error('In a browser environment, window.ENV should be defined by convention.');
7 | }
8 | return clientEnv[envVarName];
9 | }
10 | if (typeof process !== 'undefined') {
11 | return process.env[envVarName];
12 | }
13 | throw new Error('Unknown environment');
14 | }
15 |
--------------------------------------------------------------------------------
/packages/typescript-utils/src/noop.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line @typescript-eslint/no-empty-function
2 | export function noop() {}
3 |
--------------------------------------------------------------------------------
/packages/typescript-utils/src/utility-types.ts:
--------------------------------------------------------------------------------
1 | export type RequiredKeys = Omit & Required>;
2 |
3 | export type FunctionKeys = {
4 | // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
5 | [P in keyof T]: T[P] extends Function ? P : never;
6 | }[keyof T];
7 |
--------------------------------------------------------------------------------
/packages/typescript-utils/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "types": ["node"]
5 | },
6 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"],
7 | "exclude": []
8 | }
9 |
--------------------------------------------------------------------------------
/packages/ui-design-system/.gitignore:
--------------------------------------------------------------------------------
1 | storybook-static
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/main.ts:
--------------------------------------------------------------------------------
1 | import type { StorybookConfig } from '@storybook/react-vite';
2 |
3 | const config: StorybookConfig = {
4 | docs: {
5 | autodocs: 'tag',
6 | },
7 | core: {
8 | disableTelemetry: true,
9 | },
10 | stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
11 | addons: [
12 | '@storybook/addon-links',
13 | '@storybook/addon-essentials',
14 | '@storybook/addon-interactions',
15 | ],
16 | staticDirs: ['./public'],
17 | framework: {
18 | name: '@storybook/react-vite',
19 | options: {},
20 | },
21 | };
22 |
23 | export default config;
24 |
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/preview.ts:
--------------------------------------------------------------------------------
1 | import './tailwind-imports.css';
2 | import './public/fonts/Inter/inter.css';
3 |
4 | import type { Preview } from '@storybook/react';
5 |
6 | const preview: Preview = {
7 | parameters: {
8 | controls: {
9 | matchers: {
10 | color: /(background|color)$/i,
11 | date: /Date$/,
12 | },
13 | },
14 | },
15 | };
16 |
17 | export default preview;
18 |
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Black.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Black.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Black.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Black.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-BlackItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-BlackItalic.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-BlackItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-BlackItalic.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Bold.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Bold.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-BoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-BoldItalic.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-BoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-BoldItalic.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraBold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraBold.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraBold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraBold.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraBoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraBoldItalic.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraBoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraBoldItalic.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraLight.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraLight.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraLight.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraLight.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraLightItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraLightItalic.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraLightItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ExtraLightItalic.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Italic.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Italic.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Light.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Light.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-LightItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-LightItalic.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-LightItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-LightItalic.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Medium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Medium.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Medium.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-MediumItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-MediumItalic.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-MediumItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-MediumItalic.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Regular.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Regular.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-SemiBold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-SemiBold.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-SemiBold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-SemiBold.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-SemiBoldItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-SemiBoldItalic.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-SemiBoldItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-SemiBoldItalic.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Thin.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Thin.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Thin.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-Thin.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ThinItalic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ThinItalic.woff
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ThinItalic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-ThinItalic.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-italic.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-italic.var.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-roman.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter-roman.var.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/public/fonts/Inter/Inter.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-design-system/.storybook/public/fonts/Inter/Inter.var.woff2
--------------------------------------------------------------------------------
/packages/ui-design-system/.storybook/tailwind-imports.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/packages/ui-design-system/README.md:
--------------------------------------------------------------------------------
1 | # ui-design-system
2 |
3 | This library regroup the Marble design system implementation.
4 |
5 | ## Develop
6 |
7 | To develop locally, launch the Storybook :
8 |
9 | ```sh
10 | pnpm --filter ui-design-system run storybook
11 | ```
12 |
13 | You can start editing / add components in isolation
14 |
15 | ### Add a new component
16 |
17 | > Try to use Ariakit in favour of Radix to create new components
18 |
19 | 1. Create a folder following the convention (look at existing components)
20 |
21 | 2. Create a story and visualize it in Storybook
22 |
23 | 3. Iterate on the component until it's ready (don't forget to add tests)
24 |
25 | 4. Export your component in `src/index.ts`
26 |
--------------------------------------------------------------------------------
/packages/ui-design-system/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import reactConfig from '@marble/eslint-config/react.mjs';
2 | import storybookConfig from '@marble/eslint-config/storybook.mjs';
3 | import tailwindcssConfig from '@marble/eslint-config/tailwindcss.mjs';
4 | import { join } from 'path';
5 |
6 | const tailwindConfigPath = join(import.meta.dirname, 'tailwind.config.ts');
7 |
8 | export default [
9 | ...reactConfig,
10 | ...tailwindcssConfig(tailwindConfigPath),
11 | ...storybookConfig,
12 | { ignores: ['storybook-static/'] },
13 | ];
14 |
--------------------------------------------------------------------------------
/packages/ui-design-system/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Avatar/Avatar.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 |
3 | import { Avatar } from './Avatar';
4 |
5 | describe('Avatar', () => {
6 | it('should render fallback successfully', async () => {
7 | render();
8 |
9 | expect(await screen.findByText('CR')).toBeInTheDocument();
10 | });
11 |
12 | it('should render fallback if img src is wrong', async () => {
13 | render();
14 |
15 | expect(await screen.findByText('CR')).toBeInTheDocument();
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Button/Button.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import { userEvent } from '@testing-library/user-event';
3 |
4 | import { Button } from './Button';
5 |
6 | describe('Button', () => {
7 | it('should render successfully', () => {
8 | render();
9 |
10 | const button = screen.getByRole('button', { name: /test/i });
11 | expect(button).toBeInTheDocument();
12 | });
13 |
14 | it('should handle click', async () => {
15 | const onClick = vi.fn();
16 | render(
17 | ,
20 | );
21 |
22 | const button = screen.getByRole('button', { name: /test/i });
23 | await userEvent.click(button);
24 | expect(onClick).toHaveBeenCalled();
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Checkbox/Checkbox.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import { userEvent } from '@testing-library/user-event';
3 |
4 | import { Checkbox } from './Checkbox';
5 |
6 | describe('Checkbox', () => {
7 | it('should render successfully', () => {
8 | render();
9 | expect(screen.getByLabelText('checkbox')).toBeInTheDocument();
10 | });
11 |
12 | it('should check correctly', async () => {
13 | render();
14 |
15 | const checkbox = screen.getByLabelText('checkbox');
16 | expect(checkbox).not.toBeChecked();
17 |
18 | await userEvent.click(checkbox);
19 | expect(screen.getByLabelText('checkbox')).toBeChecked();
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Code/Code.stories.tsx:
--------------------------------------------------------------------------------
1 | // Code.stories.tsx
2 |
3 | import { type Meta, type StoryObj } from '@storybook/react';
4 |
5 | import Code from './Code';
6 |
7 | const meta: Meta = {
8 | title: 'Code',
9 | component: Code,
10 | tags: ['autodocs'],
11 | };
12 |
13 | export default meta;
14 |
15 | type Story = StoryObj;
16 |
17 | export const Default: Story = {
18 | args: {
19 | children: 'console.log("Hello, world!")',
20 | },
21 | };
22 | export const Multiline: Story = {
23 | args: {
24 | children: `function greet(name) {
25 | return "Hello, " + name + "!";
26 | }
27 |
28 | console.log(greet("world"));`,
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Code/Code.tsx:
--------------------------------------------------------------------------------
1 | import type React from 'react';
2 |
3 | interface CodeProps {
4 | children?: React.ReactNode;
5 | }
6 |
7 | const Code: React.FC = ({ children }) => (
8 | {children}
9 | );
10 |
11 | export default Code;
12 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/HiddenInputs/HiddenInputs.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 |
3 | import { HiddenInputs } from './HiddenInputs';
4 |
5 | describe('HiddenInputs', () => {
6 | it('should render hidden input successfully', () => {
7 | render();
8 | const input = screen.getByDisplayValue('hiddenInput');
9 | expect(input).toBeInTheDocument();
10 | expect(input).not.toBeVisible();
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/HiddenInputs/HiddenInputs.tsx:
--------------------------------------------------------------------------------
1 | export function HiddenInputs<
2 | Props extends Record['value']>,
3 | >(props: Props) {
4 | return (
5 | <>
6 | {Object.entries(props)
7 | /**
8 | * undefined value is sent as "name=&" in FormData and parsed as "" with qs on the server
9 | * It leads to bad DX when validating with zod so we remove them from the form
10 | */
11 | .filter(([_, value]) => value !== undefined)
12 | .map(([name, value]) => (
13 |
14 | ))}
15 | >
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Input/Input.constants.tsx:
--------------------------------------------------------------------------------
1 | export const inputBorderColor = ['greyfigma-90', 'redfigma-87', 'redfigma-47'] as const;
2 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Input/Input.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import { userEvent } from '@testing-library/user-event';
3 |
4 | import { Input } from './Input';
5 |
6 | describe('Input', () => {
7 | it('should render successfully', () => {
8 | render();
9 |
10 | const input = screen.getByLabelText('input');
11 | expect(input).toBeInTheDocument();
12 | });
13 |
14 | it('should be editable', async () => {
15 | render();
16 |
17 | const input = screen.getByPlaceholderText('placeholder');
18 | expect(input).toBeInTheDocument();
19 |
20 | await userEvent.type(input, 'input text');
21 | expect(input).toHaveValue('input text');
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Kbd/Kbd.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 |
3 | import { Kbd } from './Kbd';
4 |
5 | describe('Kbd', () => {
6 | it('should render with html tag', () => {
7 | render(A);
8 | const kbd = screen.getByText('A');
9 | expect(kbd).toBeInTheDocument();
10 | expect(kbd.tagName).toBe('KBD');
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Kbd/Kbd.stories.tsx:
--------------------------------------------------------------------------------
1 | import { type Meta, type StoryFn } from '@storybook/react';
2 |
3 | import { Kbd } from './Kbd';
4 |
5 | const Story: Meta = {
6 | component: Kbd,
7 | title: 'Kbd',
8 | };
9 | export default Story;
10 |
11 | export const Default: StoryFn = () => (
12 |
13 | ▲
14 | ▼
15 | to navigate
16 |
17 | );
18 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Kbd/Kbd.tsx:
--------------------------------------------------------------------------------
1 | import clsx from 'clsx';
2 |
3 | export function Kbd({ className, ...props }: React.ComponentProps<'kbd'>) {
4 | return (
5 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Select/Select.constants.tsx:
--------------------------------------------------------------------------------
1 | export const selectBorderColor = ['greyfigma-90', 'redfigma-47', 'redfigma-87'] as const;
2 | export const selectBorder = ['rounded', 'square'] as const;
3 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Separator/Separator.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 |
3 | import { Separator } from './Separator';
4 |
5 | describe('Separator', () => {
6 | it('should render with role="none"', () => {
7 | render();
8 | // it should be close by default
9 | expect(screen.getByRole('none')).toBeInTheDocument();
10 | });
11 |
12 | it('should render with role="separator"', () => {
13 | render();
14 | // it should be close by default
15 | expect(screen.getByRole('separator')).toBeInTheDocument();
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Separator/Separator.tsx:
--------------------------------------------------------------------------------
1 | import { Separator as RawSeparator, type SeparatorProps } from '@radix-ui/react-separator';
2 | import clsx from 'clsx';
3 |
4 | export function Separator({ className, ...props }: SeparatorProps) {
5 | return (
6 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Switch/Switch.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import { userEvent } from '@testing-library/user-event';
3 |
4 | import { Switch } from './Switch';
5 |
6 | describe('Switch', () => {
7 | it('should render successfully', () => {
8 | render();
9 | expect(screen.getByLabelText('switch')).toBeInTheDocument();
10 | });
11 |
12 | it('should check correctly', async () => {
13 | render();
14 |
15 | const switchButton = screen.getByLabelText('switch');
16 | expect(switchButton).not.toBeChecked();
17 |
18 | await userEvent.click(switchButton);
19 | expect(screen.getByLabelText('switch')).toBeChecked();
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Switch/Switch.stories.tsx:
--------------------------------------------------------------------------------
1 | import * as Label from '@radix-ui/react-label';
2 | import { type Meta, type StoryFn } from '@storybook/react';
3 |
4 | import { Switch } from './Switch';
5 |
6 | const Story: Meta = {
7 | component: Switch,
8 | title: 'Switch',
9 | args: { disabled: false },
10 | argTypes: {
11 | disabled: { control: 'boolean' },
12 | },
13 | };
14 | export default Story;
15 |
16 | export const WithoutLabel: StoryFn = (args) => ;
17 |
18 | export const WithLabel: StoryFn = (args) => (
19 |
25 | );
26 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Tag/Tag.constants.tsx:
--------------------------------------------------------------------------------
1 | export const tagColors = [
2 | 'purple',
3 | 'blue',
4 | 'green',
5 | 'red',
6 | 'yellow',
7 | 'orange',
8 | 'grey',
9 | 'grey-light',
10 | ] as const;
11 | export const tagSize = ['small', 'big'] as const;
12 | export const tagBorder = ['rounded', 'square'] as const;
13 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Tag/Tag.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 |
3 | import { Tag } from './Tag';
4 |
5 | describe('Tag', () => {
6 | it('should render successfully', () => {
7 | render(Tag);
8 |
9 | expect(screen.getByText('Tag')).toBeInTheDocument();
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/TextArea/TextArea.spec.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import { userEvent } from '@testing-library/user-event';
3 |
4 | import { TextArea } from './TextArea';
5 |
6 | describe('TextArea', () => {
7 | it('should render successfully', () => {
8 | render();
9 |
10 | const textarea = screen.getByLabelText('textarea');
11 | expect(textarea).toBeInTheDocument();
12 | });
13 |
14 | it('should be editable', async () => {
15 | render();
16 |
17 | const textarea = screen.getByPlaceholderText('placeholder');
18 | expect(textarea).toBeInTheDocument();
19 |
20 | await userEvent.type(textarea, 'input text');
21 | expect(textarea).toHaveValue('input text');
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/Tooltip/Tooltip.stories.tsx:
--------------------------------------------------------------------------------
1 | import { type Meta, type StoryFn } from '@storybook/react';
2 |
3 | import { Tooltip } from './Tooltip';
4 |
5 | const Story: Meta = {
6 | component: Tooltip.Default,
7 | title: 'Tooltip',
8 | args: {
9 | content: 'Tooltip...',
10 | },
11 | argTypes: {
12 | content: { type: 'string' },
13 | },
14 | decorators: [(story) => {story()}],
15 | };
16 | export default Story;
17 |
18 | const Template: StoryFn = (args) => (
19 |
20 | hover me!
21 |
22 | );
23 |
24 | export const Primary = Template.bind({});
25 | Primary.args = {};
26 |
--------------------------------------------------------------------------------
/packages/ui-design-system/src/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from 'clsx';
2 | import { twMerge } from 'tailwind-merge';
3 |
4 | export const cn = (...classLists: ClassValue[]) => twMerge(clsx(classLists));
5 |
6 | export const assertValue = (value: T | undefined, msg: string): T => {
7 | if (value !== undefined) {
8 | return value;
9 | }
10 | throw new Error(msg);
11 | };
12 |
--------------------------------------------------------------------------------
/packages/ui-design-system/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from 'tailwindcss';
2 |
3 | import sharedTailwindConfig from '../tailwind-preset/src/tailwind.config';
4 |
5 | export default {
6 | presets: [sharedTailwindConfig],
7 | content: ['./src/**/*.{ts,tsx,html}'],
8 | } satisfies Config;
9 |
--------------------------------------------------------------------------------
/packages/ui-design-system/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "types": ["vitest/globals"],
5 | "jsx": "react-jsx"
6 | },
7 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx", ".storybook/**/*.ts"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/ui-design-system/types/svg.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.svg' {
2 | let asset: string;
3 | export default asset;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/ui-design-system/vite.config.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import { defineConfig } from 'vite';
3 | import viteTsConfigPaths from 'vite-tsconfig-paths';
4 |
5 | export default defineConfig({
6 | plugins: [viteTsConfigPaths()],
7 | test: {
8 | globals: true,
9 | environment: 'jsdom',
10 | setupFiles: ['vitest-setup.ts'],
11 | },
12 | });
13 |
--------------------------------------------------------------------------------
/packages/ui-design-system/vitest-setup.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom';
2 |
3 | class MockPointerEvent extends Event {
4 | button: number;
5 | ctrlKey: boolean;
6 | pointerType: string;
7 |
8 | constructor(type: string, props: PointerEventInit) {
9 | super(type, props);
10 | this.button = props.button || 0;
11 | this.ctrlKey = props.ctrlKey || false;
12 | this.pointerType = props.pointerType || 'mouse';
13 | }
14 | }
15 |
16 | //@ts-expect-error Mock is missing some properties but the current implementation cover our needs
17 | window.PointerEvent = MockPointerEvent;
18 | window.HTMLElement.prototype.scrollIntoView = vi.fn();
19 | window.HTMLElement.prototype.releasePointerCapture = vi.fn();
20 | window.HTMLElement.prototype.hasPointerCapture = vi.fn();
21 |
--------------------------------------------------------------------------------
/packages/ui-icons/docs/extract-svg-figma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkmarble/marble-frontend/d4aefede58b0f4d2cbeca979c019b041d465a925/packages/ui-icons/docs/extract-svg-figma.png
--------------------------------------------------------------------------------
/packages/ui-icons/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import typescriptConfig from '@marble/eslint-config/typescript.mjs';
2 |
3 | export default typescriptConfig;
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ui-icons",
3 | "version": "1.0.0",
4 | "description": "",
5 | "sideEffect": false,
6 | "type": "module",
7 | "scripts": {
8 | "lint": "eslint .",
9 | "type-check": "pnpm exec tsc --noEmit",
10 | "generate-icons": "tsx scripts/generate.ts"
11 | },
12 | "devDependencies": {
13 | "@marble/eslint-config": "workspace:*",
14 | "@types/node": "22.13.10",
15 | "@types/react": "18.3.11",
16 | "@types/svg-sprite": "^0.0.39",
17 | "ora": "^8.2.0",
18 | "react": "18.3.1",
19 | "svg-sprite": "^2.0.4",
20 | "tsx": "^4.19.3"
21 | },
22 | "author": "",
23 | "license": "ISC",
24 | "peerDependencies": {
25 | "react": "18.3.1"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/packages/ui-icons/src/Icon.tsx:
--------------------------------------------------------------------------------
1 | import { forwardRef, type SVGProps } from 'react';
2 |
3 | import { type IconName } from './generated/icon-names';
4 | import svgSpriteHref from './generated/icons-svg-sprite.svg';
5 |
6 | export const Icon = forwardRef<
7 | SVGSVGElement,
8 | SVGProps & {
9 | icon: IconName;
10 | }
11 | >(function Icon({ icon, ...props }, ref) {
12 | return (
13 |
16 | );
17 | });
18 |
19 | export type IconProps = React.ComponentProps;
20 |
--------------------------------------------------------------------------------
/packages/ui-icons/src/Logo.tsx:
--------------------------------------------------------------------------------
1 | import { forwardRef, type SVGProps } from 'react';
2 |
3 | import { type LogoName } from './generated/logo-names';
4 | import svgSpriteHref from './generated/logos-svg-sprite.svg';
5 |
6 | export const Logo = forwardRef<
7 | SVGSVGElement,
8 | SVGProps & {
9 | logo: LogoName;
10 | }
11 | >(function Logo({ logo, ...props }, ref) {
12 | return (
13 |
16 | );
17 | });
18 |
19 | export type LogoProps = React.ComponentProps;
20 |
--------------------------------------------------------------------------------
/packages/ui-icons/src/generated/logo-names.ts:
--------------------------------------------------------------------------------
1 | export const logoNames = [
2 | 'google-logo',
3 | 'logo-favicon',
4 | 'logo-standard',
5 | 'logo',
6 | 'marble',
7 | 'microsoft-logo',
8 | ] as const;
9 |
10 | export type LogoName = (typeof logoNames)[number];
11 |
--------------------------------------------------------------------------------
/packages/ui-icons/src/index.ts:
--------------------------------------------------------------------------------
1 | import logosSVGSpriteHref from './generated/logos-svg-sprite.svg';
2 | export { logosSVGSpriteHref };
3 |
4 | import iconsSVGSpriteHref from './generated/icons-svg-sprite.svg';
5 | export { iconsSVGSpriteHref };
6 |
7 | export * from './generated/icon-names';
8 | export * from './generated/logo-names';
9 | export { Icon } from './Icon';
10 | export { Logo } from './Logo';
11 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/accepted.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/add-alert.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/alt-route.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/analytics.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/arrow-2-down.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/arrow-2-up.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/arrow-forward.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/arrow-left.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/arrow-range.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/arrow-top-left.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/arrow-up-right.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/arrow-up.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/backtest.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/boolean.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/caret-down.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/case-manager.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/category.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/center-focus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/check-indeterminate-small.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/checked.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/column.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/comment.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/commit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/copy.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/create-new-folder.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/cross.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/dash.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/decision.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/delete.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/denied.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/dns.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/download.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/draft.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/drawer-small.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/edit-square.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/edit.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/empty-flag.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/enum.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/field.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/filters-off.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/filters.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/full-flag.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/function.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/half-flag.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/harddrive.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/helpcenter.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/history.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/in-progress.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/inbox.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/investigating.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/left-panel-close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/left-panel-open.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/lightbulb.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/list.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/lists.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/logout.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/manage-search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/minus.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/modeling.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/monitor.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/more-menu.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/news.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/north-east.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/notifications.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/number.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/openinnew.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/parentheses.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/paste.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/play.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/plus.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/policy.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/pushtolive.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/queue-list.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/restart-alt.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/rule-settings.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/rules.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/save.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/scenarios.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/schedule.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/scheduled-execution.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/send.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/settings.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/smallarrow-up.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/snooze.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/status.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/status_snoozed.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/stop.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/string.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/subdirectory-arrow-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/swap.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/tick.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/tip.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/transfercheck.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/tree-schema.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/trigger.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/uncheck.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/unfold_less.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/unfold_more.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/upload.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/users.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/version.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/visibility-on.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/visibility.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/visibility_off.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/warning.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/icons/world.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/logos/logo-favicon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/logos/logo.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/packages/ui-icons/svgs/logos/microsoft-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packages/ui-icons/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.base.json",
3 | "compilerOptions": {
4 | "types": ["node"],
5 | "jsx": "react-jsx"
6 | },
7 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"],
8 | "exclude": []
9 | }
10 |
--------------------------------------------------------------------------------
/packages/ui-icons/types/svg.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.svg' {
2 | let asset: string;
3 | export default asset;
4 | }
5 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - 'packages/*'
3 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import("prettier").Options} */
2 | export default {
3 | plugins: ['prettier-plugin-tailwindcss'],
4 | singleQuote: true,
5 | printWidth: 100,
6 | };
7 |
--------------------------------------------------------------------------------
/vitest.workspace.ts:
--------------------------------------------------------------------------------
1 | export default ['packages/*/{vite,vitest}.config.ts'];
2 |
--------------------------------------------------------------------------------