@agent-native/core 0.154.5 → 0.157.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/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/account-health/SKILL.md +76 -0
- package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +3 -0
- package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +2 -1
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +6 -5
- package/corpus/templates/analytics/AGENTS.md +3 -0
- package/corpus/templates/analytics/actions/account-deep-dive.ts +3 -2
- package/corpus/templates/analytics/actions/bigquery.ts +1 -1
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +4 -1
- package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyCombobox.tsx +12 -4
- package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyValueCombobox.tsx +5 -2
- package/corpus/templates/analytics/app/pages/adhoc/explorer/property-label.ts +32 -0
- package/corpus/templates/analytics/changelog/2026-08-13-account-health-readouts-verify-customer-scope-and-contract-metrics.md +7 -0
- package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +43 -17
- package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +17 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
- package/corpus/templates/assets/app/i18n-data.ts +21 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +17 -13
- package/corpus/templates/calendar/AGENTS.md +2 -0
- package/corpus/templates/calendar/DEVELOPING.md +4 -4
- package/corpus/templates/calendar/actions/get-settings.ts +4 -11
- package/corpus/templates/calendar/actions/update-availability.ts +15 -4
- package/corpus/templates/calendar/actions/update-settings.ts +15 -4
- package/corpus/templates/calendar/app/components/booking/DatePicker.tsx +9 -3
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +21 -19
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +9 -6
- package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +25 -3
- package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +10 -3
- package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +9 -9
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -3
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +10 -4
- package/corpus/templates/calendar/app/i18n-data.ts +30 -0
- package/corpus/templates/calendar/app/lib/availability-schedule.ts +53 -0
- package/corpus/templates/calendar/app/lib/event-form-utils.ts +5 -0
- package/corpus/templates/calendar/app/pages/AvailabilitySettings.tsx +90 -28
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +135 -61
- package/corpus/templates/calendar/app/pages/BookingPage.tsx +2 -0
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +30 -15
- package/corpus/templates/calendar/app/pages/Settings.tsx +60 -1
- package/corpus/templates/calendar/changelog/2026-08-13-find-a-time-now-closes-from-a-clear-header-action.md +6 -0
- package/corpus/templates/calendar/server/handlers/bookings.ts +2 -1
- package/corpus/templates/calendar/server/handlers/settings.ts +12 -16
- package/corpus/templates/calendar/shared/api.ts +1 -0
- package/corpus/templates/calendar/shared/availability-schedule.ts +64 -0
- package/corpus/templates/calendar/shared/calendar-week.ts +21 -0
- package/corpus/templates/calendar/shared/settings.ts +44 -0
- package/corpus/templates/clips/AGENTS.md +2 -0
- package/corpus/templates/clips/actions/add-comment.ts +5 -2
- package/corpus/templates/clips/actions/finalize-recording.ts +31 -1
- package/corpus/templates/clips/actions/get-recording-player-data.ts +9 -0
- package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +21 -1
- package/corpus/templates/clips/actions/reply-to-comment.ts +5 -2
- package/corpus/templates/clips/actions/update-comment.ts +9 -2
- package/corpus/templates/clips/app/components/library/search-bar.tsx +26 -13
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +135 -3
- package/corpus/templates/clips/app/components/player/comments-panel.tsx +5 -99
- package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +7 -3
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +102 -59
- package/corpus/templates/clips/app/components/player/video-player.tsx +84 -24
- package/corpus/templates/clips/app/components/workspace/notifications-list.tsx +11 -3
- package/corpus/templates/clips/app/i18n/en-US.ts +12 -0
- package/corpus/templates/clips/app/lib/public-meeting.ts +11 -3
- package/corpus/templates/clips/app/lib/search-focus.ts +15 -0
- package/corpus/templates/clips/app/root.tsx +2 -1
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +94 -26
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +24 -7
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +8 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +29 -8
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +24 -6
- package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +72 -26
- package/corpus/templates/clips/changelog/2026-08-13-inline-markdown-comments.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-13-private-meeting-agent-links.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +116 -19
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +13 -29
- package/corpus/templates/clips/desktop/src/lib/recording-request.ts +39 -0
- package/corpus/templates/clips/desktop/src/lib/settings-navigation.ts +11 -0
- package/corpus/templates/clips/desktop/src/lib/whisper-model-picker.ts +7 -0
- package/corpus/templates/clips/desktop/src/styles.css +117 -0
- package/corpus/templates/clips/server/db/index.ts +10 -0
- package/corpus/templates/clips/server/db/schema.ts +1 -0
- package/corpus/templates/clips/server/lib/recordings.ts +3 -1
- package/corpus/templates/clips/server/lib/seekable-media-state.ts +90 -0
- package/corpus/templates/clips/server/plugins/db.ts +5 -0
- package/corpus/templates/clips/server/routes/api/public-meeting.get.ts +37 -4
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +16 -5
- package/corpus/templates/clips/shared/clips-ai-prefs.ts +3 -0
- package/corpus/templates/clips/shared/meeting-agent-access.ts +5 -0
- package/corpus/templates/content/actions/add-comment.ts +2 -1
- package/corpus/templates/content/actions/update-comment.ts +1 -1
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +24 -15
- package/corpus/templates/design/actions/generate-design.ts +10 -7
- package/corpus/templates/design/actions/present-design-variants.ts +35 -6
- package/corpus/templates/design/actions/run-design-audit.ts +33 -0
- package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-catches-a-screen-that-renders-behind-an.md +6 -0
- package/corpus/templates/design/shared/design-review.ts +1 -0
- package/corpus/templates/design/shared/html-integrity.ts +66 -0
- package/corpus/templates/dispatch/.env.example +5 -0
- package/corpus/templates/dispatch/AGENTS.md +24 -19
- package/corpus/templates/dispatch/app/i18n-data.ts +20 -0
- package/corpus/templates/dispatch/server/lib/identity-sso.ts +21 -90
- package/corpus/templates/dispatch/server/plugins/identity-sso.ts +3 -12
- package/corpus/templates/dispatch/shared/feature-flags.ts +4 -0
- package/corpus/templates/factory/AGENTS.md +5 -1
- package/corpus/templates/factory/README.md +23 -0
- package/corpus/templates/factory/actions/view-screen.ts +17 -0
- package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +239 -0
- package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +2 -0
- package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +130 -7
- package/corpus/templates/factory/app/i18n/en-US.ts +20 -0
- package/corpus/templates/factory/app/routes/factory.tsx +41 -0
- package/corpus/templates/factory/package.json +1 -0
- package/corpus/templates/factory/server/factory-graph/contracts.ts +2 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -0
- package/corpus/templates/factory/server/plugins/dispatch-db.ts +1 -0
- package/corpus/templates/factory/server/plugins/setup-dispatch.ts +3 -0
- package/corpus/templates/mail/app/lib/native-mcp-exclusions.ts +3 -0
- package/corpus/templates/mail/vite.config.ts +7 -0
- package/corpus/templates/plan/actions/reply-to-plan-comment.ts +7 -2
- package/corpus/templates/plan/actions/resolve-plan-comment.ts +2 -2
- package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +29 -20
- package/corpus/templates/slides/actions/add-slide-comment.ts +1 -1
- package/corpus/templates/slides/actions/update-slide-comment.ts +1 -1
- package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +9 -6
- package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
- package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +42 -2
- package/corpus/templates/slides/app/global.css +7 -40
- package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +130 -45
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/production-agent.d.ts +30 -0
- package/dist/agent/production-agent.js +105 -9
- package/dist/agent/thread-data-builder.js +17 -1
- package/dist/agent/types.d.ts +9 -0
- package/dist/cli/skills-content/help.js +6 -4
- package/dist/cli/skills.js +17 -2
- package/dist/cli/workspacify.d.ts +5 -0
- package/dist/cli/workspacify.js +65 -8
- package/dist/client/AgentPanel.d.ts +5 -0
- package/dist/client/AgentPanel.js +32 -13
- package/dist/client/AssistantChat.d.ts +36 -1
- package/dist/client/AssistantChat.js +175 -110
- package/dist/client/MultiTabAssistantChat.js +44 -27
- package/dist/client/active-run-state.d.ts +14 -1
- package/dist/client/active-run-state.js +0 -0
- package/dist/client/agent-chat-adapter.js +107 -5
- package/dist/client/analytics.js +9 -2
- package/dist/client/chat/markdown-renderer.js +4 -2
- package/dist/client/chat/message-components.d.ts +2 -2
- package/dist/client/chat/message-components.js +69 -35
- package/dist/client/chat/run-recovery.d.ts +4 -1
- package/dist/client/chat/run-recovery.js +62 -30
- package/dist/client/chat/tool-call-display.d.ts +12 -3
- package/dist/client/chat/tool-call-display.js +79 -40
- package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
- package/dist/client/chat/widgets/DataChartWidget.js +8 -2
- package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
- package/dist/client/chat/widgets/DataTableWidget.js +23 -9
- package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
- package/dist/client/chat-first/apps-rail.js +9 -4
- package/dist/client/chat-first/primary-nav.d.ts +2 -1
- package/dist/client/chat-first/primary-nav.js +3 -3
- package/dist/client/chat-first/types.d.ts +5 -1
- package/dist/client/components/ui/message-scroller.d.ts +1 -1
- package/dist/client/components/ui/message-scroller.js +7 -3
- package/dist/client/composer/runtime-adapters.js +3 -2
- package/dist/client/context-xray/ContextMeter.js +5 -1
- package/dist/client/context-xray/ContextXRayPanel.js +5 -5
- package/dist/client/error-format.d.ts +4 -0
- package/dist/client/error-format.js +93 -5
- package/dist/client/i18n.js +83 -17
- package/dist/client/markdown/InlineMarkdown.d.ts +23 -0
- package/dist/client/markdown/InlineMarkdown.js +65 -0
- package/dist/client/markdown/index.d.ts +1 -0
- package/dist/client/markdown/index.js +1 -0
- package/dist/client/observability/ThumbsFeedback.js +10 -8
- package/dist/client/review/ReviewThreadPanel.js +2 -1
- package/dist/client/run-stream-ownership.d.ts +39 -0
- package/dist/client/run-stream-ownership.js +65 -0
- package/dist/client/sharing/ShareButton.js +160 -54
- package/dist/coding-tools/run-code.js +2 -1
- package/dist/coding-tools/sandbox/background.d.ts +1 -0
- package/dist/coding-tools/sandbox/background.js +8 -1
- package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
- package/dist/coding-tools/sandbox/executions-store.js +41 -3
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/feature-flags/index.d.ts +1 -1
- package/dist/feature-flags/index.js +1 -1
- package/dist/feature-flags/store.d.ts +10 -0
- package/dist/feature-flags/store.js +112 -1
- package/dist/guards/no-env-credentials.js +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/integrations/adapters/slack.js +5 -1
- package/dist/localization/core-messages/ar-SA.d.ts +3 -0
- package/dist/localization/core-messages/ar-SA.js +541 -0
- package/dist/localization/core-messages/de-DE.d.ts +3 -0
- package/dist/localization/core-messages/de-DE.js +513 -0
- package/dist/localization/core-messages/en-US.d.ts +513 -0
- package/dist/localization/core-messages/en-US.js +513 -0
- package/dist/localization/core-messages/es-ES.d.ts +3 -0
- package/dist/localization/core-messages/es-ES.js +520 -0
- package/dist/localization/core-messages/fr-FR.d.ts +3 -0
- package/dist/localization/core-messages/fr-FR.js +520 -0
- package/dist/localization/core-messages/hi-IN.d.ts +3 -0
- package/dist/localization/core-messages/hi-IN.js +513 -0
- package/dist/localization/core-messages/ja-JP.d.ts +3 -0
- package/dist/localization/core-messages/ja-JP.js +506 -0
- package/dist/localization/core-messages/ko-KR.d.ts +3 -0
- package/dist/localization/core-messages/ko-KR.js +506 -0
- package/dist/localization/core-messages/pt-BR.d.ts +3 -0
- package/dist/localization/core-messages/pt-BR.js +520 -0
- package/dist/localization/core-messages/zh-CN.d.ts +3 -0
- package/dist/localization/core-messages/zh-CN.js +506 -0
- package/dist/localization/core-messages/zh-TW.d.ts +3 -0
- package/dist/localization/core-messages/zh-TW.js +506 -0
- package/dist/localization/core-messages.d.ts +524 -0
- package/dist/localization/core-messages.js +124 -0
- package/dist/localization/default-messages.d.ts +3 -0
- package/dist/localization/default-messages.js +3 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +2 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +15 -15
- package/dist/resources/agents.js +40 -5
- package/dist/resources/metadata.d.ts +10 -0
- package/dist/resources/metadata.js +7 -3
- package/dist/review/actions/create-review-comment.js +1 -1
- package/dist/review/actions/reply-review-comment.js +1 -1
- package/dist/review/actions/resolve-review-thread.js +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/action-routes.js +32 -6
- package/dist/server/agent-chat/plugin-options.d.ts +7 -2
- package/dist/server/agent-chat-plugin.d.ts +10 -0
- package/dist/server/agent-chat-plugin.js +144 -41
- package/dist/server/agent-discovery.js +14 -3
- package/dist/server/agent-run-context.d.ts +7 -1
- package/dist/server/agent-run-context.js +9 -2
- package/dist/server/agent-teams-run-queue.d.ts +3 -0
- package/dist/server/agent-teams.js +38 -9
- package/dist/server/core-routes-plugin.js +1 -1
- package/dist/server/identity-sso-migrations.d.ts +7 -0
- package/dist/server/identity-sso-migrations.js +36 -0
- package/dist/server/identity-sso-store.d.ts +3 -2
- package/dist/server/identity-sso-store.js +8 -3
- package/dist/server/index.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.js +4 -0
- package/dist/server/request-context.d.ts +7 -0
- package/dist/server/request-context.js +15 -0
- package/dist/tracking/providers.js +13 -3
- package/dist/workspace-files/tool.js +1 -1
- package/docs/content/agent-surfaces.mdx +30 -0
- package/package.json +3 -2
|
@@ -844,10 +844,11 @@ const enUS = {
|
|
|
844
844
|
checking: "Checking",
|
|
845
845
|
checkingUpload: "Checking upload",
|
|
846
846
|
clearAll: "Clear all",
|
|
847
|
+
clearAllWithCount: "Clear all candidates ({{count}})",
|
|
847
848
|
clearCandidates: "Clear candidates",
|
|
848
849
|
clearCandidatesTitle: "Clear {{count}} candidates?",
|
|
849
850
|
clearCandidatesDescription:
|
|
850
|
-
"Clears the live stage and deletes unsaved draft
|
|
851
|
+
"Clears the live stage and deletes every unsaved draft candidate. Saved library assets stay untouched.",
|
|
851
852
|
clearGeneratedCandidatesTitle: "Clear generated candidates?",
|
|
852
853
|
clearGeneratedCandidatesDescription:
|
|
853
854
|
"This removes every unsaved candidate from the thread and deletes the generated asset rows behind them. Saved library assets are not touched.",
|
|
@@ -986,6 +987,7 @@ const enUS = {
|
|
|
986
987
|
open: "Open",
|
|
987
988
|
openAssets: "Open Assets",
|
|
988
989
|
openChat: "Open chat",
|
|
990
|
+
hideDetails: "Hide details",
|
|
989
991
|
openDetails: "Open details",
|
|
990
992
|
preparing: "Preparing...",
|
|
991
993
|
previousImage: "Previous image",
|
|
@@ -3728,7 +3730,9 @@ export const messagesByLocale = {
|
|
|
3728
3730
|
checkingUpload: "正在检查上传",
|
|
3729
3731
|
clear: "清除",
|
|
3730
3732
|
clearAll: "全部清除",
|
|
3733
|
+
clearAllWithCount: "清除所有候选项({{count}})",
|
|
3731
3734
|
clearCandidates: "清除候选项",
|
|
3735
|
+
hideDetails: "隐藏详情",
|
|
3732
3736
|
clearCandidatesDescription: "清除实时阶段并删除未保存的草稿候选项。",
|
|
3733
3737
|
clearCandidatesTitle: "清除 {{count}} 个候选项?",
|
|
3734
3738
|
clearGeneratedCandidatesDescription:
|
|
@@ -4552,7 +4556,9 @@ export const messagesByLocale = {
|
|
|
4552
4556
|
checkingImageLibraries: "Comprobando bibliotecas de imágenes...",
|
|
4553
4557
|
checkingUpload: "Comprobando carga",
|
|
4554
4558
|
clearAll: "Borrar todo",
|
|
4559
|
+
clearAllWithCount: "Borrar todos los candidatos ({{count}})",
|
|
4555
4560
|
clearCandidates: "Limpiar candidatos",
|
|
4561
|
+
hideDetails: "Ocultar detalles",
|
|
4556
4562
|
clearCandidatesDescription:
|
|
4557
4563
|
"Limpia la etapa en vivo y elimina los candidatos de borrador no guardados.",
|
|
4558
4564
|
clearGeneratedCandidatesDescription:
|
|
@@ -5026,7 +5032,9 @@ export const messagesByLocale = {
|
|
|
5026
5032
|
checkingImageLibraries: "Vérification des bibliothèques d'images...",
|
|
5027
5033
|
checkingUpload: "Vérification du téléchargement",
|
|
5028
5034
|
clearAll: "Tout effacer",
|
|
5035
|
+
clearAllWithCount: "Effacer tous les candidats ({{count}})",
|
|
5029
5036
|
clearCandidates: "Effacer les candidats",
|
|
5037
|
+
hideDetails: "Masquer les détails",
|
|
5030
5038
|
clearCandidatesDescription:
|
|
5031
5039
|
"Efface l'étape en direct et supprime les candidats de brouillon non enregistrés.",
|
|
5032
5040
|
clearGeneratedCandidatesDescription:
|
|
@@ -5479,7 +5487,9 @@ export const messagesByLocale = {
|
|
|
5479
5487
|
checkingImageLibraries: "Bildbibliotheken werden geprüft...",
|
|
5480
5488
|
checkingUpload: "Upload wird überprüft",
|
|
5481
5489
|
clearAll: "Alles löschen",
|
|
5490
|
+
clearAllWithCount: "Alle Kandidaten löschen ({{count}})",
|
|
5482
5491
|
clearCandidates: "Kandidaten löschen",
|
|
5492
|
+
hideDetails: "Details ausblenden",
|
|
5483
5493
|
clearCandidatesDescription:
|
|
5484
5494
|
"Löscht die Live-Phase und entfernt nicht gespeicherte Entwurfskandidaten.",
|
|
5485
5495
|
clearGeneratedCandidatesDescription:
|
|
@@ -5837,7 +5847,9 @@ export const messagesByLocale = {
|
|
|
5837
5847
|
checkingImageLibraries: "画像ライブラリを確認中...",
|
|
5838
5848
|
checkingUpload: "アップロードを確認しています",
|
|
5839
5849
|
clearAll: "すべてクリア",
|
|
5850
|
+
clearAllWithCount: "候補をすべてクリア({{count}})",
|
|
5840
5851
|
clearCandidates: "候補をクリアする",
|
|
5852
|
+
hideDetails: "詳細を非表示",
|
|
5841
5853
|
clearCandidatesDescription:
|
|
5842
5854
|
"ライブ ステージをクリアし、保存されていないドラフト候補を削除します。",
|
|
5843
5855
|
clearGeneratedCandidatesDescription:
|
|
@@ -6186,7 +6198,9 @@ export const messagesByLocale = {
|
|
|
6186
6198
|
checkingImageLibraries: "이미지 라이브러리 확인 중...",
|
|
6187
6199
|
checkingUpload: "업로드 확인 중",
|
|
6188
6200
|
clearAll: "모두 지우기",
|
|
6201
|
+
clearAllWithCount: "후보 모두 지우기({{count}})",
|
|
6189
6202
|
clearCandidates: "후보 제거",
|
|
6203
|
+
hideDetails: "세부정보 숨기기",
|
|
6190
6204
|
clearCandidatesDescription:
|
|
6191
6205
|
"라이브 단계를 지우고 저장되지 않은 초안 후보를 삭제합니다.",
|
|
6192
6206
|
clearGeneratedCandidatesDescription:
|
|
@@ -6534,7 +6548,9 @@ export const messagesByLocale = {
|
|
|
6534
6548
|
checkingImageLibraries: "Verificando bibliotecas de imagens...",
|
|
6535
6549
|
checkingUpload: "Verificando upload",
|
|
6536
6550
|
clearAll: "Limpar tudo",
|
|
6551
|
+
clearAllWithCount: "Limpar todos os candidatos ({{count}})",
|
|
6537
6552
|
clearCandidates: "Limpar candidatos",
|
|
6553
|
+
hideDetails: "Ocultar detalhes",
|
|
6538
6554
|
clearCandidatesDescription:
|
|
6539
6555
|
"Limpa o estágio ao vivo e exclui candidatos de rascunho não salvos.",
|
|
6540
6556
|
clearGeneratedCandidatesDescription:
|
|
@@ -6985,7 +7001,9 @@ export const messagesByLocale = {
|
|
|
6985
7001
|
checkingImageLibraries: "Image libraries जांची जा रही हैं...",
|
|
6986
7002
|
checkingUpload: "अपलोड की जाँच की जा रही है",
|
|
6987
7003
|
clearAll: "सभी साफ करें",
|
|
7004
|
+
clearAllWithCount: "सभी उम्मीदवार साफ करें ({{count}})",
|
|
6988
7005
|
clearCandidates: "उम्मीदवारों को साफ करें",
|
|
7006
|
+
hideDetails: "विवरण छिपाएं",
|
|
6989
7007
|
clearCandidatesDescription:
|
|
6990
7008
|
"लाइव चरण को साफ करता है और अ सहेजे गए ड्राफ्ट उम्मीदवारों को हटाता है।",
|
|
6991
7009
|
clearGeneratedCandidatesDescription:
|
|
@@ -7331,7 +7349,9 @@ export const messagesByLocale = {
|
|
|
7331
7349
|
checkingImageLibraries: "جارٍ فحص مكتبات الصور...",
|
|
7332
7350
|
checkingUpload: "التحقق من التحميل",
|
|
7333
7351
|
clearAll: "مسح الكل",
|
|
7352
|
+
clearAllWithCount: "مسح كل المرشحين ({{count}})",
|
|
7334
7353
|
clearCandidates: "امسح المرشحين",
|
|
7354
|
+
hideDetails: "إخفاء التفاصيل",
|
|
7335
7355
|
clearCandidatesDescription:
|
|
7336
7356
|
"مسح مرحلة المرشح وحذف المرشحين الذين تم إنشاؤهم غير المحفوظة. أصول المكتبة المحفوظة تبقى دون تغيير.",
|
|
7337
7357
|
clearGeneratedCandidatesDescription:
|
|
@@ -4533,7 +4533,9 @@ function LiveCandidatesActions({
|
|
|
4533
4533
|
const hasFailed = failedCount > 0;
|
|
4534
4534
|
const isClearing = dismissSlots.isPending || deleteAssets.isPending;
|
|
4535
4535
|
const actionLabel =
|
|
4536
|
-
pending === "failed"
|
|
4536
|
+
pending === "failed"
|
|
4537
|
+
? t("library.dismissFailed")
|
|
4538
|
+
: t("library.clearAllWithCount", { count: totalCount });
|
|
4537
4539
|
const busyLabel =
|
|
4538
4540
|
pending === "failed" ? t("library.dismissing") : t("library.clearing");
|
|
4539
4541
|
|
|
@@ -4645,26 +4647,28 @@ function LiveCandidatesActions({
|
|
|
4645
4647
|
</Button>
|
|
4646
4648
|
</DropdownMenuTrigger>
|
|
4647
4649
|
<DropdownMenuContent align="end">
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
event
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4650
|
+
{hasFailed ? (
|
|
4651
|
+
<DropdownMenuItem
|
|
4652
|
+
disabled={isClearing}
|
|
4653
|
+
onSelect={(event) => {
|
|
4654
|
+
event.preventDefault();
|
|
4655
|
+
setPending("failed");
|
|
4656
|
+
}}
|
|
4657
|
+
>
|
|
4658
|
+
<IconTrash className="mr-2 h-4 w-4 shrink-0" />
|
|
4659
|
+
{t("library.dismissFailedWithCount", { count: failedCount })}
|
|
4660
|
+
</DropdownMenuItem>
|
|
4661
|
+
) : null}
|
|
4658
4662
|
<DropdownMenuItem
|
|
4659
4663
|
className="text-destructive focus:bg-destructive/10 focus:text-destructive"
|
|
4660
|
-
disabled={isClearing}
|
|
4664
|
+
disabled={isClearing || totalCount === 0}
|
|
4661
4665
|
onSelect={(event) => {
|
|
4662
4666
|
event.preventDefault();
|
|
4663
4667
|
setPending("all");
|
|
4664
4668
|
}}
|
|
4665
4669
|
>
|
|
4666
4670
|
<IconTrash className="mr-2 h-4 w-4 shrink-0" />
|
|
4667
|
-
{t("library.
|
|
4671
|
+
{t("library.clearAllWithCount", { count: totalCount })}
|
|
4668
4672
|
</DropdownMenuItem>
|
|
4669
4673
|
</DropdownMenuContent>
|
|
4670
4674
|
</DropdownMenu>
|
|
@@ -24,6 +24,8 @@ Detailed event, availability, booking, storage, and UI rules live in
|
|
|
24
24
|
- Never hardcode API keys, tokens, webhook URLs, signing secrets, private Builder/internal data, customer data, or credential-looking literals. Use secrets/OAuth/runtime configuration and obvious placeholders in examples.
|
|
25
25
|
- Use actions for events, availability, booking links, settings, navigation,
|
|
26
26
|
Google Calendar connection, and sharing. Do not bypass app access checks.
|
|
27
|
+
- The `get-settings` and `update-settings` actions expose the General week-start
|
|
28
|
+
setting as `weekStart`: `sunday` or `monday`.
|
|
27
29
|
- Use `connect-google-calendar` when the user asks to connect or reconnect
|
|
28
30
|
Google Calendar. Return its link to the user; do not `fetch`
|
|
29
31
|
`/_agent-native/google/auth-url` from the agent backend because that route
|
|
@@ -99,10 +99,10 @@ Structured data lives in SQL. Use `@agent-native/core/db/schema` helpers for sch
|
|
|
99
99
|
|
|
100
100
|
Configuration lives in the SQL `settings` table, accessed via the settings API:
|
|
101
101
|
|
|
102
|
-
| Key | Contents
|
|
103
|
-
| ----------------------- |
|
|
104
|
-
| `calendar-settings` | App settings (timezone, booking page config) |
|
|
105
|
-
| `calendar-availability` | Availability schedule configuration
|
|
102
|
+
| Key | Contents |
|
|
103
|
+
| ----------------------- | -------------------------------------------------------- |
|
|
104
|
+
| `calendar-settings` | App settings (timezone, week start, booking page config) |
|
|
105
|
+
| `calendar-availability` | Availability schedule configuration |
|
|
106
106
|
|
|
107
107
|
### OAuth Tokens (via `@agent-native/core/oauth-tokens`)
|
|
108
108
|
|
|
@@ -3,14 +3,7 @@ import { getRequestUserEmail } from "@agent-native/core/server";
|
|
|
3
3
|
import { getUserSetting } from "@agent-native/core/settings";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
const DEFAULT_SETTINGS: Settings = {
|
|
9
|
-
timezone: "America/New_York",
|
|
10
|
-
bookingPageTitle: "Book a Meeting",
|
|
11
|
-
bookingPageDescription: "Select a time that works for you.",
|
|
12
|
-
defaultEventDuration: 30,
|
|
13
|
-
};
|
|
6
|
+
import { normalizeCalendarSettings } from "../shared/settings.js";
|
|
14
7
|
|
|
15
8
|
export default defineAction({
|
|
16
9
|
description: "Get calendar settings",
|
|
@@ -19,8 +12,8 @@ export default defineAction({
|
|
|
19
12
|
run: async () => {
|
|
20
13
|
const email = getRequestUserEmail();
|
|
21
14
|
if (!email) throw new Error("no authenticated user");
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
return normalizeCalendarSettings(
|
|
16
|
+
await getUserSetting(email, "calendar-settings"),
|
|
17
|
+
);
|
|
25
18
|
},
|
|
26
19
|
});
|
|
@@ -8,16 +8,27 @@ import {
|
|
|
8
8
|
updateBookingUsername,
|
|
9
9
|
} from "../server/handlers/booking-usernames.js";
|
|
10
10
|
import type { AvailabilityConfig } from "../shared/api.js";
|
|
11
|
+
import { availabilitySlotsOverlap } from "../shared/availability-schedule.js";
|
|
11
12
|
|
|
12
13
|
const timeSlotSchema = z.object({
|
|
13
14
|
start: z.string(),
|
|
14
15
|
end: z.string(),
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
const dayScheduleSchema = z
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
const dayScheduleSchema = z
|
|
19
|
+
.object({
|
|
20
|
+
enabled: z.boolean(),
|
|
21
|
+
slots: z.array(timeSlotSchema),
|
|
22
|
+
})
|
|
23
|
+
.superRefine((day, ctx) => {
|
|
24
|
+
if (availabilitySlotsOverlap(day.slots)) {
|
|
25
|
+
ctx.addIssue({
|
|
26
|
+
code: z.ZodIssueCode.custom,
|
|
27
|
+
path: ["slots"],
|
|
28
|
+
message: "Availability windows must not overlap",
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
21
32
|
|
|
22
33
|
const availabilitySchema = z.object({
|
|
23
34
|
timezone: z.string(),
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { getRequestUserEmail } from "@agent-native/core/server";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getUserSetting,
|
|
5
|
+
putUserSetting,
|
|
6
|
+
putSetting,
|
|
7
|
+
} from "@agent-native/core/settings";
|
|
4
8
|
import { z } from "zod";
|
|
5
9
|
|
|
6
|
-
import
|
|
10
|
+
import { normalizeCalendarSettings } from "../shared/settings.js";
|
|
7
11
|
|
|
8
12
|
export default defineAction({
|
|
9
13
|
description: "Update calendar settings",
|
|
@@ -20,12 +24,19 @@ export default defineAction({
|
|
|
20
24
|
.positive()
|
|
21
25
|
.optional()
|
|
22
26
|
.describe("Default event duration in minutes"),
|
|
27
|
+
weekStart: z
|
|
28
|
+
.enum(["sunday", "monday"])
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("First day shown in calendar weeks"),
|
|
23
31
|
}),
|
|
24
32
|
run: async (args) => {
|
|
25
33
|
const email = getRequestUserEmail();
|
|
26
34
|
if (!email) throw new Error("no authenticated user");
|
|
27
|
-
|
|
28
|
-
const settings =
|
|
35
|
+
const currentSettings = await getUserSetting(email, "calendar-settings");
|
|
36
|
+
const settings = normalizeCalendarSettings({
|
|
37
|
+
...normalizeCalendarSettings(currentSettings),
|
|
38
|
+
...args,
|
|
39
|
+
});
|
|
29
40
|
const settingsRecord = settings as unknown as Record<string, unknown>;
|
|
30
41
|
await putUserSetting(email, "calendar-settings", settingsRecord);
|
|
31
42
|
await putSetting("calendar-settings", settingsRecord);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AvailabilityConfig } from "@shared/api";
|
|
2
|
+
import { getWeekdayOrder } from "@shared/calendar-week";
|
|
2
3
|
import { IconChevronLeft, IconChevronRight } from "@tabler/icons-react";
|
|
3
4
|
import {
|
|
4
5
|
startOfMonth,
|
|
@@ -31,6 +32,7 @@ interface DatePickerProps {
|
|
|
31
32
|
availabilityLoading?: boolean;
|
|
32
33
|
viewMonth: Date;
|
|
33
34
|
onViewMonthChange: (month: Date) => void;
|
|
35
|
+
weekStartsOn?: 0 | 1;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
const WEEKDAY_HEADERS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
@@ -53,12 +55,16 @@ export function DatePicker({
|
|
|
53
55
|
availabilityLoading = false,
|
|
54
56
|
viewMonth,
|
|
55
57
|
onViewMonthChange,
|
|
58
|
+
weekStartsOn = 0,
|
|
56
59
|
}: DatePickerProps) {
|
|
57
60
|
const monthStart = startOfMonth(viewMonth);
|
|
58
61
|
const monthEnd = endOfMonth(viewMonth);
|
|
59
|
-
const calendarStart = startOfWeek(monthStart);
|
|
60
|
-
const calendarEnd = endOfWeek(monthEnd);
|
|
62
|
+
const calendarStart = startOfWeek(monthStart, { weekStartsOn });
|
|
63
|
+
const calendarEnd = endOfWeek(monthEnd, { weekStartsOn });
|
|
61
64
|
const days = eachDayOfInterval({ start: calendarStart, end: calendarEnd });
|
|
65
|
+
const weekdayHeaders = getWeekdayOrder(weekStartsOn).map(
|
|
66
|
+
(day) => WEEKDAY_HEADERS[day],
|
|
67
|
+
);
|
|
62
68
|
const availableDateSet = useMemo(
|
|
63
69
|
() => new Set(availableDates),
|
|
64
70
|
[availableDates],
|
|
@@ -103,7 +109,7 @@ export function DatePicker({
|
|
|
103
109
|
|
|
104
110
|
{/* Weekday headers */}
|
|
105
111
|
<div className="grid grid-cols-7 mb-1">
|
|
106
|
-
{
|
|
112
|
+
{weekdayHeaders.map((d) => (
|
|
107
113
|
<div
|
|
108
114
|
key={d}
|
|
109
115
|
className="py-1 text-center text-xs font-medium text-muted-foreground"
|
|
@@ -76,8 +76,8 @@ import {
|
|
|
76
76
|
createReminderDraft,
|
|
77
77
|
dateTimeInTimezoneToIso,
|
|
78
78
|
getEventEndValidationMessage,
|
|
79
|
-
getLocalTimezone,
|
|
80
79
|
remindersToDraftState,
|
|
80
|
+
resolveEventTimezone,
|
|
81
81
|
type AttachmentDraft,
|
|
82
82
|
type ReminderDraft,
|
|
83
83
|
type ReminderMode,
|
|
@@ -236,7 +236,7 @@ export function CreateEventPopover({
|
|
|
236
236
|
const defaultDurationMinutes = Number.isFinite(rawDefaultDuration)
|
|
237
237
|
? Math.max(5, rawDefaultDuration)
|
|
238
238
|
: 30;
|
|
239
|
-
const defaultTimezone = settings?.timezone ||
|
|
239
|
+
const defaultTimezone = settings?.timezone || resolveEventTimezone();
|
|
240
240
|
const fallbackStart = "09:00";
|
|
241
241
|
const fallbackEnd = addMinutesToTimeString(
|
|
242
242
|
fallbackStart,
|
|
@@ -279,6 +279,7 @@ export function CreateEventPopover({
|
|
|
279
279
|
const [findTimeOpen, setFindTimeOpen] = useState(false);
|
|
280
280
|
const isOutOfOffice = eventType === "outOfOffice";
|
|
281
281
|
const timedOnlyStatus = eventType === "focusTime";
|
|
282
|
+
const eventTimezone = resolveEventTimezone(timezone);
|
|
282
283
|
|
|
283
284
|
const createEvent = useCreateEvent();
|
|
284
285
|
const delEvent = useDeleteEvent();
|
|
@@ -308,8 +309,9 @@ export function CreateEventPopover({
|
|
|
308
309
|
}
|
|
309
310
|
|
|
310
311
|
const nextDate = format(defaultDate || new Date(), "yyyy-MM-dd");
|
|
311
|
-
const draftTimezone =
|
|
312
|
-
draft?.startTimeZone || draft?.endTimeZone || defaultTimezone
|
|
312
|
+
const draftTimezone = resolveEventTimezone(
|
|
313
|
+
draft?.startTimeZone || draft?.endTimeZone || defaultTimezone,
|
|
314
|
+
);
|
|
313
315
|
const initKey = buildEventFormInitializationKey({
|
|
314
316
|
draftId: draft?.id,
|
|
315
317
|
date: nextDate,
|
|
@@ -455,12 +457,12 @@ export function CreateEventPopover({
|
|
|
455
457
|
? date
|
|
456
458
|
: effectiveAllDay
|
|
457
459
|
? new Date(`${date}T00:00:00`).toISOString()
|
|
458
|
-
: dateTimeInTimezoneToIso(date, startTime,
|
|
460
|
+
: dateTimeInTimezoneToIso(date, startTime, eventTimezone);
|
|
459
461
|
const endValue = fullDayOutOfOffice
|
|
460
462
|
? endDate
|
|
461
463
|
: effectiveAllDay
|
|
462
464
|
? allDayEnd.toISOString()
|
|
463
|
-
: dateTimeInTimezoneToIso(endDate, endTime,
|
|
465
|
+
: dateTimeInTimezoneToIso(endDate, endTime, eventTimezone);
|
|
464
466
|
const attachmentResult = validateAttachmentDrafts(attachments);
|
|
465
467
|
const reminderPatch = buildReminderPayload(reminderMode, reminders);
|
|
466
468
|
const nextDraft: CalendarEventDraft = {
|
|
@@ -470,8 +472,8 @@ export function CreateEventPopover({
|
|
|
470
472
|
description: isOutOfOffice ? "" : description,
|
|
471
473
|
start: startValue,
|
|
472
474
|
end: endValue,
|
|
473
|
-
startTimeZone: effectiveAllDay ? undefined :
|
|
474
|
-
endTimeZone: effectiveAllDay ? undefined :
|
|
475
|
+
startTimeZone: effectiveAllDay ? undefined : eventTimezone,
|
|
476
|
+
endTimeZone: effectiveAllDay ? undefined : eventTimezone,
|
|
475
477
|
location: isOutOfOffice ? "" : location,
|
|
476
478
|
allDay: effectiveAllDay,
|
|
477
479
|
fullDay: fullDayOutOfOffice,
|
|
@@ -547,7 +549,7 @@ export function CreateEventPopover({
|
|
|
547
549
|
declineMessage,
|
|
548
550
|
availability,
|
|
549
551
|
visibility,
|
|
550
|
-
|
|
552
|
+
eventTimezone,
|
|
551
553
|
colorId,
|
|
552
554
|
reminderMode,
|
|
553
555
|
reminders,
|
|
@@ -578,7 +580,7 @@ export function CreateEventPopover({
|
|
|
578
580
|
time: allDay
|
|
579
581
|
? t("eventForm.allDay")
|
|
580
582
|
: t("eventForm.ai.timeRange", { startTime, endTime }),
|
|
581
|
-
timezone,
|
|
583
|
+
timezone: eventTimezone,
|
|
582
584
|
location: location || t("eventForm.ai.none"),
|
|
583
585
|
attendees:
|
|
584
586
|
attendees.map((attendee) => attendee.email).join(", ") ||
|
|
@@ -636,11 +638,11 @@ export function CreateEventPopover({
|
|
|
636
638
|
const effectiveAllDay = allDay && !isOutOfOffice && !timedOnlyStatus;
|
|
637
639
|
const currentStartISO =
|
|
638
640
|
!effectiveAllDay && date && startTime
|
|
639
|
-
? dateTimeInTimezoneToIso(date, startTime,
|
|
641
|
+
? dateTimeInTimezoneToIso(date, startTime, eventTimezone)
|
|
640
642
|
: undefined;
|
|
641
643
|
const currentEndISO =
|
|
642
644
|
!effectiveAllDay && endDate && endTime
|
|
643
|
-
? dateTimeInTimezoneToIso(endDate, endTime,
|
|
645
|
+
? dateTimeInTimezoneToIso(endDate, endTime, eventTimezone)
|
|
644
646
|
: undefined;
|
|
645
647
|
const findTimeDurationMinutes =
|
|
646
648
|
currentStartISO && currentEndISO
|
|
@@ -654,8 +656,8 @@ export function CreateEventPopover({
|
|
|
654
656
|
: defaultDurationMinutes;
|
|
655
657
|
|
|
656
658
|
function handleSelectFindTimeSlot(slot: { start: string; end: string }) {
|
|
657
|
-
const startParts = dateTimePartsInTimezone(slot.start,
|
|
658
|
-
const endParts = dateTimePartsInTimezone(slot.end,
|
|
659
|
+
const startParts = dateTimePartsInTimezone(slot.start, eventTimezone);
|
|
660
|
+
const endParts = dateTimePartsInTimezone(slot.end, eventTimezone);
|
|
659
661
|
if (!startParts || !endParts) return;
|
|
660
662
|
setAllDay(false);
|
|
661
663
|
setDate(startParts.date);
|
|
@@ -708,12 +710,12 @@ export function CreateEventPopover({
|
|
|
708
710
|
? date
|
|
709
711
|
: effectiveAllDay
|
|
710
712
|
? new Date(`${date}T00:00:00`).toISOString()
|
|
711
|
-
: dateTimeInTimezoneToIso(date, startTime,
|
|
713
|
+
: dateTimeInTimezoneToIso(date, startTime, eventTimezone);
|
|
712
714
|
const endValue = fullDayOutOfOffice
|
|
713
715
|
? endDate
|
|
714
716
|
: effectiveAllDay
|
|
715
717
|
? allDayEnd.toISOString()
|
|
716
|
-
: dateTimeInTimezoneToIso(endDate, endTime,
|
|
718
|
+
: dateTimeInTimezoneToIso(endDate, endTime, eventTimezone);
|
|
717
719
|
|
|
718
720
|
if (
|
|
719
721
|
fullDayOutOfOffice
|
|
@@ -761,8 +763,8 @@ export function CreateEventPopover({
|
|
|
761
763
|
description: isOutOfOffice ? "" : description,
|
|
762
764
|
start: startValue,
|
|
763
765
|
end: endValue,
|
|
764
|
-
startTimeZone: effectiveAllDay ? undefined :
|
|
765
|
-
endTimeZone: effectiveAllDay ? undefined :
|
|
766
|
+
startTimeZone: effectiveAllDay ? undefined : eventTimezone,
|
|
767
|
+
endTimeZone: effectiveAllDay ? undefined : eventTimezone,
|
|
766
768
|
location: isOutOfOffice ? "" : location,
|
|
767
769
|
accountEmail,
|
|
768
770
|
allDay: effectiveAllDay,
|
|
@@ -1459,7 +1461,7 @@ export function CreateEventPopover({
|
|
|
1459
1461
|
(draft ? t("eventForm.invite") : t("eventForm.newEventLower"))
|
|
1460
1462
|
}
|
|
1461
1463
|
date={date}
|
|
1462
|
-
timezone={
|
|
1464
|
+
timezone={eventTimezone}
|
|
1463
1465
|
durationMinutes={findTimeDurationMinutes}
|
|
1464
1466
|
attendees={attendees}
|
|
1465
1467
|
accountEmail={accountEmail}
|
|
@@ -1441,7 +1441,7 @@ export function EventDetailPopover({
|
|
|
1441
1441
|
side={isMobile ? "bottom" : "right"}
|
|
1442
1442
|
sideOffset={isMobile ? 6 : 8}
|
|
1443
1443
|
collisionPadding={12}
|
|
1444
|
-
className="flex max-h-[
|
|
1444
|
+
className="flex max-h-[var(--radix-popover-content-available-height)] w-[min(420px,calc(100vw-2rem))] flex-col overflow-hidden p-0"
|
|
1445
1445
|
onClick={(e) => e.stopPropagation()}
|
|
1446
1446
|
onOpenAutoFocus={(e) => {
|
|
1447
1447
|
e.preventDefault();
|
|
@@ -1671,12 +1671,15 @@ export function EventDetailPopover({
|
|
|
1671
1671
|
/>
|
|
1672
1672
|
</>
|
|
1673
1673
|
)}
|
|
1674
|
+
<span className="ml-auto">
|
|
1675
|
+
<TimezonePickerPopover
|
|
1676
|
+
compact
|
|
1677
|
+
value={editTimezone}
|
|
1678
|
+
label={t("eventForm.timezone")}
|
|
1679
|
+
onChange={handleInlineTimezoneChange}
|
|
1680
|
+
/>
|
|
1681
|
+
</span>
|
|
1674
1682
|
</div>
|
|
1675
|
-
<TimezonePickerPopover
|
|
1676
|
-
value={editTimezone}
|
|
1677
|
-
label={t("eventForm.timezone")}
|
|
1678
|
-
onChange={handleInlineTimezoneChange}
|
|
1679
|
-
/>
|
|
1680
1683
|
</>
|
|
1681
1684
|
)}
|
|
1682
1685
|
</div>
|
|
@@ -5,12 +5,14 @@ import type {
|
|
|
5
5
|
FindTimeResult,
|
|
6
6
|
FindTimeSlot,
|
|
7
7
|
} from "@shared/api";
|
|
8
|
+
import { getWeekStartsOn } from "@shared/calendar-week";
|
|
8
9
|
import {
|
|
9
10
|
IconAlertCircle,
|
|
10
11
|
IconCalendarTime,
|
|
11
12
|
IconChevronLeft,
|
|
12
13
|
IconChevronRight,
|
|
13
14
|
IconLoader2,
|
|
15
|
+
IconX,
|
|
14
16
|
IconUsers,
|
|
15
17
|
} from "@tabler/icons-react";
|
|
16
18
|
import {
|
|
@@ -31,11 +33,13 @@ import { Badge } from "@/components/ui/badge";
|
|
|
31
33
|
import { Button } from "@/components/ui/button";
|
|
32
34
|
import {
|
|
33
35
|
Dialog,
|
|
36
|
+
DialogClose,
|
|
34
37
|
DialogContent,
|
|
35
38
|
DialogDescription,
|
|
36
39
|
DialogTitle,
|
|
37
40
|
} from "@/components/ui/dialog";
|
|
38
41
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
42
|
+
import { useSettings } from "@/hooks/use-settings";
|
|
39
43
|
import { dateTimeInTimezoneToIso } from "@/lib/event-form-utils";
|
|
40
44
|
import { cn } from "@/lib/utils";
|
|
41
45
|
|
|
@@ -188,6 +192,8 @@ export function FindTimePanel({
|
|
|
188
192
|
isTakeover = false,
|
|
189
193
|
}: FindTimePanelProps) {
|
|
190
194
|
const t = useT();
|
|
195
|
+
const { data: settings } = useSettings();
|
|
196
|
+
const weekStartsOn = getWeekStartsOn(settings?.weekStart);
|
|
191
197
|
const [anchorDate, setAnchorDate] = useState(() => parseDateOnly(date));
|
|
192
198
|
|
|
193
199
|
useEffect(() => {
|
|
@@ -220,7 +226,10 @@ export function FindTimePanel({
|
|
|
220
226
|
return () => window.removeEventListener("keydown", handleKeyDown, true);
|
|
221
227
|
}, [isTakeover]);
|
|
222
228
|
|
|
223
|
-
const weekStart = useMemo(
|
|
229
|
+
const weekStart = useMemo(
|
|
230
|
+
() => startOfWeek(anchorDate, { weekStartsOn }),
|
|
231
|
+
[anchorDate, weekStartsOn],
|
|
232
|
+
);
|
|
224
233
|
const days = useMemo(
|
|
225
234
|
() =>
|
|
226
235
|
eachDayOfInterval({
|
|
@@ -663,9 +672,11 @@ export function FindTimeTakeover({
|
|
|
663
672
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
664
673
|
<DialogContent
|
|
665
674
|
data-find-time-takeover
|
|
666
|
-
|
|
675
|
+
hideClose
|
|
676
|
+
overlayClassName="z-[310]"
|
|
677
|
+
className="z-[320] flex h-[100dvh] max-h-[100dvh] w-screen max-w-none translate-x-[-50%] translate-y-[-50%] flex-col gap-0 overflow-hidden border-0 p-0 shadow-xl sm:rounded-none"
|
|
667
678
|
>
|
|
668
|
-
<header className="flex h-14 shrink-0 items-center border-b border-border px-4
|
|
679
|
+
<header className="flex h-14 shrink-0 items-center border-b border-border px-4 md:px-6">
|
|
669
680
|
<div className="min-w-0">
|
|
670
681
|
<DialogTitle className="truncate text-base">
|
|
671
682
|
{dialogTitle}
|
|
@@ -679,6 +690,17 @@ export function FindTimeTakeover({
|
|
|
679
690
|
{subtitle || t("findTime.takeoverDescription")}
|
|
680
691
|
</DialogDescription>
|
|
681
692
|
</div>
|
|
693
|
+
<DialogClose asChild>
|
|
694
|
+
<button
|
|
695
|
+
type="button"
|
|
696
|
+
aria-label={t("eventDialog.close")}
|
|
697
|
+
title={t("eventDialog.close")}
|
|
698
|
+
className="ml-auto flex h-10 shrink-0 items-center gap-2 rounded-md px-3 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
699
|
+
>
|
|
700
|
+
<IconX className="h-4 w-4" />
|
|
701
|
+
<span>{t("eventDialog.close")}</span>
|
|
702
|
+
</button>
|
|
703
|
+
</DialogClose>
|
|
682
704
|
</header>
|
|
683
705
|
<div className="min-h-0 flex-1 overflow-auto p-4 md:p-6">
|
|
684
706
|
<FindTimePanel
|
|
@@ -193,10 +193,12 @@ export function TimezonePickerPopover({
|
|
|
193
193
|
value,
|
|
194
194
|
onChange,
|
|
195
195
|
label,
|
|
196
|
+
compact = false,
|
|
196
197
|
}: {
|
|
197
198
|
value: string;
|
|
198
199
|
onChange: (value: string) => void;
|
|
199
200
|
label: string;
|
|
201
|
+
compact?: boolean;
|
|
200
202
|
}) {
|
|
201
203
|
const t = useT();
|
|
202
204
|
const [open, setOpen] = useState(false);
|
|
@@ -208,11 +210,16 @@ export function TimezonePickerPopover({
|
|
|
208
210
|
type="button"
|
|
209
211
|
variant="ghost"
|
|
210
212
|
size="sm"
|
|
211
|
-
className=
|
|
213
|
+
className={cn(
|
|
214
|
+
compact
|
|
215
|
+
? "size-7 rounded-full p-0 text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
216
|
+
: "h-auto justify-start rounded px-1.5 py-0.5 text-sm font-normal text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
217
|
+
)}
|
|
212
218
|
aria-label={label}
|
|
219
|
+
title={compact ? label : undefined}
|
|
213
220
|
>
|
|
214
|
-
<IconWorld className="
|
|
215
|
-
{formatTimezoneLabel(value)}
|
|
221
|
+
<IconWorld className={cn("size-4 shrink-0", !compact && "mr-2")} />
|
|
222
|
+
{!compact && formatTimezoneLabel(value)}
|
|
216
223
|
</Button>
|
|
217
224
|
</PopoverTrigger>
|
|
218
225
|
<PopoverContent
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CalendarEvent } from "@shared/api";
|
|
2
|
+
import { getWeekdayOrder } from "@shared/calendar-week";
|
|
2
3
|
import {
|
|
3
4
|
startOfMonth,
|
|
4
5
|
endOfMonth,
|
|
@@ -49,6 +50,7 @@ interface MonthViewProps {
|
|
|
49
50
|
) => void;
|
|
50
51
|
onDraftDiscard?: (eventId: string) => void;
|
|
51
52
|
isLoading?: boolean;
|
|
53
|
+
weekStartsOn?: 0 | 1;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
// Skeleton pill widths per day-of-week (Sun–Sat), empty = no skeletons
|
|
@@ -85,6 +87,7 @@ export const MonthView = memo(function MonthView({
|
|
|
85
87
|
onDraftCreate,
|
|
86
88
|
onDraftDiscard,
|
|
87
89
|
isLoading = false,
|
|
90
|
+
weekStartsOn = 0,
|
|
88
91
|
}: MonthViewProps) {
|
|
89
92
|
const isMobile = useIsMobile();
|
|
90
93
|
const { prefs } = useViewPreferences();
|
|
@@ -93,8 +96,8 @@ export const MonthView = memo(function MonthView({
|
|
|
93
96
|
|
|
94
97
|
const monthStart = startOfMonth(selectedDate);
|
|
95
98
|
const monthEnd = endOfMonth(selectedDate);
|
|
96
|
-
const calendarStart = startOfWeek(monthStart);
|
|
97
|
-
const calendarEnd = endOfWeek(monthEnd);
|
|
99
|
+
const calendarStart = startOfWeek(monthStart, { weekStartsOn });
|
|
100
|
+
const calendarEnd = endOfWeek(monthEnd, { weekStartsOn });
|
|
98
101
|
const allDays = eachDayOfInterval({
|
|
99
102
|
start: calendarStart,
|
|
100
103
|
end: calendarEnd,
|
|
@@ -103,13 +106,10 @@ export const MonthView = memo(function MonthView({
|
|
|
103
106
|
? allDays.filter((d) => d.getDay() !== 0 && d.getDay() !== 6)
|
|
104
107
|
: allDays;
|
|
105
108
|
const colCount = prefs.hideWeekends ? 5 : 7;
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
: isMobile
|
|
111
|
-
? WEEKDAY_HEADERS_SHORT
|
|
112
|
-
: WEEKDAY_HEADERS;
|
|
109
|
+
const headerLabels = isMobile ? WEEKDAY_HEADERS_SHORT : WEEKDAY_HEADERS;
|
|
110
|
+
const headers = getWeekdayOrder(weekStartsOn)
|
|
111
|
+
.filter((day) => !prefs.hideWeekends || (day !== 0 && day !== 6))
|
|
112
|
+
.map((day) => headerLabels[day]);
|
|
113
113
|
|
|
114
114
|
// Pre-group events by every day they overlap (not just their start day) so
|
|
115
115
|
// multi-day events keep appearing as the grid moves past their start date.
|