Skip to content

Commit

Permalink
Merge pull request nexodus-io#1936 from chirino/frontend-org-membership
Browse files Browse the repository at this point in the history
frontend: show org membership when you view an org’s details
  • Loading branch information
mergify[bot] authored Feb 22, 2024
2 parents 9ad148e + b8e8e5a commit d8f71df
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 0 deletions.
87 changes: 87 additions & 0 deletions ui/src/DataProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { goOidcAgentAuthProvider } from "./providers/AuthProvider";
import simpleRestProvider from "ra-data-simple-rest";
import { fetchUtils } from "react-admin";
import {
DeleteParams,
GetListParams,
GetListResult,
RaRecord,
} from "ra-core/dist/cjs/types";

const fetchJson = (url: string, options: any = {}) => {
// Includes the encrypted session cookie in requests to the API
Expand All @@ -25,8 +31,56 @@ const baseDataProvider = simpleRestProvider(
fetchJson,
"X-Total-Count",
);

function rewriteNestedResource(
resource: string,
params: { id?: any; meta?: any },
) {
const resourceParts = resource.split("/");
if (resourceParts.length > 1) {
// to deal with nested resources
let ids: any[] | undefined = undefined;
if (params.id !== undefined) {
ids = [...params.id];
} else if (params.meta?.ids !== undefined) {
ids = [...params.meta.ids];
}
if (ids === undefined) {
throw new Error("meta.ids or id is required to access nested resources");
}

if (ids.length < resourceParts.length - 1) {
throw new Error(
`meta.ids should contain at least ${resourceParts.length - 1} elements`,
);
}

const parts = [resourceParts[0]];
for (let i = 0; i < resourceParts.length - 1; i++) {
parts.push(ids[i]);
parts.push(resourceParts[i + 1]);
}
resource = parts.join("/");

if (params.id !== undefined) {
params.id = params.id.pop();
}
}
return resource;
}

async function deleteResource(resource: string, params: DeleteParams) {
resource = rewriteNestedResource(resource, params);
let result = await baseDataProvider.delete(resource, params);
if (params.meta?.importer) {
result.data = params.meta.importer(result.data);
}
return result;
}

export const dataProvider = {
...baseDataProvider,

getFlag: (name: string) => {
return fetchJson(`${backend}/api/fflags/${name}`).then(
(response) => response,
Expand All @@ -37,4 +91,37 @@ export const dataProvider = {
[index: string]: boolean;
};
},

delete: deleteResource,

deleteMany: function (resource: string, params: any) {
return Promise.all(
params.ids.map(function (id: any) {
return deleteResource(resource, { ...params, id: id });
}),
).then(function (responses) {
return {
data: responses.map(function (a) {
return a.data.id;
}),
};
});
},

getList: async <RecordType extends RaRecord = any>(
resource: string,
params: GetListParams,
): Promise<GetListResult<RecordType>> => {
resource = rewriteNestedResource(resource, params);

let result = await baseDataProvider.getList(resource, params);

if (params.meta?.importer) {
result.data = result.data.map((record: any) => {
return params.meta.importer(record);
});
}

return result;
},
};
3 changes: 3 additions & 0 deletions ui/src/pages/Organizations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
SimpleForm,
TextInput,
} from "react-admin";
import { UserOrganizationList } from "./UserOrganizations";

const OrganizationListBulkActions = () => (
<Fragment>
Expand Down Expand Up @@ -45,6 +46,8 @@ export const OrganizationShow = () => (
<TextField label="ID" source="id" />
<TextField label="Name" source="name" />
<TextField label="Description" source="description" />
<h2>User Membership</h2>
<UserOrganizationList />
</SimpleShowLayout>
</Show>
);
Expand Down
38 changes: 38 additions & 0 deletions ui/src/pages/UserOrganizations.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
BulkDeleteButton,
BulkExportButton,
Datagrid,
List,
TextField,
} from "react-admin";
import { useParams } from "react-router-dom";
import React, { Fragment } from "react";

function importer(record: any) {
record.id = [record.organization_id, record.user_id];
return record;
}

export const UserOrganizationList = () => {
const { id } = useParams();

return (
<List
resource="organizations/users"
queryOptions={{ meta: { ids: [id], importer } }}
sort={{ field: "user_id", order: "ASC" }}
>
<Datagrid
bulkActionButtons={
<Fragment>
<BulkExportButton />
<BulkDeleteButton />
</Fragment>
}
>
<TextField label="Full Name" source="user.full_name" />
<TextField label="Full Name" source="user.username" />
</Datagrid>
</List>
);
};

0 comments on commit d8f71df

Please sign in to comment.