Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import * as React from 'react';
- import { Component } from 'react';
- import { RouteComponentProps } from 'react-router';
- import { Dispatch } from 'redux';
- import { connect } from 'react-redux';
- import { Link } from 'react-router-dom';
- import { replace } from 'react-router-redux';
- import * as _ from 'lodash';
- import AddDataSourceToolbar from '../../components/admin/AddDataSourceToolbar';
- import Loading from '../../components/common/Loading';
- import { RootState, IStorybook } from '../../types';
- import { SharedModels } from '../../types/Models';
- import {
- createStorybook,
- updateStorybook,
- StorybookPostParams,
- generateSecurityKey,
- getStorybooksSettings
- } from '../../state/storybooks/StorybooksActions';
- import { getStorybookIdFromPath, getStorybookFromId, getStorybook } from '../../state/storybook/StorybookSelector';
- import { refreshToken } from '../../state/session/SessionActions';
- import { SharedEnums } from '../../types/Enums';
- import { revealTestIsSuccessStateSelector, revealTestIsFetchingStateSelector } from '../../state/reveal/RevealSelector';
- import { fetchDataConnections } from '../../state/databaseServer/databaseServerActions';
- import { getServerConnections } from '../../state/databaseServer/databaseServerSelector';
- import { fetchRevealApiTest, clearRevealApiTest, fetchStorybook } from '../../state/actions';
- interface RouteMatchProps {
- storybookId: number | null;
- }
- interface AddStorybookProps {
- storybookId: number;
- storybook: IStorybook | null;
- storybooks: IStorybook[];
- connections: SharedModels.DatabaseServerModelRequest[];
- isCreating: boolean;
- isUpdating: boolean;
- actionError: string | null;
- settings: SharedModels.StoryBookCommonSettings | null;
- isTestSuccess: boolean | null;
- isTestFetching: boolean;
- }
- interface AddStorybookDispatchProps {
- // tslint:disable-next-line:no-any
- createStorybook: (data: StorybookPostParams) => Promise<any>;
- // tslint:disable-next-line: no-any
- updateStorybook: (storybook: IStorybook) => Promise<any>;
- fetchStorybook: (storybookId: number, cosmicGroupId?: number) => void;
- fetchDataConnections: () => void;
- getStorybooksSettings: () => void;
- redirect: (destination: string) => void;
- refreshAuthenticationToken: () => void;
- // tslint:disable-next-line:no-any
- generateSecurityKey: () => Promise<any>;
- testRevealApi: (url: string) => void;
- clearRevealApiTest: () => void;
- }
- interface AddStorybookState {
- storybookName: string;
- databaseName: string;
- serverId: number;
- externalIntegrationType: string;
- autoGenerate: boolean;
- supportDashboard: boolean;
- defaultLayoutId: number | null;
- key1: string;
- key2: string;
- externalKey: string;
- externalUrl: string;
- lastUpdatedStorybook: IStorybook | null;
- createSuccess: boolean | null;
- updateSuccess: boolean | null;
- revealFieldsIsRequired: boolean;
- validationError: string | null;
- }
- class AddStorybook extends Component<AddStorybookProps & RouteComponentProps<RouteMatchProps> & AddStorybookDispatchProps, AddStorybookState> {
- private titleContainer: HTMLHeadingElement | null;
- constructor(props: AddStorybookProps & RouteComponentProps<RouteMatchProps> & AddStorybookDispatchProps) {
- super(props);
- const externalIntegrationType = props.storybook && props.storybook.externalIntegrationType
- ? props.storybook.externalIntegrationType : SharedEnums.ExternalIntegrationType.NONE;
- const revealFieldsIsRequired = externalIntegrationType === SharedEnums.ExternalIntegrationType.REVEAL;
- this.state = {
- storybookName: props.storybook ? props.storybook.name : '',
- databaseName: '',
- serverId: -1,
- externalIntegrationType,
- autoGenerate: false,
- supportDashboard: props.storybook ? !!props.storybook.supportDashboard : false,
- defaultLayoutId: props.storybook ? props.storybook.defaultLayoutId : 0,
- key1: props.storybook ? props.storybook.key1 : '',
- key2: props.storybook ? props.storybook.key2 : '',
- lastUpdatedStorybook: null,
- createSuccess: null,
- updateSuccess: null,
- validationError: null,
- revealFieldsIsRequired: revealFieldsIsRequired,
- externalUrl: props.storybook && props.storybook.externalUrl ? props.storybook.externalUrl : '',
- externalKey: props.storybook && props.storybook.externalKey ? props.storybook.externalKey : '',
- };
- }
- componentDidMount() {
- this.props.fetchDataConnections();
- this.props.getStorybooksSettings();
- }
- componentWillUnmount() {
- this.props.clearRevealApiTest();
- }
- componentDidUpdate(prevProps: AddStorybookProps & AddStorybookDispatchProps) {
- const { isCreating, isUpdating, storybooks, storybook, storybookId } = this.props;
- if (prevProps.isCreating && !isCreating) {
- if (!_.isEqual(storybooks, prevProps.storybooks) && storybooks.length > 0) {
- this.setState({ createSuccess: true, lastUpdatedStorybook: _.last(storybooks) || null });
- } else {
- this.setState({ createSuccess: false });
- }
- }
- if (prevProps.isUpdating && !isUpdating) {
- if (!_.isEqual(storybooks, prevProps.storybooks) && storybooks.length > 0) {
- this.setState({
- updateSuccess: true,
- lastUpdatedStorybook: (storybookId === -1 ? _.last(storybooks) : storybooks.find(s => s.id === storybookId)) || null,
- });
- } else {
- this.setState({ updateSuccess: false });
- }
- }
- if (storybookId !== -1 && !prevProps.storybook && storybook) {
- const externalIntegrationType = storybook.externalIntegrationType
- ? storybook.externalIntegrationType : SharedEnums.ExternalIntegrationType.NONE;
- this.setState({
- storybookName: storybook.name,
- supportDashboard: !!storybook.supportDashboard,
- defaultLayoutId: storybook.defaultLayoutId || 0,
- key1: storybook.key1,
- key2: storybook.key2,
- externalIntegrationType,
- revealFieldsIsRequired: externalIntegrationType === SharedEnums.ExternalIntegrationType.REVEAL,
- externalKey: storybook.externalKey,
- externalUrl: storybook.externalUrl
- });
- }
- }
- onCreateNewKey = (keyName: 'key1' | 'key2') => {
- this.props.generateSecurityKey()
- .then(res => (keyName === 'key1' ? this.setState({ key1: res.key }) : this.setState({ key2: res.key })));
- }
- onSave = () => {
- const { storybookId, storybook } = this.props;
- const { storybookName, databaseName, serverId, externalIntegrationType, supportDashboard, defaultLayoutId, key1, key2, lastUpdatedStorybook, autoGenerate,
- revealFieldsIsRequired, externalKey, externalUrl } = this.state;
- let errored = false;
- if (storybookId !== -1) {
- if (storybookName && !_.isNil(defaultLayoutId) && !_.isNaN(defaultLayoutId) && key1 && key2 && (!revealFieldsIsRequired || externalKey)
- && (!revealFieldsIsRequired || externalUrl)) {
- this.setState({ updateSuccess: null, validationError: null });
- this.props.updateStorybook({
- ...(lastUpdatedStorybook || storybook)!,
- name: storybookName,
- supportDashboard,
- defaultLayoutId,
- key1,
- key2,
- externalIntegrationType,
- externalKey,
- externalUrl
- }).then(() => this.props.fetchStorybook(storybookId));
- } else {
- errored = true;
- }
- } else {
- if (storybookName && (autoGenerate || databaseName) && serverId !== -1) {
- const server = this.props.connections.find(c => c.id === serverId)!;
- this.setState({ validationError: null, createSuccess: null, updateSuccess: null });
- const data = {
- name: storybookName,
- databaseServerId: serverId,
- databaseServer: server.name,
- outputDatabaseName: databaseName,
- };
- if (lastUpdatedStorybook) {
- this.props.updateStorybook({ ...lastUpdatedStorybook!, ...data });
- } else {
- this.props.createStorybook(data).then((res) => {
- if (res) {
- if (res.storybook && res.storybook.outputDatabaseName) {
- this.setState({
- databaseName: res.storybook.outputDatabaseName
- });
- }
- this.props.refreshAuthenticationToken();
- }
- });
- }
- } else {
- errored = true;
- }
- }
- if (errored) {
- this.setState({ validationError: 'Please enter values for required fields (*)' });
- if (this.titleContainer) {
- this.titleContainer.scrollIntoView({ behavior: 'smooth' });
- }
- }
- }
- render() {
- const { connections, isCreating, isUpdating, storybookId, actionError, isTestSuccess, isTestFetching } = this.props;
- const {
- storybookName, databaseName, serverId, externalIntegrationType, autoGenerate, supportDashboard, defaultLayoutId,
- key1, key2, lastUpdatedStorybook, createSuccess, updateSuccess, validationError, externalKey, revealFieldsIsRequired,
- externalUrl
- } = this.state;
- const isAdd = storybookId === -1;
- return (
- <div className="admin-primary admin-add-storybook">
- {(isCreating || isUpdating) && <div style={{ float: 'right' }}><Loading large={true} /></div>}
- {!_.isNil(createSuccess) && !isCreating && !validationError &&
- <div className={`result-alert ${createSuccess ? 'success' : 'fail'}`}>
- {createSuccess ? 'Storybook created successfully.' : actionError}
- </div>
- }
- {!_.isNil(updateSuccess) && !isUpdating && !validationError &&
- <div className={`result-alert ${updateSuccess ? 'success' : 'fail'}`}>
- {updateSuccess ? 'Storybook updated successfully.' : actionError}
- </div>
- }
- {validationError &&
- <div className="result-alert fail">
- {validationError}
- </div>
- }
- <h2 ref={e => this.titleContainer = e}>{isAdd ? 'Add' : 'Edit'} storybook</h2>
- <p>*required</p>
- <div className="form-row">
- <div className="form-label">Name<span title="required">*</span></div>
- <div className={`form-field${validationError && !storybookName ? ' has-error' : ''}`}>
- <input
- className="form-control"
- type="text"
- value={storybookName}
- onChange={e => this.setState({
- storybookName: e.target.value,
- databaseName: !autoGenerate ? `NexLP_${e.target.value.replace(/\s/g, '_')}` : '',
- })}
- />
- </div>
- </div>
- {isAdd ? <>
- <div className="form-row">
- <div className="form-label">Storybook database name<span title="required">*</span></div>
- <div className={`form-field${validationError && (!autoGenerate && !databaseName) ? ' has-error' : ''}`}>
- <input
- className="form-control"
- type="text"
- value={databaseName}
- disabled={autoGenerate}
- onChange={e => this.setState({ databaseName: e.target.value })}
- />
- </div>
- <label>
- <span
- onClick={() => this.setState({ autoGenerate: !autoGenerate, databaseName: !autoGenerate ? '' : `NexLP_${storybookName.replace(/\s/, '_')}`})}
- className="checkbox-option"
- >
- <i className={`far fa-fw ${autoGenerate ? 'fa-check-square' : 'fa-square'}`}/>
- Autogenerate
- </span>
- </label>
- </div>
- <div className="form-row">
- <div className="form-label">Storybook database server<span title="required">*</span></div>
- <div className={`form-field${validationError && serverId === -1 ? ' has-error' : ''}`}>
- <select className="form-control" onChange={e => this.setState({ serverId: parseInt(e.target.value, 10) })} value={serverId}>
- <option value={-1}>Choose server...</option>
- {connections.map(connection => <option key={`connection-${connection.id}`} value={connection.id}>{connection.name}</option>)}
- </select>
- </div>
- </div>
- </> : <>
- <div className="form-row">
- <div className="form-label">External Integration Type</div>
- <div className={`form-field${validationError && !externalIntegrationType ? ' has-error' : ''}`}>
- <select
- className="form-control"
- onChange={e => this.setState({
- externalIntegrationType: e.target.value,
- revealFieldsIsRequired: e.target.value === SharedEnums.ExternalIntegrationType.REVEAL
- })}
- value={externalIntegrationType}
- >
- <option value={SharedEnums.ExternalIntegrationType.NONE}>{SharedEnums.ExternalIntegrationType.NONE}</option>
- <option value={SharedEnums.ExternalIntegrationType.RELATIVITY}>{SharedEnums.ExternalIntegrationType.RELATIVITY}</option>
- <option value={SharedEnums.ExternalIntegrationType.REVEAL}>{SharedEnums.ExternalIntegrationType.REVEAL}</option>
- </select>
- </div>
- </div>
- <div className="form-row">
- <div className="form-label">External Key{revealFieldsIsRequired ? <span title="required">*</span> : null}</div>
- <div className={`form-field${validationError && !externalKey && revealFieldsIsRequired ? ' has-error' : ''}`}>
- <input
- className="form-control"
- type="text"
- value={externalKey}
- onChange={e => this.setState({
- externalKey: e.target.value
- })}
- />
- </div>
- </div>
- {revealFieldsIsRequired &&
- <>
- <div className="form-row">
- <div className="form-label">External Url<span title="required">*</span></div>
- <div className={`form-field${validationError && !externalUrl ? ' has-error' : ''}`}>
- <input
- className="form-control"
- type="text"
- value={externalUrl}
- onChange={e => this.setState({
- externalUrl: e.target.value
- })}
- />
- </div>
- </div>
- <div className="form-row">
- <div className="form-label" />
- <div className="form-field">
- <div className="test-connection-result">
- {isTestSuccess !== null && <>
- {isTestSuccess ? <>
- <span className="icon-color-yes">
- <i className="fas fa-check-circle" />
- Success
- </span>
- </> : <>
- <span className="icon-color-no">
- <i className="fas fa-times-circle" />
- Connection Error
- </span>
- </>}
- </>}
- </div>
- <button className="btn btn-default pull-right" disabled={isTestFetching} onClick={() => this.props.testRevealApi(this.state.externalUrl)}>
- {isTestFetching && <Loading />} Test Connection
- </button>
- </div>
- </div>
- </>}
- {this.props.settings && this.props.settings.dashboardSupported &&
- <><div className="form-row">
- <div className="form-label">Dashboard<span title="required">*</span></div>
- <div className="form-field">
- <label>
- <input type="checkbox" checked={supportDashboard} onChange={e => this.setState({ supportDashboard: e.target.checked })} />
- Enable dashboard
- </label>
- </div>
- </div>
- <div className="form-row">
- <div className="form-label">Dashboard layout ID<span title="required">*</span></div>
- <div className={`form-field${validationError && (_.isNil(defaultLayoutId) || _.isNaN(defaultLayoutId)) ? ' has-error' : ''}`}>
- <input
- className="form-control"
- type="text"
- value={(_.isNil(defaultLayoutId) || _.isNaN(defaultLayoutId)) ? '' : `${defaultLayoutId}`}
- onChange={e => this.setState({ defaultLayoutId: e.target.value ? parseInt(e.target.value, 10) : null })}
- />
- </div>
- </div></>}
- <div className="form-row keys-row">
- <div className="form-label">Security keys</div>
- <div className="form-field">
- <p>
- {key1}
- <a className="btn-link" onClick={() => this.onCreateNewKey('key1')}>Generate new key</a>
- </p>
- <p>
- {key2}
- <a className="btn-link" onClick={() => this.onCreateNewKey('key2')}>Generate new key</a>
- </p>
- </div>
- </div>
- </>
- }
- <div className="form-row">
- <div className="form-label" />
- <div className="form-field">
- <button className="btn btn-primary" onClick={this.onSave}>Save</button>
- <Link to="/settings/storybooks" className="btn btn-link">Cancel</Link>
- </div>
- </div>
- {isAdd && lastUpdatedStorybook &&
- <>
- <hr />
- <AddDataSourceToolbar
- title="Add a data source"
- subtitle="Save this storybook and add a data source now or you can add one later."
- storybookId={lastUpdatedStorybook.id}
- />
- </>
- }
- </div>
- );
- }
- }
- const mapStateToProps = (state: RootState, ownProps: RouteComponentProps<RouteMatchProps>) => {
- const storybookId = getStorybookIdFromPath(ownProps) || -1;
- return {
- storybookId,
- storybook: storybookId !== -1 ? getStorybookFromId(state)(storybookId) || getStorybook(state) : null,
- storybooks: state.storybooks.storybooks,
- connections: getServerConnections(state),
- isCreating: state.storybooks.isCreating,
- isUpdating: state.storybooks.isUpdating,
- actionError: state.storybooks.actionError,
- settings: state.storybooks.setttings,
- isTestSuccess: revealTestIsSuccessStateSelector(state),
- isTestFetching: revealTestIsFetchingStateSelector(state)
- };
- };
- const mapDispatchToProps = (dispatch: Dispatch<RootState>) => {
- return {
- createStorybook: (data: StorybookPostParams) => dispatch(createStorybook(data)),
- updateStorybook: (storybook: IStorybook) => dispatch(updateStorybook(storybook)),
- fetchDataConnections: () => dispatch(fetchDataConnections()),
- redirect: (destination: string) => dispatch(replace(destination)),
- refreshAuthenticationToken: () => {
- dispatch(refreshToken);
- },
- generateSecurityKey: () => dispatch(generateSecurityKey()),
- getStorybooksSettings: () => dispatch(getStorybooksSettings()),
- testRevealApi: (url: string) => dispatch(fetchRevealApiTest(url)),
- clearRevealApiTest: () => dispatch(clearRevealApiTest()),
- fetchStorybook: (storybookId: number, cosmicGroupId?: number) => dispatch(fetchStorybook(storybookId, cosmicGroupId))
- };
- };
- export default connect<AddStorybookProps, AddStorybookDispatchProps>(mapStateToProps, mapDispatchToProps)(AddStorybook);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement