Skip to content

Commit

Permalink
Better handling on entity create/edit edge cases (#1455)
Browse files Browse the repository at this point in the history
* I think this is much safer and smarter. If we don't have schema we should
 not assume things can be empty

* Updating material input control to handle disabled inputs
Switching to using custom input control

* We do not want to allow editing of this field and have users only select
 the connector on the connector select page.

* Updating content since the field is not editable

* Since we do not allow editing of connector we want them to be able to go back

* Moving create routes into the entity settings

* Renaming to make it more appropriate

* Hiding iframe unless it is being shown
Adding eventing to keep an eye on this
  • Loading branch information
travjenkins authored Feb 12, 2025
1 parent 4ab35c3 commit f49e392
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 40 deletions.
3 changes: 3 additions & 0 deletions src/components/shared/Entity/DetailsForm/useConnectorField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ export default function useConnectorField(
}),
scope: `#/properties/${CONNECTOR_IMAGE_SCOPE}`,
type: 'Control',
options: {
readOnly: true,
},
};

const evaluateConnector = useCallback(
Expand Down
20 changes: 5 additions & 15 deletions src/components/shared/Entity/hooks/useEntityCreateNavigate.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { authenticatedRoutes } from 'app/routes';
import { GlobalSearchParams } from 'hooks/searchParams/useGlobalSearchParams';
import useSearchParamAppend from 'hooks/searchParams/useSearchParamAppend';
import { isEmpty } from 'lodash';
import { useCallback } from 'react';
import { useNavigate } from 'react-router';
import { ENTITY_SETTINGS } from 'settings/entity';
import { EntityWithCreateWorkflow } from 'types';
import { getPathWithParams, hasLength } from 'utils/misc-utils';

Expand Down Expand Up @@ -41,24 +41,14 @@ export default function useEntityCreateNavigate() {
? appendSearchParams(searchParamConfig)
: null;

let newPath: string | null = null;
if (entity === 'capture') {
newPath = advanceToForm
? authenticatedRoutes.captures.create.new.fullPath
: authenticatedRoutes.captures.create.fullPath;
} else {
newPath = advanceToForm
? authenticatedRoutes.materializations.create.new.fullPath
: authenticatedRoutes.materializations.create.fullPath;
}
const newPath: string = advanceToForm
? ENTITY_SETTINGS[entity].routes.createNew
: ENTITY_SETTINGS[entity].routes.connectorSelect;

navigate(
newSearchParams
? getPathWithParams(newPath, newSearchParams)
: newPath,
{
replace,
}
: newPath
);
},
[appendSearchParams, navigate]
Expand Down
2 changes: 1 addition & 1 deletion src/components/sidePanelDocs/Iframe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ function SidePanelIframe({ show }: Props) {
}, [docsURL, iframeCurrent, setAnimateOpening, show]);

