Skip to content

Commit c812174

Browse files
allinoxCopilot
andauthored
Check for isDelegable on ClientAdmin, not isAssignable (#2426)
* Do not bar delegation on isAssignable=false for client delegations * lint * undo ac update * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * prettier --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent d532b36 commit c812174

9 files changed

Lines changed: 79 additions & 19 deletions

File tree

.mock/mockServiceWorker.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
* - Please do NOT modify this file.
88
*/
99

10-
const PACKAGE_VERSION = '2.14.6';
11-
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82';
10+
const PACKAGE_VERSION = '2.15.0';
11+
const INTEGRITY_CHECKSUM = '03cb67ac84128e63d7cd722a6e5b7f1e';
1212
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse');
1313
const activeClientIds = new Set();
1414

@@ -129,8 +129,18 @@ async function handleRequest(event, requestId, requestInterceptedAt) {
129129
if (client && activeClientIds.has(client.id)) {
130130
const serializedRequest = await serializeRequest(requestCloneForEvents);
131131

132+
// Omit the body of server-sent event stream responses.
133+
// Cloning such responses would prevent client-side stream cancelations
134+
// from reaching the original stream (a teed stream only cancels its
135+
// source once both of its branches cancel) and would buffer the
136+
// entire stream into the unconsumed clone indefinitely.
137+
const isEventStreamResponse = response.headers
138+
.get('content-type')
139+
?.toLowerCase()
140+
.startsWith('text/event-stream');
141+
132142
// Clone the response so both the client and the library could consume it.
133-
const responseClone = response.clone();
143+
const responseClone = isEventStreamResponse ? null : response.clone();
134144

135145
sendToClient(
136146
client,
@@ -143,15 +153,15 @@ async function handleRequest(event, requestId, requestInterceptedAt) {
143153
...serializedRequest,
144154
},
145155
response: {
146-
type: responseClone.type,
147-
status: responseClone.status,
148-
statusText: responseClone.statusText,
149-
headers: Object.fromEntries(responseClone.headers.entries()),
150-
body: responseClone.body,
156+
type: response.type,
157+
status: response.status,
158+
statusText: response.statusText,
159+
headers: Object.fromEntries(response.headers.entries()),
160+
body: responseClone ? responseClone.body : null,
151161
},
152162
},
153163
},
154-
responseClone.body ? [serializedRequest.body, responseClone.body] : [],
164+
responseClone && responseClone.body ? [serializedRequest.body, responseClone.body] : [],
155165
);
156166
}
157167

