@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
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
useAvatarUrl,
|
|
4
4
|
} from "@agent-native/core/client/hooks";
|
|
5
5
|
import { useT } from "@agent-native/core/client/i18n";
|
|
6
|
+
import { InlineMarkdown } from "@agent-native/core/client/markdown";
|
|
6
7
|
import {
|
|
7
8
|
IconSend,
|
|
8
9
|
IconCheck,
|
|
@@ -895,7 +896,6 @@ function CommentCard({
|
|
|
895
896
|
return updatedReactions;
|
|
896
897
|
}
|
|
897
898
|
|
|
898
|
-
const commentContent = linkifyCommentContent(comment.content);
|
|
899
899
|
const avatarUrl = useAvatarUrl(comment.authorEmail);
|
|
900
900
|
|
|
901
901
|
return (
|
|
@@ -940,9 +940,10 @@ function CommentCard({
|
|
|
940
940
|
/>
|
|
941
941
|
) : (
|
|
942
942
|
<>
|
|
943
|
-
<
|
|
944
|
-
{
|
|
945
|
-
|
|
943
|
+
<InlineMarkdown
|
|
944
|
+
content={comment.content}
|
|
945
|
+
className="mt-0.5 text-sm text-foreground"
|
|
946
|
+
/>
|
|
946
947
|
|
|
947
948
|
<div className="flex items-center gap-2 mt-1.5 text-xs text-muted-foreground">
|
|
948
949
|
{canComment ? (
|
|
@@ -1070,101 +1071,6 @@ function CommentCard({
|
|
|
1070
1071
|
);
|
|
1071
1072
|
}
|
|
1072
1073
|
|
|
1073
|
-
const COMMENT_URL_PATTERN = /\b(?:https?:\/\/|www\.)[^\s<]+/gi;
|
|
1074
|
-
const ALWAYS_TRAILING_PUNCTUATION = new Set([
|
|
1075
|
-
".",
|
|
1076
|
-
",",
|
|
1077
|
-
"!",
|
|
1078
|
-
"?",
|
|
1079
|
-
";",
|
|
1080
|
-
":",
|
|
1081
|
-
"'",
|
|
1082
|
-
'"',
|
|
1083
|
-
]);
|
|
1084
|
-
const PAIRED_TRAILING_PUNCTUATION: Record<string, string> = {
|
|
1085
|
-
")": "(",
|
|
1086
|
-
"]": "[",
|
|
1087
|
-
"}": "{",
|
|
1088
|
-
};
|
|
1089
|
-
|
|
1090
|
-
function trimTrailingUrlPunctuation(value: string): {
|
|
1091
|
-
url: string;
|
|
1092
|
-
trailing: string;
|
|
1093
|
-
} {
|
|
1094
|
-
let end = value.length;
|
|
1095
|
-
|
|
1096
|
-
while (end > 0) {
|
|
1097
|
-
const lastCharacter = value[end - 1];
|
|
1098
|
-
if (ALWAYS_TRAILING_PUNCTUATION.has(lastCharacter)) {
|
|
1099
|
-
end -= 1;
|
|
1100
|
-
continue;
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
const openingCharacter = PAIRED_TRAILING_PUNCTUATION[lastCharacter];
|
|
1104
|
-
if (openingCharacter) {
|
|
1105
|
-
const candidate = value.slice(0, end);
|
|
1106
|
-
const openingCount = candidate.split(openingCharacter).length - 1;
|
|
1107
|
-
const closingCount = candidate.split(lastCharacter).length - 1;
|
|
1108
|
-
if (closingCount > openingCount) {
|
|
1109
|
-
end -= 1;
|
|
1110
|
-
continue;
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
break;
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
return {
|
|
1118
|
-
url: value.slice(0, end),
|
|
1119
|
-
trailing: value.slice(end),
|
|
1120
|
-
};
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
function linkifyCommentContent(content: string): React.ReactNode[] {
|
|
1124
|
-
const result: React.ReactNode[] = [];
|
|
1125
|
-
let lastIndex = 0;
|
|
1126
|
-
|
|
1127
|
-
for (const match of content.matchAll(COMMENT_URL_PATTERN)) {
|
|
1128
|
-
const matchIndex = match.index;
|
|
1129
|
-
const matchedText = match[0];
|
|
1130
|
-
const { url, trailing } = trimTrailingUrlPunctuation(matchedText);
|
|
1131
|
-
const href = url.toLowerCase().startsWith("www.") ? `https://${url}` : url;
|
|
1132
|
-
|
|
1133
|
-
let isValidUrl = false;
|
|
1134
|
-
try {
|
|
1135
|
-
isValidUrl = Boolean(new URL(href).hostname);
|
|
1136
|
-
} catch {
|
|
1137
|
-
// Leave malformed URL-like text unlinked.
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
|
-
if (!isValidUrl) continue;
|
|
1141
|
-
|
|
1142
|
-
if (matchIndex > lastIndex) {
|
|
1143
|
-
result.push(content.slice(lastIndex, matchIndex));
|
|
1144
|
-
}
|
|
1145
|
-
result.push(
|
|
1146
|
-
<a
|
|
1147
|
-
key={`${matchIndex}-${url}`}
|
|
1148
|
-
href={href}
|
|
1149
|
-
target="_blank"
|
|
1150
|
-
rel="noopener noreferrer"
|
|
1151
|
-
className="text-primary hover:underline"
|
|
1152
|
-
>
|
|
1153
|
-
{url}
|
|
1154
|
-
</a>,
|
|
1155
|
-
);
|
|
1156
|
-
if (trailing) result.push(trailing);
|
|
1157
|
-
|
|
1158
|
-
lastIndex = matchIndex + matchedText.length;
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
if (lastIndex < content.length) {
|
|
1162
|
-
result.push(content.slice(lastIndex));
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
return result;
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
1074
|
function parseReactions(raw: string): Record<string, string[]> {
|
|
1169
1075
|
try {
|
|
1170
1076
|
const v = JSON.parse(raw ?? "{}");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useAvatarUrl } from "@agent-native/core/client/hooks";
|
|
2
|
+
import { InlineMarkdown } from "@agent-native/core/client/markdown";
|
|
2
3
|
|
|
3
4
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
|
4
5
|
import { cn } from "@/lib/utils";
|
|
@@ -100,9 +101,12 @@ export function PlaybackCommentOverlay({
|
|
|
100
101
|
<p className="truncate text-xs font-semibold text-white/80">
|
|
101
102
|
{author}
|
|
102
103
|
</p>
|
|
103
|
-
<
|
|
104
|
-
{comment.content}
|
|
105
|
-
|
|
104
|
+
<InlineMarkdown
|
|
105
|
+
content={comment.content}
|
|
106
|
+
className="line-clamp-3 text-sm leading-5 text-primary-foreground"
|
|
107
|
+
linkClassName="text-primary-foreground underline decoration-primary-foreground/60 hover:decoration-primary-foreground"
|
|
108
|
+
codeClassName="bg-primary-foreground/15 text-primary-foreground"
|
|
109
|
+
/>
|
|
106
110
|
</div>
|
|
107
111
|
</div>
|
|
108
112
|
{rest.length > 0 && (
|
|
@@ -72,6 +72,13 @@ export interface ShareRecordingPopoverProps {
|
|
|
72
72
|
animatedThumbnailUrl?: string | null;
|
|
73
73
|
isLoomRecording?: boolean;
|
|
74
74
|
hasPassword?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Restricts the dialog to a bare copy-link control for viewers who can
|
|
77
|
+
* reshare a public/org clip's link but have no edit access: it skips
|
|
78
|
+
* `list-resource-shares` (which returns every individually-shared
|
|
79
|
+
* principal's email to any reader) and hides the Invite tab entirely.
|
|
80
|
+
*/
|
|
81
|
+
viewerReshareOnly?: boolean;
|
|
75
82
|
/** Trigger element rendered as the popover anchor (usually the Share button). */
|
|
76
83
|
children: ReactNode;
|
|
77
84
|
open?: boolean;
|
|
@@ -103,6 +110,7 @@ export function ShareRecordingPopover({
|
|
|
103
110
|
animatedThumbnailUrl,
|
|
104
111
|
isLoomRecording = false,
|
|
105
112
|
hasPassword,
|
|
113
|
+
viewerReshareOnly = false,
|
|
106
114
|
children,
|
|
107
115
|
open,
|
|
108
116
|
onOpenChange,
|
|
@@ -125,6 +133,7 @@ export function ShareRecordingPopover({
|
|
|
125
133
|
animatedThumbnailUrl={animatedThumbnailUrl}
|
|
126
134
|
isLoomRecording={isLoomRecording}
|
|
127
135
|
hasPassword={hasPassword}
|
|
136
|
+
viewerReshareOnly={viewerReshareOnly}
|
|
128
137
|
/>
|
|
129
138
|
</PopoverContent>
|
|
130
139
|
</Popover>
|
|
@@ -148,6 +157,7 @@ export function ShareRecordingDialog({
|
|
|
148
157
|
open,
|
|
149
158
|
onOpenChange,
|
|
150
159
|
hasPassword,
|
|
160
|
+
viewerReshareOnly = false,
|
|
151
161
|
}: ShareRecordingDialogProps) {
|
|
152
162
|
const t = useT();
|
|
153
163
|
return (
|
|
@@ -168,6 +178,7 @@ export function ShareRecordingDialog({
|
|
|
168
178
|
animatedThumbnailUrl={animatedThumbnailUrl}
|
|
169
179
|
isLoomRecording={isLoomRecording}
|
|
170
180
|
hasPassword={hasPassword}
|
|
181
|
+
viewerReshareOnly={viewerReshareOnly}
|
|
171
182
|
reserveCloseButton
|
|
172
183
|
/>
|
|
173
184
|
</DialogContent>
|
|
@@ -186,6 +197,7 @@ function ShareRecordingContent({
|
|
|
186
197
|
isLoomRecording = false,
|
|
187
198
|
reserveCloseButton = false,
|
|
188
199
|
hasPassword,
|
|
200
|
+
viewerReshareOnly = false,
|
|
189
201
|
}: {
|
|
190
202
|
recordingId: string;
|
|
191
203
|
recordingTitle?: string;
|
|
@@ -197,20 +209,34 @@ function ShareRecordingContent({
|
|
|
197
209
|
isLoomRecording?: boolean;
|
|
198
210
|
reserveCloseButton?: boolean;
|
|
199
211
|
hasPassword?: boolean;
|
|
212
|
+
viewerReshareOnly?: boolean;
|
|
200
213
|
}) {
|
|
201
214
|
const t = useT();
|
|
202
|
-
const sharesQuery = useActionQuery<SharesResponse>(
|
|
203
|
-
|
|
204
|
-
resourceId: recordingId,
|
|
205
|
-
|
|
215
|
+
const sharesQuery = useActionQuery<SharesResponse>(
|
|
216
|
+
"list-resource-shares",
|
|
217
|
+
{ resourceType: "recording", resourceId: recordingId },
|
|
218
|
+
{ enabled: !viewerReshareOnly },
|
|
219
|
+
);
|
|
206
220
|
|
|
207
|
-
const data = sharesQuery.data;
|
|
221
|
+
const data = viewerReshareOnly ? undefined : sharesQuery.data;
|
|
208
222
|
const role = data?.role ?? initialRole;
|
|
209
223
|
const canManage = role === "owner" || role === "admin";
|
|
224
|
+
// Editors could always see (read-only) who a clip is shared with; only
|
|
225
|
+
// gate the Invite tab's mutation controls behind canManage. Commenters are
|
|
226
|
+
// grouped with plain viewers here -- neither can manage shares.
|
|
227
|
+
const canViewShares =
|
|
228
|
+
role === "owner" || role === "admin" || role === "editor";
|
|
210
229
|
const visibility =
|
|
211
230
|
(data?.visibility as Visibility | null | undefined) ??
|
|
212
231
|
initialVisibility ??
|
|
213
232
|
null;
|
|
233
|
+
// A plain viewer/commenter can't produce a working embed for a non-public
|
|
234
|
+
// clip (they have no way to make it public), so don't dangle the tab in
|
|
235
|
+
// front of them only to show an "ask the owner" dead end. Owner/admin/
|
|
236
|
+
// editor keep it regardless of visibility since they can flip to public
|
|
237
|
+
// from inside it.
|
|
238
|
+
const canEmbed = canViewShares || visibility === "public";
|
|
239
|
+
const tabCount = 1 + (canViewShares ? 1 : 0) + (canEmbed ? 1 : 0);
|
|
214
240
|
|
|
215
241
|
// Attribution `via` must be a stable non-PII id, never an email. The only
|
|
216
242
|
// owner id available client-side is the *current* session's userId, which is
|
|
@@ -234,20 +260,28 @@ function ShareRecordingContent({
|
|
|
234
260
|
defaultValue="link"
|
|
235
261
|
className={cn("min-w-0 px-4 py-3", reserveCloseButton && "pe-12")}
|
|
236
262
|
>
|
|
237
|
-
|
|
238
|
-
<
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
263
|
+
{tabCount > 1 ? (
|
|
264
|
+
<TabsList
|
|
265
|
+
className={`grid w-full ${tabCount === 3 ? "grid-cols-3" : "grid-cols-2"}`}
|
|
266
|
+
>
|
|
267
|
+
<TabsTrigger value="link" className="gap-1.5">
|
|
268
|
+
<IconLink size={14} />
|
|
269
|
+
{t("shareDialog.link")}
|
|
270
|
+
</TabsTrigger>
|
|
271
|
+
{canViewShares ? (
|
|
272
|
+
<TabsTrigger value="invite" className="gap-1.5">
|
|
273
|
+
<IconMail size={14} />
|
|
274
|
+
{t("shareDialog.invite")}
|
|
275
|
+
</TabsTrigger>
|
|
276
|
+
) : null}
|
|
277
|
+
{canEmbed ? (
|
|
278
|
+
<TabsTrigger value="embed" className="gap-1.5">
|
|
279
|
+
<IconCode size={14} />
|
|
280
|
+
{t("shareDialog.embed")}
|
|
281
|
+
</TabsTrigger>
|
|
282
|
+
) : null}
|
|
283
|
+
</TabsList>
|
|
284
|
+
) : null}
|
|
251
285
|
|
|
252
286
|
<TabsContent value="link" className="mt-3">
|
|
253
287
|
<LinkTab
|
|
@@ -262,34 +296,39 @@ function ShareRecordingContent({
|
|
|
262
296
|
animatedThumbnailUrl={animatedThumbnailUrl}
|
|
263
297
|
isLoomRecording={isLoomRecording}
|
|
264
298
|
hasPassword={hasPassword}
|
|
299
|
+
canViewShares={canViewShares}
|
|
265
300
|
/>
|
|
266
301
|
</TabsContent>
|
|
267
302
|
|
|
268
|
-
|
|
269
|
-
<
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
303
|
+
{canViewShares ? (
|
|
304
|
+
<TabsContent value="invite" className="mt-3">
|
|
305
|
+
<SharePeopleTab
|
|
306
|
+
resourceType="recording"
|
|
307
|
+
resourceId={recordingId}
|
|
308
|
+
resourceUrl={absoluteAppUrl(`/r/${recordingId}`)}
|
|
309
|
+
sharesQuery={sharesQuery}
|
|
310
|
+
canManage={canManage}
|
|
311
|
+
roleCopy={{
|
|
312
|
+
commenter: {
|
|
313
|
+
label: t("shareUi.recordingCommenter.label"),
|
|
314
|
+
description: t("shareUi.recordingCommenter.description"),
|
|
315
|
+
},
|
|
316
|
+
}}
|
|
317
|
+
/>
|
|
318
|
+
</TabsContent>
|
|
319
|
+
) : null}
|
|
320
|
+
|
|
321
|
+
{canEmbed ? (
|
|
322
|
+
<TabsContent value="embed" className="mt-3">
|
|
323
|
+
<ClipsEmbedConfigurator
|
|
324
|
+
recordingId={recordingId}
|
|
325
|
+
sharesQuery={sharesQuery}
|
|
326
|
+
visibility={visibility}
|
|
327
|
+
canManage={canManage}
|
|
328
|
+
ownerViaId={ownerViaId}
|
|
329
|
+
/>
|
|
330
|
+
</TabsContent>
|
|
331
|
+
) : null}
|
|
293
332
|
</Tabs>
|
|
294
333
|
</>
|
|
295
334
|
);
|
|
@@ -311,6 +350,7 @@ function LinkTab({
|
|
|
311
350
|
animatedThumbnailUrl,
|
|
312
351
|
isLoomRecording: isLoomRecordingProp,
|
|
313
352
|
hasPassword,
|
|
353
|
+
canViewShares,
|
|
314
354
|
}: {
|
|
315
355
|
recordingId: string;
|
|
316
356
|
recordingTitle?: string;
|
|
@@ -323,6 +363,7 @@ function LinkTab({
|
|
|
323
363
|
animatedThumbnailUrl?: string | null;
|
|
324
364
|
isLoomRecording?: boolean;
|
|
325
365
|
hasPassword?: boolean;
|
|
366
|
+
canViewShares: boolean;
|
|
326
367
|
}) {
|
|
327
368
|
const t = useT();
|
|
328
369
|
const { setResourceVisibility, isPending } = useResourceVisibilityMutation(
|
|
@@ -460,21 +501,23 @@ function LinkTab({
|
|
|
460
501
|
|
|
461
502
|
return (
|
|
462
503
|
<div className="space-y-4">
|
|
463
|
-
{
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
<div className="
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
504
|
+
{canViewShares ? (
|
|
505
|
+
visibility ? (
|
|
506
|
+
<GeneralAccessSelect
|
|
507
|
+
visibility={visibility}
|
|
508
|
+
canManage={canManage}
|
|
509
|
+
isPending={visibilityPending}
|
|
510
|
+
onChange={(next) => setResourceVisibility(next)}
|
|
511
|
+
publicDescription={t("shareDialog.publicDescription")}
|
|
512
|
+
showDescription={false}
|
|
513
|
+
/>
|
|
514
|
+
) : (
|
|
515
|
+
<div className="space-y-2" aria-hidden>
|
|
516
|
+
<div className="h-3 w-24 animate-pulse rounded bg-muted" />
|
|
517
|
+
<div className="h-12 w-full animate-pulse rounded bg-muted" />
|
|
518
|
+
</div>
|
|
519
|
+
)
|
|
520
|
+
) : null}
|
|
478
521
|
|
|
479
522
|
<CopyField
|
|
480
523
|
label={
|
|
@@ -353,6 +353,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
353
353
|
const [captionsOn, setCaptionsOn] = useState(false);
|
|
354
354
|
const [hasPlaybackStarted, setHasPlaybackStarted] = useState(false);
|
|
355
355
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
356
|
+
const nativeFullscreenRef = useRef(false);
|
|
356
357
|
const [isPip, setIsPip] = useState(false);
|
|
357
358
|
const [canPlay, setCanPlay] = useState(false);
|
|
358
359
|
const [isPlayPending, setIsPlayPending] = useState(false);
|
|
@@ -1362,33 +1363,83 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
1362
1363
|
const el = containerRef.current;
|
|
1363
1364
|
const video = videoRef.current as WebkitFullscreenVideo | null;
|
|
1364
1365
|
if (!el) return;
|
|
1366
|
+
const hasNativeVideoFullscreen =
|
|
1367
|
+
typeof video?.webkitEnterFullscreen === "function";
|
|
1368
|
+
let nativeFullscreenAttempted = false;
|
|
1365
1369
|
try {
|
|
1366
|
-
if (
|
|
1367
|
-
if (
|
|
1368
|
-
video?.webkitDisplayingFullscreen ||
|
|
1369
|
-
(isFullscreen && video?.webkitExitFullscreen)
|
|
1370
|
-
) {
|
|
1371
|
-
video?.webkitExitFullscreen?.();
|
|
1372
|
-
setIsFullscreen(false);
|
|
1373
|
-
} else if (typeof el.requestFullscreen === "function") {
|
|
1374
|
-
await el.requestFullscreen();
|
|
1375
|
-
setIsFullscreen(true);
|
|
1376
|
-
} else if (video?.webkitEnterFullscreen) {
|
|
1377
|
-
// iPhone Safari exposes fullscreen on the video element, not the
|
|
1378
|
-
// containing div used by the custom player controls.
|
|
1379
|
-
video.webkitEnterFullscreen();
|
|
1380
|
-
setIsFullscreen(true);
|
|
1381
|
-
} else {
|
|
1382
|
-
console.warn("[clips] Fullscreen unavailable");
|
|
1383
|
-
}
|
|
1384
|
-
} else {
|
|
1370
|
+
if (document.fullscreenElement) {
|
|
1385
1371
|
await document.exitFullscreen();
|
|
1386
1372
|
setIsFullscreen(false);
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
if (nativeFullscreenRef.current || video?.webkitDisplayingFullscreen) {
|
|
1377
|
+
video?.webkitExitFullscreen?.();
|
|
1378
|
+
nativeFullscreenRef.current = false;
|
|
1379
|
+
setIsFullscreen(false);
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// iPhone Safari exposes fullscreen on the video element, not the
|
|
1384
|
+
// containing div used by the custom player controls. Older versions
|
|
1385
|
+
// can expose requestFullscreen on the div without supporting it.
|
|
1386
|
+
const documentFullscreenUnavailable = !document.fullscreenEnabled;
|
|
1387
|
+
if (
|
|
1388
|
+
hasNativeVideoFullscreen &&
|
|
1389
|
+
(documentFullscreenUnavailable ||
|
|
1390
|
+
typeof el.requestFullscreen !== "function")
|
|
1391
|
+
) {
|
|
1392
|
+
nativeFullscreenAttempted = true;
|
|
1393
|
+
video.webkitEnterFullscreen?.();
|
|
1394
|
+
nativeFullscreenRef.current = true;
|
|
1395
|
+
setIsFullscreen(true);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
if (isFullscreen) {
|
|
1400
|
+
// Keep the control reversible when neither browser fullscreen API
|
|
1401
|
+
// is available and the player is using its fixed-viewport fallback.
|
|
1402
|
+
setIsFullscreen(false);
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
if (typeof el.requestFullscreen === "function") {
|
|
1407
|
+
await el.requestFullscreen();
|
|
1408
|
+
if (document.fullscreenElement || !hasNativeVideoFullscreen) {
|
|
1409
|
+
setIsFullscreen(true);
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
// A few mobile WebKit versions resolve the container request but do
|
|
1414
|
+
// not enter fullscreen. Retry against the video before falling back
|
|
1415
|
+
// to the in-app fixed viewport.
|
|
1416
|
+
nativeFullscreenAttempted = true;
|
|
1417
|
+
video.webkitEnterFullscreen?.();
|
|
1418
|
+
nativeFullscreenRef.current = true;
|
|
1419
|
+
setIsFullscreen(true);
|
|
1420
|
+
return;
|
|
1387
1421
|
}
|
|
1422
|
+
|
|
1423
|
+
if (hasNativeVideoFullscreen) {
|
|
1424
|
+
nativeFullscreenAttempted = true;
|
|
1425
|
+
video.webkitEnterFullscreen?.();
|
|
1426
|
+
nativeFullscreenRef.current = true;
|
|
1427
|
+
setIsFullscreen(true);
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
// Keep fullscreen usable in browsers that expose neither API.
|
|
1432
|
+
setIsFullscreen(true);
|
|
1388
1433
|
} catch (err) {
|
|
1389
|
-
if (
|
|
1434
|
+
if (
|
|
1435
|
+
!nativeFullscreenAttempted &&
|
|
1436
|
+
hasNativeVideoFullscreen &&
|
|
1437
|
+
!document.fullscreenElement
|
|
1438
|
+
) {
|
|
1390
1439
|
try {
|
|
1391
|
-
|
|
1440
|
+
nativeFullscreenAttempted = true;
|
|
1441
|
+
video.webkitEnterFullscreen?.();
|
|
1442
|
+
nativeFullscreenRef.current = true;
|
|
1392
1443
|
setIsFullscreen(true);
|
|
1393
1444
|
return;
|
|
1394
1445
|
} catch (fallbackErr) {
|
|
@@ -1396,14 +1447,21 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
1396
1447
|
}
|
|
1397
1448
|
}
|
|
1398
1449
|
console.warn("[clips] Fullscreen failed", err);
|
|
1450
|
+
setIsFullscreen(true);
|
|
1399
1451
|
}
|
|
1400
1452
|
}
|
|
1401
1453
|
|
|
1402
1454
|
useEffect(() => {
|
|
1403
1455
|
const video = videoRef.current as WebkitFullscreenVideo | null;
|
|
1404
1456
|
const onFs = () => setIsFullscreen(!!document.fullscreenElement);
|
|
1405
|
-
const onNativeFsEnter = () =>
|
|
1406
|
-
|
|
1457
|
+
const onNativeFsEnter = () => {
|
|
1458
|
+
nativeFullscreenRef.current = true;
|
|
1459
|
+
setIsFullscreen(true);
|
|
1460
|
+
};
|
|
1461
|
+
const onNativeFsExit = () => {
|
|
1462
|
+
nativeFullscreenRef.current = false;
|
|
1463
|
+
setIsFullscreen(false);
|
|
1464
|
+
};
|
|
1407
1465
|
document.addEventListener("fullscreenchange", onFs);
|
|
1408
1466
|
video?.addEventListener("webkitbeginfullscreen", onNativeFsEnter);
|
|
1409
1467
|
video?.addEventListener("webkitendfullscreen", onNativeFsExit);
|
|
@@ -1456,7 +1514,9 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
1456
1514
|
// width (see CenterPlaybackOverlay) so it isn't oversized inside
|
|
1457
1515
|
// small embeds like the Slack unfurl iframe.
|
|
1458
1516
|
"relative @container bg-black overflow-hidden select-none group",
|
|
1459
|
-
theaterMode
|
|
1517
|
+
theaterMode || isFullscreen
|
|
1518
|
+
? "fixed inset-0 z-40 h-dvh w-dvw"
|
|
1519
|
+
: "rounded-xl",
|
|
1460
1520
|
className,
|
|
1461
1521
|
)}
|
|
1462
1522
|
onMouseMove={bumpControls}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useFormatters, useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
import { InlineMarkdown } from "@agent-native/core/client/markdown";
|
|
2
3
|
import {
|
|
3
4
|
IconMessage,
|
|
4
5
|
IconMoodSmile,
|
|
@@ -87,9 +88,16 @@ export function NotificationsList({ items, onReply }: NotificationsListProps) {
|
|
|
87
88
|
</span>
|
|
88
89
|
</div>
|
|
89
90
|
{item.preview ? (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
item.kind === "comment" || item.kind === "mention" ? (
|
|
92
|
+
<InlineMarkdown
|
|
93
|
+
content={item.preview}
|
|
94
|
+
className="mt-1 line-clamp-2 text-sm text-muted-foreground"
|
|
95
|
+
/>
|
|
96
|
+
) : (
|
|
97
|
+
<div className="mt-1 line-clamp-2 text-sm text-muted-foreground">
|
|
98
|
+
{item.preview}
|
|
99
|
+
</div>
|
|
100
|
+
)
|
|
93
101
|
) : null}
|
|
94
102
|
<div className="mt-1.5 flex items-center gap-3 text-xs">
|
|
95
103
|
<Link
|
|
@@ -969,6 +969,8 @@ All notable user-facing changes to Clips are documented here. Open it any time f
|
|
|
969
969
|
includeTranscriptDescription:
|
|
970
970
|
"Anyone with access to this meeting can read the complete transcript.",
|
|
971
971
|
transcriptUnavailable: "The transcript isn't ready yet.",
|
|
972
|
+
agentLinkDescription:
|
|
973
|
+
"This temporary link lets agents read these meeting notes without making them public. It expires after two hours.",
|
|
972
974
|
transcript: "Transcript",
|
|
973
975
|
copyTranscript: "Copy transcript",
|
|
974
976
|
transcriptCopied: "Transcript copied",
|
|
@@ -1545,6 +1547,16 @@ All notable user-facing changes to Clips are documented here. Open it any time f
|
|
|
1545
1547
|
calendarConnected: "Calendar connected",
|
|
1546
1548
|
calendarDisconnected: "Calendar disconnected",
|
|
1547
1549
|
calendarSettings: "Calendar settings",
|
|
1550
|
+
calendarAccountsButton: "Calendars",
|
|
1551
|
+
connectedAccounts: "Connected accounts",
|
|
1552
|
+
calendarConnectedLabel: "Connected",
|
|
1553
|
+
calendarNeedsReconnectLabel: "Needs reconnect",
|
|
1554
|
+
calendarDisconnectedLabel: "Disconnected",
|
|
1555
|
+
calendarStatusUnavailable: "Status unavailable",
|
|
1556
|
+
reconnectCalendar: "Reconnect calendar",
|
|
1557
|
+
addAnotherCalendarAccount: "Add another account",
|
|
1558
|
+
connectCalendar: "Connect calendar",
|
|
1559
|
+
disconnectCalendarAccount: "Disconnect an account",
|
|
1548
1560
|
connectCalendarReminder: "Connect Google Calendar for meeting reminders.",
|
|
1549
1561
|
disconnectGoogleCalendarTitle: "Disconnect Google Calendar?",
|
|
1550
1562
|
title: "Meetings",
|
|
@@ -2,6 +2,8 @@ import { appBasePath } from "@agent-native/core/client/api-path";
|
|
|
2
2
|
|
|
3
3
|
import type { TranscriptSegment } from "@/components/meetings/transcript-bubbles";
|
|
4
4
|
|
|
5
|
+
import { CLIPS_MEETING_AGENT_ACCESS_PARAM } from "../../shared/meeting-agent-access";
|
|
6
|
+
|
|
5
7
|
export interface PublicMeetingBullet {
|
|
6
8
|
text: string;
|
|
7
9
|
}
|
|
@@ -59,9 +61,13 @@ export function publicMeetingUrl(
|
|
|
59
61
|
meetingId: string,
|
|
60
62
|
origin: string,
|
|
61
63
|
basePath: string,
|
|
64
|
+
agentAccessToken?: string,
|
|
62
65
|
): string {
|
|
63
66
|
const url = new URL(`${basePath}/api/public-meeting`, origin);
|
|
64
67
|
url.searchParams.set("id", meetingId);
|
|
68
|
+
if (agentAccessToken) {
|
|
69
|
+
url.searchParams.set(CLIPS_MEETING_AGENT_ACCESS_PARAM, agentAccessToken);
|
|
70
|
+
}
|
|
65
71
|
return url.toString();
|
|
66
72
|
}
|
|
67
73
|
|
|
@@ -71,13 +77,15 @@ export async function fetchPublicMeeting(
|
|
|
71
77
|
signal?: AbortSignal;
|
|
72
78
|
origin?: string;
|
|
73
79
|
basePath?: string;
|
|
80
|
+
agentAccessToken?: string;
|
|
74
81
|
} = {},
|
|
75
82
|
): Promise<PublicMeetingResult> {
|
|
76
83
|
const origin = options.origin ?? window.location.origin;
|
|
77
84
|
const basePath = options.basePath ?? appBasePath();
|
|
78
|
-
const response = await fetch(
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
const response = await fetch(
|
|
86
|
+
publicMeetingUrl(meetingId, origin, basePath, options.agentAccessToken),
|
|
87
|
+
{ signal: options.signal },
|
|
88
|
+
);
|
|
81
89
|
const data = (await response.json().catch(() => ({}))) as
|
|
82
90
|
| PublicMeetingPayload
|
|
83
91
|
| { error?: string };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const SEARCH_FOCUS_PARAM = "focus";
|
|
2
|
+
export const SEARCH_FOCUS_VALUE = "search";
|
|
3
|
+
export const SEARCH_FOCUS_PATH = `/library?${SEARCH_FOCUS_PARAM}=${SEARCH_FOCUS_VALUE}`;
|
|
4
|
+
|
|
5
|
+
export function hasSearchFocusRequest(params: URLSearchParams): boolean {
|
|
6
|
+
return params.get(SEARCH_FOCUS_PARAM) === SEARCH_FOCUS_VALUE;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function clearSearchFocusRequest(
|
|
10
|
+
params: URLSearchParams,
|
|
11
|
+
): URLSearchParams {
|
|
12
|
+
const next = new URLSearchParams(params);
|
|
13
|
+
next.delete(SEARCH_FOCUS_PARAM);
|
|
14
|
+
return next;
|
|
15
|
+
}
|