// Make sure we don't include an iframe unless we actually need it
if (!hasLength(docsURL)) {
if (!hasLength(docsURL) || !show) {
return null;
}

Expand Down
5 changes: 5 additions & 0 deletions src/components/sidePanelDocs/OpenButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
import { useShowSidePanelDocs } from 'context/SidePanelDocs';
import { SidebarCollapse } from 'iconoir-react';
import { FormattedMessage } from 'react-intl';
import { logRocketEvent } from 'services/shared';
import { CustomEvents } from 'services/types';
import { useSidePanelDocsStore } from 'stores/SidePanelDocs/Store';
import { hasLength } from 'utils/misc-utils';

Expand Down Expand Up @@ -40,6 +42,9 @@ function SidePanelDocsOpenButton() {
size="small"
variant="outlined"
onClick={() => {
logRocketEvent(CustomEvents.HELP_DOCS, {
show: true,
});
setShowDocs(true);
}}
endIcon={
Expand Down
5 changes: 5 additions & 0 deletions src/components/sidePanelDocs/SidePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Drawer, IconButton, Toolbar, Typography } from '@mui/material';
import { useShowSidePanelDocs } from 'context/SidePanelDocs';
import { Xmark } from 'iconoir-react';
import { FormattedMessage } from 'react-intl';
import { logRocketEvent } from 'services/shared';
import { CustomEvents } from 'services/types';
import SidePanelIframe from './Iframe';

interface Props {
Expand Down Expand Up @@ -42,6 +44,9 @@ function DocsSidePanel({ show }: Props) {
<IconButton
size="small"
onClick={() => {
logRocketEvent(CustomEvents.HELP_DOCS, {
show: false,
});
setShowDocs(false);
}}
sx={{ color: (theme) => theme.palette.text.primary }}
Expand Down
7 changes: 4 additions & 3 deletions src/forms/renderers/Connectors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ import {
rankWith,
scopeEndsWith,
} from '@jsonforms/core';
import { MaterialInputControl } from '@jsonforms/material-renderers';
import { WithOptionLabel } from '@jsonforms/material-renderers/lib/mui-controls/MuiAutocomplete';
import { withJsonFormsOneOfEnumProps } from '@jsonforms/react';
import { ConnectorAutoComplete } from 'forms/renderers/ConnectorSelect/AutoComplete';
import { CustomMaterialInputControl } from './Overrides/material/controls/MaterialInputControl';

export const CONNECTOR_IMAGE_SCOPE = 'connectorImage';

Expand All @@ -44,11 +44,12 @@ export const connectorTypeTester: RankedTester = rankWith(
and(isOneOfEnumControl, scopeEndsWith(CONNECTOR_IMAGE_SCOPE))
);

// This is blank on purpose. For right now we can just show null settings are nothing
const ConnectorTypeRenderer = (
props: ControlProps & OwnPropsOfEnum & WithOptionLabel
) => {
return <MaterialInputControl {...props} input={ConnectorAutoComplete} />;
return (
<CustomMaterialInputControl {...props} input={ConnectorAutoComplete} />
);
};

export const ConnectorType = withJsonFormsOneOfEnumProps(ConnectorTypeRenderer);
7 changes: 4 additions & 3 deletions src/forms/renderers/DataPlanes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ import {
rankWith,
scopeEndsWith,
} from '@jsonforms/core';
import { MaterialInputControl } from '@jsonforms/material-renderers';
import { WithOptionLabel } from '@jsonforms/material-renderers/lib/mui-controls/MuiAutocomplete';
import { withJsonFormsOneOfEnumProps } from '@jsonforms/react';
import { DataPlaneAutoComplete } from './DataPlaneSelector/AutoComplete';
import { CustomMaterialInputControl } from './Overrides/material/controls/MaterialInputControl';

export const DATA_PLANE_SCOPE = 'dataPlane';

Expand All @@ -44,11 +44,12 @@ export const dataPlaneTester: RankedTester = rankWith(
and(isOneOfEnumControl, scopeEndsWith(DATA_PLANE_SCOPE))
);

// This is blank on purpose. For right now we can just show null settings are nothing
const DataPlaneRenderer = (
props: ControlProps & OwnPropsOfEnum & WithOptionLabel
) => {
return <MaterialInputControl {...props} input={DataPlaneAutoComplete} />;
return (
<CustomMaterialInputControl {...props} input={DataPlaneAutoComplete} />
);
};

export const DataPlane = withJsonFormsOneOfEnumProps(DataPlaneRenderer);
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,25 @@ export interface WithInput {
}

interface Props {
inputEvents: {
inputEvents?: {
keyDown: (event?: any) => any;
focus: (event?: any) => any;
};
}

// ONLY USE THIS WHEN YOU NEED TO CONTROL FOCUS.
// Customizations:
// 1. inputEvents
// Allows you to pass in a focus function that fires when the input is focused
//
// 2. FormControl disable-able :
// This uses the `enabled` flag to set `disable` on form control so labels and helper text show as disabled
export const CustomMaterialInputControl = (
props: Props & ControlProps & WithInput
) => {
const [focused, onFocus, onBlur] = useFocus();
const {
id,
description,
enabled,
errors,
label,
uischema,
Expand Down Expand Up @@ -88,24 +89,38 @@ export const CustomMaterialInputControl = (
return (
<Hidden xsUp={!visible}>
<FormControl
disabled={!enabled}
fullWidth={!appliedUiSchemaOptions.trim}
id={id}
variant="standard"
onBlur={onBlur}
onFocus={(event) => {
if (endsWith(event.target.id, CLEAR_BUTTON_ID_SUFFIX)) {
// Clear button was clicked so we do not want to fire the focus event
// Return here so we do not fire the focus events. This way when a user
// clicks on the reset button the date picker is not opened right up
return;
}
onFocus={
inputEvents
? (event) => {
if (
endsWith(
event.target.id,
CLEAR_BUTTON_ID_SUFFIX
)
) {
// Clear button was clicked so we do not want to fire the focus event
// Return here so we do not fire the focus events. This way when a user
// clicks on the reset button the date picker is not opened right up
return;
}

inputEvents.focus();
onFocus();
}}
onKeyDown={() => {
inputEvents.keyDown();
}}
inputEvents.focus();
onFocus();
}
: undefined
}
onKeyDown={
inputEvents
? () => {
inputEvents.keyDown();
}
: undefined
}
>
<InputLabel
htmlFor={`${id}-input`}
Expand Down
2 changes: 1 addition & 1 deletion src/lang/en-US/CommonMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export const CommonMessages: Record<string, string> = {
'entityPrefix.description': `Prefix for the entity name.`,
'entityName.label': `Name`,
'connector.label': `Connector`,
'connector.description': `Choose the external system you're connecting to.`,
'connector.description': `The external system you're connecting to.`,
'description.label': `Details`,
'description.description': `Describe your changes or why you're changing things.`,

Expand Down
1 change: 1 addition & 0 deletions src/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export enum CustomEvents {
FIELD_SELECTION_REFRESH_MANUAL = 'Field_Selection_Refresh:Manual',
FORM_STATE_PREVENTED = 'FormState:Prevented',
FULL_PAGE_ERROR_DISPLAYED = 'Full_Page_Error_Displayed',
HELP_DOCS = 'Help_Docs',
INCOMPATIBLE_SCHEMA_CHANGE = 'IncompatibleSchemaChange',
LAZY_LOADING = 'Lazy Loading',
LOGIN = 'Login',
Expand Down
8 changes: 8 additions & 0 deletions src/settings/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const ENTITY_SETTINGS: { [k in Entity]: EntitySetting } = {
bindingTermId: 'terms.bindings.plural',
pluralId: 'terms.sources.plural',
routes: {
connectorSelect: authenticatedRoutes.captures.create.fullPath,
createNew: authenticatedRoutes.captures.create.new.fullPath,
details: authenticatedRoutes.captures.details.overview.fullPath,
viewAll: authenticatedRoutes.captures.fullPath,
},
Expand Down Expand Up @@ -44,6 +46,8 @@ export const ENTITY_SETTINGS: { [k in Entity]: EntitySetting } = {
bindingTermId: 'terms.collections.plural',
pluralId: 'terms.collections.plural',
routes: {
connectorSelect: authenticatedRoutes.collections.create.fullPath,
createNew: authenticatedRoutes.collections.create.new.fullPath,
details: authenticatedRoutes.collections.details.overview.fullPath,
viewAll: authenticatedRoutes.collections.fullPath,
},
Expand Down Expand Up @@ -71,6 +75,10 @@ export const ENTITY_SETTINGS: { [k in Entity]: EntitySetting } = {
bindingTermId: 'terms.collections.plural',
pluralId: 'terms.destinations.plural',
routes: {
connectorSelect:
authenticatedRoutes.materializations.create.fullPath,
createNew: authenticatedRoutes.materializations.create.new.fullPath,

details:
authenticatedRoutes.materializations.details.overview.fullPath,
viewAll: authenticatedRoutes.materializations.fullPath,
Expand Down
2 changes: 2 additions & 0 deletions src/settings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export interface EntitySetting {
bindingTermId: string;
pluralId: string;
routes: {
connectorSelect: string;
createNew: string;
details: string;
viewAll: string;
};
Expand Down
6 changes: 5 additions & 1 deletion src/utils/misc-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,11 @@ export const getDereffedSchema = async (val: any) => {
};

export const configCanBeEmpty = (schema: any) => {
return Boolean(!schema?.properties || isEmpty(schema?.properties));
if (!schema) {
return false;
}

return Boolean(!schema.properties || isEmpty(schema.properties));
};

export const isReactElement = (value: ReactNode): value is ReactElement =>
Expand Down

0 comments on commit f49e392

Please sign in to comment.