.yarn/releases/yarn-4.18.0.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env node
2-
/* eslint-disable */
2+
33
//prettier-ignore
44
(()=>{var QXe=Object.create;var A6=Object.defineProperty;var FXe=Object.getOwnPropertyDescriptor;var NXe=Object.getOwnPropertyNames;var OXe=Object.getPrototypeOf,LXe=Object.prototype.hasOwnProperty;var Ae=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var tt=(t,e)=>()=>(t&&(e=t(t=0)),e);var H=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),lr=(t,e)=>{for(var r in e)A6(t,r,{get:e[r],enumerable:!0})},_Xe=(t,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of NXe(e))!LXe.call(t,a)&&a!==r&&A6(t,a,{get:()=>e[a],enumerable:!(s=FXe(e,a))||s.enumerable});return t};var st=(t,e,r)=>(r=t!=null?QXe(OXe(t)):{},_Xe(e||!t||!t.__esModule?A6(r,"default",{value:t,enumerable:!0}):r,t));var Oi={};lr(Oi,{SAFE_TIME:()=>bae,S_IFDIR:()=>fT,S_IFLNK:()=>hT,S_IFMT:()=>Rh,S_IFREG:()=>nS});var Rh,fT,nS,hT,bae,Dae=tt(()=>{Rh=61440,fT=16384,nS=32768,hT=40960,bae=456789e3});var vr={};lr(vr,{EBADF:()=>ha,EBUSY:()=>MXe,EEXIST:()=>VXe,EINVAL:()=>HXe,EISDIR:()=>qXe,ENOENT:()=>jXe,ENOSYS:()=>UXe,ENOTDIR:()=>GXe,ENOTEMPTY:()=>YXe,EOPNOTSUPP:()=>KXe,EROFS:()=>WXe,ERR_DIR_CLOSED:()=>p6});function ou(t,e){return Object.assign(new Error(`${t}: ${e}`),{code:t})}function MXe(t){return ou("EBUSY",t)}function UXe(t,e){return ou("ENOSYS",`${t}, ${e}`)}function HXe(t){return ou("EINVAL",`invalid argument, ${t}`)}function ha(t){return ou("EBADF",`bad file descriptor, ${t}`)}function jXe(t){return ou("ENOENT",`no such file or directory, ${t}`)}function GXe(t){return ou("ENOTDIR",`not a directory, ${t}`)}function qXe(t){return ou("EISDIR",`illegal operation on a directory, ${t}`)}function VXe(t){return ou("EEXIST",`file already exists, ${t}`)}function WXe(t){return ou("EROFS",`read-only filesystem, ${t}`)}function YXe(t){return ou("ENOTEMPTY",`directory not empty, ${t}`)}function KXe(t){return ou("EOPNOTSUPP",`operation not supported, ${t}`)}function p6(){return ou("ERR_DIR_CLOSED","Directory handle was closed")}var AT=tt(()=>{});var Lc={};lr(Lc,{BigIntStatsEntry:()=>iw,DEFAULT_MODE:()=>m6,DirEntry:()=>d6,StatEntry:()=>nw,areStatsEqual:()=>y6,clearStats:()=>pT,convertToBigIntStats:()=>JXe,makeDefaultStats:()=>Pae,makeEmptyStats:()=>zXe});function Pae(){return new nw}function zXe(){return pT(Pae())}function pT(t){for(let e in t)if(Object.hasOwn(t,e)){let r=t[e];typeof r=="number"?t[e]=0:typeof r=="bigint"?t[e]=BigInt(0):g6.types.isDate(r)&&(t[e]=new Date(0))}return t}function JXe(t){let e=new iw;for(let r in t)if(Object.hasOwn(t,r)){let s=t[r];typeof s=="number"?e[r]=BigInt(Math.floor(s)):g6.types.isDate(s)&&(e[r]=new Date(s))}return e.atimeNs=e.atimeMs*BigInt(1e6)+BigInt(Math.floor(t.atimeMs%1*1e3))*BigInt(1e3),e.mtimeNs=e.mtimeMs*BigInt(1e6)+BigInt(Math.floor(t.mtimeMs%1*1e3))*BigInt(1e3),e.ctimeNs=e.ctimeMs*BigInt(1e6)+BigInt(Math.floor(t.ctimeMs%1*1e3))*BigInt(1e3),e.birthtimeNs=e.birthtimeMs*BigInt(1e6)+BigInt(Math.floor(t.birthtimeMs%1*1e3))*BigInt(1e3),e}function y6(t,e){if(t.atimeMs!==e.atimeMs||t.birthtimeMs!==e.birthtimeMs||t.blksize!==e.blksize||t.blocks!==e.blocks||t.ctimeMs!==e.ctimeMs||t.dev!==e.dev||t.gid!==e.gid||t.ino!==e.ino||t.isBlockDevice()!==e.isBlockDevice()||t.isCharacterDevice()!==e.isCharacterDevice()||t.isDirectory()!==e.isDirectory()||t.isFIFO()!==e.isFIFO()||t.isFile()!==e.isFile()||t.isSocket()!==e.isSocket()||t.isSymbolicLink()!==e.isSymbolicLink()||t.mode!==e.mode||t.mtimeMs!==e.mtimeMs||t.nlink!==e.nlink||t.rdev!==e.rdev||t.size!==e.size||t.uid!==e.uid)return!1;let r=t,s=e;return!(r.atimeNs!==s.atimeNs||r.mtimeNs!==s.mtimeNs||r.ctimeNs!==s.ctimeNs||r.birthtimeNs!==s.birthtimeNs)}var g6,m6,d6,nw,iw,E6=tt(()=>{g6=st(Ae("util")),m6=33188,d6=class{constructor(){this.name="";this.path="";this.mode=0}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},nw=class{constructor(){this.uid=0;this.gid=0;this.size=0;this.blksize=0;this.atimeMs=0;this.mtimeMs=0;this.ctimeMs=0;this.birthtimeMs=0;this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=0;this.ino=0;this.mode=m6;this.nlink=1;this.rdev=0;this.blocks=1}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},iw=class{constructor(){this.uid=BigInt(0);this.gid=BigInt(0);this.size=BigInt(0);this.blksize=BigInt(0);this.atimeMs=BigInt(0);this.mtimeMs=BigInt(0);this.ctimeMs=BigInt(0);this.birthtimeMs=BigInt(0);this.atimeNs=BigInt(0);this.mtimeNs=BigInt(0);this.ctimeNs=BigInt(0);this.birthtimeNs=BigInt(0);this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=BigInt(0);this.ino=BigInt(0);this.mode=BigInt(m6);this.nlink=BigInt(1);this.rdev=BigInt(0);this.blocks=BigInt(1)}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&BigInt(61440))===BigInt(16384)}isFIFO(){return!1}isFile(){return(this.mode&BigInt(61440))===BigInt(32768)}isSocket(){return!1}isSymbolicLink(){return(this.mode&BigInt(61440))===BigInt(40960)}}});function t$e(t){let e,r;if(e=t.match($Xe))t=e[1];else if(r=t.match(e$e))t=`\\\\${r[1]?".\\":""}${r[2]}`;else return t;return t.replace(/\//g,"\\")}function r$e(t){t=t.replace(/\\/g,"/");let e,r;return(e=t.match(ZXe))?t=`/${e[1]}`:(r=t.match(XXe))&&(t=`/unc/${r[1]?".dot/":""}${r[2]}`),t}function dT(t,e){return t===me?kae(e):I6(e)}var iS,Rt,Or,me,Y,xae,ZXe,XXe,$Xe,e$e,I6,kae,_c=tt(()=>{iS=st(Ae("path")),Rt={root:"/",dot:".",parent:".."},Or={home:"~",nodeModules:"node_modules",manifest:"package.json",lockfile:"yarn.lock",virtual:"__virtual__",pnpJs:".pnp.js",pnpCjs:".pnp.cjs",pnpData:".pnp.data.json",pnpEsmLoader:".pnp.loader.mjs",rc:".yarnrc.yml",env:".env"},me=Object.create(iS.default),Y=Object.create(iS.default.posix);me.cwd=()=>process.cwd();Y.cwd=process.platform==="win32"?()=>I6(process.cwd()):process.cwd;process.platform==="win32"&&(Y.resolve=(...t)=>t.length>0&&Y.isAbsolute(t[0])?iS.default.posix.resolve(...t):iS.default.posix.resolve(Y.cwd(),...t));xae=function(t,e,r){return e=t.normalize(e),r=t.normalize(r),e===r?".":(e.endsWith(t.sep)||(e=e+t.sep),r.startsWith(e)?r.slice(e.length):null)};me.contains=(t,e)=>xae(me,t,e);Y.contains=(t,e)=>xae(Y,t,e);ZXe=/^([a-zA-Z]:.*)$/,XXe=/^\/\/(\.\/)?(.*)$/,$Xe=/^\/([a-zA-Z]:.*)$/,e$e=/^\/unc\/(\.dot\/)?(.*)$/;I6=process.platform==="win32"?r$e:t=>t,kae=process.platform==="win32"?t$e:t=>t;me.fromPortablePath=kae;me.toPortablePath=I6});async function gT(t,e){let r="0123456789abcdef";await t.mkdirPromise(e.indexPath,{recursive:!0});let s=[];for(let a of r)for(let n of r)s.push(t.mkdirPromise(t.pathUtils.join(e.indexPath,`${a}${n}`),{recursive:!0}));return await Promise.all(s),e.indexPath}async function Rae(t,e,r,s,a){let n=t.pathUtils.normalize(e),l=r.pathUtils.normalize(s),f=[],h=[],{atime:A,mtime:m}=a.stableTime?{atime:Xm,mtime:Xm}:await r.lstatPromise(l);await t.mkdirpPromise(t.pathUtils.dirname(e),{utimes:[A,m]}),await w6(f,h,t,n,r,l,{...a,didParentExist:!0});for(let w of f)await w();await Promise.all(h.map(w=>w()))}async function w6(t,e,r,s,a,n,l){let f=l.didParentExist?await Tae(r,s):null,h=await a.lstatPromise(n),{atime:A,mtime:m}=l.stableTime?{atime:Xm,mtime:Xm}:h,w;switch(!0){case h.isDirectory():w=await i$e(t,e,r,s,f,a,n,h,l);break;case h.isFile():w=await a$e(t,e,r,s,f,a,n,h,l);break;case h.isSymbolicLink():w=await c$e(t,e,r,s,f,a,n,h,l);break;default:throw new Error(`Unsupported file type (${h.mode})`)}return(l.linkStrategy?.type!=="HardlinkFromIndex"||!h.isFile())&&((w||f?.mtime?.getTime()!==m.getTime()||f?.atime?.getTime()!==A.getTime())&&(e.push(()=>r.lutimesPromise(s,A,m)),w=!0),(f===null||(f.mode&511)!==(h.mode&511))&&(e.push(()=>r.chmodPromise(s,h.mode&511)),w=!0)),w}async function Tae(t,e){try{return await t.lstatPromise(e)}catch{return null}}async function i$e(t,e,r,s,a,n,l,f,h){if(a!==null&&!a.isDirectory())if(h.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1;let A=!1;a===null&&(t.push(async()=>{try{await r.mkdirPromise(s,{mode:f.mode})}catch(v){if(v.code!=="EEXIST")throw v}}),A=!0);let m=await n.readdirPromise(l),w=h.didParentExist&&!a?{...h,didParentExist:!1}:h;if(h.stableSort)for(let v of m.sort())await w6(t,e,r,r.pathUtils.join(s,v),n,n.pathUtils.join(l,v),w)&&(A=!0);else(await Promise.all(m.map(async D=>{await w6(t,e,r,r.pathUtils.join(s,D),n,n.pathUtils.join(l,D),w)}))).some(D=>D)&&(A=!0);return A}async function s$e(t,e,r,s,a,n,l,f,h,A){let m=await n.checksumFilePromise(l,{algorithm:"sha1"}),w=420,v=f.mode&511,D=`${m}${v!==w?v.toString(8):""}`,I=r.pathUtils.join(A.indexPath,m.slice(0,2),`${D}.dat`),R;(ae=>(ae[ae.Lock=0]="Lock",ae[ae.Rename=1]="Rename"))(R||={});let N=1,U=await Tae(r,I);if(a){let te=U&&a.dev===U.dev&&a.ino===U.ino,ie=U?.mtimeMs!==n$e;if(te&&ie&&A.autoRepair&&(N=0,U=null),!te)if(h.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1}let V=!U&&N===1?`${I}.${Math.floor(Math.random()*4294967296).toString(16).padStart(8,"0")}`:null,ee=!1;return t.push(async()=>{if(!U&&(N===0&&await r.lockPromise(I,async()=>{let te=await n.readFilePromise(l);await r.writeFilePromise(I,te)}),N===1&&V)){let te=await n.readFilePromise(l);await r.writeFilePromise(V,te);try{await r.linkPromise(V,I)}catch(ie){if(ie.code==="EEXIST")ee=!0,await r.unlinkPromise(V);else throw ie}}a||await r.linkPromise(I,s)}),e.push(async()=>{U||(await r.lutimesPromise(I,Xm,Xm),v!==w&&await r.chmodPromise(I,v)),V&&!ee&&await r.unlinkPromise(V)}),!1}async function o$e(t,e,r,s,a,n,l,f,h){if(a!==null)if(h.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1;return t.push(async()=>{let A=await n.readFilePromise(l);await r.writeFilePromise(s,A)}),!0}async function a$e(t,e,r,s,a,n,l,f,h){return h.linkStrategy?.type==="HardlinkFromIndex"?s$e(t,e,r,s,a,n,l,f,h,h.linkStrategy):o$e(t,e,r,s,a,n,l,f,h)}async function c$e(t,e,r,s,a,n,l,f,h){if(a!==null)if(h.overwrite)t.push(async()=>r.removePromise(s)),a=null;else return!1;return t.push(async()=>{await r.symlinkPromise(dT(r.pathUtils,await n.readlinkPromise(l)),s)}),!0}var Xm,n$e,C6=tt(()=>{_c();Xm=new Date(456789e3*1e3),n$e=Xm.getTime()});function mT(t,e,r,s){let a=()=>{let n=r.shift();if(typeof n>"u")return null;let l=t.pathUtils.join(e,n);return Object.assign(t.statSync(l),{name:n,path:void 0})};return new sS(e,a,s)}var sS,Qae=tt(()=>{AT();sS=class{constructor(e,r,s={}){this.path=e;this.nextDirent=r;this.opts=s;this.closed=!1}throwIfClosed(){if(this.closed)throw p6()}async*[Symbol.asyncIterator](){try{let e;for(;(e=await this.read())!==null;)yield e}finally{await this.close()}}read(e){let r=this.readSync();return typeof e<"u"?e(null,r):Promise.resolve(r)}readSync(){return this.throwIfClosed(),this.nextDirent()}close(e){return this.closeSync(),typeof e<"u"?e(null):Promise.resolve()}closeSync(){this.throwIfClosed(),this.opts.onClose?.(),this.closed=!0}}});function Fae(t,e){if(t!==e)throw new Error(`Invalid StatWatcher status: expected '${e}', got '${t}'`)}var Nae,yT,Oae=tt(()=>{Nae=Ae("events");E6();yT=class t extends Nae.EventEmitter{constructor(r,s,{bigint:a=!1}={}){super();this.status="ready";this.changeListeners=new Map;this.startTimeout=null;this.fakeFs=r,this.path=s,this.bigint=a,this.lastStats=this.stat()}static create(r,s,a){let n=new t(r,s,a);return n.start(),n}start(){Fae(this.status,"ready"),this.status="running",this.startTimeout=setTimeout(()=>{this.startTimeout=null,this.fakeFs.existsSync(this.path)||this.emit("change",this.lastStats,this.lastStats)},3)}stop(){Fae(this.status,"running"),this.status="stopped",this.startTimeout!==null&&(clearTimeout(this.startTimeout),this.startTimeout=null),this.emit("stop")}stat(){try{return this.fakeFs.statSync(this.path,{bigint:this.bigint})}catch{let r=this.bigint?new iw:new nw;return pT(r)}}makeInterval(r){let s=setInterval(()=>{let a=this.stat(),n=this.lastStats;y6(a,n)||(this.lastStats=a,this.emit("change",a,n))},r.interval);return r.persistent?s:s.unref()}registerChangeListener(r,s){this.addListener("change",r),this.changeListeners.set(r,this.makeInterval(s))}unregisterChangeListener(r){this.removeListener("change",r);let s=this.changeListeners.get(r);typeof s<"u"&&clearInterval(s),this.changeListeners.delete(r)}unregisterAllChangeListeners(){for(let r of this.changeListeners.keys())this.unregisterChangeListener(r)}hasChangeListeners(){return this.changeListeners.size>0}ref(){for(let r of this.changeListeners.values())r.ref();return this}unref(){for(let r of this.changeListeners.values())r.unref();return this}}});function sw(t,e,r,s){let a,n,l,f;switch(typeof r){case"function":a=!1,n=!0,l=5007,f=r;break;default:({bigint:a=!1,persistent:n=!0,interval:l=5007}=r),f=s;break}let h=ET.get(t);typeof h>"u"&&ET.set(t,h=new Map);let A=h.get(e);return typeof A>"u"&&(A=yT.create(t,e,{bigint:a}),h.set(e,A)),A.registerChangeListener(f,{persistent:n,interval:l}),A}function $m(t,e,r){let s=ET.get(t);if(typeof s>"u")return;let a=s.get(e);typeof a>"u"||(typeof r>"u"?a.unregisterAllChangeListeners():a.unregisterChangeListener(r),a.hasChangeListeners()||(a.stop(),s.delete(e)))}function ey(t){let e=ET.get(t);if(!(typeof e>"u"))for(let r of e.keys())$m(t,r)}var ET,B6=tt(()=>{Oae();ET=new WeakMap});function l$e(t){let e=t.match(/\r?\n/g);if(e===null)return _ae.EOL;let r=e.filter(a=>a===`\r
55
`).length,s=e.length-r;return r>s?`\r

src/features/amUI/agentDetails/AgentDetails.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ export const AgentDetails = () => {
6868
clients,
6969
});
7070
const [searchString, setSearchString] = useState<string>('');
71+
const [expandedIds, setExpandedIds] = useState<string[]>([]);
72+
const toggleExpanded = (id: string) =>
73+
setExpandedIds((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]));
74+
React.useEffect(() => {
75+
setExpandedIds([]);
76+
}, [id]);
7177

7278
const backUrl = `/${amUIPath.ClientAdministration}#users`;
7379
const userName = formatDisplayName({
@@ -183,6 +189,8 @@ export const AgentDetails = () => {
183189
removeAgentResources={removeAgentResources}
184190
searchString={searchString}
185191
emptyText={t('client_administration_page.no_delegations')}
192+
expandedIds={expandedIds}
193+
onToggleExpanded={toggleExpanded}
186194
/>
187195
</section>
188196
<section aria-labelledby={unassignedSectionId}>
@@ -209,6 +217,8 @@ export const AgentDetails = () => {
209217
removeAgentResources={removeAgentResources}
210218
searchString={searchString}
211219
emptyText={t('client_administration_page.no_clients')}
220+
expandedIds={expandedIds}
221+
onToggleExpanded={toggleExpanded}
212222
/>
213223
</CollapsibleContainer>
214224
</section>

src/features/amUI/agentDetails/AgentDetailsClientsList.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ type AgentDetailsClientsListProps = {
2929
removeAgentResources?: RemoveAgentResourcesFn;
3030
searchString?: string;
3131
emptyText?: string;
32+
expandedIds?: string[];
33+
onToggleExpanded?: (id: string) => void;
3234
};
3335

3436
export const AgentDetailsClientsList = ({
@@ -44,6 +46,8 @@ export const AgentDetailsClientsList = ({
4446
removeAgentResources,
4547
searchString,
4648
emptyText,
49+
expandedIds,
50+
onToggleExpanded,
4751
}: AgentDetailsClientsListProps) => {
4852
const delegateDisabled = isLoading || !toPartyUuid || !actingPartyUuid;
4953
const removeDisabled = isLoading || !toPartyUuid || !actingPartyUuid;
@@ -74,6 +78,8 @@ export const AgentDetailsClientsList = ({
7478
removeDisabled={removeDisabled}
7579
searchString={searchString}
7680
emptyText={emptyText}
81+
expandedIds={expandedIds}
82+
onToggleExpanded={onToggleExpanded}
7783
onAddAccessPackage={(
7884
{ clientId, roleCode, packageId, accessPackageName },
7985
onSuccess?: () => void,

src/features/amUI/clientDetails/ClientDetails.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ export const ClientDetails = () => {
8181
const recentlyAddedSectionId = useId();
8282
const assignedSectionId = useId();
8383
const unassignedSectionId = useId();
84+
const [expandedIds, setExpandedIds] = useState<string[]>([]);
85+
const toggleExpanded = (id: string) =>
86+
setExpandedIds((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]));
87+
React.useEffect(() => {
88+
setExpandedIds([]);
89+
}, [id]);
8490
const selectedClient = clients?.find((client) => client.client.id === id);
8591
const delegablePackages = selectedClient?.access?.flatMap((access) => access.packages) ?? [];
8692
const delegableResources =
@@ -211,6 +217,8 @@ export const ClientDetails = () => {
211217
removeAgentResources={removeAgentResources}
212218
emptyText={t('client_administration_page.no_agents')}
213219
searchString={searchString}
220+
expandedIds={expandedIds}
221+
onToggleExpanded={toggleExpanded}
214222
/>
215223
</section>
216224
)}
@@ -241,6 +249,8 @@ export const ClientDetails = () => {
241249
removeAgentResources={removeAgentResources}
242250
emptyText={t('client_administration_page.no_agents')}
243251
searchString={searchString}
252+
expandedIds={expandedIds}
253+
onToggleExpanded={toggleExpanded}
244254
/>
245255
</section>
246256
<section aria-labelledby={unassignedSectionId}>
@@ -268,6 +278,8 @@ export const ClientDetails = () => {
268278
removeAgentResources={removeAgentResources}
269279
emptyText={`${t('client_administration_page.no_agents')} ${t('client_administration_page.addUserPrompt')}`}
270280
searchString={searchString}
281+
expandedIds={expandedIds}
282+
onToggleExpanded={toggleExpanded}
271283
/>
272284
</CollapsibleContainer>
273285
</section>

0 commit comments

Comments
 (0)