Skip to content

Commit a26401f

Browse files
Updates share button to only be displayed when user can actually share
Signed-off-by: Darshit Chanpura <dchanp@amazon.com>
1 parent b018096 commit a26401f

File tree

1 file changed

+60
-28
lines changed

1 file changed

+60
-28
lines changed

public/apps/resource-sharing/resource-sharing-panel.tsx

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,12 @@ interface ResourceRow {
5858
resource_type: string;
5959
created_by: CreatedBy;
6060
share_with?: ShareWith; // may be empty/undefined
61+
can_share?: boolean; // whether the current user can share this resource
6162
}
6263
interface TypeEntry {
6364
type: string; // fully qualified class name
6465
index: string; // name of the index to be supplied to the API as resource_type
66+
action_groups: string[]; // known action-groups for this type
6567
}
6668
// Tiny API that the panel consumes
6769
interface Api {
@@ -91,17 +93,6 @@ interface Props {
9193
toasts: CoreStart['notifications']['toasts'];
9294
}
9395

94-
const ACTION_GROUP_SUGGESTIONS = [
95-
'read',
96-
'write',
97-
'manage',
98-
'admin',
99-
'monitor',
100-
'index',
101-
'delete',
102-
'all',
103-
];
104-
10596
const hasSharingInfo = (sw?: ShareWith) =>
10697
!!sw &&
10798
Object.values(sw).some(
@@ -226,6 +217,7 @@ interface ModalProps {
226217
resource: ResourceRow;
227218
resourceType: string;
228219
resourceTypeIndex: string;
220+
actionGroups: string[];
229221
}
230222

231223
const hasNonEmptyRecipients = (r?: ShareRecipients) =>
@@ -247,6 +239,7 @@ const ShareAccessModal: React.FC<ModalProps> = ({
247239
resource,
248240
resourceType,
249241
resourceTypeIndex,
242+
actionGroups,
250243
}) => {
251244
const original = useMemo(() => cloneShareWith(resource?.share_with), [resource?.share_with]);
252245
const [working, setWorking] = useState<ShareWith>(() =>
@@ -262,9 +255,21 @@ const ShareAccessModal: React.FC<ModalProps> = ({
262255
}, [mode, resource]);
263256

264257
const groups = Object.keys(working);
258+
// suggestions list for this modal (unique + keep order)
259+
const SUGGESTIONS = useMemo(() => Array.from(new Set(actionGroups ?? [])), [actionGroups]);
260+
265261
const addGroup = () => {
266-
const base =
267-
ACTION_GROUP_SUGGESTIONS.find((g) => !groups.includes(g)) || `GROUP_${groups.length + 1}`;
262+
// If no suggestions were provided for this type, do nothing.
263+
if (!SUGGESTIONS.length) {
264+
// Optional: show a subtle warning/toast instead of silent no-op
265+
// toasts?.addWarning?.('No predefined action-groups for this type');
266+
return;
267+
}
268+
269+
// Pick the first unused suggestion
270+
const base = SUGGESTIONS.find((g) => !groups.includes(g));
271+
if (!base) return; // all suggestions already used
272+
268273
setWorking({ ...working, [base]: {} });
269274
};
270275

@@ -391,18 +396,18 @@ const ShareAccessModal: React.FC<ModalProps> = ({
391396
)}
392397

393398
{Object.entries(working).map(([groupName, recipients]) => {
394-
// TODO: update these to fetch static action-groups from backend
395-
const groupSuggestions = [
396-
...new Set([groupName, ...ACTION_GROUP_SUGGESTIONS]),
397-
].map((l) => ({ label: l }));
399+
const groupOptions = [...new Set([groupName, ...SUGGESTIONS])].map((l) => ({
400+
label: l,
401+
}));
402+
398403
return (
399404
<EuiPanel key={groupName} paddingSize="m" hasShadow={false} hasBorder>
400405
<EuiFlexGroup gutterSize="m" alignItems="center">
401406
<EuiFlexItem grow={3}>
402407
<EuiFormRow label="Action-group">
403408
<EuiComboBox
404409
singleSelection={{ asPlainText: true }}
405-
options={groupSuggestions}
410+
options={groupOptions}
406411
selectedOptions={[{ label: groupName }]}
407412
onChange={(opts) => {
408413
const newLabel = opts[0]?.label || groupName;
@@ -539,7 +544,7 @@ const humanizeClassName = (fqn: string) => {
539544
/** ---------- Main table ---------- */
540545
export const ResourceSharingPanel: React.FC<Props> = ({ api, toasts }) => {
541546
const [typeOptions, setTypeOptions] = useState<
542-
Array<{ value: string; text: string; fqn: string }>
547+
Array<{ value: string; text: string; fqn: string; actionGroups: string[] }>
543548
>([]);
544549
const [selectedType, setSelectedType] = useState<string>(''); // no default selection
545550
const [rows, setRows] = useState<ResourceRow[]>([]);
@@ -561,7 +566,12 @@ export const ResourceSharingPanel: React.FC<Props> = ({ api, toasts }) => {
561566
const raw: TypeEntry[] = Array.isArray(res) ? res : res?.types || [];
562567
// value = index (what we send as resourceType); text = type (what we display)
563568
const options = raw
564-
.map((t) => ({ value: t.index, text: humanizeClassName(t.type), fqn: t.type }))
569+
.map((t) => ({
570+
value: t.index,
571+
text: humanizeClassName(t.type),
572+
fqn: t.type,
573+
actionGroups: t.action_groups,
574+
}))
565575
// sort alphabetically by text (and by value if text is equal)
566576
.sort((a, b) => {
567577
const byText = a.text.localeCompare(b.text, undefined, { sensitivity: 'base' });
@@ -601,6 +611,11 @@ export const ResourceSharingPanel: React.FC<Props> = ({ api, toasts }) => {
601611
const selectedTypeLabel = selectedTypeMeta?.text ?? (selectedType || '—');
602612
const selectedTypeTooltip = selectedTypeMeta?.fqn; // actual class name
603613

614+
const currentActionGroups = useMemo(
615+
() => Array.from(new Set(selectedTypeMeta?.actionGroups ?? [])).sort(),
616+
[selectedTypeMeta]
617+
);
618+
604619
const columns = [
605620
// id column
606621
{
@@ -674,20 +689,36 @@ export const ResourceSharingPanel: React.FC<Props> = ({ api, toasts }) => {
674689
name: 'Actions',
675690
render: (item: ResourceRow) => {
676691
const label = hasSharingInfo(item.share_with) ? 'Update Access' : 'Share';
677-
return (
692+
const canShare = item.can_share === true;
693+
694+
const handleClick = () => {
695+
if (!canShare) return;
696+
setModalState({
697+
open: true,
698+
mode: hasSharingInfo(item.share_with) ? 'edit' : 'create',
699+
resource: item,
700+
});
701+
};
702+
703+
const btn = (
678704
<EuiButton
679705
size="s"
680-
onClick={() => {
681-
setModalState({
682-
open: true,
683-
mode: hasSharingInfo(item.share_with) ? 'edit' : 'create',
684-
resource: item,
685-
});
686-
}}
706+
isDisabled={!canShare}
707+
data-test-subj={`share-button-${item.resource_id}`}
708+
onClick={handleClick}
687709
>
688710
{label}
689711
</EuiButton>
690712
);
713+
714+
// Show tooltip only when disabled
715+
return canShare ? (
716+
btn
717+
) : (
718+
<EuiToolTip content="You do not have access to update sharing information of this resource">
719+
<span>{btn}</span>
720+
</EuiToolTip>
721+
);
691722
},
692723
},
693724
];
@@ -818,6 +849,7 @@ export const ResourceSharingPanel: React.FC<Props> = ({ api, toasts }) => {
818849
resource={modalState.resource as ResourceRow}
819850
resourceType={selectedTypeLabel}
820851
resourceTypeIndex={selectedType}
852+
actionGroups={currentActionGroups}
821853
/>
822854
</EuiPanel>
823855
);

0 commit comments

Comments
 (0)