Skip to content

Commit

Permalink
35477 Add Identifer management view
Browse files Browse the repository at this point in the history
- Added AgentIdentifierType interface
- Implemented Identifier edit and view page
- Saving/loading Identifiers should work
- The uriTemplate needs to have a $1 placeholder in the string
  • Loading branch information
johnphan96 committed Jan 14, 2025
1 parent 8c88316 commit 69347a3
Show file tree
Hide file tree
Showing 8 changed files with 287 additions and 63 deletions.
2 changes: 0 additions & 2 deletions packages/dina-ui/components/add-person/PersonForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
DeleteButton,
DinaForm,
DinaFormOnSubmit,
filterBy,
Expand All @@ -12,7 +11,6 @@ import {
OperationError,
SaveArgs,
useApiClient,
DeleteArgs,
BackButton,
ButtonBar
} from "common-ui";
Expand Down
7 changes: 1 addition & 6 deletions packages/dina-ui/components/add-person/PersonFormFields.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
FieldSet,
FormikButton,
useDinaFormContext,
SelectOption
} from "common-ui";
import { FieldSet, FormikButton, useDinaFormContext } from "common-ui";
import { Person } from "../../../dina-ui/types/objectstore-api";
import React, { useState } from "react";
import { FieldArray } from "formik";
Expand Down
5 changes: 2 additions & 3 deletions packages/dina-ui/intl/dina-ui-en.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { ColumnSelector } from "packages/common-ui/lib";

/**
* English Object Store messages. A message must be set here in English before other languages.
*/
Expand Down Expand Up @@ -1170,5 +1168,6 @@ export const DINAUI_MESSAGES_ENGLISH = {
collecting_event_tag_info:
"Tag suggestions are currently based on collecting event tags associated with Material Samples.",
selectFunctionToUse: "Select function to use",
selectFieldToUseWithFunction: "Select a field to use with the function"
selectFieldToUseWithFunction: "Select a field to use with the function",
editIdentifierTitle: "Edit Identifier"
};
181 changes: 181 additions & 0 deletions packages/dina-ui/pages/identifier/edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import {
ApiClientContext,
BackButton,
ButtonBar,
DinaForm,
DinaFormOnSubmit,
SubmitButton,
TextField,
useQuery,
withResponse,
MultilingualTitle
} from "common-ui";
import { InputResource, PersistedResource } from "kitsu";
import { fromPairs, toPairs } from "lodash";
import { useRouter } from "next/router";
import { Fragment, useContext } from "react";
import { DinaMessage, useDinaIntl } from "../../intl/dina-ui-intl";
import { AgentIdentifierType } from "../../types/agent-api/resources/AgentIdentifierType";
import { Head, Nav, Footer } from "../../components";
import Link from "next/link";

interface IdentifierFormProps {
fetchedIdentifierType?: AgentIdentifierType;
onSaved: (
identifierType: PersistedResource<AgentIdentifierType>
) => Promise<void>;
}

export default function IdentifierTypeEditPage() {
const router = useRouter();
const {
query: { id }
} = router;
const { formatMessage } = useDinaIntl();

async function goToViewPage(
identifier: PersistedResource<AgentIdentifierType>
) {
await router.push(`/identifier/view?id=${identifier.id}`);
}

const title = id ? "editIdentifierTitle" : "addIdentifier";

const query = useQuery<AgentIdentifierType>(
{
path: `agent-api/identifier-type/${id}`
},
{ disabled: !id }
);

return (
<div>
<Head title={formatMessage(title)} />
<Nav />
<main className="container-fluid">
<div>
<h1 id="wb-cont">
<DinaMessage id={title} />
</h1>
{id ? (
withResponse(query, ({ data }) => (
<IdentifierTypeForm
fetchedIdentifierType={data}
onSaved={goToViewPage}
/>
))
) : (
<IdentifierTypeForm onSaved={goToViewPage} />
)}
</div>
</main>
<Footer />
</div>
);
}

export function IdentifierTypeForm({
fetchedIdentifierType,
onSaved
}: IdentifierFormProps) {
const { apiClient } = useContext(ApiClientContext);

const initialValues: AgentIdentifierType = fetchedIdentifierType
? {
...fetchedIdentifierType,
// Convert multilingualDescription to editable Dictionary format:
multilingualTitle: fromPairs<string | undefined>(
fetchedIdentifierType.multilingualTitle?.titles?.map(
({ title, lang }) => [lang ?? "", title ?? ""]
)
)
}
: { type: "identifier-type" };

const onSubmit: DinaFormOnSubmit<AgentIdentifierType> = async ({
submittedValues
}) => {
const input: InputResource<AgentIdentifierType> = {
...submittedValues,
// Convert the editable format to the stored format:
multilingualTitle: {
titles: toPairs(submittedValues.multilingualTitle).map(
([lang, title]) => ({ lang, title })
)
}
};
delete (input as any).type;
const savedIdentifierType = await apiClient.axios.post(
`agent-api/identifier-type`,
{
data: {
type: "identifier-type",
attributes: {
...input,
...(input.uriTemplate && { uriTemplate: `${input.uriTemplate}$1` })
}
}
},
{
headers: {
"Content-Type": "application/vnd.api+json"
}
}
);
await onSaved(savedIdentifierType?.data?.data);
};

return (
<DinaForm<AgentIdentifierType>
initialValues={initialValues}
onSubmit={onSubmit}
>
<ButtonBar className="mb-4">
<div className="col-md-6 col-sm-12 mt-2">
<BackButton
entityId={fetchedIdentifierType?.id}
entityLink="/identifier"
/>
</div>
<div className="col-md-6 col-sm-12 d-flex">
<SubmitButton className="ms-auto" />
</div>
</ButtonBar>
<IdentifierTypeFormLayout />
</DinaForm>
);
}

