Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions app/javascript/components/service-dialog-form/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import {
CheckboxChecked32, RadioButtonChecked32, Time32, StringText32, TextSmallCaps32, CaretDown32, Tag32, Calendar32,
} from '@carbon/icons-react';

export const dragItems = {
COMPONENT: 'component',
SECTION: 'section',
FIELD: 'field',
};

/** Data needed to render the dynamic components on the left hand side of the form. */
export const dynamicComponents = [
{ id: 1, title: 'Text Box', icon: <StringText32 /> },
{ id: 2, title: 'Text Area', icon: <TextSmallCaps32 /> },
{ id: 3, title: 'Check Box', icon: <CheckboxChecked32 /> },
{ id: 4, title: 'Dropdown', icon: <CaretDown32 /> },
{ id: 5, title: 'Radio Button', icon: <RadioButtonChecked32 /> },
{ id: 6, title: 'Datepicker', icon: <Calendar32 /> },
{ id: 7, title: 'Timepicker', icon: <Time32 /> },
{ id: 8, title: 'Tag Control', icon: <Tag32 /> },
];

/** Function which returens the default data for a section under a tab. */
export const defaultSectionContents = (tabId, sectionId) => ({
tabId,
sectionId,
title: 'New Section',
fields: [],
order: 0,
});

/** Function which returns the default data for a tab with default section. */
export const defaultTabContents = (tabId) => ({
tabId,
name: tabId === 0 ? __('New Tab') : __(`New Tab ${tabId}`),
sections: [defaultSectionContents(tabId, 0)],
});

