Commit c79a4f4c authored by Stefan Probst's avatar Stefan Probst
Browse files

feat: add facets to curation page, use urltemplate for externalids

parent c3f641cb
Pipeline #223834 failed with stages
in 10 minutes and 53 seconds
......@@ -163,8 +163,8 @@
"vfile-matter": "^3.0.0"
},
"engines": {
"node": ">=12.9",
"yarn": "^1"
"node": "14.x",
"yarn": "1.x"
},
"babel": {
"presets": [
......
......@@ -47,7 +47,7 @@ export function convertToInitialFormValues(
| WorkflowCore
) & { persistentId?: string } {
const initialValues = {
label: item.label,
label: item.label!,
version: item.version,
description: item.description,
accessibleAt: item.accessibleAt,
......@@ -65,7 +65,7 @@ export function convertToInitialFormValues(
properties: item.properties?.map((property) => {
return {
// id: property.id, // this is in ItemDto but not in ItemCore
type: { code: property.type?.code },
type: { code: property.type?.code, hidden: property.type?.hidden },
value: property.value,
concept: {
code: property.concept?.code,
......@@ -80,7 +80,7 @@ export function convertToInitialFormValues(
relatedItems: item.relatedItems?.map((relation) => {
return {
id: relation.id,
persistentId: relation.persistentId,
persistentId: relation.persistentId!,
relation: relation.relation && { code: relation.relation.code },
}
}),
......
This diff is collapsed.
......@@ -42,6 +42,11 @@ export type ItemSearchQuery = Omit<SearchItems.QueryParameters, 'f' | 'd'> & {
'f.source'?: Array<string>
'd.status'?: Exclude<Item['status'], 'draft'> | string // draft items are not indexed with solr
'd.owner'?: string
'd.lastInfoUpdate'?: string
'd.curation-flag-description'?: string
'd.curation-flag-url'?: string
'd.curation-flag-coverage'?: string
'd.curation-flag-relations'?: string
}
/**
......
......@@ -5,9 +5,9 @@ import { useQueryClient } from 'react-query'
import type { ActorCore } from '@/api/sshoc'
import {
useCreateActor,
useGetActors,
useGetAllActorRoles,
useGetAllActorSources,
useSearchActors,
} from '@/api/sshoc'
import { Button } from '@/elements/Button/Button'
import { Icon } from '@/elements/Icon/Icon'
......@@ -147,7 +147,7 @@ function ActorComboBox(props: ActorComboBoxProps): JSX.Element {
const [searchTerm, setSearchTerm] = useState(initialLabel)
const debouncedsearchTerm = useDebouncedState(searchTerm, 150).trim()
const actors = useGetActors(
const actors = useSearchActors(
{ q: debouncedsearchTerm },
{
// enabled: debouncedsearchTerm.length > 2,
......
......@@ -71,7 +71,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
queryKey: ['getDatasets'],
})
// queryClient.invalidateQueries({
// queryKey: ['getDataset', { id: data.persistentId }],
// queryKey: ['getDataset', { persistentId: data.persistentId }],
// })
if (data.status === 'draft') {
queryClient.invalidateQueries({
......
......@@ -76,7 +76,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
queryKey: ['getDatasets'],
})
queryClient.invalidateQueries({
queryKey: ['getDataset', { id: data.persistentId }],
queryKey: ['getDataset', { persistentId: data.persistentId }],
})
if (data.status === 'draft') {
queryClient.invalidateQueries({
......@@ -119,7 +119,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
const values = sanitizeFormValues(unsanitized)
await create.mutateAsync([
{ id },
{ persistentId: id },
{ draft },
values,
{ token: auth.session.accessToken },
......
......@@ -8,6 +8,7 @@ import type {
} from '@/api/sshoc'
import { useGetPropertyTypes, useSearchConcepts } from '@/api/sshoc'
import { useDebouncedState } from '@/lib/hooks/useDebouncedState'
import { useAuth } from '@/modules/auth/AuthContext'
import { FormComboBox } from '@/modules/form/components/FormComboBox/FormComboBox'
import { FormFieldAddButton } from '@/modules/form/components/FormFieldAddButton/FormFieldAddButton'
import { FormFieldRemoveButton } from '@/modules/form/components/FormFieldRemoveButton/FormFieldRemoveButton'
......@@ -32,6 +33,8 @@ export interface PropertiesFormSectionProps {
export function PropertiesFormSection(
props: PropertiesFormSectionProps,
): JSX.Element {
const auth = useAuth()
const prefix = props.prefix ?? ''
const propertyTypes = useGetPropertyTypes(
......@@ -46,6 +49,9 @@ export function PropertiesFormSection(
return data
},
},
{
token: auth.session?.accessToken,
},
)
const propertyTypesById = useMemo(() => {
const map = {} as Record<string, PropertyTypeDto>
......@@ -69,65 +75,80 @@ export function PropertiesFormSection(
<FormRecords>
{fields.map((name, index) => {
return (
<FormRecord
/** Don't display hidden properties */
<FormFieldCondition
key={name}
actions={
<FormFieldRemoveButton
onPress={() => fields.remove(index)}
aria-label={'Remove property'}
/>
}
>
<PropertyTypeSelect
name={`${name}.type.code`}
label={'Property type'}
propertyTypes={propertyTypes}
/>
<FormFieldCondition
name={`${name}.type.code`}
condition={(id) =>
id !== '' &&
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
propertyTypesById[id] !== undefined &&
propertyTypesById[id].type === 'concept'
name={`${name}.type.hidden`}
condition={(hidden) => {
/** Always show hidden properties for admins. */
/** Requires that `property-types` are fetch with token. */
if (auth.session?.user.username === 'Administrator') {
return true
}
>
{(id: string) => {
return (
<PropertyConceptSelect
name={`${name}.concept.uri`}
parentName={name}
label={'Concept'}
propertyTypeId={id}
initialValues={props.initialValues}
index={index}
/>
)
}}
</FormFieldCondition>
<FormFieldCondition
name={`${name}.type.code`}
condition={(id) =>
id !== '' &&
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
propertyTypesById[id] !== undefined &&
propertyTypesById[id].type !== 'concept'
return hidden !== true
}}
>
<FormRecord
key={name}
actions={
<FormFieldRemoveButton
onPress={() => fields.remove(index)}
aria-label={'Remove property'}
/>
}
>
{(id: string) => {
return (
<FormTextField
name={`${name}.value`}
label={'Value'}
variant="form"
style={{ flex: 1 }}
// @ts-expect-error It's ok
helpText={helpText.properties[id]}
/>
)
}}
</FormFieldCondition>
</FormRecord>
<PropertyTypeSelect
name={`${name}.type.code`}
label={'Property type'}
propertyTypes={propertyTypes}
/>
<FormFieldCondition
name={`${name}.type.code`}
condition={(id) =>
id !== '' &&
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
propertyTypesById[id] !== undefined &&
propertyTypesById[id].type === 'concept'
}
>
{(id: string) => {
return (
<PropertyConceptSelect
name={`${name}.concept.uri`}
parentName={name}
label={'Concept'}
propertyTypeId={id}
initialValues={props.initialValues}
index={index}
/>
)
}}
</FormFieldCondition>
<FormFieldCondition
name={`${name}.type.code`}
condition={(id) =>
id !== '' &&
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
propertyTypesById[id] !== undefined &&
propertyTypesById[id].type !== 'concept'
}
>
{(id: string) => {
return (
<FormTextField
name={`${name}.value`}
label={'Value'}
variant="form"
style={{ flex: 1 }}
// @ts-expect-error It's ok
helpText={helpText.properties[id]}
/>
)
}}
</FormFieldCondition>
</FormRecord>
</FormFieldCondition>
)
})}
<FormFieldAddButton onPress={() => fields.push(undefined)}>
......
......@@ -71,7 +71,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
queryKey: ['getPublications'],
})
// queryClient.invalidateQueries({
// queryKey: ['getPublication', { id: data.persistentId }],
// queryKey: ['getPublication', { persistentId: data.persistentId }],
// })
if (data.status === 'draft') {
queryClient.invalidateQueries({
......
......@@ -76,7 +76,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
queryKey: ['getPublications'],
})
queryClient.invalidateQueries({
queryKey: ['getPublication', { id: data.persistentId }],
queryKey: ['getPublication', { persistentId: data.persistentId }],
})
if (data.status === 'draft') {
queryClient.invalidateQueries({
......@@ -119,7 +119,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
const values = sanitizeFormValues(unsanitized)
await create.mutateAsync([
{ id },
{ persistentId: id },
{ draft },
values,
{ token: auth.session.accessToken },
......
......@@ -69,7 +69,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
queryKey: ['getTools'],
})
// queryClient.invalidateQueries({
// queryKey: ['getTool', { id: data.persistentId }],
// queryKey: ['getTool', { persistentId: data.persistentId }],
// })
if (data.status === 'draft') {
queryClient.invalidateQueries({
......
......@@ -74,7 +74,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
queryKey: ['getTools'],
})
queryClient.invalidateQueries({
queryKey: ['getTool', { id: data.persistentId }],
queryKey: ['getTool', { persistentId: data.persistentId }],
})
if (data.status === 'draft') {
queryClient.invalidateQueries({
......@@ -117,7 +117,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
const values = sanitizeFormValues(unsanitized)
await create.mutateAsync([
{ id },
{ persistentId: id },
{ draft },
values,
{ token: auth.session.accessToken },
......
......@@ -69,7 +69,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
queryKey: ['getTrainingMaterials'],
})
// queryClient.invalidateQueries({
// queryKey: ['getTrainingMaterial', { id: data.persistentId }],
// queryKey: ['getTrainingMaterial', { persistentId: data.persistentId }],
// })
if (data.status === 'draft') {
queryClient.invalidateQueries({
......
......@@ -74,7 +74,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
queryKey: ['getTrainingMaterials'],
})
queryClient.invalidateQueries({
queryKey: ['getTrainingMaterial', { id: data.persistentId }],
queryKey: ['getTrainingMaterial', { persistentId: data.persistentId }],
})
if (data.status === 'draft') {
queryClient.invalidateQueries({
......@@ -117,7 +117,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
const values = sanitizeFormValues(unsanitized)
await create.mutateAsync([
{ id },
{ persistentId: id },
{ draft },
values,
{ token: auth.session.accessToken },
......
......@@ -111,7 +111,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
queryKey: ['getWorkflows'],
})
// queryClient.invalidateQueries({
// queryKey: ['getWorkflow', { workflowId: data.persistentId }],
// queryKey: ['getWorkflow', { persistentId: data.persistentId }],
// })
if (data.status === 'draft') {
queryClient.invalidateQueries({
......@@ -165,7 +165,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
await (composedOf ?? []).reduce((operations, step) => {
return operations.then(() => {
return createStep.mutateAsync([
{ workflowId },
{ persistentId: workflowId },
{ draft },
sanitizeFormValues(step),
{ token: auth.session?.accessToken },
......@@ -215,7 +215,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
PageKey,
{
Page: FC<FormPageProps>
onValidate?: FormConfig<ItemFormValues>['validate']
onValidate?: FormConfig<Partial<ItemFormValues>>['validate']
}
> = {
workflow: {
......@@ -274,7 +274,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
function handleSubmit(values: Partial<ItemFormValues>) {
if (currentPageKey === 'steps') {
return onSubmit(values)
return onSubmit(values as ItemFormValues)
} else {
onNextPage(values)
}
......
......@@ -127,7 +127,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
queryKey: ['getWorkflows'],
})
queryClient.invalidateQueries({
queryKey: ['getWorkflow', { workflowId: data.persistentId }],
queryKey: ['getWorkflow', { persistentId: data.persistentId }],
})
if (data.status === 'draft') {
queryClient.invalidateQueries({
......@@ -163,7 +163,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
const { composedOf, ...workflow } = values
const updatedWorkflow = await updateWorkflow.mutateAsync([
{ workflowId: id },
{ persistentId: id },
{ draft },
workflow,
{ token: auth.session.accessToken },
......@@ -194,7 +194,10 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
step.persistentId !== originalStep?.persistentId
) {
return updateStep.mutateAsync([
{ workflowId, stepId: step.persistentId },
{
persistentId: workflowId,
stepPersistentId: step.persistentId,
},
{ draft },
sanitizeFormValues(step),
{ token: auth.session?.accessToken },
......@@ -205,7 +208,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
}
return createStep.mutateAsync([
{ workflowId },
{ persistentId: workflowId },
{ draft },
sanitizeFormValues(step),
{ token: auth.session?.accessToken },
......@@ -256,7 +259,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
PageKey,
{
Page: FC<FormPageProps>
onValidate?: FormConfig<ItemFormValues>['validate']
onValidate?: FormConfig<Partial<ItemFormValues>>['validate']
}
> = {
workflow: {
......@@ -315,7 +318,7 @@ export function ItemForm(props: ItemFormProps<ItemFormValues>): JSX.Element {
function handleSubmit(values: Partial<ItemFormValues>) {
if (currentPageKey === 'steps') {
return onSubmit(values)
return onSubmit(values as ItemFormValues)
} else {
onNextPage(values)
}
......
......@@ -10,7 +10,7 @@ export interface TextFieldProps extends AriaTextFieldProps {
/** @default "default" */
variant?: 'default' | 'form'
/** @default "md" */
size?: 'md' | 'lg'
size?: 'sm' | 'md' | 'lg'
necessityIndicator?: NecessityIndicator
validationMessage?: ReactNode
helpText?: ReactNode
......
......@@ -53,7 +53,11 @@ export function TextFieldBase(
textField: {
default: cx(
'text-base rounded placeholder-gray-350 border border-gray-300 focus:border-secondary-600 hover:bg-gray-75 hover:border-gray-350',
size === 'lg' ? 'px-4 py-4' : 'px-4 py-2',
size === 'lg'
? 'px-4 py-4'
: size === 'md'
? 'px-4 py-2'
: 'px-3 py-1.5 text-ui-base',
),
states: {
enabled: 'text-gray-800',
......@@ -67,7 +71,11 @@ export function TextFieldBase(
textField: {
default: cx(
'text-ui-base rounded bg-gray-75 border border-gray-300 placeholder-gray-350 focus:bg-highlight-75 focus:border-secondary-600 focus:placeholder-highlight-300 hover:border-secondary-600 hover:bg-white',
size === 'lg' ? 'px-4 py-4' : 'px-4 py-3',
size === 'lg'
? 'px-4 py-4'
: size === 'md'
? 'px-4 py-3'
: 'px-3 py-1.5 text-ui-base',
),
states: {
enabled: 'text-gray-800',
......
......@@ -266,7 +266,14 @@ export function useValidateCommonFormFields() {
function mapPropertyTypes(response: PaginatedPropertyTypes) {
const map: Record<
string,
'string' | 'concept' | 'url' | 'int' | 'float' | 'date' | undefined
| 'string'
| 'boolean'
| 'concept'
| 'url'
| 'int'
| 'float'
| 'date'
| undefined
> = {}
response.propertyTypes?.forEach((propertyType) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
......
......@@ -29,7 +29,7 @@ export async function getServerSideProps(
}
try {
const dataset = await getDataset({ id }, {})
const dataset = await getDataset({ persistentId: id }, {})
return { props: { dataset } }
} catch (error) {
console.log(`Failed to fetch dataset ${id}: ${JSON.stringify(error)}`)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment