Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/share-edit-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ function GranteeItem({
<span className="swan-shares-grantee-icon" title={grantee.type === 'GRANTEE_TYPE_USER' ? 'User' : 'Group'}>
{grantee.type === 'GRANTEE_TYPE_USER' ? UserEmoji : GroupEmoji}
</span>
<span className="swan-shares-grantee-name">{grantee.opaqueId}</span>
<span className="swan-shares-grantee-name">
{'displayName' in grantee ? grantee.displayName : grantee.opaqueId}
</span>
</div>
<RoleDropdown value={role} onChange={handleRole} disabled={busy} />
<button className="swan-shares-grantee-remove" title="Remove" onClick={() => onRemove(grantee.shareId)}>
Expand Down
16 changes: 12 additions & 4 deletions src/shares-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,19 @@ const TABS: { id: TabId; label: string; icon: React.ReactElement }[] = [

function FileTypeIcon({ share, registry }: { share: Share; registry: FileTypeRegistry }) {
if (share.resourceType !== 'RESOURCE_TYPE_FILE') {
return <span className="swan-shares-item-icon"><folderIcon.react stylesheet="listing" /></span>;
return (

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a formatting change

<span className="swan-shares-item-icon">
<folderIcon.react stylesheet="listing" />
</span>
);
}
const fileTypes = registry.getFileTypesForPath(share.name);
const Icon = fileTypes.length > 0 && fileTypes[0].icon ? fileTypes[0].icon.react : fileIcon.react;
return <span className="swan-shares-item-icon"><Icon stylesheet="listing" /></span>;
return (
<span className="swan-shares-item-icon">

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

<Icon stylesheet="listing" />
</span>
);
}

function ShareItem({
Expand All @@ -44,9 +52,9 @@ function ShareItem({
}) {
let meta = '';
if (share.shareDirection === 'WITH_ME' && share.sharedBy) {
meta = `from ${share.sharedBy}`;
meta = `from ${share.sharedBy.displayName || share.sharedBy.opaqueId}`;
} else if (share.shareDirection === 'BY_ME' && share.shareType === 'REGULAR' && share.sharedWith.length > 0) {
meta = `with ${share.sharedWith.map(g => g.opaqueId).join(', ')}`;
meta = `with ${share.sharedWith.map(g => ('displayName' in g ? g.displayName : g.opaqueId)).join(', ')}`;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These types of checks can be simplified, but it's a minor suggestion

Suggested change
meta = `with ${share.sharedWith.map(g => ('displayName' in g ? g.displayName : g.opaqueId)).join(', ')}`;
meta = `with ${share.sharedWith.map(g => g.displayName ?? g.opaqueId).join(', ')}`;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are other places where this can be applied.

}

const handleContext = (e: React.MouseEvent) => {
Expand Down
109 changes: 84 additions & 25 deletions src/shares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,39 @@ interface RawResourceInfo {
type?: ResourceType;
}

interface RawSharedByMeRegular {
interface RawGranteeUserInfo {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to have different interfaces that are the same? They actually represent the same entity (user, person, account.. not sure what's the most appropriate name), that can be a person that creates or receives a share.

id: { opaque_id: string };
mail: string;
display_name: string;
}

interface RawCreatorUserInfo {
id: { opaque_id: string };
mail: string;
display_name: string;
}

interface RawSharedByMeRegularUser {
share: {
id: { opaque_id: string };
resource_id: { opaque_id: string };
grantee: RawUserGrantee | RawGroupGrantee;
grantee: RawUserGrantee;
};
resource_info: RawResourceInfo;
grantee_user_info: RawGranteeUserInfo;
}

interface RawSharedByMeRegularGroup {
share: {
id: { opaque_id: string };
resource_id: { opaque_id: string };
grantee: RawGroupGrantee;
};
resource_info: RawResourceInfo;
}

type RawSharedByMeRegular = RawSharedByMeRegularUser | RawSharedByMeRegularGroup;

interface RawSharedByMePublic {
public_share: {
id: { opaque_id: string };
Expand All @@ -52,12 +76,31 @@ interface RawSharedWithMe {
};
};
resource_info: RawResourceInfo;
creator_user_info?: RawCreatorUserInfo;
}

interface Grantee {
type: GranteeType;
interface InvalidGrantee {
type: 'GRANTEE_TYPE_INVALID';
opaqueId: string;
}
interface GroupGrantee {
type: 'GRANTEE_TYPE_GROUP';
opaqueId: string;
}
interface UserGrantee {
type: 'GRANTEE_TYPE_USER';
opaqueId: string;
mail: string;
displayName: string;
}

type Grantee = InvalidGrantee | GroupGrantee | UserGrantee;

interface Creator {
opaqueId: string;
mail?: string;
displayName?: string;
}

interface _Share {
shareDirection: ShareDirection;
Expand All @@ -83,7 +126,7 @@ interface ByMePublicShare extends _Share {
interface WithMeRegularShare extends _Share {
shareDirection: 'WITH_ME';
shareType: 'REGULAR';
sharedBy: string;
sharedBy: Creator;
}

export type Share = ByMeRegularShare | ByMePublicShare | WithMeRegularShare;
Expand Down Expand Up @@ -116,6 +159,19 @@ export async function fetchShares(): Promise<Share[]> {
? share.share.grantee.user_id.opaque_id
: share.share.grantee.group_id.opaque_id;

const grantee: Grantee =
'grantee_user_info' in share
? {
type: 'GRANTEE_TYPE_USER',
opaqueId: sharedWithOpaqueId,
mail: share.grantee_user_info.mail,
displayName: share.grantee_user_info.display_name
}
: {
type: share.share.grantee.type,
opaqueId: sharedWithOpaqueId
};

if (!byMeMerged.has(resourceId)) {
byMeMerged.set(resourceId, {
shareDirection: 'BY_ME',
Expand All @@ -125,18 +181,10 @@ export async function fetchShares(): Promise<Share[]> {
name: share.resource_info.name,
path: share.resource_info.path.slice('/eos'.length), // TODO: Don't hardcode this prefix
rawPath: share.resource_info.path,
sharedWith: [
{
type: share.share.grantee.type,
opaqueId: sharedWithOpaqueId
}
]
sharedWith: [grantee]
});
} else {
byMeMerged.get(resourceId)?.sharedWith.push({
type: share.share.grantee.type,
opaqueId: sharedWithOpaqueId
});
byMeMerged.get(resourceId)?.sharedWith.push(grantee);
}
}

Expand Down Expand Up @@ -168,7 +216,11 @@ export async function fetchShares(): Promise<Share[]> {
name: share.resource_info.name,
path: share.resource_info.path.slice('/eos'.length), // TODO: Don't hardcode this prefix
rawPath: share.resource_info.path,
sharedBy: share.received_share.share.creator.opaque_id
sharedBy: {
opaqueId: share.received_share.share.creator.opaque_id,
mail: share.creator_user_info?.mail,
displayName: share.creator_user_info?.display_name
}
});
}

Expand All @@ -180,6 +232,7 @@ export interface ShareGranteeDetail {
type: GranteeType;
opaqueId: string;
role: ShareRole;
displayName?: string;
}

export interface UserSearchResult {
Expand Down Expand Up @@ -214,16 +267,22 @@ export async function fetchSharesForResource(rawPath: string): Promise<ShareGran

for (const item of data.shares as RawSharedByMeRegular[]) {
const grantee = item.share.grantee;
const opaqueId =
grantee.type === 'GRANTEE_TYPE_USER'
? grantee.user_id.opaque_id
: grantee.group_id.opaque_id;
results.push({
const opaqueId = grantee.type === 'GRANTEE_TYPE_USER' ? grantee.user_id.opaque_id : grantee.group_id.opaque_id;

const detail: ShareGranteeDetail = {
shareId: item.share.id.opaque_id,
type: grantee.type,
opaqueId,
role: roleFromRawPermissions((item.share as Record<string, unknown>).permissions as Record<string, unknown> | undefined)
});
role: roleFromRawPermissions(
(item.share as Record<string, unknown>).permissions as Record<string, unknown> | undefined
)
};

if ('grantee_user_info' in item) {
detail.displayName = item.grantee_user_info.display_name;
}

results.push(detail);
}

return results;
Expand Down Expand Up @@ -298,7 +357,7 @@ export async function findUsers(query: string, signal?: AbortSignal): Promise<Us
}

const data = await resp.json();
return (data.items as Array<Record<string, unknown>>).map((u) => ({
return (data.items as Array<Record<string, unknown>>).map(u => ({
opaqueId: (u.id as Record<string, string>).opaque_id,
idp: (u.id as Record<string, string>).idp,
displayName: (u.display_name as string) || (u.username as string) || '',
Expand All @@ -317,7 +376,7 @@ export async function findGroups(query: string, signal?: AbortSignal): Promise<G
}

const data = await resp.json();
return (data.items as Array<Record<string, unknown>>).map((g) => ({
return (data.items as Array<Record<string, unknown>>).map(g => ({
opaqueId: (g.id as Record<string, string>).opaque_id,
displayName: (g.group_name as string) || (g.id as Record<string, string>).opaque_id
}));
Expand Down