/** Function to create a dummy tab for creating new tabs. */
export const createNewTab = () => ({
tabId: 'new',
name: 'Create Tab',
sections: [],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import PropTypes from 'prop-types';
import { dragItems } from './data';

/** Component to render the components list vertically on left side.
* Components can be used to drag and drop into the tab Contents */
const DynamicComponentChooser = ({ list, onDragStartComponent }) => (
<div className="components-list-wrapper">
{
list.map((item, index) => (
<div
title={`Drag and Drop a ${item.title.toLowerCase()} to any section`}
id={item.id}
className="component-item-wrapper"
draggable="true"
onDragStart={(event) => onDragStartComponent(event, dragItems.COMPONENT)}
key={index.toString()}
>
<div className="component-item">
{item.icon}
{item.title}
</div>
</div>
))
}
</div>
);

DynamicComponentChooser.propTypes = {
list: PropTypes.arrayOf(PropTypes.any).isRequired,
onDragStartComponent: PropTypes.func.isRequired,
};

export default DynamicComponentChooser;
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Button } from 'carbon-components-react';
import { Close16, Edit16 } from '@carbon/icons-react';
import { SD_ACTIONS } from './helper';
import EditFieldModal from './edit-field-modal';

/** Component to render a Field. */
const DynamicFieldActions = ({ componentId, dynamicFieldAction, fieldConfiguration }) => {
const [{ showModal }, setState] = useState({ showModal: false });

const onModalHide = () => setState((state) => ({ ...state, showModal: false }));
const onModalShow = () => setState((state) => ({ ...state, showModal: true }));
const onModalApply = () => setState((state) => ({ ...state, showModal: false }));

const renderEditButton = () => (
<Button
renderIcon={Edit16}
kind="ghost"
iconDescription={__('Edit')}
onClick={onModalShow}
onKeyPress={(event) => dynamicFieldAction(SD_ACTIONS.field.edit, event)}
title={__('Edit field')}
/>
);

const renderRemoveButton = () => (
<Button
renderIcon={Close16}
kind="ghost"
iconDescription={__('Remove')}
onClick={(event) => dynamicFieldAction(SD_ACTIONS.field.delete, event)}
onKeyPress={(event) => dynamicFieldAction(SD_ACTIONS.field.delete, event)}
title={__('Remove field')}
/>
);

const renderEditFieldModal = () => (
showModal && (
<EditFieldModal
componentId={componentId}
fieldConfiguration={fieldConfiguration}
showModal={showModal}
onModalHide={onModalHide}
onModalApply={onModalApply}
/>
)
);

return (
<div className="dynamic-form-field-actions">
{renderEditButton()}
{renderRemoveButton()}
{renderEditFieldModal()}
</div>
);
};

DynamicFieldActions.propTypes = {
componentId: PropTypes.number.isRequired,
dynamicFieldAction: PropTypes.func.isRequired,
fieldConfiguration: PropTypes.arrayOf(PropTypes.any).isRequired,
};

export default DynamicFieldActions;
47 changes: 47 additions & 0 deletions app/javascript/components/service-dialog-form/dynamic-field.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';
import DynamicTextInput from './dynamic-fields/dynamic-text-input';
import DynamicTextArea from './dynamic-fields/dynamic-text-area';
import { dynamicFieldDataProps } from './helper';
/** Component to render a Field. */
const DynamicField = ({ fieldData, onFieldAction }) => {
const fieldSelector = (fieldData) => {
switch (fieldData.field.componentId) {
case 1:
return <DynamicTextInput dynamicFieldData={fieldData} onFieldAction={(newFieldData) => onFieldAction(newFieldData)} />;
case 2:
return <DynamicTextArea dynamicFieldData={fieldData} onFieldAction={(newFieldData) => onFieldAction(newFieldData)} />;
case 3:
return fieldData.field.componentId;
case 4:
return fieldData.field.componentId;
case 5:
return fieldData.field.componentId;
case 6:
return fieldData.field.componentId;
case 7:
return fieldData.field.componentId;
case 8:
return fieldData.field.componentId;
case 9:
return fieldData.field.componentId;
default:
return <DynamicTextInput dynamicFieldData={fieldData} onFieldAction={(newFieldData) => onFieldAction(newFieldData)} />;
}
};

return (
<>
{
fieldSelector(fieldData)
}
</>
);
};

DynamicField.propTypes = {
fieldData: dynamicFieldDataProps.isRequired,
onFieldAction: PropTypes.func.isRequired,
};

export default DynamicField;
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { componentTypes } from '@data-driven-forms/react-form-renderer';

export const dynamicFields = {
defaultValue: { label: __('Default value'), field: componentTypes.TEXT_FIELD },
dynamic: { label: __('Dynamic'), field: componentTypes.SWITCH },
entries: { label: __('Entries'), field: 'component', component: componentTypes.SELECT },
entryPoint: { label: __('Entry point'), field: componentTypes.SELECT },
fieldsToRefresh: { label: __('Fields to refresh'), field: componentTypes.SELECT },
help: { label: __('Help'), field: componentTypes.TEXTAREA },
label: { label: __('Label'), field: componentTypes.TEXT_FIELD },
loadOnInit: { label: __('Load values on init'), field: componentTypes.SWITCH },
multiselect: { label: __('Multiselect'), field: componentTypes.SWITCH },
name: { label: __('Name'), field: componentTypes.TEXT_FIELD },
protected: { label: __('Protected'), field: componentTypes.SWITCH },
reconfigurable: { label: __('Reconfigurable'), field: componentTypes.SWITCH },
required: { label: __('Required'), field: componentTypes.SWITCH },
readOnly: { label: __('Read only'), field: componentTypes.SWITCH },
showRefresh: { label: __('Show refresh button'), field: componentTypes.SWITCH },
sortBy: { label: __('Sort by'), field: componentTypes.SELECT },
sortOrder: { label: __('Sort order'), field: componentTypes.SELECT },
showPastDates: { label: __('Show Past Dates'), field: componentTypes.SWITCH },
singleValue: { label: __('Single value'), field: componentTypes.SWITCH },
visible: { label: __('Visible'), field: componentTypes.SWITCH },
valueType: { label: __('Value type'), field: componentTypes.SELECT },
validation: { label: __('Validation'), field: componentTypes.SWITCH },
validator: { label: __('Validator'), field: componentTypes.TEXT_FIELD },
};

export const fieldTab = {
fieldInformation: __('Field Information'),
options: __('Options'),
advanced: __('Advanced'),
overridableOptions: __('Overridable Options'),
};

export const fieldInformation = () => ({
name: fieldTab.fieldInformation,
fields: [
dynamicFields.label,
dynamicFields.name,
dynamicFields.help,
dynamicFields.dynamic, // not there for tag control.
],
});

export const advanced = () => ({
name: fieldTab.advanced,
fields: [dynamicFields.reconfigurable],
});

export const overridableOptions = () => ({
name: fieldTab.overridableOptions,
fields: [
dynamicFields.readOnly,
dynamicFields.visible,
dynamicFields.defaultValue,
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TextArea, FormLabel } from 'carbon-components-react';
import { dynamicFieldDataProps, SD_ACTIONS } from '../helper';
import DynamicFieldActions from '../dynamic-field-actions';
import {
fieldInformation, advanced, overridableOptions, fieldTab, dynamicFields,
} from './dynamic-field-configuration';

/** Component to render a Field. */
const DynamicTextArea = ({ dynamicFieldData: { section, field, fieldPosition }, onFieldAction }) => {
const { tabId, sectionId } = section;
const fieldActions = (event, type) => onFieldAction({
event,
fieldPosition,
type,
});

const ordinaryTextAreaOptions = () => ([
dynamicFields.defaultValue,
dynamicFields.required,
dynamicFields.readOnly,
dynamicFields.visible,
dynamicFields.validation,
dynamicFields.validator,
dynamicFields.fieldsToRefresh,
]);

const dynamicTextAreaOptions = () => ([
dynamicFields.entryPoint,
dynamicFields.showRefresh,
dynamicFields.loadOnInit,
dynamicFields.required,
dynamicFields.validation,
dynamicFields.validator,
dynamicFields.fieldsToRefresh,
]);

const textAreaOptions = (dynamic) => ({
name: fieldTab.options,
fields: dynamic ? dynamicTextAreaOptions() : ordinaryTextAreaOptions(),
});

const textAreaEditFields = (dynamic) => {
const tabs = [
fieldInformation(),
textAreaOptions(dynamic),
advanced(),
];
if (dynamic) {
tabs.push(overridableOptions());
}
return tabs;
};

return (
<div className="dynamic-form-field">
<div className="dynamic-form-field-item">
<FormLabel>
Text Area
</FormLabel>
<TextArea
id={`tab-${tabId}-section-${sectionId}-field-${fieldPosition}-text-area`}
labelText={__('Text Area')}
hideLabel
placeholder={__('Text Area')}
name={`tab-${tabId}-section-${sectionId}-field-${fieldPosition}-text-area`}
value="default text area value"
title={__('Text Area')}
onChange={(event) => fieldActions(event, SD_ACTIONS.textAreaOnChange)}
/>
</div>
<DynamicFieldActions
componentId={field.componentId}
dynamicFieldAction={(action) => console.log(action)}
fieldConfiguration={textAreaEditFields(false)}
/>
</div>
);
};

DynamicTextArea.propTypes = {
dynamicFieldData: dynamicFieldDataProps.isRequired,
onFieldAction: PropTypes.func.isRequired,
};

export default DynamicTextArea;
Loading