@crievo/omni 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +41 -0
- package/README.md +2 -2
- package/bin/omni.mjs +14 -0
- package/docs/onboarding/clone-voice.png +0 -0
- package/docs/onboarding/getting-started.png +0 -0
- package/docs/onboarding/new-video.png +0 -0
- package/docs/onboarding/providers.png +0 -0
- package/docs/onboarding/publish.png +0 -0
- package/docs/onboarding/references.png +0 -0
- package/docs/onboarding.md +212 -0
- package/omnivideo.config.example.json +437 -0
- package/package.json +40 -4
- package/reference/captions.md +156 -0
- package/reference/carousel-contract.md +91 -0
- package/reference/cloud.md +96 -0
- package/reference/learnings.md +792 -0
- package/reference/omnichat.md +305 -0
- package/reference/premiere-mcp.md +91 -0
- package/reference/publish.md +305 -0
- package/reference/scenes-contract.md +109 -0
- package/reference/studio.md +666 -0
- package/reference/voicestudio.md +81 -0
- package/reference/writing-for-voice.md +67 -0
- package/requirements.txt +3 -0
- package/studio/api/app.ts +87 -0
- package/studio/api/lib/errors.ts +33 -0
- package/studio/api/lib/files.ts +41 -0
- package/studio/api/lib/hono.ts +9 -0
- package/studio/api/lib/result.ts +14 -0
- package/studio/api/lib/validate.ts +31 -0
- package/studio/api/lib/video.ts +10 -0
- package/studio/api/middleware/json-charset.ts +11 -0
- package/studio/api/middleware/local-only.ts +32 -0
- package/studio/api/middleware/no-timeout.ts +10 -0
- package/studio/api/routes/admin.ts +18 -0
- package/studio/api/routes/agent-cascade.ts +100 -0
- package/studio/api/routes/agent-history.ts +23 -0
- package/studio/api/routes/agent.ts +162 -0
- package/studio/api/routes/analytics.ts +31 -0
- package/studio/api/routes/approval.ts +60 -0
- package/studio/api/routes/archive.ts +12 -0
- package/studio/api/routes/captions.ts +28 -0
- package/studio/api/routes/carousel.ts +38 -0
- package/studio/api/routes/clone.ts +27 -0
- package/studio/api/routes/create.ts +19 -0
- package/studio/api/routes/events.ts +11 -0
- package/studio/api/routes/export.ts +14 -0
- package/studio/api/routes/media.ts +30 -0
- package/studio/api/routes/omnichat.ts +113 -0
- package/studio/api/routes/onboarding.ts +14 -0
- package/studio/api/routes/publish.ts +40 -0
- package/studio/api/routes/queue.ts +14 -0
- package/studio/api/routes/references.ts +40 -0
- package/studio/api/routes/runner.ts +17 -0
- package/studio/api/routes/schedule.ts +47 -0
- package/studio/api/routes/services.ts +11 -0
- package/studio/api/routes/sessions.ts +27 -0
- package/studio/api/routes/settings.ts +102 -0
- package/studio/api/routes/sound.ts +45 -0
- package/studio/api/routes/thumbnail.ts +18 -0
- package/studio/api/routes/usage.ts +13 -0
- package/studio/api/routes/videos.ts +41 -0
- package/studio/api/routes/voices.ts +71 -0
- package/studio/api/services/admin.ts +113 -0
- package/studio/api/services/agent-cascade.ts +975 -0
- package/studio/api/services/agent-claude.ts +47 -0
- package/studio/api/services/agent-history.ts +103 -0
- package/studio/api/services/agent-persona.ts +77 -0
- package/studio/api/services/agent-tools.ts +2237 -0
- package/studio/api/services/agent-ui-tools.ts +259 -0
- package/studio/api/services/agent-wait.ts +32 -0
- package/studio/api/services/agent.ts +553 -0
- package/studio/api/services/analytics.ts +92 -0
- package/studio/api/services/approval.ts +134 -0
- package/studio/api/services/archive.ts +38 -0
- package/studio/api/services/captions.ts +268 -0
- package/studio/api/services/carousel.ts +206 -0
- package/studio/api/services/classify.ts +196 -0
- package/studio/api/services/clone-phrases.ts +75 -0
- package/studio/api/services/clone.ts +722 -0
- package/studio/api/services/create.ts +421 -0
- package/studio/api/services/events.ts +215 -0
- package/studio/api/services/media.ts +32 -0
- package/studio/api/services/omnichat.ts +624 -0
- package/studio/api/services/onboarding.ts +77 -0
- package/studio/api/services/publish.ts +287 -0
- package/studio/api/services/queue.ts +150 -0
- package/studio/api/services/references.ts +269 -0
- package/studio/api/services/root.ts +60 -0
- package/studio/api/services/services.ts +114 -0
- package/studio/api/services/sessions.ts +1007 -0
- package/studio/api/services/settings.ts +983 -0
- package/studio/api/services/sound.ts +311 -0
- package/studio/api/services/thumbnail.ts +133 -0
- package/studio/api/services/usage.ts +27 -0
- package/studio/api/services/videos.ts +418 -0
- package/studio/api/services/voice-pause.ts +98 -0
- package/studio/api/services/voices.ts +324 -0
- package/studio/runner/runner.ts +244 -0
- package/studio/shared/omni-actions.ts +68 -0
- package/studio/shared/omni-admin.ts +52 -0
- package/studio/shared/omni-farewell.ts +48 -0
- package/studio/shared/omni-hotword.ts +20 -0
- package/studio/shared/omni-screens.ts +228 -0
- package/studio/shared/schemas/admin.ts +15 -0
- package/studio/shared/schemas/agent-cascade.ts +58 -0
- package/studio/shared/schemas/agent-history.ts +73 -0
- package/studio/shared/schemas/agent.ts +50 -0
- package/studio/shared/schemas/analytics.ts +6 -0
- package/studio/shared/schemas/approval.ts +22 -0
- package/studio/shared/schemas/captions.ts +19 -0
- package/studio/shared/schemas/carousel.ts +26 -0
- package/studio/shared/schemas/clone.ts +40 -0
- package/studio/shared/schemas/common.ts +16 -0
- package/studio/shared/schemas/omnichat.ts +54 -0
- package/studio/shared/schemas/onboarding.ts +5 -0
- package/studio/shared/schemas/publish.ts +45 -0
- package/studio/shared/schemas/references.ts +20 -0
- package/studio/shared/schemas/settings.ts +82 -0
- package/studio/shared/schemas/sound.ts +22 -0
- package/studio/shared/schemas/videos.ts +38 -0
- package/studio/shared/schemas/voices.ts +23 -0
- package/studio/shared/types/api.ts +1290 -0
- package/studio/studio.ts +148 -0
- package/studio/tsconfig.json +15 -0
- package/studio/web/assets/logos/cartesia.svg +4 -0
- package/studio/web/assets/logos/elevenlabs.svg +12 -0
- package/studio/web/assets/logos/fish.svg +24 -0
- package/studio/web/assets/logos/omni-black.png +0 -0
- package/studio/web/assets/logos/omni-white.png +0 -0
- package/studio/web/assets/logos/voicestudio.svg +21 -0
- package/studio/web/components/AgentMark.tsx +7 -0
- package/studio/web/components/AgentWalking.tsx +11 -0
- package/studio/web/components/ApiKeyField.tsx +104 -0
- package/studio/web/components/AppShell.tsx +64 -0
- package/studio/web/components/ApprovalNotice.tsx +65 -0
- package/studio/web/components/AvatarGroupIcon.tsx +22 -0
- package/studio/web/components/AvatarNameField.tsx +86 -0
- package/studio/web/components/AvatarPicker.tsx +84 -0
- package/studio/web/components/BrandLogo.tsx +16 -0
- package/studio/web/components/CartesiaPlanSetting.tsx +90 -0
- package/studio/web/components/ClaudeWalking.tsx +32 -0
- package/studio/web/components/CloneVoiceDialog/GuidedScript.tsx +39 -0
- package/studio/web/components/CloneVoiceDialog/LanguageBar.tsx +37 -0
- package/studio/web/components/CloneVoiceDialog/LevelMeter.tsx +31 -0
- package/studio/web/components/CloneVoiceDialog/ProviderChoice.tsx +81 -0
- package/studio/web/components/CloneVoiceDialog/QualityPanel.tsx +62 -0
- package/studio/web/components/CloneVoiceDialog/RecordStep.tsx +50 -0
- package/studio/web/components/CloneVoiceDialog/RecorderBar.tsx +79 -0
- package/studio/web/components/CloneVoiceDialog/RedoSummary.tsx +54 -0
- package/studio/web/components/CloneVoiceDialog/SaveStep.tsx +91 -0
- package/studio/web/components/CloneVoiceDialog/SourceBar.tsx +30 -0
- package/studio/web/components/CloneVoiceDialog/index.tsx +141 -0
- package/studio/web/components/CloneVoiceDialog/types.ts +28 -0
- package/studio/web/components/CloneVoiceDialog/useCloneVoice.ts +528 -0
- package/studio/web/components/ConnectionSignals.tsx +51 -0
- package/studio/web/components/EditVoiceDialog/EditVoiceFooter.tsx +72 -0
- package/studio/web/components/EditVoiceDialog/ProviderCards.tsx +81 -0
- package/studio/web/components/EditVoiceDialog/index.tsx +256 -0
- package/studio/web/components/ErrorBanner.tsx +115 -0
- package/studio/web/components/FinishedTask.tsx +41 -0
- package/studio/web/components/FishModelSetting.tsx +69 -0
- package/studio/web/components/FishPriceSetting.tsx +44 -0
- package/studio/web/components/HumanBanner.tsx +64 -0
- package/studio/web/components/Lightbox.tsx +41 -0
- package/studio/web/components/LogStream.tsx +42 -0
- package/studio/web/components/Markdown.tsx +21 -0
- package/studio/web/components/MissingDmsPanel/BatchSend.tsx +137 -0
- package/studio/web/components/MissingDmsPanel/CommentCard.tsx +168 -0
- package/studio/web/components/MissingDmsPanel/CommentFeed.tsx +45 -0
- package/studio/web/components/MissingDmsPanel/DmBubble.tsx +38 -0
- package/studio/web/components/MissingDmsPanel/ReplyComposer.tsx +63 -0
- package/studio/web/components/MissingDmsPanel/index.tsx +98 -0
- package/studio/web/components/NotFound.tsx +48 -0
- package/studio/web/components/Omni/OmniAvatarPicker.tsx +92 -0
- package/studio/web/components/Omni/OmniCards.tsx +202 -0
- package/studio/web/components/Omni/OmniGlow.tsx +183 -0
- package/studio/web/components/Omni/OmniHistory.tsx +119 -0
- package/studio/web/components/Omni/OmniHotword.tsx +40 -0
- package/studio/web/components/Omni/OmniMicSelect.tsx +92 -0
- package/studio/web/components/Omni/OmniVoiceSample.tsx +81 -0
- package/studio/web/components/Omni/OmniWidget.tsx +743 -0
- package/studio/web/components/Omni/PendingActions.tsx +200 -0
- package/studio/web/components/Omni/Transcript.tsx +127 -0
- package/studio/web/components/OmnichatAccountStatus.tsx +87 -0
- package/studio/web/components/OmnichatRulePanel/RuleConfig.tsx +150 -0
- package/studio/web/components/OmnichatRulePanel/RuleDryRun.tsx +15 -0
- package/studio/web/components/OmnichatRulePanel/RuleEnableConfirm.tsx +42 -0
- package/studio/web/components/OmnichatRulePanel/RuleSkeleton.tsx +18 -0
- package/studio/web/components/OmnichatRulePanel/RuleStatus.tsx +55 -0
- package/studio/web/components/OmnichatRulePanel/index.tsx +115 -0
- package/studio/web/components/OmnichatRulePanel/rule-steps.ts +67 -0
- package/studio/web/components/OmnichatRulePanel/steps/MessageStep.tsx +91 -0
- package/studio/web/components/OmnichatRulePanel/steps/RepliesStep.tsx +201 -0
- package/studio/web/components/OmnichatRulePanel/steps/TriggerStep.tsx +76 -0
- package/studio/web/components/OmnichatRulePanel/steps/types.ts +11 -0
- package/studio/web/components/Palette.tsx +17 -0
- package/studio/web/components/PlatformCard.tsx +109 -0
- package/studio/web/components/PlatformIcon.tsx +19 -0
- package/studio/web/components/ProviderCard.tsx +80 -0
- package/studio/web/components/ProviderDetail.tsx +367 -0
- package/studio/web/components/ProviderLogo.tsx +20 -0
- package/studio/web/components/QueuePanel.tsx +77 -0
- package/studio/web/components/ReferenceActions.tsx +89 -0
- package/studio/web/components/ReferencePicker.tsx +136 -0
- package/studio/web/components/ResultMessage.tsx +7 -0
- package/studio/web/components/RuleForm.tsx +138 -0
- package/studio/web/components/RuleLog.tsx +151 -0
- package/studio/web/components/RunningTask.tsx +23 -0
- package/studio/web/components/SampleList.tsx +55 -0
- package/studio/web/components/SessionPanel.tsx +352 -0
- package/studio/web/components/SettingRow.tsx +14 -0
- package/studio/web/components/SettingsCategorySkeleton.tsx +25 -0
- package/studio/web/components/SidePanel.tsx +77 -0
- package/studio/web/components/Sidebar.tsx +289 -0
- package/studio/web/components/StageStepper.tsx +87 -0
- package/studio/web/components/StudioOffline.tsx +80 -0
- package/studio/web/components/TaskName.tsx +17 -0
- package/studio/web/components/TopBanners.tsx +30 -0
- package/studio/web/components/VideoOmnichatPanel.tsx +287 -0
- package/studio/web/components/VoiceAvatar.tsx +33 -0
- package/studio/web/components/VoiceCarousel.tsx +196 -0
- package/studio/web/components/VoiceCategory.tsx +9 -0
- package/studio/web/components/VoiceModal.tsx +39 -0
- package/studio/web/components/VoiceProfileCard.tsx +75 -0
- package/studio/web/components/VoiceProfilePicker.tsx +107 -0
- package/studio/web/components/VoiceProfilesSettings.tsx +150 -0
- package/studio/web/components/VoiceProviderCard.tsx +118 -0
- package/studio/web/components/VoiceProvidersCard.tsx +26 -0
- package/studio/web/components/WaitList.tsx +21 -0
- package/studio/web/components/icons.tsx +247 -0
- package/studio/web/components/ui/accordion.tsx +47 -0
- package/studio/web/components/ui/badge.tsx +18 -0
- package/studio/web/components/ui/calendar.tsx +43 -0
- package/studio/web/components/ui/chart.tsx +229 -0
- package/studio/web/components/ui/checkbox.tsx +26 -0
- package/studio/web/components/ui/cx.ts +2 -0
- package/studio/web/components/ui/date-time-picker.tsx +84 -0
- package/studio/web/components/ui/panel.tsx +23 -0
- package/studio/web/components/ui/picker.tsx +58 -0
- package/studio/web/components/ui/popover.tsx +24 -0
- package/studio/web/components/ui/select.tsx +89 -0
- package/studio/web/components/ui/skeleton.tsx +10 -0
- package/studio/web/components/ui/slider.tsx +68 -0
- package/studio/web/components/ui/switch.tsx +13 -0
- package/studio/web/components/ui/tooltip.test.tsx +30 -0
- package/studio/web/components/ui/tooltip.tsx +59 -0
- package/studio/web/hooks/useAccounts.ts +27 -0
- package/studio/web/hooks/useAdmin.ts +12 -0
- package/studio/web/hooks/useAnalytics.ts +21 -0
- package/studio/web/hooks/useAvatarAudioReactive.ts +87 -0
- package/studio/web/hooks/useBrowserConnect.ts +48 -0
- package/studio/web/hooks/useClonePlan.ts +14 -0
- package/studio/web/hooks/useConnected.ts +7 -0
- package/studio/web/hooks/useLiveQuery.ts +29 -0
- package/studio/web/hooks/useMenuCollapsed.ts +32 -0
- package/studio/web/hooks/useMicDevices.ts +53 -0
- package/studio/web/hooks/useMissingDms.ts +211 -0
- package/studio/web/hooks/useMissingSetupSteps.ts +26 -0
- package/studio/web/hooks/useNow.ts +11 -0
- package/studio/web/hooks/useOmniAgent.ts +278 -0
- package/studio/web/hooks/useOmniClaude.ts +124 -0
- package/studio/web/hooks/useOmniDock.ts +142 -0
- package/studio/web/hooks/useOmniGreeting.ts +60 -0
- package/studio/web/hooks/useOmniHotword.ts +128 -0
- package/studio/web/hooks/useOmnichat.ts +26 -0
- package/studio/web/hooks/useOnboarding.ts +27 -0
- package/studio/web/hooks/usePost.ts +23 -0
- package/studio/web/hooks/useQueue.ts +10 -0
- package/studio/web/hooks/useReferences.ts +20 -0
- package/studio/web/hooks/useRuleEditor.ts +101 -0
- package/studio/web/hooks/useRunner.ts +24 -0
- package/studio/web/hooks/useSaveAction.ts +23 -0
- package/studio/web/hooks/useSchedule.ts +11 -0
- package/studio/web/hooks/useServices.ts +10 -0
- package/studio/web/hooks/useSessions.ts +15 -0
- package/studio/web/hooks/useSettings.ts +11 -0
- package/studio/web/hooks/useSettingsSection.ts +30 -0
- package/studio/web/hooks/useSidePanel.ts +23 -0
- package/studio/web/hooks/useSound.ts +30 -0
- package/studio/web/hooks/useUsage.ts +11 -0
- package/studio/web/hooks/useVideoVoice.ts +36 -0
- package/studio/web/hooks/useVideos.ts +21 -0
- package/studio/web/hooks/useVoiceProfilePreview.ts +52 -0
- package/studio/web/hooks/useVoiceProfiles.ts +7 -0
- package/studio/web/hooks/useVoiceRunning.ts +10 -0
- package/studio/web/hooks/useVoiceStudioClosed.ts +8 -0
- package/studio/web/index.html +19 -0
- package/studio/web/lib/agent.ts +7 -0
- package/studio/web/lib/alerts.ts +210 -0
- package/studio/web/lib/analytics-metrics.ts +351 -0
- package/studio/web/lib/api.ts +70 -0
- package/studio/web/lib/audio.ts +39 -0
- package/studio/web/lib/avatars.ts +41 -0
- package/studio/web/lib/calendar.ts +218 -0
- package/studio/web/lib/caption-position.ts +249 -0
- package/studio/web/lib/carousel.ts +24 -0
- package/studio/web/lib/chime.ts +42 -0
- package/studio/web/lib/clone-voice.ts +55 -0
- package/studio/web/lib/export.ts +11 -0
- package/studio/web/lib/files.ts +8 -0
- package/studio/web/lib/format.ts +93 -0
- package/studio/web/lib/media.ts +29 -0
- package/studio/web/lib/mic-device.ts +72 -0
- package/studio/web/lib/missing-dms.ts +70 -0
- package/studio/web/lib/omni-cards.ts +42 -0
- package/studio/web/lib/omni-cascade.ts +1067 -0
- package/studio/web/lib/omni-greeting-audio.ts +24 -0
- package/studio/web/lib/omni-hotword.ts +231 -0
- package/studio/web/lib/omni-panel.ts +67 -0
- package/studio/web/lib/omni-realtime.ts +811 -0
- package/studio/web/lib/omni-ui.ts +402 -0
- package/studio/web/lib/omni-wait.ts +174 -0
- package/studio/web/lib/omnichat-api.ts +44 -0
- package/studio/web/lib/orb.ts +270 -0
- package/studio/web/lib/pcm-recorder.ts +115 -0
- package/studio/web/lib/platforms.ts +17 -0
- package/studio/web/lib/providers.ts +27 -0
- package/studio/web/lib/publish-draft.ts +52 -0
- package/studio/web/lib/publish-settings.ts +81 -0
- package/studio/web/lib/query-client.ts +122 -0
- package/studio/web/lib/references.ts +13 -0
- package/studio/web/lib/services.ts +40 -0
- package/studio/web/lib/sessions.ts +103 -0
- package/studio/web/lib/settings-categories.ts +58 -0
- package/studio/web/lib/sound-audio.ts +33 -0
- package/studio/web/lib/sound-timeline.ts +291 -0
- package/studio/web/lib/sse.ts +86 -0
- package/studio/web/lib/stage-history.ts +141 -0
- package/studio/web/lib/stages.ts +344 -0
- package/studio/web/lib/studio-offline.ts +60 -0
- package/studio/web/lib/upload.ts +24 -0
- package/studio/web/lib/video-tabs.ts +118 -0
- package/studio/web/lib/voice-profile-draft.ts +34 -0
- package/studio/web/lib/voice-profiles.ts +3 -0
- package/studio/web/main.tsx +14 -0
- package/studio/web/pages/AdminPage/index.tsx +123 -0
- package/studio/web/pages/AgentPage/components/Measurements.tsx +102 -0
- package/studio/web/pages/AgentPage/index.tsx +28 -0
- package/studio/web/pages/AnalyticsPage/components/About.tsx +52 -0
- package/studio/web/pages/AnalyticsPage/components/ChannelCards.tsx +106 -0
- package/studio/web/pages/AnalyticsPage/components/ChannelView.tsx +137 -0
- package/studio/web/pages/AnalyticsPage/components/CollectionStatus.tsx +46 -0
- package/studio/web/pages/AnalyticsPage/components/Comparison.tsx +68 -0
- package/studio/web/pages/AnalyticsPage/components/Diagnosis.tsx +50 -0
- package/studio/web/pages/AnalyticsPage/components/Highlights.tsx +49 -0
- package/studio/web/pages/AnalyticsPage/components/Hint.tsx +11 -0
- package/studio/web/pages/AnalyticsPage/components/HookVsBody.tsx +100 -0
- package/studio/web/pages/AnalyticsPage/components/HourlyWave.tsx +133 -0
- package/studio/web/pages/AnalyticsPage/components/Insights.tsx +70 -0
- package/studio/web/pages/AnalyticsPage/components/MetricCard.tsx +46 -0
- package/studio/web/pages/AnalyticsPage/components/PlanSection.tsx +40 -0
- package/studio/web/pages/AnalyticsPage/components/ProgressionChart.tsx +155 -0
- package/studio/web/pages/AnalyticsPage/components/ReelBarsChart.tsx +154 -0
- package/studio/web/pages/AnalyticsPage/components/ReelThumb.tsx +19 -0
- package/studio/web/pages/AnalyticsPage/components/ReelView.tsx +290 -0
- package/studio/web/pages/AnalyticsPage/components/ReelsTable.tsx +269 -0
- package/studio/web/pages/AnalyticsPage/components/RequestWithFocus.tsx +38 -0
- package/studio/web/pages/AnalyticsPage/components/SegmentedControl.tsx +35 -0
- package/studio/web/pages/AnalyticsPage/components/VsMedian.tsx +31 -0
- package/studio/web/pages/AnalyticsPage/index.tsx +17 -0
- package/studio/web/pages/GettingStartedPage/index.tsx +174 -0
- package/studio/web/pages/NewVideoPage/components/DeliverablesPicker.tsx +62 -0
- package/studio/web/pages/NewVideoPage/components/FormatPicker.tsx +33 -0
- package/studio/web/pages/NewVideoPage/index.tsx +133 -0
- package/studio/web/pages/NotFoundPage/index.tsx +9 -0
- package/studio/web/pages/OmnichatPage/components/NewFromLink.tsx +59 -0
- package/studio/web/pages/OmnichatPage/components/RuleListItem.tsx +64 -0
- package/studio/web/pages/OmnichatPage/components/RulePreview.tsx +14 -0
- package/studio/web/pages/OmnichatPage/components/RuleView.tsx +88 -0
- package/studio/web/pages/OmnichatPage/index.tsx +153 -0
- package/studio/web/pages/QueuePage/index.tsx +22 -0
- package/studio/web/pages/ReferencePage/components/ReferenceTexts.tsx +131 -0
- package/studio/web/pages/ReferencePage/index.tsx +216 -0
- package/studio/web/pages/ReferencesPage/components/NewReferenceForm.tsx +150 -0
- package/studio/web/pages/ReferencesPage/components/ReferenceCard.tsx +42 -0
- package/studio/web/pages/ReferencesPage/components/ReferenceGridSkeleton.tsx +31 -0
- package/studio/web/pages/ReferencesPage/index.tsx +67 -0
- package/studio/web/pages/SchedulePage/components/CalendarSkeleton.tsx +18 -0
- package/studio/web/pages/SchedulePage/components/DayView.tsx +177 -0
- package/studio/web/pages/SchedulePage/components/HourPicker.tsx +103 -0
- package/studio/web/pages/SchedulePage/components/MonthDayCell.tsx +111 -0
- package/studio/web/pages/SchedulePage/components/MonthView.tsx +47 -0
- package/studio/web/pages/SchedulePage/components/PlatformIcons.tsx +12 -0
- package/studio/web/pages/SchedulePage/components/PostThumb.tsx +15 -0
- package/studio/web/pages/SchedulePage/components/WeekColumn.tsx +75 -0
- package/studio/web/pages/SchedulePage/components/WeekView.tsx +35 -0
- package/studio/web/pages/SchedulePage/index.tsx +285 -0
- package/studio/web/pages/SettingsPage/components/AgentAccounts.tsx +263 -0
- package/studio/web/pages/SettingsPage/components/AgentCategory.tsx +20 -0
- package/studio/web/pages/SettingsPage/components/ModelPicker.tsx +49 -0
- package/studio/web/pages/SettingsPage/components/ModelsSettings.tsx +138 -0
- package/studio/web/pages/SettingsPage/components/PlatformsCategory.tsx +23 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/AccountStatus.tsx +29 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/AutoPublishPanel.tsx +90 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/BrowserConnect.tsx +62 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/CheckField.tsx +19 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/InstagramPanel.tsx +113 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/OmnichatSettingsPanel.tsx +146 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/SaveBar.tsx +33 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/SchedulePanel.tsx +132 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/SettingsCard.tsx +47 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/SettingsCardGroup.tsx +19 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/TextPanel.tsx +55 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/TiktokPanel.tsx +123 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/YoutubePanel.tsx +100 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/badges.tsx +15 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/index.tsx +40 -0
- package/studio/web/pages/SettingsPage/components/PublishingCategory/types.ts +10 -0
- package/studio/web/pages/SettingsPage/components/UsageCategory.tsx +389 -0
- package/studio/web/pages/SettingsPage/components/VoiceProvidersCategory.tsx +97 -0
- package/studio/web/pages/SettingsPage/index.tsx +85 -0
- package/studio/web/pages/VideoPage/components/AudioPlayer.tsx +113 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/AxisField.tsx +50 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionList.tsx +56 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionListItem.tsx +92 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionMargins.tsx +57 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionStyleFields.tsx +70 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionTextForm.tsx +87 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/ColorField.tsx +37 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/MarginField.tsx +59 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/NumberField.tsx +57 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/PositionControls.tsx +140 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/captionEditor.ts +215 -0
- package/studio/web/pages/VideoPage/components/CaptionPositionEditor/useCaptionPosition.ts +154 -0
- package/studio/web/pages/VideoPage/components/CarouselChangeRequest.tsx +72 -0
- package/studio/web/pages/VideoPage/components/CarouselCompositionStage.tsx +80 -0
- package/studio/web/pages/VideoPage/components/CarouselCreate.tsx +63 -0
- package/studio/web/pages/VideoPage/components/CarouselMissing.tsx +19 -0
- package/studio/web/pages/VideoPage/components/CarouselPublishStage.tsx +173 -0
- package/studio/web/pages/VideoPage/components/CarouselScriptStage.tsx +82 -0
- package/studio/web/pages/VideoPage/components/CarouselSlideCard.tsx +49 -0
- package/studio/web/pages/VideoPage/components/CarouselViewer.tsx +55 -0
- package/studio/web/pages/VideoPage/components/ChangedVoices.tsx +53 -0
- package/studio/web/pages/VideoPage/components/CompositionStage.tsx +78 -0
- package/studio/web/pages/VideoPage/components/CoverPicker.tsx +32 -0
- package/studio/web/pages/VideoPage/components/EditorStage.tsx +53 -0
- package/studio/web/pages/VideoPage/components/LineTakes.tsx +160 -0
- package/studio/web/pages/VideoPage/components/LineTextEditor.tsx +124 -0
- package/studio/web/pages/VideoPage/components/LineVoicePicker.tsx +37 -0
- package/studio/web/pages/VideoPage/components/MediaImage.tsx +25 -0
- package/studio/web/pages/VideoPage/components/MotionScriptStage.tsx +39 -0
- package/studio/web/pages/VideoPage/components/NarrationStage.tsx +70 -0
- package/studio/web/pages/VideoPage/components/PublishForm.tsx +387 -0
- package/studio/web/pages/VideoPage/components/PublishStage.tsx +76 -0
- package/studio/web/pages/VideoPage/components/PublishText.tsx +149 -0
- package/studio/web/pages/VideoPage/components/ScenesApprovalPanel.tsx +278 -0
- package/studio/web/pages/VideoPage/components/ScheduledInfo.tsx +72 -0
- package/studio/web/pages/VideoPage/components/ScriptApprovalPanel.tsx +189 -0
- package/studio/web/pages/VideoPage/components/ScriptStage.tsx +17 -0
- package/studio/web/pages/VideoPage/components/SequencePlayer.tsx +146 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/AddSound.tsx +117 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/AreaSelection.tsx +74 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/BedPanel.tsx +94 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/BedRow.tsx +45 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionOverlay.tsx +44 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionSaveBar.tsx +32 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionsPanel.tsx +22 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/ClipBlock.tsx +111 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/ClipPanel.tsx +76 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/CutsPanel.tsx +44 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/EditorTabBar.tsx +73 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/EffectChoice.tsx +46 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/EffectItem.tsx +89 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/EffectPanel.tsx +232 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/EffectsRow.tsx +21 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/Lane.tsx +39 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/MarkerRow.tsx +40 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/MuteButton.tsx +36 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/NumberInput.tsx +37 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/PlanWarnings.tsx +19 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/PlayerResizeHandle.tsx +50 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/PreviewControls.tsx +51 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/SceneRow.tsx +54 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/SettingsPanel.tsx +65 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/SoundLibrary.tsx +99 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/SoundPreview.tsx +82 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/SpeedPanel.tsx +128 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineDock.tsx +56 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineFooter.tsx +26 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineSkeleton.tsx +21 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineToolbar.tsx +160 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineTracks.tsx +121 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/TrackSidebar.tsx +30 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/VoiceRow.tsx +53 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/Waveform.tsx +97 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/clipActions.ts +50 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/effectActions.ts +161 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/index.tsx +161 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/timelineGeometry.ts +45 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/types.ts +43 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useAutosave.ts +107 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useEditorShortcuts.ts +168 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useFitHeight.ts +40 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useFollowPlayhead.ts +21 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useListenMix.ts +43 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/usePlayback.ts +231 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/usePlayerWidth.ts +27 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useSoundData.ts +124 -0
- package/studio/web/pages/VideoPage/components/SoundTimeline/useSoundTimeline.ts +511 -0
- package/studio/web/pages/VideoPage/components/StageDrawer/CompareVersions.tsx +111 -0
- package/studio/web/pages/VideoPage/components/StageDrawer/VersionCard.tsx +81 -0
- package/studio/web/pages/VideoPage/components/StageDrawer/VersionMedia.tsx +24 -0
- package/studio/web/pages/VideoPage/components/StageDrawer/VersionText.tsx +15 -0
- package/studio/web/pages/VideoPage/components/StageDrawer/index.tsx +109 -0
- package/studio/web/pages/VideoPage/components/StageProcess.tsx +126 -0
- package/studio/web/pages/VideoPage/components/StageResult.tsx +69 -0
- package/studio/web/pages/VideoPage/components/SwapReference.tsx +92 -0
- package/studio/web/pages/VideoPage/components/ThumbnailPanel.tsx +252 -0
- package/studio/web/pages/VideoPage/components/TimingPanel.tsx +89 -0
- package/studio/web/pages/VideoPage/components/VideoPlayer.tsx +18 -0
- package/studio/web/pages/VideoPage/components/VideoSkeleton.tsx +50 -0
- package/studio/web/pages/VideoPage/components/VideoVoiceInfo.tsx +33 -0
- package/studio/web/pages/VideoPage/components/VideoVoicePicker.tsx +165 -0
- package/studio/web/pages/VideoPage/components/VoicePauseBanner.tsx +56 -0
- package/studio/web/pages/VideoPage/components/WithLogo.tsx +10 -0
- package/studio/web/pages/VideoPage/index.tsx +295 -0
- package/studio/web/pages/VideosPage/components/PublishedOn.tsx +85 -0
- package/studio/web/pages/VideosPage/components/ServicesPanel.tsx +81 -0
- package/studio/web/pages/VideosPage/components/SessionsPanel.tsx +62 -0
- package/studio/web/pages/VideosPage/components/VideoListSkeleton.tsx +25 -0
- package/studio/web/pages/VideosPage/components/VideoRow.tsx +122 -0
- package/studio/web/pages/VideosPage/index.tsx +134 -0
- package/studio/web/pages/VoicePage/index.tsx +28 -0
- package/studio/web/router.tsx +201 -0
- package/studio/web/styles/base/elements.css +55 -0
- package/studio/web/styles/base/utilities.css +25 -0
- package/studio/web/styles/components/badge.css +33 -0
- package/studio/web/styles/components/claude-running.css +27 -0
- package/studio/web/styles/components/claude-session.css +212 -0
- package/studio/web/styles/components/claude-walking.css +92 -0
- package/studio/web/styles/components/clone-voice-save.css +136 -0
- package/studio/web/styles/components/clone-voice.css +379 -0
- package/studio/web/styles/components/controls.css +70 -0
- package/studio/web/styles/components/data-and-image.css +54 -0
- package/studio/web/styles/components/forms.css +132 -0
- package/studio/web/styles/components/human-banner.css +99 -0
- package/studio/web/styles/components/lightbox.css +50 -0
- package/studio/web/styles/components/markdown.css +68 -0
- package/studio/web/styles/components/modal.css +70 -0
- package/studio/web/styles/components/omni-cards.css +105 -0
- package/studio/web/styles/components/omni.css +859 -0
- package/studio/web/styles/components/omnichat.css +538 -0
- package/studio/web/styles/components/panel.css +115 -0
- package/studio/web/styles/components/platform-card.css +140 -0
- package/studio/web/styles/components/provider-card.css +132 -0
- package/studio/web/styles/components/queue.css +185 -0
- package/studio/web/styles/components/reference-actions.css +133 -0
- package/studio/web/styles/components/reference-picker.css +146 -0
- package/studio/web/styles/components/results-drawer.css +224 -0
- package/studio/web/styles/components/segmented.css +115 -0
- package/studio/web/styles/components/side-panel-tab.css +23 -0
- package/studio/web/styles/components/status-signals.css +66 -0
- package/studio/web/styles/components/stepper.css +208 -0
- package/studio/web/styles/components/table.css +19 -0
- package/studio/web/styles/components/tabs.css +24 -0
- package/studio/web/styles/components/ui/accordion.css +71 -0
- package/studio/web/styles/components/ui/chart.css +162 -0
- package/studio/web/styles/components/ui/checkbox.css +37 -0
- package/studio/web/styles/components/ui/date-picker.css +153 -0
- package/studio/web/styles/components/ui/select.css +110 -0
- package/studio/web/styles/components/ui/skeleton.css +25 -0
- package/studio/web/styles/components/ui/slider.css +81 -0
- package/studio/web/styles/components/ui/switch.css +41 -0
- package/studio/web/styles/components/ui/tooltip.css +24 -0
- package/studio/web/styles/components/voice-carousel.css +255 -0
- package/studio/web/styles/components/voice-editor.css +179 -0
- package/studio/web/styles/components/voice-grid.css +56 -0
- package/studio/web/styles/components/voice-profiles.css +192 -0
- package/studio/web/styles/design-system.md +136 -0
- package/studio/web/styles/index.css +116 -0
- package/studio/web/styles/layout/page.css +41 -0
- package/studio/web/styles/layout/sidebar-groups.css +39 -0
- package/studio/web/styles/layout/sidebar.css +111 -0
- package/studio/web/styles/pages/agent.css +26 -0
- package/studio/web/styles/pages/analytics/dashboard.css +614 -0
- package/studio/web/styles/pages/analytics/insights.css +48 -0
- package/studio/web/styles/pages/getting-started.css +166 -0
- package/studio/web/styles/pages/new-video/form.css +32 -0
- package/studio/web/styles/pages/not-found.css +59 -0
- package/studio/web/styles/pages/references.css +204 -0
- package/studio/web/styles/pages/schedule/calendar.css +541 -0
- package/studio/web/styles/pages/schedule/chip-states.css +60 -0
- package/studio/web/styles/pages/settings/models.css +72 -0
- package/studio/web/styles/pages/settings/shell.css +361 -0
- package/studio/web/styles/pages/settings/usage.css +63 -0
- package/studio/web/styles/pages/studio-offline.css +105 -0
- package/studio/web/styles/pages/video/caption-controls.css +194 -0
- package/studio/web/styles/pages/video/captions-grid.css +70 -0
- package/studio/web/styles/pages/video/captions.css +79 -0
- package/studio/web/styles/pages/video/editor-chat.css +103 -0
- package/studio/web/styles/pages/video/export.css +50 -0
- package/studio/web/styles/pages/video/frames.css +29 -0
- package/studio/web/styles/pages/video/fullscreen-stage.css +400 -0
- package/studio/web/styles/pages/video/instagram-carousel.css +309 -0
- package/studio/web/styles/pages/video/layout.css +285 -0
- package/studio/web/styles/pages/video/narration.css +138 -0
- package/studio/web/styles/pages/video/preview-overview.css +11 -0
- package/studio/web/styles/pages/video/processing-notice.css +34 -0
- package/studio/web/styles/pages/video/publish-when.css +76 -0
- package/studio/web/styles/pages/video/publish.css +97 -0
- package/studio/web/styles/pages/video/result.css +96 -0
- package/studio/web/styles/pages/video/scenes.css +167 -0
- package/studio/web/styles/pages/video/sound-timeline.css +672 -0
- package/studio/web/styles/pages/video/sound-toolbar.css +149 -0
- package/studio/web/styles/pages/video/take-player.css +100 -0
- package/studio/web/styles/pages/video/thumbnail.css +157 -0
- package/studio/web/styles/pages/video/timeline.css +117 -0
- package/studio/web/styles/pages/video/voice-picker.css +14 -0
- package/studio/web/styles/pages/video-list/active-row.css +27 -0
- package/studio/web/styles/pages/video-list/card-link.css +49 -0
- package/studio/web/styles/pages/video-list/list.css +86 -0
- package/studio/web/styles/theme/identity/details.css +204 -0
- package/studio/web/styles/theme/identity/shell.css +249 -0
- package/studio/web/styles/theme/identity/surfaces.css +183 -0
- package/studio/web/styles/theme/identity/titles-and-buttons.css +120 -0
- package/studio/web/styles/theme/no-borders/blocks.css +208 -0
- package/studio/web/styles/theme/no-borders/controls.css +256 -0
- package/studio/web/styles/tokens.css +245 -0
- package/studio/web/types/api.ts +2 -0
- package/studio/web/types/assets.d.ts +9 -0
- package/templates/brief.md +27 -0
- package/templates/captions.html +204 -0
- package/templates/carousel-composition.md +47 -0
- package/templates/carousel-script.md +60 -0
- package/templates/components/voiceavatar/README.md +87 -0
- package/templates/components/voiceavatar/demo.html +50 -0
- package/templates/components/voiceavatar/voiceavatar.js +415 -0
- package/templates/motion.md +80 -0
- package/templates/playbook.md +43 -0
- package/templates/reference.md +123 -0
- package/templates/scene.html +112 -0
- package/templates/scenes.example.json +96 -0
- package/templates/script.md +63 -0
- package/templates/slide.html +71 -0
- package/templates/wireframe.html +91 -0
- package/tools/analysis.mjs +300 -0
- package/tools/approval.mjs +442 -0
- package/tools/assemble.mjs +942 -0
- package/tools/build-motion.mjs +437 -0
- package/tools/captions.mjs +246 -0
- package/tools/carousel.mjs +558 -0
- package/tools/compose.mjs +307 -0
- package/tools/cuts.mjs +74 -0
- package/tools/editor.mjs +419 -0
- package/tools/epidemic-capture.js +54 -0
- package/tools/fanout.mjs +69 -0
- package/tools/history.mjs +70 -0
- package/tools/history.py +61 -0
- package/tools/job-queue.mjs +180 -0
- package/tools/job_queue.py +430 -0
- package/tools/lib/agents.mjs +412 -0
- package/tools/lib/channel.mjs +399 -0
- package/tools/lib/claude-settings.mjs +67 -0
- package/tools/lib/cli.mjs +9 -0
- package/tools/lib/fanout.mjs +234 -0
- package/tools/lib/http.mjs +94 -0
- package/tools/lib/index.js +14 -0
- package/tools/lib/mcp-server.mjs +69 -0
- package/tools/lib/metrics/metrics.mjs +204 -0
- package/tools/lib/narration.mjs +15 -0
- package/tools/lib/oauth-client.mjs +295 -0
- package/tools/lib/omnichat/config.mjs +139 -0
- package/tools/lib/omnichat/errors.mjs +42 -0
- package/tools/lib/omnichat/extract.mjs +82 -0
- package/tools/lib/omnichat/gate.mjs +151 -0
- package/tools/lib/omnichat/manual.mjs +166 -0
- package/tools/lib/omnichat/match.mjs +78 -0
- package/tools/lib/omnichat/pass.mjs +393 -0
- package/tools/lib/omnichat/record.mjs +208 -0
- package/tools/lib/omnichat/text.mjs +315 -0
- package/tools/lib/omnichat/webhook.mjs +166 -0
- package/tools/lib/pairing.mjs +99 -0
- package/tools/lib/paths.mjs +41 -0
- package/tools/lib/platforms/instagram.mjs +469 -0
- package/tools/lib/platforms/tiktok.mjs +343 -0
- package/tools/lib/platforms/youtube.mjs +228 -0
- package/tools/lib/publish/publish.mjs +244 -0
- package/tools/lib/schedule/schedule.mjs +191 -0
- package/tools/lib/service.mjs +134 -0
- package/tools/lib/skill-client.mjs +126 -0
- package/tools/lib/skills-release.mjs +196 -0
- package/tools/lib/testing.mjs +52 -0
- package/tools/lib/up.mjs +187 -0
- package/tools/metrics.mjs +415 -0
- package/tools/models.mjs +134 -0
- package/tools/narrate.mjs +257 -0
- package/tools/omni.mjs +298 -0
- package/tools/omni_paths.py +12 -0
- package/tools/omnichat.mjs +1577 -0
- package/tools/omnivideo.py +1122 -0
- package/tools/package.mjs +130 -0
- package/tools/platforms.mjs +236 -0
- package/tools/premiere.mjs +533 -0
- package/tools/publish.mjs +1496 -0
- package/tools/reference.mjs +1408 -0
- package/tools/render.mjs +426 -0
- package/tools/runner.mjs +156 -0
- package/tools/setup.mjs +466 -0
- package/tools/skills-release.mjs +93 -0
- package/tools/sound.mjs +1323 -0
- package/tools/soundtrack.mjs +217 -0
- package/tools/thumbnail.mjs +271 -0
- package/tools/timing.mjs +108 -0
- package/tools/usage.py +628 -0
- package/tools/voice-envelope.mjs +185 -0
- package/tools/voice.py +448 -0
- package/tools/voice_sample.py +75 -0
- package/tools/wireframe.mjs +230 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/* An action Omni staged: nothing runs until the user presses Confirmar here, or says yes to Omni, who
|
|
2
|
+
then presses it (confirm_action; the server only takes a card the user has spoken after). */
|
|
3
|
+
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
import { CaretLeft, CaretRight } from "../icons";
|
|
6
|
+
import type { AgentPendingAction } from "../../types/api";
|
|
7
|
+
|
|
8
|
+
const KIND_TITLE: Record<AgentPendingAction["kind"], string> = {
|
|
9
|
+
change: "Pedir alteração ao Claude",
|
|
10
|
+
create: "Criar conteúdo",
|
|
11
|
+
thumbnail: "Pedir thumbnails",
|
|
12
|
+
publish: "Publicar agora",
|
|
13
|
+
schedule: "Agendar publicação",
|
|
14
|
+
approval: "Responder a aprovação",
|
|
15
|
+
reference: "Pedir edição no estilo visual",
|
|
16
|
+
new_reference: "Criar estilo visual",
|
|
17
|
+
choose_thumbnail: "Escolher a thumbnail",
|
|
18
|
+
analysis: "Pedir análise",
|
|
19
|
+
omnichat: "Mudar o Omnichat",
|
|
20
|
+
omnichat_send: "Mandar o Omnichat",
|
|
21
|
+
};
|
|
22
|
+
const KIND_BUSY: Record<AgentPendingAction["kind"], string> = {
|
|
23
|
+
change: "Enviando…",
|
|
24
|
+
create: "Criando…",
|
|
25
|
+
thumbnail: "Enviando…",
|
|
26
|
+
publish: "Publicando…",
|
|
27
|
+
schedule: "Agendando…",
|
|
28
|
+
approval: "Enviando…",
|
|
29
|
+
reference: "Enviando…",
|
|
30
|
+
new_reference: "Criando…",
|
|
31
|
+
choose_thumbnail: "Aplicando…",
|
|
32
|
+
analysis: "Enviando…",
|
|
33
|
+
omnichat: "Gravando…",
|
|
34
|
+
omnichat_send: "Mandando…",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/* a summary past three lines folds, with a "Mostrar tudo" that opens it */
|
|
38
|
+
function Summary({ text }: { text: string }) {
|
|
39
|
+
const ref = useRef<HTMLParagraphElement>(null);
|
|
40
|
+
const [open, setOpen] = useState(false);
|
|
41
|
+
const [long, setLong] = useState(false);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const el = ref.current;
|
|
44
|
+
if (!el) return;
|
|
45
|
+
const measure = () => {
|
|
46
|
+
if (!open) setLong(el.scrollHeight > el.clientHeight + 1);
|
|
47
|
+
};
|
|
48
|
+
measure();
|
|
49
|
+
const ro = new ResizeObserver(measure);
|
|
50
|
+
ro.observe(el);
|
|
51
|
+
return () => ro.disconnect();
|
|
52
|
+
}, [text, open]);
|
|
53
|
+
return (
|
|
54
|
+
<>
|
|
55
|
+
<p ref={ref} className={`omni-pending-summary${open ? "" : " clamped"}`}>
|
|
56
|
+
{text}
|
|
57
|
+
</p>
|
|
58
|
+
{(long || open) && (
|
|
59
|
+
<button type="button" className="omni-pending-more" onClick={() => setOpen(o => !o)}>
|
|
60
|
+
{open ? "Mostrar menos" : "Mostrar tudo"}
|
|
61
|
+
</button>
|
|
62
|
+
)}
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function PendingActions({
|
|
68
|
+
actions,
|
|
69
|
+
onResolve,
|
|
70
|
+
}: {
|
|
71
|
+
actions: AgentPendingAction[];
|
|
72
|
+
onResolve: (a: AgentPendingAction, confirm: boolean) => Promise<{ ok: boolean; error?: string }>;
|
|
73
|
+
}) {
|
|
74
|
+
const [busy, setBusy] = useState<string | null>(null);
|
|
75
|
+
const [dragging, setDragging] = useState(false);
|
|
76
|
+
const drag = useRef<{ x: number; left: number; moved: boolean } | null>(null);
|
|
77
|
+
const scroller = useRef<HTMLDivElement>(null);
|
|
78
|
+
const [index, setIndex] = useState(0);
|
|
79
|
+
const [errors, setErrors] = useState<Record<string, string>>({});
|
|
80
|
+
if (!actions.length) return null;
|
|
81
|
+
const act = async (a: AgentPendingAction, confirm: boolean) => {
|
|
82
|
+
setBusy(a.id);
|
|
83
|
+
const r = await onResolve(a, confirm);
|
|
84
|
+
setBusy(null);
|
|
85
|
+
setErrors(e => ({ ...e, [a.id]: r.ok ? "" : (r.error ?? "falhou") }));
|
|
86
|
+
};
|
|
87
|
+
/* mouse drag scrolls the carousel (touch scrolls natively); a drag never presses a button */
|
|
88
|
+
const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
|
|
89
|
+
if (e.pointerType !== "mouse" || e.button !== 0 || actions.length < 2) return;
|
|
90
|
+
if ((e.target as HTMLElement).closest("button")) return;
|
|
91
|
+
drag.current = {
|
|
92
|
+
x: e.clientX,
|
|
93
|
+
left: e.currentTarget.scrollLeft,
|
|
94
|
+
moved: false,
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
const onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {
|
|
98
|
+
const d = drag.current;
|
|
99
|
+
if (!d) return;
|
|
100
|
+
const dx = e.clientX - d.x;
|
|
101
|
+
if (!d.moved && Math.abs(dx) < 4) return;
|
|
102
|
+
if (!d.moved) {
|
|
103
|
+
d.moved = true;
|
|
104
|
+
setDragging(true);
|
|
105
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
106
|
+
}
|
|
107
|
+
e.currentTarget.scrollLeft = d.left - dx;
|
|
108
|
+
};
|
|
109
|
+
const onPointerUp = (e: React.PointerEvent<HTMLDivElement>) => {
|
|
110
|
+
if (!drag.current) return;
|
|
111
|
+
drag.current = null;
|
|
112
|
+
setDragging(false);
|
|
113
|
+
/* snap to the nearest card once released */
|
|
114
|
+
const el = e.currentTarget;
|
|
115
|
+
const card = el.querySelector<HTMLElement>(".omni-pending-card");
|
|
116
|
+
if (!card) return;
|
|
117
|
+
const step = card.offsetWidth + 8;
|
|
118
|
+
el.scrollTo({
|
|
119
|
+
left: Math.round(el.scrollLeft / step) * step,
|
|
120
|
+
behavior: "smooth",
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
const stepWidth = () => (scroller.current?.querySelector<HTMLElement>(".omni-pending-card")?.offsetWidth ?? 0) + 8;
|
|
124
|
+
const goTo = (i: number) => {
|
|
125
|
+
const n = Math.max(0, Math.min(actions.length - 1, i));
|
|
126
|
+
scroller.current?.scrollTo({ left: n * stepWidth(), behavior: "smooth" });
|
|
127
|
+
};
|
|
128
|
+
/* the active card follows the scroll (drag, swipe, arrows or dots) */
|
|
129
|
+
const onScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
|
130
|
+
const w = stepWidth();
|
|
131
|
+
if (w > 8) setIndex(Math.round(e.currentTarget.scrollLeft / w));
|
|
132
|
+
};
|
|
133
|
+
const active = Math.min(index, actions.length - 1);
|
|
134
|
+
return (
|
|
135
|
+
<div className="omni-pending-carousel">
|
|
136
|
+
<div
|
|
137
|
+
ref={scroller}
|
|
138
|
+
className={`omni-pending${dragging ? " dragging" : ""}`}
|
|
139
|
+
onPointerDown={onPointerDown}
|
|
140
|
+
onPointerMove={onPointerMove}
|
|
141
|
+
onPointerUp={onPointerUp}
|
|
142
|
+
onPointerCancel={onPointerUp}
|
|
143
|
+
onScroll={onScroll}
|
|
144
|
+
>
|
|
145
|
+
{actions.map(a => (
|
|
146
|
+
<div key={a.id} className="omni-pending-card" role="alert">
|
|
147
|
+
<div className="omni-pending-body">
|
|
148
|
+
<strong>{KIND_TITLE[a.kind]}</strong>
|
|
149
|
+
<Summary text={a.summary} />
|
|
150
|
+
{errors[a.id] && <p className="response error">{errors[a.id]}</p>}
|
|
151
|
+
</div>
|
|
152
|
+
<div className="omni-pending-actions">
|
|
153
|
+
<button type="button" className="button" disabled={busy === a.id} onClick={() => act(a, false)}>
|
|
154
|
+
Cancelar
|
|
155
|
+
</button>
|
|
156
|
+
<button type="button" className="button primary" disabled={busy === a.id} onClick={() => act(a, true)}>
|
|
157
|
+
{busy === a.id ? KIND_BUSY[a.kind] : "Confirmar"}
|
|
158
|
+
</button>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
))}
|
|
162
|
+
</div>
|
|
163
|
+
{actions.length > 1 && (
|
|
164
|
+
<div className="omni-pending-nav">
|
|
165
|
+
<button
|
|
166
|
+
type="button"
|
|
167
|
+
className="mini-button omni-icon-button ghost"
|
|
168
|
+
aria-label="Pedido anterior"
|
|
169
|
+
disabled={active === 0}
|
|
170
|
+
onClick={() => goTo(active - 1)}
|
|
171
|
+
>
|
|
172
|
+
<CaretLeft />
|
|
173
|
+
</button>
|
|
174
|
+
<div className="omni-pending-dots" role="tablist" aria-label="Pedidos pendentes">
|
|
175
|
+
{actions.map((a, i) => (
|
|
176
|
+
<button
|
|
177
|
+
key={a.id}
|
|
178
|
+
type="button"
|
|
179
|
+
role="tab"
|
|
180
|
+
aria-selected={i === active}
|
|
181
|
+
aria-label={`Pedido ${i + 1} de ${actions.length}`}
|
|
182
|
+
className={i === active ? "active" : ""}
|
|
183
|
+
onClick={() => goTo(i)}
|
|
184
|
+
/>
|
|
185
|
+
))}
|
|
186
|
+
</div>
|
|
187
|
+
<button
|
|
188
|
+
type="button"
|
|
189
|
+
className="mini-button omni-icon-button ghost"
|
|
190
|
+
aria-label="Próximo pedido"
|
|
191
|
+
disabled={active === actions.length - 1}
|
|
192
|
+
onClick={() => goTo(active + 1)}
|
|
193
|
+
>
|
|
194
|
+
<CaretRight />
|
|
195
|
+
</button>
|
|
196
|
+
</div>
|
|
197
|
+
)}
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/* The conversation as text: what the user said, Omni's replies (with the latency to the first audio
|
|
2
|
+
and 👍/👎) and each tool Omni called, in order. */
|
|
3
|
+
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
5
|
+
import { Check, ThumbsDown, ThumbsUp, X } from "../icons";
|
|
6
|
+
import type { OmniEntry } from "../../lib/omni-realtime";
|
|
7
|
+
|
|
8
|
+
const TOOL_LABELS: Record<string, string> = {
|
|
9
|
+
list_videos: "Lendo seus conteúdos",
|
|
10
|
+
get_video: "Abrindo o vídeo",
|
|
11
|
+
channel_metrics: "Lendo as métricas do canal",
|
|
12
|
+
queue_status: "Olhando a fila da máquina",
|
|
13
|
+
inspect_content: "Analisando o conteúdo",
|
|
14
|
+
request_change: "Preparando a alteração",
|
|
15
|
+
create_content: "Preparando o conteúdo novo",
|
|
16
|
+
request_thumbnail: "Preparando o pedido de thumbnails",
|
|
17
|
+
prepare_publish: "Preparando a publicação",
|
|
18
|
+
navigate: "Abrindo a tela",
|
|
19
|
+
pending_approvals: "Vendo o que espera você",
|
|
20
|
+
get_motion_script: "Lendo o roteiro de motion",
|
|
21
|
+
answer_approval: "Preparando a resposta da aprovação",
|
|
22
|
+
list_references: "Lendo os estilos visuais",
|
|
23
|
+
get_reference: "Abrindo o estilo visual",
|
|
24
|
+
inspect_reference: "Olhando o estilo visual",
|
|
25
|
+
request_reference_change: "Preparando o pedido para o estilo visual",
|
|
26
|
+
open_claude: "Abrindo o processo do Claude",
|
|
27
|
+
stop_claude: "Parando o Claude",
|
|
28
|
+
write_to_claude: "Escrevendo para o Claude",
|
|
29
|
+
send_to_claude: "Enviando ao Claude",
|
|
30
|
+
create_reference: "Preparando o estilo visual novo",
|
|
31
|
+
choose_thumbnail: "Preparando a escolha da thumbnail",
|
|
32
|
+
request_analysis: "Preparando o pedido de análise",
|
|
33
|
+
omnichat_status: "Lendo o Omnichat",
|
|
34
|
+
set_omnichat: "Configurando o Omnichat",
|
|
35
|
+
omnichat_comments: "Lendo os comentários sem DM",
|
|
36
|
+
send_omnichat: "Preparando o envio do Omnichat",
|
|
37
|
+
confirm_action: "Confirmando",
|
|
38
|
+
cancel_action: "Cancelando",
|
|
39
|
+
control_editor: "Mexendo no player do editor",
|
|
40
|
+
add_epidemic_sound: "Buscando na Epidemic",
|
|
41
|
+
show_card: "Mostrando no painel",
|
|
42
|
+
ask_in_chat: "Abrindo o chat",
|
|
43
|
+
wait_for_work: "Pondo a conversa em espera",
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export function Transcript({
|
|
47
|
+
entries,
|
|
48
|
+
onFeedback,
|
|
49
|
+
}: {
|
|
50
|
+
entries: OmniEntry[];
|
|
51
|
+
onFeedback: (item: string, value: "up" | "down" | null) => void;
|
|
52
|
+
}) {
|
|
53
|
+
const end = useRef<HTMLDivElement>(null);
|
|
54
|
+
/* follows the reply as it is written, not only when a new message arrives */
|
|
55
|
+
const last = entries.at(-1);
|
|
56
|
+
const tail = last && "text" in last ? last.text.length : 0;
|
|
57
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: re-runs on purpose when a message arrives or grows
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
end.current?.scrollIntoView({ block: "nearest" });
|
|
60
|
+
}, [entries.length, tail]);
|
|
61
|
+
if (!entries.length) return null;
|
|
62
|
+
return (
|
|
63
|
+
<div className="omni-transcript" aria-live="polite">
|
|
64
|
+
{entries.map(e => {
|
|
65
|
+
if (e.kind === "user")
|
|
66
|
+
return (
|
|
67
|
+
<p key={`u-${e.id}`} className={`omni-msg user${e.pending ? " pending" : ""}`}>
|
|
68
|
+
{e.pending ? "…" : e.text}
|
|
69
|
+
</p>
|
|
70
|
+
);
|
|
71
|
+
if (e.kind === "tool")
|
|
72
|
+
return (
|
|
73
|
+
<p key={e.id} className={`omni-tool ${e.state}`}>
|
|
74
|
+
{e.state === "ok" ? (
|
|
75
|
+
<Check className="ic" />
|
|
76
|
+
) : e.state === "error" ? (
|
|
77
|
+
<X className="ic" />
|
|
78
|
+
) : (
|
|
79
|
+
<span className="omni-spinner" aria-hidden="true" />
|
|
80
|
+
)}
|
|
81
|
+
{TOOL_LABELS[e.name] ?? e.name}
|
|
82
|
+
{e.ms != null && <span className="subtle"> · {(e.ms / 1000).toFixed(1)} s</span>}
|
|
83
|
+
{e.detail && <span className="omni-tool-error"> · {e.detail}</span>}
|
|
84
|
+
</p>
|
|
85
|
+
);
|
|
86
|
+
if (e.kind === "note")
|
|
87
|
+
return (
|
|
88
|
+
<p key={e.id} className="omni-note subtle">
|
|
89
|
+
{e.text}
|
|
90
|
+
</p>
|
|
91
|
+
);
|
|
92
|
+
return (
|
|
93
|
+
<div key={`a-${e.id}`} className="omni-msg assistant">
|
|
94
|
+
<p>{e.text || "…"}</p>
|
|
95
|
+
<div className="omni-msg-meta">
|
|
96
|
+
{e.latency_ms != null && (
|
|
97
|
+
<span className="subtle" title={e.breakdown}>
|
|
98
|
+
{(e.latency_ms / 1000).toFixed(2)} s
|
|
99
|
+
</span>
|
|
100
|
+
)}
|
|
101
|
+
{e.breakdown && <span className="subtle omni-breakdown">{e.breakdown}</span>}
|
|
102
|
+
<button
|
|
103
|
+
type="button"
|
|
104
|
+
className={`omni-vote${e.feedback === "up" ? " on" : ""}`}
|
|
105
|
+
onClick={() => onFeedback(e.id, e.feedback === "up" ? null : "up")}
|
|
106
|
+
aria-label="Resposta boa"
|
|
107
|
+
aria-pressed={e.feedback === "up"}
|
|
108
|
+
>
|
|
109
|
+
<ThumbsUp />
|
|
110
|
+
</button>
|
|
111
|
+
<button
|
|
112
|
+
type="button"
|
|
113
|
+
className={`omni-vote${e.feedback === "down" ? " on" : ""}`}
|
|
114
|
+
onClick={() => onFeedback(e.id, e.feedback === "down" ? null : "down")}
|
|
115
|
+
aria-label="Resposta ruim"
|
|
116
|
+
aria-pressed={e.feedback === "down"}
|
|
117
|
+
>
|
|
118
|
+
<ThumbsDown />
|
|
119
|
+
</button>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
})}
|
|
124
|
+
<div ref={end} />
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/* The account, the comments permission, the agent and the pause. `enabled`: some rule is on
|
|
2
|
+
(then a stopped agent is a warning, not a hint). */
|
|
3
|
+
|
|
4
|
+
import { Link } from "@tanstack/react-router";
|
|
5
|
+
import { formatDayTime } from "../lib/format";
|
|
6
|
+
import type { OmnichatState } from "../types/api";
|
|
7
|
+
import { Skeleton } from "./ui/skeleton";
|
|
8
|
+
|
|
9
|
+
export function OmnichatAccountStatus({ state, enabled = false }: { state: OmnichatState | null; enabled?: boolean }) {
|
|
10
|
+
if (!state) return <Skeleton className="row" aria-busy="true" style={{ width: 240 }} />;
|
|
11
|
+
const { account, comments, agent, pause } = state;
|
|
12
|
+
return (
|
|
13
|
+
<div className="omnichat-account">
|
|
14
|
+
{!account.ready ? (
|
|
15
|
+
<p className="warning">
|
|
16
|
+
Instagram não conectado: {account.reason}. Conecte em{" "}
|
|
17
|
+
<Link to="/settings/$category" params={{ category: "platforms" }} className="link">
|
|
18
|
+
Configurações → Plataformas
|
|
19
|
+
</Link>
|
|
20
|
+
.
|
|
21
|
+
</p>
|
|
22
|
+
) : comments?.ready === false ? (
|
|
23
|
+
<div className="omnichat-token">
|
|
24
|
+
<p className="warning">
|
|
25
|
+
<strong>A API não lê os comentários de {account.username}.</strong> {comments.reason}
|
|
26
|
+
</p>
|
|
27
|
+
<ol>
|
|
28
|
+
<li>
|
|
29
|
+
Em{" "}
|
|
30
|
+
<a className="link" href="https://developers.facebook.com/apps" target="_blank" rel="noreferrer">
|
|
31
|
+
developers.facebook.com/apps
|
|
32
|
+
</a>{" "}
|
|
33
|
+
→ seu app → Instagram → API setup with Instagram login → Generate access tokens, gere o token marcando{" "}
|
|
34
|
+
<code>instagram_business_basic</code>, <code>instagram_business_content_publish</code>,{" "}
|
|
35
|
+
<code>instagram_business_manage_comments</code> e <code>instagram_business_manage_messages</code>.
|
|
36
|
+
</li>
|
|
37
|
+
<li>
|
|
38
|
+
Cole em{" "}
|
|
39
|
+
<Link to="/settings/$category" params={{ category: "platforms" }} className="link">
|
|
40
|
+
Configurações → Plataformas → Instagram
|
|
41
|
+
</Link>
|
|
42
|
+
.
|
|
43
|
+
</li>
|
|
44
|
+
<li>
|
|
45
|
+
Se a DM der erro de permissão: no app do Instagram, Configurações → Mensagens e respostas ao story →
|
|
46
|
+
Controles de mensagens → Ferramentas conectadas → permitir acesso às mensagens.
|
|
47
|
+
</li>
|
|
48
|
+
</ol>
|
|
49
|
+
<p className="hint">
|
|
50
|
+
Passo a passo em <code>reference/omnichat.md</code>.
|
|
51
|
+
</p>
|
|
52
|
+
</div>
|
|
53
|
+
) : comments && !comments.ready && comments.reason ? (
|
|
54
|
+
<p className="hint">Permissão de comentários sem conferir: {comments.reason}</p>
|
|
55
|
+
) : null}
|
|
56
|
+
{pause && (
|
|
57
|
+
<p className="warning">
|
|
58
|
+
Em pausa até {formatDayTime(pause.until)}: {pause.reason}
|
|
59
|
+
</p>
|
|
60
|
+
)}
|
|
61
|
+
{agent?.cloud ? (
|
|
62
|
+
agent.cloud.ready ? (
|
|
63
|
+
agent.cloud.active ? null : (
|
|
64
|
+
<p className="warning">
|
|
65
|
+
A cloud está configurada para responder, mas está desligada lá: rode{" "}
|
|
66
|
+
<code>node tools/omnichat.mjs cloud push</code>.
|
|
67
|
+
</p>
|
|
68
|
+
)
|
|
69
|
+
) : (
|
|
70
|
+
<p className="warning">Não deu para falar com a cloud: {agent.cloud.reason}</p>
|
|
71
|
+
)
|
|
72
|
+
) : null}
|
|
73
|
+
{agent && !agent.cloud && !agent.loaded && (
|
|
74
|
+
<p className={enabled ? "warning" : "hint"}>
|
|
75
|
+
O agente do omnichat está desligado: nada é respondido sozinho. Ligue em{" "}
|
|
76
|
+
<Link to="/settings/$category" params={{ category: "publishing" }} className="link">
|
|
77
|
+
Configurações → Publicação → Omnichat
|
|
78
|
+
</Link>
|
|
79
|
+
.
|
|
80
|
+
</p>
|
|
81
|
+
)}
|
|
82
|
+
{agent?.installed && !agent.node_ok && (
|
|
83
|
+
<p className="warning">O node que o agente usa não existe mais: desligue e ligue o agente de novo.</p>
|
|
84
|
+
)}
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/* the rule config (collapsed when the rule exists; without a rule, it opens to create one), in steps:
|
|
2
|
+
trigger, message and replies (which also holds how the link is delivered). A new rule walks them with
|
|
3
|
+
Next (the defaults already fill the texts); a saved one jumps straight to the step to change. Save, discard and dry run stay in the
|
|
4
|
+
footer of every step. */
|
|
5
|
+
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
import type { RuleEditor } from "../../hooks/useRuleEditor";
|
|
8
|
+
import type { OmnichatRuleDetail } from "../../types/api";
|
|
9
|
+
import { ArrowCounterClockwise, ArrowLeft, ArrowRight, Check, FloppyDisk, Play, SlidersHorizontal, X } from "../icons";
|
|
10
|
+
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "../ui/accordion";
|
|
11
|
+
import { STEPS, stepInfo, type StepId } from "./rule-steps";
|
|
12
|
+
import { MessageStep } from "./steps/MessageStep";
|
|
13
|
+
import { RepliesStep } from "./steps/RepliesStep";
|
|
14
|
+
import { TriggerStep } from "./steps/TriggerStep";
|
|
15
|
+
import type { StepProps } from "./steps/types";
|
|
16
|
+
|
|
17
|
+
const BODIES: Record<StepId, (p: StepProps) => React.ReactNode> = {
|
|
18
|
+
trigger: p => <TriggerStep {...p} />,
|
|
19
|
+
message: p => <MessageStep {...p} />,
|
|
20
|
+
replies: p => <RepliesStep {...p} />,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function RuleConfig({
|
|
24
|
+
editor,
|
|
25
|
+
detail: d,
|
|
26
|
+
enabled,
|
|
27
|
+
onBehalf,
|
|
28
|
+
post,
|
|
29
|
+
thePost,
|
|
30
|
+
defaultOpen = false,
|
|
31
|
+
}: {
|
|
32
|
+
editor: RuleEditor;
|
|
33
|
+
detail: OmnichatRuleDetail;
|
|
34
|
+
enabled: boolean;
|
|
35
|
+
onBehalf: string;
|
|
36
|
+
post: string;
|
|
37
|
+
thePost: string;
|
|
38
|
+
/* open from the start even when the rule exists (the rule's own screen) */
|
|
39
|
+
defaultOpen?: boolean;
|
|
40
|
+
}) {
|
|
41
|
+
const { rule, initial, changed, form, setForm, busy, confirmSave, setConfirmSave, save, runDry } = editor;
|
|
42
|
+
const [index, setIndex] = useState(0);
|
|
43
|
+
/* how far a new rule has walked: a step it has not reached shows its number, not a check */
|
|
44
|
+
const [reached, setReached] = useState(0);
|
|
45
|
+
const go = (i: number) => {
|
|
46
|
+
setIndex(i);
|
|
47
|
+
setReached(r => Math.max(r, i));
|
|
48
|
+
};
|
|
49
|
+
const last = index === STEPS.length - 1;
|
|
50
|
+
const step = STEPS[index];
|
|
51
|
+
const infos = STEPS.map(s => stepInfo(s.id, form, d, post));
|
|
52
|
+
/* a saved rule has been through every step; a new one only the ones it walked */
|
|
53
|
+
const seen = (i: number) => !!rule || i <= reached;
|
|
54
|
+
const saveFirst = last || !!rule;
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<Accordion
|
|
58
|
+
type="single"
|
|
59
|
+
collapsible
|
|
60
|
+
defaultValue={rule && !defaultOpen ? undefined : "config"}
|
|
61
|
+
className="auto-rule-config"
|
|
62
|
+
>
|
|
63
|
+
<AccordionItem value="config">
|
|
64
|
+
<AccordionTrigger>
|
|
65
|
+
<SlidersHorizontal className="ic" />
|
|
66
|
+
<span>Configuração do chat</span>
|
|
67
|
+
<span className="subtle auto-rule-config-summary">
|
|
68
|
+
{infos[0].summary}
|
|
69
|
+
{changed ? " · não gravado" : ""}
|
|
70
|
+
</span>
|
|
71
|
+
</AccordionTrigger>
|
|
72
|
+
<AccordionContent className="auto-rule-config-fields">
|
|
73
|
+
<ol className="stepper compact rule-steps">
|
|
74
|
+
{STEPS.map((s, i) => {
|
|
75
|
+
const { missing, summary } = infos[i];
|
|
76
|
+
const kind = !seen(i) ? "" : missing ? "warning" : "done";
|
|
77
|
+
return (
|
|
78
|
+
<li key={s.id} className={`step ${kind}${i === index ? " chosen" : ""}`}>
|
|
79
|
+
<button type="button" onClick={() => go(i)} aria-current={i === index ? "step" : undefined}>
|
|
80
|
+
<span className="step-mark">{kind === "done" ? <Check weight="bold" /> : kind ? "!" : i + 1}</span>
|
|
81
|
+
<span className="step-name">{s.name}</span>
|
|
82
|
+
<span className="step-status">{summary}</span>
|
|
83
|
+
</button>
|
|
84
|
+
</li>
|
|
85
|
+
);
|
|
86
|
+
})}
|
|
87
|
+
</ol>
|
|
88
|
+
|
|
89
|
+
<div className="auto-rule-step">{BODIES[step.id]({ editor, detail: d, post, thePost })}</div>
|
|
90
|
+
|
|
91
|
+
{confirmSave && enabled && (
|
|
92
|
+
<p className="warning">
|
|
93
|
+
A regra está ligada: a nova vale na próxima passada e relê os comentários dos últimos 7 dias, respondendo{" "}
|
|
94
|
+
{onBehalf} os que passarem a disparar.
|
|
95
|
+
</p>
|
|
96
|
+
)}
|
|
97
|
+
<div className="actions">
|
|
98
|
+
{index > 0 && !confirmSave && (
|
|
99
|
+
<button className="button" disabled={!!busy} onClick={() => go(index - 1)}>
|
|
100
|
+
<ArrowLeft className="ic" /> Voltar
|
|
101
|
+
</button>
|
|
102
|
+
)}
|
|
103
|
+
{!last && !confirmSave && (
|
|
104
|
+
<button
|
|
105
|
+
className={`button${saveFirst ? "" : " primary"}`}
|
|
106
|
+
disabled={!!busy}
|
|
107
|
+
onClick={() => go(index + 1)}
|
|
108
|
+
>
|
|
109
|
+
Próximo <ArrowRight className="ic" />
|
|
110
|
+
</button>
|
|
111
|
+
)}
|
|
112
|
+
{confirmSave && enabled ? (
|
|
113
|
+
<>
|
|
114
|
+
<button className="button approve" disabled={!!busy} onClick={save}>
|
|
115
|
+
<Check className="ic" /> {busy === "save" ? "Gravando…" : "Confirmar: gravar com a regra ligada"}
|
|
116
|
+
</button>
|
|
117
|
+
<button className="button" disabled={!!busy} onClick={() => setConfirmSave(false)}>
|
|
118
|
+
<X className="ic" /> Cancelar
|
|
119
|
+
</button>
|
|
120
|
+
</>
|
|
121
|
+
) : (
|
|
122
|
+
<button
|
|
123
|
+
className={`button${saveFirst ? " primary" : ""}`}
|
|
124
|
+
disabled={!!busy || (!changed && !!rule)}
|
|
125
|
+
onClick={() => (enabled ? setConfirmSave(true) : save())}
|
|
126
|
+
>
|
|
127
|
+
<FloppyDisk className="ic" /> {busy === "save" ? "Gravando…" : "Gravar"}
|
|
128
|
+
</button>
|
|
129
|
+
)}
|
|
130
|
+
{changed && rule && !confirmSave && (
|
|
131
|
+
<button className="button" disabled={!!busy} onClick={() => setForm(initial)}>
|
|
132
|
+
<ArrowCounterClockwise className="ic" /> Descartar
|
|
133
|
+
</button>
|
|
134
|
+
)}
|
|
135
|
+
<button
|
|
136
|
+
className="button"
|
|
137
|
+
disabled={!!busy || !rule || changed}
|
|
138
|
+
onClick={runDry}
|
|
139
|
+
title={
|
|
140
|
+
changed ? "Grave antes: a simulação usa a regra gravada" : "Mostra o que mandaria, sem mandar nada"
|
|
141
|
+
}
|
|
142
|
+
>
|
|
143
|
+
<Play className="ic" /> {busy === "dry-run" ? "Simulando…" : "Simular"}
|
|
144
|
+
</button>
|
|
145
|
+
</div>
|
|
146
|
+
</AccordionContent>
|
|
147
|
+
</AccordionItem>
|
|
148
|
+
</Accordion>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/* the dry run's output: what the rule would send now, sending nothing */
|
|
2
|
+
|
|
3
|
+
export function RuleDryRun({ output, onClose }: { output: string; onClose: () => void }) {
|
|
4
|
+
return (
|
|
5
|
+
<div className="auto-rule-dry-run">
|
|
6
|
+
<h3>
|
|
7
|
+
Simulação <span className="subtle">o que mandaria agora, sem mandar nada</span>
|
|
8
|
+
<button className="subtle-link" onClick={onClose}>
|
|
9
|
+
Fechar
|
|
10
|
+
</button>
|
|
11
|
+
</h3>
|
|
12
|
+
<pre className="log">{output}</pre>
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* the second click of turning the rule on: it answers outside, on behalf of the account */
|
|
2
|
+
|
|
3
|
+
import { capitalize } from "../../lib/format";
|
|
4
|
+
import type { RuleEditor } from "../../hooks/useRuleEditor";
|
|
5
|
+
import type { OmnichatRuleDetail } from "../../types/api";
|
|
6
|
+
import { Power, X } from "../icons";
|
|
7
|
+
import { triggerLabel } from "../RuleForm";
|
|
8
|
+
|
|
9
|
+
export function RuleEnableConfirm({
|
|
10
|
+
editor: { form, busy, setConfirm, enable },
|
|
11
|
+
detail: d,
|
|
12
|
+
onBehalf,
|
|
13
|
+
thePost,
|
|
14
|
+
publicReplies,
|
|
15
|
+
}: {
|
|
16
|
+
editor: RuleEditor;
|
|
17
|
+
detail: OmnichatRuleDetail;
|
|
18
|
+
onBehalf: string;
|
|
19
|
+
thePost: string;
|
|
20
|
+
publicReplies: string[];
|
|
21
|
+
}) {
|
|
22
|
+
return (
|
|
23
|
+
<div className="auto-rule-confirm">
|
|
24
|
+
<p>
|
|
25
|
+
<strong>Ligar responde para fora, {onBehalf}.</strong> Quem comentar{" "}
|
|
26
|
+
{triggerLabel({ any_comment: form.any_comment, keywords: form.keywords })} recebe a DM
|
|
27
|
+
{publicReplies.length ? " e uma resposta pública no comentário" : ""}.
|
|
28
|
+
{d.published
|
|
29
|
+
? ` Os comentários dos últimos 7 dias que disparam também entram${d.defaults.max_per_pass ? `, até ${d.defaults.max_per_pass} por passada` : ""}.`
|
|
30
|
+
: ` ${capitalize(thePost)} ainda não subiu: começa quando ele for publicado.`}
|
|
31
|
+
</p>
|
|
32
|
+
<div className="actions">
|
|
33
|
+
<button className="button approve" disabled={!!busy} onClick={() => enable(true)}>
|
|
34
|
+
<Power className="ic" /> {busy === "enable" ? "Ligando…" : `Confirmar: responder ${onBehalf}`}
|
|
35
|
+
</button>
|
|
36
|
+
<button className="button" disabled={!!busy} onClick={() => setConfirm(false)}>
|
|
37
|
+
<X className="ic" /> Cancelar
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Skeleton } from "../ui/skeleton";
|
|
2
|
+
|
|
3
|
+
/* the rule has not arrived yet: the state, the term, the message and the button, in form order */
|
|
4
|
+
export function RuleSkeleton() {
|
|
5
|
+
return (
|
|
6
|
+
<div
|
|
7
|
+
className="omnichat-rule-skeleton"
|
|
8
|
+
aria-busy="true"
|
|
9
|
+
aria-label="Lendo a regra"
|
|
10
|
+
style={{ display: "flex", flexDirection: "column", gap: 10 }}
|
|
11
|
+
>
|
|
12
|
+
<Skeleton className="row" style={{ width: 200 }} />
|
|
13
|
+
<Skeleton style={{ height: 36, width: "100%", maxWidth: 360 }} />
|
|
14
|
+
<Skeleton style={{ height: 72, width: "100%" }} />
|
|
15
|
+
<Skeleton style={{ height: 32, width: 120 }} />
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
}
|