@ai-matrx/sharing 0.1.1 → 0.1.3
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/CHANGELOG.md +12 -0
- package/dist/access-react.cjs +3 -1
- package/dist/access-react.cjs.map +1 -1
- package/dist/access-react.js +5 -1
- package/dist/access-react.js.map +1 -1
- package/dist/core.cjs +29 -26
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +6 -6
- package/dist/core.d.ts +6 -6
- package/dist/core.js +29 -26
- package/dist/core.js.map +1 -1
- package/dist/react.cjs +224 -86
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +24 -3
- package/dist/react.d.ts +24 -3
- package/dist/react.js +225 -86
- package/dist/react.js.map +1 -1
- package/package.json +4 -4
package/dist/react.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import react__default, { ReactNode, ComponentType } from 'react';
|
|
3
3
|
import { ConfirmOptions } from '@ai-matrx/kit/confirm-opener';
|
|
4
|
-
import { ResourceType, PermissionWithDetails, PermissionLevel, ShareActionResult, SharingCopyContext, AccessSummary, ShownTo, WhoCanSee, LaneChoice, Permission, CheckPermissionOptions } from '@ai-matrx/sharing/core';
|
|
4
|
+
import { ResourceType, PermissionWithDetails, PermissionLevel, ShareActionResult, SharingCopyContext, AccessSummary, ShownTo, WhoCanSee, LaneChoice, ShareLink, Permission, CheckPermissionOptions } from '@ai-matrx/sharing/core';
|
|
5
5
|
import { EntityTypeToken } from '@ai-matrx/associations';
|
|
6
6
|
|
|
7
7
|
type LooseProps = {
|
|
@@ -342,12 +342,33 @@ interface WhoCanSeeThisProps {
|
|
|
342
342
|
}
|
|
343
343
|
declare function WhoCanSeeThis({ whoCanSee, canChange, onChoose, row, }: WhoCanSeeThisProps): react__default.JSX.Element | null;
|
|
344
344
|
|
|
345
|
+
/** One more URL a link opens at (e.g. a file's direct byte URL), shown with copy + open. */
|
|
346
|
+
interface ShareLinkExtraUrl {
|
|
347
|
+
key: string;
|
|
348
|
+
label: string;
|
|
349
|
+
sublabel?: string | undefined;
|
|
350
|
+
url: string;
|
|
351
|
+
/** Highlighted as the main URL to hand out. */
|
|
352
|
+
primary?: boolean | undefined;
|
|
353
|
+
}
|
|
345
354
|
interface ShareLinkPanelProps {
|
|
346
355
|
resourceType: ResourceType;
|
|
347
356
|
resourceId: string;
|
|
348
357
|
isOwner: boolean;
|
|
349
358
|
/** Whether this resource type offers no-login links (admin policy). Hidden when false. */
|
|
350
359
|
enabled?: boolean | undefined;
|
|
360
|
+
/** Ask permission, expiry and max uses before a link is created. */
|
|
361
|
+
linkSettings?: boolean | undefined;
|
|
362
|
+
/** Show each link's access, expiry and uses. */
|
|
363
|
+
showLinkDetails?: boolean | undefined;
|
|
364
|
+
/** An open-in-new-tab control on each link. */
|
|
365
|
+
showOpenLink?: boolean | undefined;
|
|
366
|
+
/** Extra URLs per link (a file's direct byte URL), each with copy + open. */
|
|
367
|
+
extraUrls?: ((link: ShareLink) => ShareLinkExtraUrl[]) | undefined;
|
|
368
|
+
/** The origin link URLs are built on; defaults to the app URL. */
|
|
369
|
+
appOrigin?: string | undefined;
|
|
370
|
+
/** Every fresh list read — lets a host keep its own store of links in step. */
|
|
371
|
+
onLinksChange?: ((links: ShareLink[]) => void) | undefined;
|
|
351
372
|
}
|
|
352
373
|
/**
|
|
353
374
|
* "Anyone with the link" — mint / copy / revoke no-login share links.
|
|
@@ -357,7 +378,7 @@ interface ShareLinkPanelProps {
|
|
|
357
378
|
* link-carries-everything path — distinct from publishing to the web (which
|
|
358
379
|
* needs a public render route). Owner-only.
|
|
359
380
|
*/
|
|
360
|
-
declare function ShareLinkPanel({ resourceType, resourceId, isOwner, enabled, }: ShareLinkPanelProps): react__default.JSX.Element | null;
|
|
381
|
+
declare function ShareLinkPanel({ resourceType, resourceId, isOwner, enabled, linkSettings, showLinkDetails, showOpenLink, extraUrls, appOrigin, onLinksChange, }: ShareLinkPanelProps): react__default.JSX.Element | null;
|
|
361
382
|
|
|
362
383
|
type GrantableLevels = {
|
|
363
384
|
loading: boolean;
|
|
@@ -776,4 +797,4 @@ declare function WhoCouldSeeOn({ recordId }: {
|
|
|
776
797
|
recordId: string;
|
|
777
798
|
}): react.JSX.Element;
|
|
778
799
|
|
|
779
|
-
export { AccessSummaryPanel, type AccessSummaryPanelProps, type AccessSummaryState, AddEveryoneInOrg, type AddEveryoneInOrgProps, type GrantableLevels, GuestBadge, LANE_CLOSED_SAY, OrgAvailabilityNote, type OrgMemberPerson, OutsideSharePanel, type OutsideSharePanelProps, PermissionBadge, PermissionLevelDescription, PermissionsList, PublicAccessTab, PublicBadge, RowControls, type RowControlsProps, SearchEngineIndexedSwitch, SecureLinkPanel, ShareLinkPanel, ShareModal, type ShareOutcome, type ShareSheetConnection, type ShareSheetConnections, type ShareSheetOrganization, type ShareSheetToastOptions, type ShareSheetUi, ShareWithUserTab, type UseAccessSummaryArgs, type UseAccessSummaryResult, type UseShareResult, WhoCanSeeThis, type WhoCanSeeThisProps, WhoCouldSeeOn, anyoneReachWords, configureShareSheetUi, resetShareSheetCache, shareSheetUi, useAccessSummary, useCanAdmin, useCanEdit, useGrantableLevels, useIsOwner, usePermissionCheck, usePermissions, useResourcePermissions, useShare, useSharedWithMe, useSharing, useSharingStatus };
|
|
800
|
+
export { AccessSummaryPanel, type AccessSummaryPanelProps, type AccessSummaryState, AddEveryoneInOrg, type AddEveryoneInOrgProps, type GrantableLevels, GuestBadge, LANE_CLOSED_SAY, OrgAvailabilityNote, type OrgMemberPerson, OutsideSharePanel, type OutsideSharePanelProps, PermissionBadge, PermissionLevelDescription, PermissionsList, PublicAccessTab, PublicBadge, RowControls, type RowControlsProps, SearchEngineIndexedSwitch, SecureLinkPanel, type ShareLinkExtraUrl, ShareLinkPanel, type ShareLinkPanelProps, ShareModal, type ShareOutcome, type ShareSheetConnection, type ShareSheetConnections, type ShareSheetOrganization, type ShareSheetToastOptions, type ShareSheetUi, ShareWithUserTab, type UseAccessSummaryArgs, type UseAccessSummaryResult, type UseShareResult, WhoCanSeeThis, type WhoCanSeeThisProps, WhoCouldSeeOn, anyoneReachWords, configureShareSheetUi, resetShareSheetCache, shareSheetUi, useAccessSummary, useCanAdmin, useCanEdit, useGrantableLevels, useIsOwner, usePermissionCheck, usePermissions, useResourcePermissions, useShare, useSharedWithMe, useSharing, useSharingStatus };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import react__default, { ReactNode, ComponentType } from 'react';
|
|
3
3
|
import { ConfirmOptions } from '@ai-matrx/kit/confirm-opener';
|
|
4
|
-
import { ResourceType, PermissionWithDetails, PermissionLevel, ShareActionResult, SharingCopyContext, AccessSummary, ShownTo, WhoCanSee, LaneChoice, Permission, CheckPermissionOptions } from '@ai-matrx/sharing/core';
|
|
4
|
+
import { ResourceType, PermissionWithDetails, PermissionLevel, ShareActionResult, SharingCopyContext, AccessSummary, ShownTo, WhoCanSee, LaneChoice, ShareLink, Permission, CheckPermissionOptions } from '@ai-matrx/sharing/core';
|
|
5
5
|
import { EntityTypeToken } from '@ai-matrx/associations';
|
|
6
6
|
|
|
7
7
|
type LooseProps = {
|
|
@@ -342,12 +342,33 @@ interface WhoCanSeeThisProps {
|
|
|
342
342
|
}
|
|
343
343
|
declare function WhoCanSeeThis({ whoCanSee, canChange, onChoose, row, }: WhoCanSeeThisProps): react__default.JSX.Element | null;
|
|
344
344
|
|
|
345
|
+
/** One more URL a link opens at (e.g. a file's direct byte URL), shown with copy + open. */
|
|
346
|
+
interface ShareLinkExtraUrl {
|
|
347
|
+
key: string;
|
|
348
|
+
label: string;
|
|
349
|
+
sublabel?: string | undefined;
|
|
350
|
+
url: string;
|
|
351
|
+
/** Highlighted as the main URL to hand out. */
|
|
352
|
+
primary?: boolean | undefined;
|
|
353
|
+
}
|
|
345
354
|
interface ShareLinkPanelProps {
|
|
346
355
|
resourceType: ResourceType;
|
|
347
356
|
resourceId: string;
|
|
348
357
|
isOwner: boolean;
|
|
349
358
|
/** Whether this resource type offers no-login links (admin policy). Hidden when false. */
|
|
350
359
|
enabled?: boolean | undefined;
|
|
360
|
+
/** Ask permission, expiry and max uses before a link is created. */
|
|
361
|
+
linkSettings?: boolean | undefined;
|
|
362
|
+
/** Show each link's access, expiry and uses. */
|
|
363
|
+
showLinkDetails?: boolean | undefined;
|
|
364
|
+
/** An open-in-new-tab control on each link. */
|
|
365
|
+
showOpenLink?: boolean | undefined;
|
|
366
|
+
/** Extra URLs per link (a file's direct byte URL), each with copy + open. */
|
|
367
|
+
extraUrls?: ((link: ShareLink) => ShareLinkExtraUrl[]) | undefined;
|
|
368
|
+
/** The origin link URLs are built on; defaults to the app URL. */
|
|
369
|
+
appOrigin?: string | undefined;
|
|
370
|
+
/** Every fresh list read — lets a host keep its own store of links in step. */
|
|
371
|
+
onLinksChange?: ((links: ShareLink[]) => void) | undefined;
|
|
351
372
|
}
|
|
352
373
|
/**
|
|
353
374
|
* "Anyone with the link" — mint / copy / revoke no-login share links.
|
|
@@ -357,7 +378,7 @@ interface ShareLinkPanelProps {
|
|
|
357
378
|
* link-carries-everything path — distinct from publishing to the web (which
|
|
358
379
|
* needs a public render route). Owner-only.
|
|
359
380
|
*/
|
|
360
|
-
declare function ShareLinkPanel({ resourceType, resourceId, isOwner, enabled, }: ShareLinkPanelProps): react__default.JSX.Element | null;
|
|
381
|
+
declare function ShareLinkPanel({ resourceType, resourceId, isOwner, enabled, linkSettings, showLinkDetails, showOpenLink, extraUrls, appOrigin, onLinksChange, }: ShareLinkPanelProps): react__default.JSX.Element | null;
|
|
361
382
|
|
|
362
383
|
type GrantableLevels = {
|
|
363
384
|
loading: boolean;
|
|
@@ -776,4 +797,4 @@ declare function WhoCouldSeeOn({ recordId }: {
|
|
|
776
797
|
recordId: string;
|
|
777
798
|
}): react.JSX.Element;
|
|
778
799
|
|
|
779
|
-
export { AccessSummaryPanel, type AccessSummaryPanelProps, type AccessSummaryState, AddEveryoneInOrg, type AddEveryoneInOrgProps, type GrantableLevels, GuestBadge, LANE_CLOSED_SAY, OrgAvailabilityNote, type OrgMemberPerson, OutsideSharePanel, type OutsideSharePanelProps, PermissionBadge, PermissionLevelDescription, PermissionsList, PublicAccessTab, PublicBadge, RowControls, type RowControlsProps, SearchEngineIndexedSwitch, SecureLinkPanel, ShareLinkPanel, ShareModal, type ShareOutcome, type ShareSheetConnection, type ShareSheetConnections, type ShareSheetOrganization, type ShareSheetToastOptions, type ShareSheetUi, ShareWithUserTab, type UseAccessSummaryArgs, type UseAccessSummaryResult, type UseShareResult, WhoCanSeeThis, type WhoCanSeeThisProps, WhoCouldSeeOn, anyoneReachWords, configureShareSheetUi, resetShareSheetCache, shareSheetUi, useAccessSummary, useCanAdmin, useCanEdit, useGrantableLevels, useIsOwner, usePermissionCheck, usePermissions, useResourcePermissions, useShare, useSharedWithMe, useSharing, useSharingStatus };
|
|
800
|
+
export { AccessSummaryPanel, type AccessSummaryPanelProps, type AccessSummaryState, AddEveryoneInOrg, type AddEveryoneInOrgProps, type GrantableLevels, GuestBadge, LANE_CLOSED_SAY, OrgAvailabilityNote, type OrgMemberPerson, OutsideSharePanel, type OutsideSharePanelProps, PermissionBadge, PermissionLevelDescription, PermissionsList, PublicAccessTab, PublicBadge, RowControls, type RowControlsProps, SearchEngineIndexedSwitch, SecureLinkPanel, type ShareLinkExtraUrl, ShareLinkPanel, type ShareLinkPanelProps, ShareModal, type ShareOutcome, type ShareSheetConnection, type ShareSheetConnections, type ShareSheetOrganization, type ShareSheetToastOptions, type ShareSheetUi, ShareWithUserTab, type UseAccessSummaryArgs, type UseAccessSummaryResult, type UseShareResult, WhoCanSeeThis, type WhoCanSeeThisProps, WhoCouldSeeOn, anyoneReachWords, configureShareSheetUi, resetShareSheetCache, shareSheetUi, useAccessSummary, useCanAdmin, useCanEdit, useGrantableLevels, useIsOwner, usePermissionCheck, usePermissions, useResourcePermissions, useShare, useSharedWithMe, useSharing, useSharingStatus };
|
package/dist/react.js
CHANGED
|
@@ -1978,7 +1978,7 @@ var SOURCE_LABELS = {
|
|
|
1978
1978
|
};
|
|
1979
1979
|
var EMAIL_SHAPE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1980
1980
|
async function lookupConnectionByEmail(typed) {
|
|
1981
|
-
const { data } = await createClient2().rpc("lookup_user_by_email", { lookup_email: typed });
|
|
1981
|
+
const { data } = await createClient2().schema("users").rpc("lookup_user_by_email", { lookup_email: typed });
|
|
1982
1982
|
const row = data?.[0];
|
|
1983
1983
|
return row ? {
|
|
1984
1984
|
user_id: row.user_id,
|
|
@@ -2105,7 +2105,7 @@ function ShareWithUserTab({
|
|
|
2105
2105
|
targetUserId = selectedContact.user_id;
|
|
2106
2106
|
} else {
|
|
2107
2107
|
const client = createClient2();
|
|
2108
|
-
const { data: lookupData, error: lookupError } = await client.rpc(
|
|
2108
|
+
const { data: lookupData, error: lookupError } = await client.schema("users").rpc(
|
|
2109
2109
|
"lookup_user_by_email",
|
|
2110
2110
|
{ lookup_email: trimmedEmail }
|
|
2111
2111
|
);
|
|
@@ -2840,7 +2840,9 @@ import { AlertTriangle as AlertTriangle3 } from "lucide-react";
|
|
|
2840
2840
|
// src/react/sheet/ShareLinkPanel.tsx
|
|
2841
2841
|
import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef2, useState as useState10 } from "react";
|
|
2842
2842
|
import { Button as Button7 } from "@ai-matrx/design-system";
|
|
2843
|
-
import { Input as Input3 } from "@ai-matrx/design-system/controls";
|
|
2843
|
+
import { DateTimeField as DateTimeField2, Input as Input3, Select as Select5 } from "@ai-matrx/design-system/controls";
|
|
2844
|
+
import { OutboundLink } from "@ai-matrx/kit/outbound-react";
|
|
2845
|
+
import { formatAbsoluteDate } from "@ai-matrx/kit/format";
|
|
2844
2846
|
import {
|
|
2845
2847
|
Link2 as Link22,
|
|
2846
2848
|
Copy,
|
|
@@ -2850,7 +2852,8 @@ import {
|
|
|
2850
2852
|
Plus,
|
|
2851
2853
|
Eye as Eye2,
|
|
2852
2854
|
MessageSquareText,
|
|
2853
|
-
RefreshCw
|
|
2855
|
+
RefreshCw,
|
|
2856
|
+
ExternalLink
|
|
2854
2857
|
} from "lucide-react";
|
|
2855
2858
|
import {
|
|
2856
2859
|
createShareLink,
|
|
@@ -2958,8 +2961,23 @@ function ShareLinkPanel({
|
|
|
2958
2961
|
resourceType,
|
|
2959
2962
|
resourceId,
|
|
2960
2963
|
isOwner,
|
|
2961
|
-
enabled = true
|
|
2964
|
+
enabled = true,
|
|
2965
|
+
linkSettings = false,
|
|
2966
|
+
showLinkDetails = false,
|
|
2967
|
+
showOpenLink = false,
|
|
2968
|
+
extraUrls,
|
|
2969
|
+
appOrigin,
|
|
2970
|
+
onLinksChange
|
|
2962
2971
|
}) {
|
|
2972
|
+
const [permissionLevel, setPermissionLevel] = useState10("viewer");
|
|
2973
|
+
const [expiresAt, setExpiresAt] = useState10("");
|
|
2974
|
+
const [maxUses, setMaxUses] = useState10("");
|
|
2975
|
+
const onLinksChangeRef = useRef2(onLinksChange);
|
|
2976
|
+
onLinksChangeRef.current = onLinksChange;
|
|
2977
|
+
const urlFor = useCallback5(
|
|
2978
|
+
(link) => shareUrlForLink(link, appOrigin),
|
|
2979
|
+
[appOrigin]
|
|
2980
|
+
);
|
|
2963
2981
|
const { toast } = useToast();
|
|
2964
2982
|
const [links, setLinks] = useState10([]);
|
|
2965
2983
|
const [loading, setLoading] = useState10(true);
|
|
@@ -2975,10 +2993,11 @@ function ShareLinkPanel({
|
|
|
2975
2993
|
const [handoffBusy, setHandoffBusy] = useState10(false);
|
|
2976
2994
|
const { share, copy: copyMessage, fallbackDialog } = useShare();
|
|
2977
2995
|
const resourceKey = `${resourceType}\0${resourceId}`;
|
|
2978
|
-
const fetchLinks = useCallback5(
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2996
|
+
const fetchLinks = useCallback5(async () => {
|
|
2997
|
+
const fresh = await listShareLinks(resourceType, resourceId);
|
|
2998
|
+
onLinksChangeRef.current?.(fresh);
|
|
2999
|
+
return fresh;
|
|
3000
|
+
}, [resourceType, resourceId]);
|
|
2982
3001
|
const refresh = useCallback5(async () => {
|
|
2983
3002
|
setLoading(true);
|
|
2984
3003
|
setShareError(null);
|
|
@@ -3051,7 +3070,7 @@ function ShareLinkPanel({
|
|
|
3051
3070
|
});
|
|
3052
3071
|
return;
|
|
3053
3072
|
}
|
|
3054
|
-
const outcome = await copyMessage(
|
|
3073
|
+
const outcome = await copyMessage(urlFor(currentLink), {
|
|
3055
3074
|
title: "Copy link",
|
|
3056
3075
|
description: "Copy this link and send it to the person you want to share with."
|
|
3057
3076
|
});
|
|
@@ -3064,11 +3083,36 @@ function ShareLinkPanel({
|
|
|
3064
3083
|
});
|
|
3065
3084
|
}
|
|
3066
3085
|
},
|
|
3067
|
-
[copyMessage, refresh, toast]
|
|
3086
|
+
[copyMessage, refresh, toast, urlFor]
|
|
3087
|
+
);
|
|
3088
|
+
const copyExtraUrl = useCallback5(
|
|
3089
|
+
async (key, url) => {
|
|
3090
|
+
const outcome = await copyMessage(url, {
|
|
3091
|
+
title: "Copy link",
|
|
3092
|
+
description: "Copy this link and send it to the person you want to share with."
|
|
3093
|
+
});
|
|
3094
|
+
if (outcome === "copied") {
|
|
3095
|
+
setCopiedId(key);
|
|
3096
|
+
setTimeout(() => setCopiedId((k) => k === key ? null : k), 2e3);
|
|
3097
|
+
}
|
|
3098
|
+
},
|
|
3099
|
+
[copyMessage]
|
|
3068
3100
|
);
|
|
3069
3101
|
const createLinkOnce = useCallback5(async () => {
|
|
3070
|
-
const result = await createShareLink(
|
|
3102
|
+
const result = await createShareLink(
|
|
3103
|
+
linkSettings ? {
|
|
3104
|
+
resourceType,
|
|
3105
|
+
resourceId,
|
|
3106
|
+
permissionLevel,
|
|
3107
|
+
expiresAt: expiresAt ? new Date(expiresAt).toISOString() : null,
|
|
3108
|
+
maxUses: maxUses ? Number(maxUses) : null
|
|
3109
|
+
} : { resourceType, resourceId }
|
|
3110
|
+
);
|
|
3071
3111
|
if (result.success && result.url) {
|
|
3112
|
+
if (linkSettings) {
|
|
3113
|
+
setExpiresAt("");
|
|
3114
|
+
setMaxUses("");
|
|
3115
|
+
}
|
|
3072
3116
|
const freshLinks = await refresh();
|
|
3073
3117
|
const createdLink = result.token && freshLinks ? freshLinks.find((link) => link.token === result.token) : void 0;
|
|
3074
3118
|
if (!createdLink || !freshLinks) {
|
|
@@ -3087,7 +3131,17 @@ function ShareLinkPanel({
|
|
|
3087
3131
|
variant: "destructive"
|
|
3088
3132
|
});
|
|
3089
3133
|
}
|
|
3090
|
-
}, [
|
|
3134
|
+
}, [
|
|
3135
|
+
resourceType,
|
|
3136
|
+
resourceId,
|
|
3137
|
+
refresh,
|
|
3138
|
+
copyLink,
|
|
3139
|
+
toast,
|
|
3140
|
+
linkSettings,
|
|
3141
|
+
permissionLevel,
|
|
3142
|
+
expiresAt,
|
|
3143
|
+
maxUses
|
|
3144
|
+
]);
|
|
3091
3145
|
const creatingRef = useRef2(false);
|
|
3092
3146
|
const handleCreate = useCallback5(async () => {
|
|
3093
3147
|
if (creatingRef.current) return;
|
|
@@ -3198,7 +3252,7 @@ function ShareLinkPanel({
|
|
|
3198
3252
|
});
|
|
3199
3253
|
return;
|
|
3200
3254
|
}
|
|
3201
|
-
const message = createSafeShareMessage(
|
|
3255
|
+
const message = createSafeShareMessage(urlFor(currentLink));
|
|
3202
3256
|
const outcome = await share({
|
|
3203
3257
|
title: "AI Matrx share",
|
|
3204
3258
|
text: message,
|
|
@@ -3223,7 +3277,7 @@ function ShareLinkPanel({
|
|
|
3223
3277
|
} finally {
|
|
3224
3278
|
setHandoffBusy(false);
|
|
3225
3279
|
}
|
|
3226
|
-
}, [shareTarget, refresh, share, toast]);
|
|
3280
|
+
}, [shareTarget, refresh, share, toast, urlFor]);
|
|
3227
3281
|
const handleCopyReviewedMessage = useCallback5(async () => {
|
|
3228
3282
|
if (!shareTarget) return;
|
|
3229
3283
|
setHandoffBusy(true);
|
|
@@ -3266,7 +3320,7 @@ function ShareLinkPanel({
|
|
|
3266
3320
|
});
|
|
3267
3321
|
return;
|
|
3268
3322
|
}
|
|
3269
|
-
const message = createSafeShareMessage(
|
|
3323
|
+
const message = createSafeShareMessage(urlFor(currentLink));
|
|
3270
3324
|
const outcome = await copyMessage(message, {
|
|
3271
3325
|
title: "Copy message",
|
|
3272
3326
|
description: "Copy the reviewed message below and paste it into your messaging app."
|
|
@@ -3281,7 +3335,7 @@ function ShareLinkPanel({
|
|
|
3281
3335
|
} finally {
|
|
3282
3336
|
setHandoffBusy(false);
|
|
3283
3337
|
}
|
|
3284
|
-
}, [shareTarget, refresh, copyMessage, toast]);
|
|
3338
|
+
}, [shareTarget, refresh, copyMessage, toast, urlFor]);
|
|
3285
3339
|
if (!isOwner) return null;
|
|
3286
3340
|
if (!enabled) {
|
|
3287
3341
|
return /* @__PURE__ */ jsxs10("div", { className: "flex items-start gap-2 p-3 bg-muted/30 rounded-lg border", children: [
|
|
@@ -3315,79 +3369,164 @@ function ShareLinkPanel({
|
|
|
3315
3369
|
}
|
|
3316
3370
|
)
|
|
3317
3371
|
] }),
|
|
3372
|
+
linkSettings ? /* @__PURE__ */ jsxs10("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-3", children: [
|
|
3373
|
+
/* @__PURE__ */ jsxs10("label", { className: "flex flex-col gap-1 text-xs", children: [
|
|
3374
|
+
/* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: "Permission" }),
|
|
3375
|
+
/* @__PURE__ */ jsx14(
|
|
3376
|
+
Select5,
|
|
3377
|
+
{
|
|
3378
|
+
value: permissionLevel,
|
|
3379
|
+
onValueChange: setPermissionLevel,
|
|
3380
|
+
"aria-label": "Link permission",
|
|
3381
|
+
options: [
|
|
3382
|
+
{ value: "viewer", label: "Read only" },
|
|
3383
|
+
{ value: "editor", label: "Read + write" }
|
|
3384
|
+
]
|
|
3385
|
+
}
|
|
3386
|
+
)
|
|
3387
|
+
] }),
|
|
3388
|
+
/* @__PURE__ */ jsxs10("label", { className: "flex flex-col gap-1 text-xs", children: [
|
|
3389
|
+
/* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: "Expires" }),
|
|
3390
|
+
/* @__PURE__ */ jsx14(DateTimeField2, { value: expiresAt, onValueChange: (v) => setExpiresAt(v ?? "") })
|
|
3391
|
+
] }),
|
|
3392
|
+
/* @__PURE__ */ jsxs10("label", { className: "flex flex-col gap-1 text-xs", children: [
|
|
3393
|
+
/* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: "Max uses" }),
|
|
3394
|
+
/* @__PURE__ */ jsx14(
|
|
3395
|
+
Input3,
|
|
3396
|
+
{
|
|
3397
|
+
type: "number",
|
|
3398
|
+
min: 1,
|
|
3399
|
+
"aria-label": "Max uses",
|
|
3400
|
+
value: maxUses,
|
|
3401
|
+
onChange: (e) => setMaxUses(e.target.value)
|
|
3402
|
+
}
|
|
3403
|
+
)
|
|
3404
|
+
] })
|
|
3405
|
+
] }) : null,
|
|
3318
3406
|
isLoading ? /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-center py-3 text-xs text-muted-foreground", children: [
|
|
3319
3407
|
/* @__PURE__ */ jsx14(Loader27, { className: "w-3.5 h-3.5 animate-spin mr-2" }),
|
|
3320
3408
|
"Loading links\u2026"
|
|
3321
3409
|
] }) : activeLinks.length === 0 && !shareError ? /* @__PURE__ */ jsx14("p", { className: "text-xs text-muted-foreground py-1", children: "No share links yet. Create one to share this with anyone." }) : /* @__PURE__ */ jsx14("div", { className: "space-y-1.5", children: activeLinks.map((link) => {
|
|
3322
3410
|
const unavailableReason = shareLinkUnavailableReason(link);
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
children:
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
className: "
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
}
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3411
|
+
const linkUrl = urlFor(link);
|
|
3412
|
+
const extras = extraUrls?.(link) ?? [];
|
|
3413
|
+
return /* @__PURE__ */ jsxs10("div", { className: "space-y-1", children: [
|
|
3414
|
+
showLinkDetails ? /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center gap-1.5 px-0.5 text-[11px] text-muted-foreground", children: [
|
|
3415
|
+
/* @__PURE__ */ jsx14("span", { className: "rounded bg-muted px-1.5 py-0.5 font-medium text-foreground", children: link.permissionLevel === "viewer" ? "Read only" : "Read + write" }),
|
|
3416
|
+
/* @__PURE__ */ jsx14("span", { children: link.expiresAt ? `Expires ${formatAbsoluteDate(link.expiresAt)}` : "No expiry" }),
|
|
3417
|
+
link.maxUses ? /* @__PURE__ */ jsx14("span", { children: `${link.useCount}/${link.maxUses} uses` }) : null
|
|
3418
|
+
] }) : null,
|
|
3419
|
+
extras.map((extra) => /* @__PURE__ */ jsxs10(
|
|
3420
|
+
"div",
|
|
3421
|
+
{
|
|
3422
|
+
className: extra.primary ? "flex items-center gap-1.5 rounded-md border border-primary/30 bg-primary/5 p-1.5" : "flex items-center gap-1.5 rounded-md border bg-background p-1.5",
|
|
3423
|
+
children: [
|
|
3424
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex min-w-0 flex-1 flex-col px-1", children: [
|
|
3425
|
+
/* @__PURE__ */ jsxs10("span", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: [
|
|
3426
|
+
extra.label,
|
|
3427
|
+
extra.sublabel ? ` \xB7 ${extra.sublabel}` : ""
|
|
3428
|
+
] }),
|
|
3429
|
+
/* @__PURE__ */ jsx14("span", { className: "truncate font-mono text-xs", title: extra.url, children: extra.url })
|
|
3430
|
+
] }),
|
|
3431
|
+
/* @__PURE__ */ jsx14(
|
|
3432
|
+
OutboundLink,
|
|
3433
|
+
{
|
|
3434
|
+
href: extra.url,
|
|
3435
|
+
"aria-label": `Open ${extra.label}`,
|
|
3436
|
+
title: "Open in new tab",
|
|
3437
|
+
className: "flex h-11 w-11 flex-shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground sm:h-8 sm:w-8",
|
|
3438
|
+
children: /* @__PURE__ */ jsx14(ExternalLink, { className: "w-4 h-4" })
|
|
3439
|
+
}
|
|
3440
|
+
),
|
|
3441
|
+
/* @__PURE__ */ jsx14(
|
|
3442
|
+
Button7,
|
|
3443
|
+
{
|
|
3444
|
+
variant: "ghost",
|
|
3445
|
+
size: "icon",
|
|
3446
|
+
className: "h-11 w-11 flex-shrink-0 sm:h-8 sm:w-8",
|
|
3447
|
+
onClick: () => copyExtraUrl(`${link.id}:${extra.key}`, extra.url),
|
|
3448
|
+
disabled: !!unavailableReason,
|
|
3449
|
+
title: unavailableReason ?? "Copy",
|
|
3450
|
+
"aria-label": `Copy ${extra.label}`,
|
|
3451
|
+
children: copiedId === `${link.id}:${extra.key}` ? /* @__PURE__ */ jsx14(Check2, { className: "w-4 h-4 text-green-500" }) : /* @__PURE__ */ jsx14(Copy, { className: "w-4 h-4" })
|
|
3452
|
+
}
|
|
3453
|
+
)
|
|
3454
|
+
]
|
|
3455
|
+
},
|
|
3456
|
+
extra.key
|
|
3457
|
+
)),
|
|
3458
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1.5 rounded-md border bg-background p-1.5", children: [
|
|
3459
|
+
/* @__PURE__ */ jsx14(
|
|
3460
|
+
Input3,
|
|
3461
|
+
{
|
|
3462
|
+
mono: true,
|
|
3463
|
+
readOnly: true,
|
|
3464
|
+
value: linkUrl,
|
|
3465
|
+
className: "min-w-0 flex-1",
|
|
3466
|
+
onFocus: (e) => e.currentTarget.select()
|
|
3467
|
+
}
|
|
3468
|
+
),
|
|
3469
|
+
/* @__PURE__ */ jsxs10(
|
|
3470
|
+
"span",
|
|
3471
|
+
{
|
|
3472
|
+
className: "flex items-center gap-1 text-[10px] text-muted-foreground px-1",
|
|
3473
|
+
title: `${link.useCount} view${link.useCount === 1 ? "" : "s"}`,
|
|
3474
|
+
children: [
|
|
3475
|
+
/* @__PURE__ */ jsx14(Eye2, { className: "w-3 h-3" }),
|
|
3476
|
+
link.useCount
|
|
3477
|
+
]
|
|
3478
|
+
}
|
|
3479
|
+
),
|
|
3480
|
+
showOpenLink ? /* @__PURE__ */ jsx14(
|
|
3481
|
+
OutboundLink,
|
|
3482
|
+
{
|
|
3483
|
+
href: linkUrl,
|
|
3484
|
+
"aria-label": "Open share link",
|
|
3485
|
+
title: "Open in new tab",
|
|
3486
|
+
className: "flex h-11 w-11 flex-shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground sm:h-8 sm:w-8",
|
|
3487
|
+
children: /* @__PURE__ */ jsx14(ExternalLink, { className: "w-4 h-4" })
|
|
3488
|
+
}
|
|
3489
|
+
) : null,
|
|
3490
|
+
/* @__PURE__ */ jsx14(
|
|
3491
|
+
Button7,
|
|
3492
|
+
{
|
|
3493
|
+
variant: "ghost",
|
|
3494
|
+
size: "icon",
|
|
3495
|
+
className: "h-11 w-11 flex-shrink-0 sm:h-8 sm:w-8",
|
|
3496
|
+
onClick: () => copyLink(link),
|
|
3497
|
+
disabled: !!unavailableReason,
|
|
3498
|
+
title: unavailableReason ?? "Copy link",
|
|
3499
|
+
"aria-label": "Copy share link",
|
|
3500
|
+
children: copiedId === link.id ? /* @__PURE__ */ jsx14(Check2, { className: "w-4 h-4 text-green-500" }) : /* @__PURE__ */ jsx14(Copy, { className: "w-4 h-4" })
|
|
3501
|
+
}
|
|
3502
|
+
),
|
|
3503
|
+
/* @__PURE__ */ jsx14(
|
|
3504
|
+
Button7,
|
|
3505
|
+
{
|
|
3506
|
+
variant: "ghost",
|
|
3507
|
+
size: "icon",
|
|
3508
|
+
className: "h-11 w-11 flex-shrink-0 sm:h-8 sm:w-8",
|
|
3509
|
+
onClick: () => prepareTextShare(link.id),
|
|
3510
|
+
disabled: !!unavailableReason || refreshing,
|
|
3511
|
+
title: unavailableReason ?? "Review before sharing by text",
|
|
3512
|
+
"aria-label": "Share by text",
|
|
3513
|
+
children: refreshing ? /* @__PURE__ */ jsx14(Loader27, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ jsx14(MessageSquareText, { className: "w-4 h-4" })
|
|
3514
|
+
}
|
|
3515
|
+
),
|
|
3516
|
+
/* @__PURE__ */ jsx14(
|
|
3517
|
+
Button7,
|
|
3518
|
+
{
|
|
3519
|
+
variant: "ghost",
|
|
3520
|
+
size: "icon",
|
|
3521
|
+
className: "h-11 w-11 flex-shrink-0 text-destructive sm:h-8 sm:w-8",
|
|
3522
|
+
onClick: () => setRevokeTarget(link),
|
|
3523
|
+
title: "Turn off link",
|
|
3524
|
+
"aria-label": "Turn off share link",
|
|
3525
|
+
children: /* @__PURE__ */ jsx14(Trash22, { className: "w-4 h-4" })
|
|
3526
|
+
}
|
|
3527
|
+
)
|
|
3528
|
+
] })
|
|
3529
|
+
] }, link.id);
|
|
3391
3530
|
}) }),
|
|
3392
3531
|
shareError ? /* @__PURE__ */ jsxs10(
|
|
3393
3532
|
"div",
|
|
@@ -3439,7 +3578,7 @@ function ShareLinkPanel({
|
|
|
3439
3578
|
] }),
|
|
3440
3579
|
/* @__PURE__ */ jsxs10("div", { className: "space-y-1", children: [
|
|
3441
3580
|
/* @__PURE__ */ jsx14("p", { className: "text-xs font-medium", children: "Message preview" }),
|
|
3442
|
-
/* @__PURE__ */ jsx14("p", { className: "rounded-md border bg-muted/30 p-3 break-words", children: createSafeShareMessage(
|
|
3581
|
+
/* @__PURE__ */ jsx14("p", { className: "rounded-md border bg-muted/30 p-3 break-words", children: createSafeShareMessage(urlFor(shareTarget)) })
|
|
3443
3582
|
] }),
|
|
3444
3583
|
/* @__PURE__ */ jsxs10(
|
|
3445
3584
|
Button7,
|