mirror of
https://github.com/datahub-project/datahub.git
synced 2025-12-04 22:52:54 +00:00
fix(forms) Update styles of submit/confirm button and fix num input bug (#9797)
This commit is contained in:
parent
f6e96dc0d3
commit
33dc96bc24
@ -140,8 +140,6 @@ export function getCompletedPrompts(entityData: GenericEntityProperties | null)
|
||||
completedPrompts = completedPrompts.concat(
|
||||
forms?.completedForms?.flatMap((form) => (form.completedPrompts ? form.completedPrompts : [])) || [],
|
||||
);
|
||||
console.log('entityData', entityData);
|
||||
console.log('getCompletedPrompts', completedPrompts);
|
||||
return completedPrompts;
|
||||
}
|
||||
|
||||
|
||||
@ -40,7 +40,9 @@ export default function MultiSelectInput({
|
||||
allowedValues,
|
||||
selectedValues,
|
||||
}: Props) {
|
||||
return allowedValues.length > 5 ? (
|
||||
const shouldShowSelectDropdown = allowedValues.length > 5;
|
||||
|
||||
return shouldShowSelectDropdown ? (
|
||||
<Select
|
||||
style={DROPDOWN_STYLE as any}
|
||||
placeholder="Select"
|
||||
@ -65,7 +67,7 @@ export default function MultiSelectInput({
|
||||
onChange={(value) => updateSelectedValues(value)}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
{allowedValues.map((allowedValue) => (
|
||||
<StyledCheckbox
|
||||
key={getStructuredPropertyValue(allowedValue.value)}
|
||||
@ -77,6 +79,6 @@ export default function MultiSelectInput({
|
||||
{allowedValue.description && <ValueDescription description={allowedValue.description} />}
|
||||
</StyledCheckbox>
|
||||
))}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ export default function MultipleStringInput({ selectedValues, updateSelectedValu
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
{selectedValues.length > 1 &&
|
||||
selectedValues.map((selectedValue, index) => {
|
||||
const key = `${index}`;
|
||||
@ -78,6 +78,6 @@ export default function MultipleStringInput({ selectedValues, updateSelectedValu
|
||||
<StyledButton type="link" onClick={addNewValue}>
|
||||
+ Add More
|
||||
</StyledButton>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -19,5 +19,11 @@ export default function NumberInput({ selectedValues, updateSelectedValues }: Pr
|
||||
updateSelectedValues([number]);
|
||||
}
|
||||
|
||||
return <StyledInput type="number" value={selectedValues[0] || null} onChange={updateInput} />;
|
||||
return (
|
||||
<StyledInput
|
||||
type="number"
|
||||
value={selectedValues[0] !== undefined ? selectedValues[0] : null}
|
||||
onChange={updateInput}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ import { Button } from 'antd';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
EntityType,
|
||||
FormPrompt,
|
||||
PropertyCardinality,
|
||||
SchemaField,
|
||||
@ -17,20 +16,9 @@ import RichTextInput from './RichTextInput';
|
||||
import DateInput from './DateInput';
|
||||
import NumberInput from './NumberInput';
|
||||
import UrnInput from './UrnInput/UrnInput';
|
||||
import { useEntityData } from '../../../EntityContext';
|
||||
import {
|
||||
findCompletedFieldPrompt,
|
||||
findPromptAssociation,
|
||||
getCompletedPrompts,
|
||||
getIncompletePrompts,
|
||||
isFieldPromptComplete,
|
||||
isPromptComplete,
|
||||
} from '../../../containers/profile/sidebar/FormInfo/utils';
|
||||
import { useEntityRegistry } from '../../../../../useEntityRegistry';
|
||||
import { getTimeFromNow } from '../../../../../shared/time/timeUtils';
|
||||
import CompletedPromptAuditStamp from './CompletedPromptAuditStamp';
|
||||
import { applyOpacity } from '../../../../../shared/styleUtils';
|
||||
import { useUserContext } from '../../../../../context/useUserContext';
|
||||
import usePromptCompletionInfo from '../usePromptCompletionInfo';
|
||||
|
||||
const PromptWrapper = styled.div<{ displayBulkStyles?: boolean }>`
|
||||
display: flex;
|
||||
@ -67,11 +55,11 @@ export const PromptSubTitle = styled.div`
|
||||
|
||||
const InputSection = styled.div`
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
align-self: end;
|
||||
margin-left: 8px;
|
||||
margin-top: 16px;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 3px 2px ${(props) => applyOpacity(props.theme.styles['primary-color'] || '', 50)};
|
||||
@ -80,6 +68,7 @@ const StyledButton = styled(Button)`
|
||||
|
||||
const PromptInputWrapper = styled.div`
|
||||
flex: 1;
|
||||
margin-right: 8px;
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
@ -98,110 +87,93 @@ export default function StructuredPropertyPrompt({
|
||||
optimisticCompletedTimestamp,
|
||||
}: Props) {
|
||||
const {
|
||||
isSaveVisible,
|
||||
hasEditedPrompt,
|
||||
selectedValues,
|
||||
selectSingleValue,
|
||||
toggleSelectedValue,
|
||||
submitStructuredPropertyResponse,
|
||||
updateSelectedValues,
|
||||
} = useStructuredPropertyPrompt({ prompt, submitResponse, field });
|
||||
const { entityData } = useEntityData();
|
||||
const { user } = useUserContext();
|
||||
const entityRegistry = useEntityRegistry();
|
||||
const completedPrompts = getCompletedPrompts(entityData);
|
||||
const incompletePrompts = getIncompletePrompts(entityData);
|
||||
const promptAssociation = findPromptAssociation(prompt, completedPrompts.concat(incompletePrompts));
|
||||
const completedFieldPrompt = findCompletedFieldPrompt(field, promptAssociation);
|
||||
const { isComplete, completedByName, completedByTime } = usePromptCompletionInfo({
|
||||
prompt,
|
||||
field,
|
||||
optimisticCompletedTimestamp,
|
||||
});
|
||||
|
||||
const structuredProperty = prompt.structuredPropertyParams?.structuredProperty;
|
||||
if (!structuredProperty) return null;
|
||||
|
||||
const { displayName, description, allowedValues, cardinality, valueType } = structuredProperty.definition;
|
||||
|
||||
function getCompletedByName() {
|
||||
let actor = completedFieldPrompt?.lastModified?.actor || promptAssociation?.lastModified?.actor;
|
||||
if (optimisticCompletedTimestamp) {
|
||||
actor = user;
|
||||
}
|
||||
return actor ? entityRegistry.getDisplayName(EntityType.CorpUser, actor) : '';
|
||||
}
|
||||
|
||||
function getCompletedByRelativeTime() {
|
||||
let completedTimestamp = completedFieldPrompt?.lastModified?.time || promptAssociation?.lastModified?.time;
|
||||
if (optimisticCompletedTimestamp) {
|
||||
completedTimestamp = optimisticCompletedTimestamp;
|
||||
}
|
||||
return completedTimestamp ? getTimeFromNow(completedTimestamp) : '';
|
||||
}
|
||||
const showSaveButton = hasEditedPrompt && selectedValues.length > 0;
|
||||
const showConfirmButton = !hasEditedPrompt && !isComplete && selectedValues.length > 0;
|
||||
|
||||
return (
|
||||
<PromptWrapper>
|
||||
<PromptInputWrapper>
|
||||
<PromptTitle>
|
||||
{promptNumber !== undefined && <>{promptNumber}. </>}
|
||||
{displayName}
|
||||
{prompt.required && <RequiredText>required</RequiredText>}
|
||||
</PromptTitle>
|
||||
{description && <PromptSubTitle>{description}</PromptSubTitle>}
|
||||
<InputSection>
|
||||
{allowedValues && allowedValues.length > 0 && (
|
||||
<>
|
||||
{cardinality === PropertyCardinality.Single && (
|
||||
<SingleSelectInput
|
||||
allowedValues={allowedValues}
|
||||
selectedValues={selectedValues}
|
||||
selectSingleValue={selectSingleValue}
|
||||
/>
|
||||
)}
|
||||
{cardinality === PropertyCardinality.Multiple && (
|
||||
<MultiSelectInput
|
||||
allowedValues={allowedValues}
|
||||
selectedValues={selectedValues}
|
||||
toggleSelectedValue={toggleSelectedValue}
|
||||
updateSelectedValues={updateSelectedValues}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!allowedValues && valueType.info.type === StdDataType.String && (
|
||||
<StringInput
|
||||
selectedValues={selectedValues}
|
||||
cardinality={cardinality}
|
||||
updateSelectedValues={updateSelectedValues}
|
||||
/>
|
||||
)}
|
||||
{!allowedValues && valueType.info.type === StdDataType.RichText && (
|
||||
<RichTextInput selectedValues={selectedValues} updateSelectedValues={updateSelectedValues} />
|
||||
)}
|
||||
{!allowedValues && valueType.info.type === StdDataType.Date && (
|
||||
<DateInput selectedValues={selectedValues} updateSelectedValues={updateSelectedValues} />
|
||||
)}
|
||||
{!allowedValues && valueType.info.type === StdDataType.Number && (
|
||||
<NumberInput selectedValues={selectedValues} updateSelectedValues={updateSelectedValues} />
|
||||
)}
|
||||
{!allowedValues && valueType.info.type === StdDataType.Urn && (
|
||||
<UrnInput
|
||||
structuredProperty={structuredProperty}
|
||||
selectedValues={selectedValues}
|
||||
updateSelectedValues={updateSelectedValues}
|
||||
/>
|
||||
)}
|
||||
</InputSection>
|
||||
</PromptInputWrapper>
|
||||
{isSaveVisible && selectedValues.length > 0 && (
|
||||
<>
|
||||
<PromptWrapper>
|
||||
<PromptInputWrapper>
|
||||
<PromptTitle>
|
||||
{promptNumber !== undefined && <>{promptNumber}. </>}
|
||||
{displayName}
|
||||
{prompt.required && <RequiredText>required</RequiredText>}
|
||||
</PromptTitle>
|
||||
{description && <PromptSubTitle>{description}</PromptSubTitle>}
|
||||
<InputSection>
|
||||
{allowedValues && allowedValues.length > 0 && (
|
||||
<>
|
||||
{cardinality === PropertyCardinality.Single && (
|
||||
<SingleSelectInput
|
||||
allowedValues={allowedValues}
|
||||
selectedValues={selectedValues}
|
||||
selectSingleValue={selectSingleValue}
|
||||
/>
|
||||
)}
|
||||
{cardinality === PropertyCardinality.Multiple && (
|
||||
<MultiSelectInput
|
||||
allowedValues={allowedValues}
|
||||
selectedValues={selectedValues}
|
||||
toggleSelectedValue={toggleSelectedValue}
|
||||
updateSelectedValues={updateSelectedValues}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!allowedValues && valueType.info.type === StdDataType.String && (
|
||||
<StringInput
|
||||
selectedValues={selectedValues}
|
||||
cardinality={cardinality}
|
||||
updateSelectedValues={updateSelectedValues}
|
||||
/>
|
||||
)}
|
||||
{!allowedValues && valueType.info.type === StdDataType.RichText && (
|
||||
<RichTextInput
|
||||
selectedValues={selectedValues}
|
||||
updateSelectedValues={updateSelectedValues}
|
||||
/>
|
||||
)}
|
||||
{!allowedValues && valueType.info.type === StdDataType.Date && (
|
||||
<DateInput selectedValues={selectedValues} updateSelectedValues={updateSelectedValues} />
|
||||
)}
|
||||
{!allowedValues && valueType.info.type === StdDataType.Number && (
|
||||
<NumberInput selectedValues={selectedValues} updateSelectedValues={updateSelectedValues} />
|
||||
)}
|
||||
{!allowedValues && valueType.info.type === StdDataType.Urn && (
|
||||
<UrnInput
|
||||
structuredProperty={structuredProperty}
|
||||
selectedValues={selectedValues}
|
||||
updateSelectedValues={updateSelectedValues}
|
||||
/>
|
||||
)}
|
||||
</InputSection>
|
||||
</PromptInputWrapper>
|
||||
{isComplete && !hasEditedPrompt && (
|
||||
<CompletedPromptAuditStamp completedByName={completedByName} completedByTime={completedByTime} />
|
||||
)}
|
||||
</PromptWrapper>
|
||||
{(showSaveButton || showConfirmButton) && (
|
||||
<StyledButton type="primary" onClick={submitStructuredPropertyResponse}>
|
||||
Save
|
||||
{showSaveButton ? 'Save' : 'Confirm'}
|
||||
</StyledButton>
|
||||
)}
|
||||
{(isPromptComplete(prompt, completedPrompts) ||
|
||||
isFieldPromptComplete(field, promptAssociation) ||
|
||||
optimisticCompletedTimestamp) &&
|
||||
!isSaveVisible && (
|
||||
<CompletedPromptAuditStamp
|
||||
completedByName={getCompletedByName()}
|
||||
completedByTime={getCompletedByRelativeTime()}
|
||||
/>
|
||||
)}
|
||||
</PromptWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import { getInitialValues } from './utils';
|
||||
import usePrevious from '../../../../../shared/usePrevious';
|
||||
import { useGetEntityWithSchema } from '../../../tabs/Dataset/Schema/useGetEntitySchema';
|
||||
import { FormView, useEntityFormContext } from '../../EntityFormContext';
|
||||
import { SCHEMA_FIELD_PROMPT_TYPES } from '../../constants';
|
||||
|
||||
interface Props {
|
||||
prompt: FormPrompt;
|
||||
@ -13,10 +14,10 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function useStructuredPropertyPrompt({ prompt, submitResponse, field }: Props) {
|
||||
const { refetch: refetchSchema } = useGetEntityWithSchema();
|
||||
const { refetch: refetchSchema } = useGetEntityWithSchema(!SCHEMA_FIELD_PROMPT_TYPES.includes(prompt.type));
|
||||
const { refetch, entityData } = useEntityContext();
|
||||
const { selectedPromptId, formView } = useEntityFormContext();
|
||||
const [isSaveVisible, setIsSaveVisible] = useState(false);
|
||||
const [hasEditedPrompt, setHasEditedPrompt] = useState(false);
|
||||
const initialValues = useMemo(
|
||||
() => (formView === FormView.BY_ENTITY ? getInitialValues(prompt, entityData, field) : []),
|
||||
[formView, entityData, prompt, field],
|
||||
@ -35,19 +36,19 @@ export default function useStructuredPropertyPrompt({ prompt, submitResponse, fi
|
||||
const previousSelectedPromptId = usePrevious(selectedPromptId);
|
||||
useEffect(() => {
|
||||
if (selectedPromptId !== previousSelectedPromptId) {
|
||||
setIsSaveVisible(false);
|
||||
setHasEditedPrompt(false);
|
||||
setSelectedValues(initialValues || []);
|
||||
}
|
||||
}, [previousSelectedPromptId, selectedPromptId, initialValues]);
|
||||
|
||||
// respond to prompts
|
||||
function selectSingleValue(value: string | number) {
|
||||
setIsSaveVisible(true);
|
||||
setHasEditedPrompt(true);
|
||||
setSelectedValues([value as string]);
|
||||
}
|
||||
|
||||
function toggleSelectedValue(value: string | number) {
|
||||
setIsSaveVisible(true);
|
||||
setHasEditedPrompt(true);
|
||||
if (selectedValues.includes(value)) {
|
||||
setSelectedValues((prev) => prev.filter((v) => v !== value));
|
||||
} else {
|
||||
@ -57,7 +58,7 @@ export default function useStructuredPropertyPrompt({ prompt, submitResponse, fi
|
||||
|
||||
function updateSelectedValues(values: any[]) {
|
||||
setSelectedValues(values);
|
||||
setIsSaveVisible(true);
|
||||
setHasEditedPrompt(true);
|
||||
}
|
||||
|
||||
// submit structured property prompt
|
||||
@ -80,7 +81,7 @@ export default function useStructuredPropertyPrompt({ prompt, submitResponse, fi
|
||||
},
|
||||
() => {
|
||||
refetch();
|
||||
setIsSaveVisible(false);
|
||||
setHasEditedPrompt(false);
|
||||
if (field) {
|
||||
refetchSchema();
|
||||
}
|
||||
@ -89,7 +90,7 @@ export default function useStructuredPropertyPrompt({ prompt, submitResponse, fi
|
||||
}
|
||||
|
||||
return {
|
||||
isSaveVisible,
|
||||
hasEditedPrompt,
|
||||
selectedValues,
|
||||
selectSingleValue,
|
||||
toggleSelectedValue,
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
import { useMemo } from 'react';
|
||||
import { EntityType, FormPrompt, SchemaField } from '../../../../../types.generated';
|
||||
import { useUserContext } from '../../../../context/useUserContext';
|
||||
import { useEntityRegistry } from '../../../../useEntityRegistry';
|
||||
import { useEntityData } from '../../EntityContext';
|
||||
import {
|
||||
findCompletedFieldPrompt,
|
||||
findPromptAssociation,
|
||||
getCompletedPrompts,
|
||||
getIncompletePrompts,
|
||||
isFieldPromptComplete,
|
||||
isPromptComplete,
|
||||
} from '../../containers/profile/sidebar/FormInfo/utils';
|
||||
import { getTimeFromNow } from '../../../../shared/time/timeUtils';
|
||||
|
||||
interface CompletionProps {
|
||||
prompt: FormPrompt;
|
||||
field?: SchemaField;
|
||||
optimisticCompletedTimestamp?: number | null;
|
||||
}
|
||||
|
||||
export default function usePromptCompletionInfo({ prompt, field, optimisticCompletedTimestamp }: CompletionProps) {
|
||||
const { entityData } = useEntityData();
|
||||
const { user } = useUserContext();
|
||||
const entityRegistry = useEntityRegistry();
|
||||
const completedPrompts = getCompletedPrompts(entityData);
|
||||
const incompletePrompts = getIncompletePrompts(entityData);
|
||||
const promptAssociation = findPromptAssociation(prompt, completedPrompts.concat(incompletePrompts));
|
||||
const completedFieldPrompt = findCompletedFieldPrompt(field, promptAssociation);
|
||||
const isComplete =
|
||||
isPromptComplete(prompt, completedPrompts) ||
|
||||
isFieldPromptComplete(field, promptAssociation) ||
|
||||
!!optimisticCompletedTimestamp;
|
||||
|
||||
const completedByName = useMemo(() => {
|
||||
let actor = completedFieldPrompt?.lastModified?.actor || promptAssociation?.lastModified?.actor;
|
||||
if (optimisticCompletedTimestamp) {
|
||||
actor = user;
|
||||
}
|
||||
return actor ? entityRegistry.getDisplayName(EntityType.CorpUser, actor) : '';
|
||||
}, [
|
||||
completedFieldPrompt?.lastModified?.actor,
|
||||
entityRegistry,
|
||||
optimisticCompletedTimestamp,
|
||||
promptAssociation?.lastModified?.actor,
|
||||
user,
|
||||
]);
|
||||
|
||||
const completedByTime = useMemo(() => {
|
||||
let completedTimestamp = completedFieldPrompt?.lastModified?.time || promptAssociation?.lastModified?.time;
|
||||
if (optimisticCompletedTimestamp) {
|
||||
completedTimestamp = optimisticCompletedTimestamp;
|
||||
}
|
||||
return completedTimestamp ? getTimeFromNow(completedTimestamp) : '';
|
||||
}, [completedFieldPrompt?.lastModified?.time, optimisticCompletedTimestamp, promptAssociation?.lastModified?.time]);
|
||||
|
||||
return {
|
||||
completedByName,
|
||||
completedByTime,
|
||||
isComplete,
|
||||
};
|
||||
}
|
||||
@ -9,7 +9,7 @@ const shouldLoadSchema = (entityType, entityData) => {
|
||||
return entityType === EntityType.Dataset && !entityData?.schemaMetadata;
|
||||
};
|
||||
|
||||
export const useGetEntityWithSchema = () => {
|
||||
export const useGetEntityWithSchema = (skip?: boolean) => {
|
||||
const { urn, entityData, entityType } = useEntityData();
|
||||
// Load the dataset schema lazily.
|
||||
const {
|
||||
@ -20,7 +20,7 @@ export const useGetEntityWithSchema = () => {
|
||||
variables: {
|
||||
urn,
|
||||
},
|
||||
skip: !shouldLoadSchema(entityType, entityData),
|
||||
skip: skip || !shouldLoadSchema(entityType, entityData),
|
||||
fetchPolicy: 'cache-first',
|
||||
});
|
||||
const isHideSiblingMode = useIsSeparateSiblingsMode();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user