export function IdentifierTypeFormLayout() {
return (
<div>
<div className="row">
<TextField className="col-md-6" name="name" />
<TextField className="col-md-6" name="term" />
</div>
<div className="row">
<TextField
className="col-md-6"
name={"uriTemplate"}
readOnlyRender={(value) => {
try {
const url = new URL(value);
if (url.protocol === "http:" || url.protocol === "https:") {
return (
<Fragment key={value}>
<Link href={value} passHref={true}>
<a>{value}</a>
</Link>
</Fragment>
);
}
} catch (_) {
return value;
}
}}
/>
</div>
<MultilingualTitle />
</div>
);
}
102 changes: 51 additions & 51 deletions packages/dina-ui/pages/identifier/list.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
ColumnDefinition,
dateCell,
descriptionCell,
intlContext,
ListLayoutFilterType,
ListPageLayout
ListPageLayout,
titleCell
} from "common-ui";
import Link from "next/link";
import { useRouter } from "next/router";
Expand All @@ -16,39 +16,38 @@ import { DinaMessage, useDinaIntl } from "../../intl/dina-ui-intl";

import { groupCell, GroupSelectField } from "../../components";
import PageLayout from "../../components/page/PageLayout";
import { ManagedAttribute } from "../../types/collection-api";
import { Identifier } from "../../types/agent-api/resources/Identifier";
import { AgentIdentifierType } from "packages/dina-ui/types/agent-api/resources/AgentIdentifierType";

export function useFilterManagedAttribute() {
export function useFilterIdentifierType() {
const { locale: language } = useContext(intlContext);
const filterManagedAttributes = (
const filterIdentifierType = (
filterForm: any,
value: ManagedAttribute
value: AgentIdentifierType
) => {
let result = true;
if (filterForm?.group) {
result = result && value.group === filterForm.group;
}
if (filterForm?.filterBuilderModel?.value) {
result =
result &&
(value.name
.toLowerCase()
.indexOf(filterForm.filterBuilderModel.value.toLowerCase()) > -1 ||
(
value.multilingualDescription?.descriptions?.filter(
(item) =>
item.lang === language &&
(item.desc ?? "")
.toLowerCase()
.indexOf(filterForm.filterBuilderModel.value.toLowerCase()) >
-1
) ?? []
).length > 0);
if (value.name) {
result =
result &&
(value.name
.toLowerCase()
.indexOf(filterForm.filterBuilderModel.value.toLowerCase()) > -1 ||
(
value.multilingualTitle?.titles?.filter(
(item) =>
item.lang === language &&
(item.title ?? "")
.toLowerCase()
.indexOf(
filterForm.filterBuilderModel.value.toLowerCase()
) > -1
) ?? []
).length > 0);
}
}
return result;
};
return { filterManagedAttributes };
return { filterIdentifierType };
}

export default function IdentifiersListPage() {
Expand Down Expand Up @@ -97,26 +96,27 @@ function CreateNewSection({ href }: CreateButtonProps) {
}

function AgentIdentifiersListView() {
const COLLECTIONS_ATTRIBUTES_FILTER_ATTRIBUTES = [
"name",
"multilingualDescription"
];
const AGENT_IDENTIFIERS_FILTER_ATTRIBUTES = ["name", "multilingualTitle"];
const { filterIdentifierType } = useFilterIdentifierType();

const AGENT_IDENTIFIERS_LIST_COLUMNS: ColumnDefinition<Identifier>[] = [
{
cell: ({
row: {
original: { id }
}
}) => <Link href={`/collection/managed-attribute/view?id=${id}`}></Link>,
header: "Name",
accessorKey: "name"
},
descriptionCell(false, false, "multilingualDescription"),
groupCell("group"),
"createdBy",
dateCell("createdOn")
];
const AGENT_IDENTIFIERS_LIST_COLUMNS: ColumnDefinition<AgentIdentifierType>[] =
[
{
cell: ({ row: { original } }) => {
return (
<Link href={`/identifier/view?id=${original.id}`}>
{original.name}
</Link>
);
},
header: "Name",
accessorKey: "name"
},
titleCell(false, false, "multilingualTitle"),
groupCell("group"),
"createdBy",
dateCell("createdOn")
];

return (
<>
Expand All @@ -125,17 +125,17 @@ function AgentIdentifiersListView() {
</h3>

{/* Quick create menu */}
<CreateNewSection href="/collection/managed-attribute/edit" />
<CreateNewSection href="/identifier/edit" />

<ListPageLayout<Identifier>
<ListPageLayout<AgentIdentifierType>
enableInMemoryFilter={true}
// filterFn={filterManagedAttributes}
filterFn={filterIdentifierType}
filterType={ListLayoutFilterType.FREE_TEXT}
filterAttributes={COLLECTIONS_ATTRIBUTES_FILTER_ATTRIBUTES}
id="collections-module-managed-attribute-list"
filterAttributes={AGENT_IDENTIFIERS_FILTER_ATTRIBUTES}
id="agent-identifiers-list"
queryTableProps={{
columns: AGENT_IDENTIFIERS_LIST_COLUMNS,
path: "collection-api/managed-attribute?page[limit]=1000"
path: "agent-api/identifier-type?page[limit]=1000"
}}
additionalFilters={(filterForm) => ({
isCompleted: false,
Expand Down
Loading

0 comments on commit 69347a3

Please sign in to comment.