From 2f95483b0570db075507cb087994988e4c71d56f Mon Sep 17 00:00:00 2001 From: Brian Gilkey Date: Tue, 22 Jan 2019 15:12:38 -0800 Subject: [PATCH 01/11] user profile widget update for edit profile in core --- .../src/widgets/UserProfile/index.js | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/veritone-widgets/src/widgets/UserProfile/index.js b/packages/veritone-widgets/src/widgets/UserProfile/index.js index 9b8ba0e54..873783d41 100644 --- a/packages/veritone-widgets/src/widgets/UserProfile/index.js +++ b/packages/veritone-widgets/src/widgets/UserProfile/index.js @@ -1,6 +1,6 @@ import React from 'react'; import { connect } from 'react-redux'; -import { startCase, noop, isEmpty } from 'lodash'; +import { startCase, noop, isEmpty, get } from 'lodash'; import { string, func, bool, shape } from 'prop-types'; import { withProps, branch, renderNothing } from 'recompose'; import { @@ -31,6 +31,7 @@ import ChangeNameModal from './Modals/ChangeName'; import ResetPasswordModal from './Modals/ResetPassword'; import styles from './styles.scss'; +const defaultAvatarImg = 'https://static.veritone.com/veritone-ui/default-avatar.png'; @connect( state => ({ @@ -87,11 +88,16 @@ export class UserProfile extends React.Component { handleSubmit: func.isRequired, resetUserPassword: func.isRequired, updateCurrentUserProfile: func.isRequired, + onUserUpdated: func, invalid: bool, pristine: bool, submitting: bool }; + static defaultProps = { + onUserUpdated: noop + }; + state = { currentModal: null }; @@ -160,7 +166,11 @@ export class UserProfile extends React.Component { }); }; - afterChange = () => { + afterChange = userResponse => { + const updatedUser = get(userResponse, 'updateCurrentUser'); + if (updatedUser) { + this.props.onUserUpdated(updatedUser); + } this.closeModal(); }; @@ -186,7 +196,7 @@ export class UserProfile extends React.Component { // eslint-disable-next-line renderButton={({ handlePickFiles }) => ( @@ -268,7 +278,8 @@ class UserProfileDialog extends React.Component { static propTypes = { open: bool, title: string, - onClose: func + onClose: func, + onUserUpdated: func }; static defaultProps = { @@ -322,4 +333,4 @@ class UserProfileDialog extends React.Component { } const UserProfileWidget = widget(UserProfileDialog); -export { UserProfileDialog as default, UserProfileWidget }; +export { UserProfileDialog as default, UserProfileWidget }; \ No newline at end of file From cc2fcf0f7211e353b4bb04c5c18bb925cf167830 Mon Sep 17 00:00:00 2001 From: Alex Bu Date: Tue, 22 Jan 2019 16:05:37 -0800 Subject: [PATCH 02/11] remove sdo-integration branch components (will be in veritone-react-components) and update any outstanding components with changes that were unsynced between branches --- .../OverlayPositioningProvider.js | 6 +- .../ContentTemplateForm/index.js | 130 -------- .../ContentTemplateForm/styles.scss | 11 - .../ContentTemplates/FormCard/index.js | 42 --- .../ContentTemplates/FormCard/styles.scss | 29 -- .../ContentTemplates/NullState/index.js | 22 -- .../ContentTemplates/NullState/styles.scss | 23 -- .../ContentTemplates/TemplateForms/index.js | 308 ----------------- .../TemplateForms/styles.scss | 44 --- .../ContentTemplates/TemplateList/index.js | 86 ----- .../ContentTemplates/TemplateList/styles.scss | 61 ---- .../src/components/ContentTemplates/index.js | 66 ---- .../components/ContentTemplates/index.test.js | 159 --------- .../ContentTemplates/sample-data.js | 184 ---------- .../src/components/ContentTemplates/story.js | 218 ------------ .../components/ContentTemplates/styles.scss | 16 - .../src/components/DataTable/MenuColumn.js | 13 +- .../components/DataTable/styles/index.scss | 1 + .../FilePicker/FilePickerHeader/styles.scss | 3 +- .../src/components/FilePicker/index.js | 12 +- .../src/components/FullScreenDialog/index.js | 8 +- .../IngestionJobs/ListView/index.js | 121 ------- .../IngestionJobs/ListView/styles.scss | 40 --- .../IngestionJobs/NullState/index.js | 38 --- .../IngestionJobs/NullState/styles.scss | 13 - .../src/components/IngestionJobs/index.js | 2 - .../src/components/IngestionJobs/story.js | 220 ------------ .../src/components/SDOTable/index.js | 124 ------- .../src/components/SDOTable/story.js | 260 --------------- .../components/Scheduler/ContinuousSection.js | 19 -- .../components/Scheduler/DateTimeSelector.js | 30 -- .../components/Scheduler/ImmediateSection.js | 7 - .../components/Scheduler/LabeledInputGroup.js | 29 -- .../components/Scheduler/OnDemandSection.js | 7 - .../components/Scheduler/RecurringSection.js | 130 -------- .../Scheduler/TimePeriodSelector.js | 45 --- .../src/components/Scheduler/index.js | 267 --------------- .../src/components/Scheduler/story.js | 85 ----- .../src/components/Scheduler/styles.scss | 122 ------- .../SchemaDrivenSelectForm/index.js | 137 -------- .../SchemaDrivenSelectForm/styles.scss | 67 ---- .../components/SourceConfiguration/index.js | 205 ------------ .../SourceConfiguration/index.test.js | 136 -------- .../components/SourceConfiguration/story.js | 99 ------ .../SourceConfiguration/styles.scss | 87 ----- .../SourceManagement/NullState/index.js | 39 --- .../SourceManagement/NullState/styles.scss | 13 - .../SourceManagement/SourceTileView/index.js | 101 ------ .../src/components/SourceManagement/index.js | 2 - .../src/components/SourceManagement/story.js | 59 ---- .../components/SourceManagementForm/index.js | 266 --------------- .../components/SourceManagementForm/story.js | 314 ------------------ .../SourceManagementForm/styles.scss | 40 --- .../src/components/SourceTypeField/index.js | 167 ---------- .../components/SourceTypeField/index.test.js | 23 -- .../src/components/SourceTypeField/story.js | 107 ------ .../components/SourceTypeField/styles.scss | 16 - .../src/components/TopBar/styles.scss | 1 + .../formComponents/DateTimePicker.js | 73 ++-- .../formComponents/TimeRangePicker.js | 37 ++- .../src/components/formComponents/index.js | 1 + .../src/components/formComponents/story.js | 30 +- packages/veritone-react-common/src/index.js | 7 - .../src/styles/global.scss | 2 +- .../src/styles/modules/_variables.scss | 1 + .../src/helpers/api/fetchGraphQLApi.js | 4 +- packages/veritone-widgets/src/build-entry.js | 11 +- .../redux/modules/engineOutputExport/index.js | 145 +++++++- .../src/widgets/ContentTemplate/index.js | 125 ------- .../src/widgets/ContentTemplate/story.js | 186 ----------- .../src/widgets/ContentTemplateForm/index.js | 31 -- .../src/widgets/ContentTemplateForm/story.js | 186 ----------- .../EngineCategoryConfig.js | 58 +++- .../EngineCategoryConfigList.js | 45 ++- .../widgets/EngineOutputExport/index.test.js | 90 ++++- .../widgets/EngineOutputExport/styles.scss | 6 +- .../EngineSelectionRow/index.js | 1 + .../src/widgets/IngestionJobsList/index.js | 59 ---- .../src/widgets/IngestionJobsList/story.js | 245 -------------- .../src/widgets/SDOTable/index.js | 22 -- .../src/widgets/SDOTable/story.js | 120 ------- .../src/widgets/Scheduler/index.js | 36 -- .../src/widgets/Scheduler/story.js | 54 --- .../src/widgets/SourceList/index.js | 65 ---- .../src/widgets/SourceList/story.js | 84 ----- .../src/widgets/SourceManagementForm/index.js | 22 -- .../src/widgets/SourceManagementForm/story.js | 284 ---------------- .../src/widgets/UserProfile/index.js | 21 +- 88 files changed, 474 insertions(+), 6457 deletions(-) delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/ContentTemplateForm/index.js delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/ContentTemplateForm/styles.scss delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/FormCard/index.js delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/FormCard/styles.scss delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/NullState/index.js delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/NullState/styles.scss delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/TemplateForms/index.js delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/TemplateForms/styles.scss delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/TemplateList/index.js delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/TemplateList/styles.scss delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/index.js delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/index.test.js delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/sample-data.js delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/story.js delete mode 100644 packages/veritone-react-common/src/components/ContentTemplates/styles.scss delete mode 100644 packages/veritone-react-common/src/components/IngestionJobs/ListView/index.js delete mode 100644 packages/veritone-react-common/src/components/IngestionJobs/ListView/styles.scss delete mode 100644 packages/veritone-react-common/src/components/IngestionJobs/NullState/index.js delete mode 100644 packages/veritone-react-common/src/components/IngestionJobs/NullState/styles.scss delete mode 100644 packages/veritone-react-common/src/components/IngestionJobs/index.js delete mode 100644 packages/veritone-react-common/src/components/IngestionJobs/story.js delete mode 100644 packages/veritone-react-common/src/components/SDOTable/index.js delete mode 100644 packages/veritone-react-common/src/components/SDOTable/story.js delete mode 100644 packages/veritone-react-common/src/components/Scheduler/ContinuousSection.js delete mode 100644 packages/veritone-react-common/src/components/Scheduler/DateTimeSelector.js delete mode 100644 packages/veritone-react-common/src/components/Scheduler/ImmediateSection.js delete mode 100644 packages/veritone-react-common/src/components/Scheduler/LabeledInputGroup.js delete mode 100644 packages/veritone-react-common/src/components/Scheduler/OnDemandSection.js delete mode 100644 packages/veritone-react-common/src/components/Scheduler/RecurringSection.js delete mode 100644 packages/veritone-react-common/src/components/Scheduler/TimePeriodSelector.js delete mode 100644 packages/veritone-react-common/src/components/Scheduler/index.js delete mode 100644 packages/veritone-react-common/src/components/Scheduler/story.js delete mode 100644 packages/veritone-react-common/src/components/Scheduler/styles.scss delete mode 100644 packages/veritone-react-common/src/components/SourceConfiguration/SchemaDrivenSelectForm/index.js delete mode 100644 packages/veritone-react-common/src/components/SourceConfiguration/SchemaDrivenSelectForm/styles.scss delete mode 100644 packages/veritone-react-common/src/components/SourceConfiguration/index.js delete mode 100644 packages/veritone-react-common/src/components/SourceConfiguration/index.test.js delete mode 100644 packages/veritone-react-common/src/components/SourceConfiguration/story.js delete mode 100644 packages/veritone-react-common/src/components/SourceConfiguration/styles.scss delete mode 100644 packages/veritone-react-common/src/components/SourceManagement/NullState/index.js delete mode 100644 packages/veritone-react-common/src/components/SourceManagement/NullState/styles.scss delete mode 100644 packages/veritone-react-common/src/components/SourceManagement/SourceTileView/index.js delete mode 100644 packages/veritone-react-common/src/components/SourceManagement/index.js delete mode 100644 packages/veritone-react-common/src/components/SourceManagement/story.js delete mode 100644 packages/veritone-react-common/src/components/SourceManagementForm/index.js delete mode 100644 packages/veritone-react-common/src/components/SourceManagementForm/story.js delete mode 100644 packages/veritone-react-common/src/components/SourceManagementForm/styles.scss delete mode 100644 packages/veritone-react-common/src/components/SourceTypeField/index.js delete mode 100644 packages/veritone-react-common/src/components/SourceTypeField/index.test.js delete mode 100644 packages/veritone-react-common/src/components/SourceTypeField/story.js delete mode 100644 packages/veritone-react-common/src/components/SourceTypeField/styles.scss delete mode 100644 packages/veritone-widgets/src/widgets/ContentTemplate/index.js delete mode 100644 packages/veritone-widgets/src/widgets/ContentTemplate/story.js delete mode 100644 packages/veritone-widgets/src/widgets/ContentTemplateForm/index.js delete mode 100644 packages/veritone-widgets/src/widgets/ContentTemplateForm/story.js delete mode 100644 packages/veritone-widgets/src/widgets/IngestionJobsList/index.js delete mode 100644 packages/veritone-widgets/src/widgets/IngestionJobsList/story.js delete mode 100644 packages/veritone-widgets/src/widgets/SDOTable/index.js delete mode 100644 packages/veritone-widgets/src/widgets/SDOTable/story.js delete mode 100644 packages/veritone-widgets/src/widgets/Scheduler/index.js delete mode 100644 packages/veritone-widgets/src/widgets/Scheduler/story.js delete mode 100644 packages/veritone-widgets/src/widgets/SourceList/index.js delete mode 100644 packages/veritone-widgets/src/widgets/SourceList/story.js delete mode 100644 packages/veritone-widgets/src/widgets/SourceManagementForm/index.js delete mode 100644 packages/veritone-widgets/src/widgets/SourceManagementForm/story.js diff --git a/packages/veritone-react-common/src/components/BoundingPolyOverlay/OverlayPositioningProvider.js b/packages/veritone-react-common/src/components/BoundingPolyOverlay/OverlayPositioningProvider.js index 490ac7e93..c84a55ce2 100644 --- a/packages/veritone-react-common/src/components/BoundingPolyOverlay/OverlayPositioningProvider.js +++ b/packages/veritone-react-common/src/components/BoundingPolyOverlay/OverlayPositioningProvider.js @@ -1,5 +1,5 @@ import React from 'react'; -import { node, number, bool } from 'prop-types'; +import { node, number, bool, string } from 'prop-types'; import { isEqual } from 'lodash'; import cx from 'classnames'; import styles from './overlayPositioningProvider.styles.scss'; @@ -15,7 +15,8 @@ export default class OverlayPositioningProvider extends React.Component { contentHeight: number.isRequired, contentWidth: number.isRequired, fixedWidth: bool, - children: node + children: node, + contentClassName: string }; static defaultProps = {}; @@ -97,6 +98,7 @@ export default class OverlayPositioningProvider extends React.Component {
{ - const { templateData, initialTemplates } = this.props; - const data = {}; - - Object.keys(templateData[templateSchemaId].definition.properties).reduce( - (fields, schemaDefProp) => { - data[schemaDefProp] = get( - initialTemplates, - [templateSchemaId, 'data', schemaDefProp], - '' - ); - }, - data - ); - - this.setState(prevState => ({ - contentTemplates: { - [templateSchemaId]: { - ...templateData[templateSchemaId], - data - }, - ...prevState.contentTemplates - } - })); - }; - - removeFromTemplateList = templateSchemaId => { - if (this.state.contentTemplates[templateSchemaId]) { - return this.setState(prevState => { - const contentTemplates = { ...prevState.contentTemplates }; - delete contentTemplates[templateSchemaId]; - - return { contentTemplates }; - }); - } - }; - - updateTemplateDetails = (templateSchemaId, fieldId, value) => { - this.setState(prevState => ({ - contentTemplates: { - ...prevState.contentTemplates, - [templateSchemaId]: { - ...prevState.contentTemplates[templateSchemaId], - data: { - ...prevState.contentTemplates[templateSchemaId].data, - [fieldId]: value - } - } - } - })); - }; - - handleSubmit = e => { - e.preventDefault(); - return this.props.onSubmit({ - contentTemplates: this.state.contentTemplates - }); - }; - - render() { - return ( -
- -
- -
- - ); - } -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/ContentTemplateForm/styles.scss b/packages/veritone-react-common/src/components/ContentTemplates/ContentTemplateForm/styles.scss deleted file mode 100644 index 98f5e1c7b..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/ContentTemplateForm/styles.scss +++ /dev/null @@ -1,11 +0,0 @@ -.btn-container { - position: absolute; - width: 96%; - display: flex; - justify-content: flex-end; - margin-top: -50px; -} - -.form-content-templates { - height: calc(100% - 110px); // Account for header height -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/FormCard/index.js b/packages/veritone-react-common/src/components/ContentTemplates/FormCard/index.js deleted file mode 100644 index df4e7c071..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/FormCard/index.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { any, arrayOf, func, string } from 'prop-types'; - -import Icon from '@material-ui/core/Icon'; -import IconButton from '@material-ui/core/IconButton'; -import styles from './styles.scss'; - -export default class FormCard extends React.Component { - static propTypes = { - fields: arrayOf(any), // take in an array of field elements, i.e. ; styling of form elements is intended to be done by the parent - name: string.isRequired, - remove: func.isRequired, - id: string.isRequired - }; - - handleClick = () => { - this.props.remove(this.props.id); - }; - - render() { - const { name, fields } = this.props; - - return ( -
-
{name}
- - - - {fields.map((field, index) => { - return React.cloneElement(field, { - key: `${name}-field-${index}`, // eslint-disable-line - className: styles.formElements - }); - })} -
- ); - } -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/FormCard/styles.scss b/packages/veritone-react-common/src/components/ContentTemplates/FormCard/styles.scss deleted file mode 100644 index 05ed0c925..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/FormCard/styles.scss +++ /dev/null @@ -1,29 +0,0 @@ -@import 'src/styles/modules/variables'; -@import 'src/styles/modules/muiTypography'; - -.formCard { - width: 60%; - background-color: $fullWhite; - padding: 24px 24px 50px; - position: relative; - box-shadow: 0 0 2px 0 $faint-black, 0 2px 2px 0 $faint-black; - margin-bottom: 30px; - - .name { - @include mui-text('subhead'); - color: $dark-black; - font-weight: 500 !important; - } - - .trashIcon { - height: 14px; - width: 14px; - position: absolute; - top: 15px; - right: 15px; - } - - .formElements { - margin-top: 20px; - } -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/NullState/index.js b/packages/veritone-react-common/src/components/ContentTemplates/NullState/index.js deleted file mode 100644 index 28583998e..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/NullState/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; - -import NullState from 'components/NullState'; -import NullstateImage from 'images/cms-content-templates-null.svg'; - -export default class ContentTemplatesNullState extends React.Component { - render() { - return ( - - ); - } -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/NullState/styles.scss b/packages/veritone-react-common/src/components/ContentTemplates/NullState/styles.scss deleted file mode 100644 index 419cfbaa5..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/NullState/styles.scss +++ /dev/null @@ -1,23 +0,0 @@ -@import 'src/styles/modules/variables'; - -.nullStateView { - width: 100%; - height: 100vh; - margin: auto; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - - .titleText { - color: $dark-black; - font-size: 20px; - font-weight: 300; - line-height: 24px; - margin-bottom: 250px; - } - - .imageObject { - height: auto; - } -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/TemplateForms/index.js b/packages/veritone-react-common/src/components/ContentTemplates/TemplateForms/index.js deleted file mode 100644 index 12e1019c0..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/TemplateForms/index.js +++ /dev/null @@ -1,308 +0,0 @@ -import React from 'react'; -import { string, shape, any, objectOf, func, number } from 'prop-types'; -import { - isObject, - compact, - cloneDeep, - isArray, - isNumber, - toSafeInteger -} from 'lodash'; -import AddIcon from '@material-ui/icons/Add'; -import Icon from '@material-ui/core/Icon'; -import IconButton from '@material-ui/core/IconButton'; - -import SourceTypeField from 'components/SourceTypeField'; -import FormCard from '../FormCard'; -import styles from './styles.scss'; - -export default class TemplateForms extends React.Component { - static propTypes = { - templates: objectOf( - shape({ - id: string.isRequired, - name: string.isRequired, - definition: objectOf(any), - data: objectOf(any) - }) - ).isRequired, - onTemplateDetailsChange: func.isRequired, - onRemoveTemplate: func.isRequired, - textInputMaxRows: number - }; - static defaultProps = {}; - - handleRemoveTemplate = schemaId => { - this.props.onRemoveTemplate(schemaId); - }; - - handleFieldChange = (schemaId, fieldId, type) => event => { - const GEO_REGEX = /^-{0,1}[0-9]+\.[0-9]+, -{0,1}[0-9]+\.[0-9]+$/; - // fieldId can be object/array prop accessors. eg. 'wind.windSpeed' or 'tags.0' - let currentValue; // Maintain root object reference - const fields = fieldId.split('.'); - const rootObject = fields[0]; - let eventValue; - let pointer; - - if (type.includes('boolean')) { - eventValue = event.target.checked; - } else if (type.includes('dateTime')) { - eventValue = event; - } else { - eventValue = event.target.value; - } - - if (type.includes('geoPoint')) { - if (!GEO_REGEX.test(eventValue)) { - eventValue = '0.0, 0.0'; - } - } - - if (fields.length > 1) { - let objectTraverse = fields.slice(1 - fields.length); - if (!!parseInt(objectTraverse[0]) || objectTraverse[0] === '0') { - currentValue = cloneDeep( - this.props.templates[schemaId].data[rootObject] || [''] - ); - } else { - currentValue = Object.assign( - {}, - this.props.templates[schemaId].data[rootObject] - ); - } - pointer = currentValue; - objectTraverse.forEach((field, index) => { - // Initialize any undefined nested objects - if (!isObject(pointer[field]) && index !== objectTraverse.length - 1) { - pointer[field] = {}; - pointer = pointer[field]; - } else { - if (event.target.value) { - pointer[field] = this.parseType(type, eventValue); - } else { - delete pointer[field]; - } - } - }); - } else { - currentValue = this.parseType(type, eventValue); - } - return this.props.onTemplateDetailsChange( - schemaId, - rootObject, - currentValue - ); - }; - - handleArrayElementAdd = (schemaId, fieldId) => $event => { - let curArray = cloneDeep(this.props.templates[schemaId].data[fieldId]); - if (isArray(curArray)) { - curArray.push(''); - this.props.onTemplateDetailsChange(schemaId, fieldId, curArray); - } - }; - - handleArrayElementRemove = (schemaId, fieldId, index) => $event => { - let curArray = cloneDeep(this.props.templates[schemaId].data[fieldId]); - if (isArray(curArray)) { - curArray.splice(index, 1); - this.props.onTemplateDetailsChange(schemaId, fieldId, curArray); - } - }; - - parseType = (type, value) => { - let returnValue = value; - if (type.includes('number')) { - returnValue = parseFloat(value); - } else if (type.includes('integer')) { - returnValue = parseInt(value); - } else if (type.includes('boolean')) { - return value; - } else if (type.includes('dateTime')) { - returnValue = value.toISOString(); - } - return returnValue || ''; - }; - - render() { - const { templates } = this.props; - - return ( -
- {Object.keys(templates).map((schemaId, index) => { - const schemaProps = templates[schemaId].definition.properties; - const formFields = Object.keys(schemaProps).map( - (schemaProp, propIdx) => { - const { type, items } = schemaProps[schemaProp]; - - return ( - type && ( - - ) - ); - } - ); - - return ( - - ); - })} -
- ); - } -} - -function TemplateFormFieldRenderer({ - fieldId, - schemaId, - schemaProp, - type, - items, - title, - value, - objectProperties, - onChange, - depth = 0, - handleArrayElementAdd, - handleArrayElementRemove, - textInputMaxRows, - ...rest -}) { - if (!type) { - return undefined; - } - - let element; - - if (!type.includes('object') && !type.includes('array')) { - const fieldProps = { - id: fieldId, - type, - title, - value: value || '' - }; - - // make all text fields `textarea` inputs - if (type === 'string') { - (fieldProps.multiline = true), - (fieldProps.rowsMax = - textInputMaxRows && - isNumber(textInputMaxRows) && - textInputMaxRows >= 1 - ? toSafeInteger(textInputMaxRows) - : 15); - } - - element = ( - - ); - } - - if (type.includes('array')) { - element = (value || ['']).map((elem, index) => { - return ( -
- - {isArray(value) && value.length > 1 ? ( -
- - - -
- ) : null} -
- ); - }); - element = ( -
- {title} - {element} -
- - - -
-
- ); - } - - if (type.includes('object') && objectProperties) { - element = Object.keys(objectProperties).map(objProp => { - return ( - - ); - }); - element = ( -
- {title} - {element} -
- ); - } - - if (depth) { - element =
{element}
; // eslint-disable-line - } - - return element; -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/TemplateForms/styles.scss b/packages/veritone-react-common/src/components/ContentTemplates/TemplateForms/styles.scss deleted file mode 100644 index 09fee8e24..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/TemplateForms/styles.scss +++ /dev/null @@ -1,44 +0,0 @@ -.formsContainer { - padding-top: 20px; - padding-left: 30px; -} - -.insetSection { - padding-top: 20px; - - & > span { - font-size: 15px; - } -} - -.arrayRow { - display: flex; - flex-direction: row; - - & > div:first-child { - width: 100%; - } -} - -.arrayAdd { - text-align: center; -} - -.arrayRemove { - cursor: pointer; - padding-top: 40px; - padding-left: 10px; -} - -.noHover { - &:hover { - background-color: transparent !important; - } -} - -.arrayAdd, -.arrayRemove { - span { - cursor: pointer; - } -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/TemplateList/index.js b/packages/veritone-react-common/src/components/ContentTemplates/TemplateList/index.js deleted file mode 100644 index 0e3a611cc..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/TemplateList/index.js +++ /dev/null @@ -1,86 +0,0 @@ -import React from 'react'; -import { string, shape, objectOf, func } from 'prop-types'; -import cx from 'classnames'; -import Icon from '@material-ui/core/Icon'; -import IconButton from '@material-ui/core/IconButton'; - -import styles from './styles.scss'; - -export default class TemplateList extends React.Component { - static propTypes = { - templates: objectOf( - shape({ - id: string.isRequired, - name: string.isRequired - }) - ).isRequired, - selectedTemplates: objectOf( - // an array of content template objects that had already been added to the source - shape({ - id: string - }) - ), - addTemplate: func.isRequired, - removeTemplate: func.isRequired - }; - - static defaultProps = { - selectedTemplates: {} - }; - - addTemplate = schemaId => () => { - this.props.addTemplate(schemaId); - }; - - removeTemplate = schemaId => () => { - this.props.removeTemplate(schemaId); - }; - - buildTemplateList = () => { - const { templates, selectedTemplates } = this.props; - - return Object.keys(templates).map((schemaId, index) => { - const isAdded = !!selectedTemplates[schemaId]; - - return ( -
-
- {templates[schemaId].name} -
- {isAdded ? ( - - - - ) : ( - - - - )} -
- ); - }); - }; - - render() { - return ( -
-
Content Templates
-
- Add more information to the files you ingest to help organize, search - and filter quickly. -
- {this.buildTemplateList()} -
- ); - } -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/TemplateList/styles.scss b/packages/veritone-react-common/src/components/ContentTemplates/TemplateList/styles.scss deleted file mode 100644 index ead196b8d..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/TemplateList/styles.scss +++ /dev/null @@ -1,61 +0,0 @@ -@import 'src/styles/modules/variables'; -@import 'src/styles/modules/muiTypography'; - -.template-list { - height: 100%; - overflow: auto; - border-right: 6px solid $grey-2; - - .title { - @include mui-text('title'); - - color: $dark-black; - padding-left: 20px; - padding-top: 20px; - } - - .description { - @include mui-text('body1'); - - color: $light-black; - margin-top: 5px; - margin-bottom: 30px; - padding-left: 20px; - padding-right: 30px; - } - - .templateRow { - height: 40px; - width: 100%; - padding-left: 20px; - - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - - .name { - font-size: 14px; - color: $dark-black; - } - - .addedTemplate { - font-weight: 500; - } - - .trashIcon { - height: auto; - width: auto; - padding: 4px; - margin-right: 20px; - - &:hover { - background-color: transparent !important; - } - } - - &:hover { - background-color: $grey-2; - } - } -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/index.js b/packages/veritone-react-common/src/components/ContentTemplates/index.js deleted file mode 100644 index c328c9dd8..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/index.js +++ /dev/null @@ -1,66 +0,0 @@ -import React from 'react'; -import { string, shape, objectOf, any, func, number } from 'prop-types'; - -import TemplateForms from './TemplateForms'; -import TemplateList from './TemplateList'; -import ContentTemplatesNullState from './NullState'; -import styles from './styles.scss'; - -export default class ContentTemplates extends React.Component { - static propTypes = { - templateData: objectOf( - shape({ - id: string, - name: string.isRequired, - status: string, - definition: objectOf(any) - }) - ).isRequired, - selectedTemplateSchemas: objectOf( - shape({ - id: string, - name: string.isRequired, - status: string, - definition: objectOf(any), - data: objectOf(any) - }) - ), - onAddTemplate: func.isRequired, - onRemoveTemplate: func.isRequired, - onInputChange: func.isRequired, - textInputMaxRows: number - }; - static defaultProps = { - selectedTemplateSchemas: {} - }; - - render() { - const { selectedTemplateSchemas } = this.props; - const showNullstate = !Object.keys(selectedTemplateSchemas).length; - - return ( -
-
- -
-
- {showNullstate ? ( - - ) : ( - - )} -
-
- ); - } -} diff --git a/packages/veritone-react-common/src/components/ContentTemplates/index.test.js b/packages/veritone-react-common/src/components/ContentTemplates/index.test.js deleted file mode 100644 index 536f72718..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/index.test.js +++ /dev/null @@ -1,159 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import IconButton from '@material-ui/core/IconButton'; -import { templateData, initialTemplates } from './sample-data'; -import TemplateList from './TemplateList'; -import TemplateForms from './TemplateForms'; -import FormCard from './FormCard'; -import ContentTemplateForm from './ContentTemplateForm'; - -describe('Content Templates', () => { - const handleSubmit = jest.fn(); - - it('should render initial templates if supplied', () => { - const wrapper = mount( - - ); - - const iconButtons = wrapper.find(TemplateList).find(IconButton); - const formCardContainer = wrapper.find(TemplateForms).find(FormCard); - - expect(iconButtons).toHaveLength(2); - expect(formCardContainer).toHaveLength(1); - }); - it('should not render initial templates if supplied', () => { - const wrapper = mount( - - ); - - const iconButtons = wrapper.find(TemplateList).find(IconButton); - const formCardContainer = wrapper.find(TemplateForms).find(FormCard); - - expect(iconButtons).toHaveLength(2); - expect(formCardContainer).toHaveLength(0); - }); - it('should add template', () => { - const wrapper = mount( - - ); - - let formCardContainer = wrapper.find(TemplateForms).find(FormCard); - - expect(formCardContainer).toHaveLength(1); - - wrapper - .find(TemplateList) - .find('.icon-zoom-in') - .first() - .simulate('click'); - - formCardContainer = wrapper.find(TemplateForms).find(FormCard); - expect(formCardContainer).toHaveLength(2); - }); - it('should remove template', () => { - const wrapper = mount( - - ); - - let formCardContainer = wrapper.find(TemplateForms).find(FormCard); - expect(formCardContainer).toHaveLength(1); - - wrapper - .find(TemplateList) - .find('.icon-trash') - .first() - .simulate('click'); - - formCardContainer = wrapper.find(TemplateForms).find(FormCard); - expect(formCardContainer).toHaveLength(0); - }); - it('should submit form', () => { - const wrapper = mount( - - ); - - wrapper.find('button[type="submit"]').simulate('submit'); - expect(handleSubmit.mock.calls.length).toBe(1); - }); - it('should update template details', () => { - const testFn = jest.fn(); - const wrapper = mount( - - ); - - const firstTemplate = Object.keys(templateData)[0]; - const firstTemplateDefProp = Object.keys( - templateData[firstTemplate].definition.properties - )[0]; - const templateDataField = `${firstTemplateDefProp}-${ - templateData[firstTemplate].id - }`; - const inputVal = 'Hello'; - - const formField = wrapper.find(`#${templateDataField}`).last(); - - formField.simulate('change', { target: { value: inputVal } }); - expect( - wrapper - .find(`#${templateDataField}`) - .last() - .props().value - ).toEqual(inputVal); - - wrapper.find('button[type="submit"]').simulate('submit'); - expect(testFn.mock.calls[0][0]).toHaveProperty( - `contentTemplates.${ - templateData[firstTemplate].id - }.data.${firstTemplateDefProp}`, - inputVal - ); - }); - it('should only allow valid row size for text input fields', () => { - const maxRows = [[-1, 15], [0, 15], [5, 5], [1.5, 1], [-1.5, 15]]; - - maxRows.forEach(rowSize => { - const wrapper = mount( - - ); - - const firstTemplate = Object.keys(templateData)[0]; - const firstTemplateDefProp = Object.keys( - templateData[firstTemplate].definition.properties - )[0]; - const templateDataField = `${firstTemplateDefProp}-${ - templateData[firstTemplate].id - }`; - - const formField = wrapper.find(`#${templateDataField}`).first(); - expect(formField.prop('rowsMax')).toEqual(rowSize[1]); - }); - }); -}); diff --git a/packages/veritone-react-common/src/components/ContentTemplates/sample-data.js b/packages/veritone-react-common/src/components/ContentTemplates/sample-data.js deleted file mode 100644 index a5aa06f50..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/sample-data.js +++ /dev/null @@ -1,184 +0,0 @@ -import { has } from 'lodash'; - -// CONTENT TEMPLATES SETUP -const templateSource = { - data: { - source: { - id: '666', - name: 'KWOL--FM', - contentTemplates: [ - { - schemaId: 'schemaGuid1', - data: { - url: 'twitter.com', - username: 'THEREALTRUMP' - } - } - ] - } - } -}; - -const dataSchemas = { - data: { - dataRegistries: { - records: [ - { - name: 'Twitter Schema', - schemas: { - records: [ - { - id: 'schemaGuid1', - status: 'published', - definition: { - properties: { - url: { - type: 'string', - title: 'URL' - }, - username: { - type: 'string' - }, - testArray: { - type: 'array', - title: 'Array Test', - items: { - type: 'number', - title: 'item title' - } - }, - testObject: { - type: 'object', - title: 'Object Test', - properties: { - objectString: { - type: 'string', - title: 'Object String' - }, - objectNumber: { - type: 'number', - title: 'Object Number' - } - } - }, - number: { - type: 'number', - title: 'Number' - }, - geoLocation: { - type: 'geoPoint', - title: 'geoLocation' - }, - trueOrFalse: { - type: 'boolean', - title: 'Boolean' - }, - datetimeEnd: { - type: 'dateTime', - title: 'datetimeEnd' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema 2' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - }, - password: { - type: 'string' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - test: 'citest' - } - }, - { - id: 'schemaGuid2', - status: 'draft', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - } - } - } - } - ] - } - } - ] - } - } -}; - -function createTemplateData(dataSchemas) { - const templateSchemas = {}; - // array of data registries containing an array of schemas - dataSchemas.reduce((schemaStore, registryData) => { - registryData.schemas.records.forEach(schema => { - // only take schemas that are 'published' and also define field types - if ( - schema.status === 'published' && - has(schema.definition, 'properties') - ) { - schemaStore[schema.id] = { - name: registryData.name, - ...schema - }; - } - }); - }, templateSchemas); - - return templateSchemas; -} - -function createInitialTemplates(templateSources) { - const selectedTemplateSchemas = {}; - - const templateSchemas = createTemplateData( - dataSchemas.data.dataRegistries.records - ); - templateSources.forEach(template => { - if (has(templateSchemas, template.schemaId)) { - selectedTemplateSchemas[template.schemaId] = - templateSchemas[template.schemaId]; - if (template.data) { - // if we need to fill out the form with pre-data - selectedTemplateSchemas[template.schemaId].data = template.data; - } - } - }); - - return selectedTemplateSchemas; -} - -export const templateData = createTemplateData( - dataSchemas.data.dataRegistries.records -); -export const initialTemplates = createInitialTemplates( - templateSource.data.source.contentTemplates -); diff --git a/packages/veritone-react-common/src/components/ContentTemplates/story.js b/packages/veritone-react-common/src/components/ContentTemplates/story.js deleted file mode 100644 index f2d6743f1..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/story.js +++ /dev/null @@ -1,218 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { has, noop } from 'lodash'; -import NullState from './NullState'; -import TemplateList from './TemplateList'; -import TemplateForms from './TemplateForms'; -import ContentTemplateForm from './ContentTemplateForm'; - -// CONTENT TEMPLATES SETUP -const templateSource = { - data: { - source: { - id: '666', - name: 'KWOL--FM', - contentTemplates: [ - { - schemaId: 'schemaGuid1', - data: { - url: 'twitter.com', - username: 'THEREALTRUMP' - } - } - ] - } - } -}; - -const dataSchemas = { - data: { - dataRegistries: { - records: [ - { - name: 'Twitter Schema', - schemas: { - records: [ - { - id: 'schemaGuid1', - status: 'published', - definition: { - properties: { - url: { - type: 'string', - title: 'URL' - }, - username: { - type: 'string' - }, - testArray: { - type: 'array', - title: 'Array Test', - items: { - type: 'number', - title: 'item title' - } - }, - testObject: { - type: 'object', - title: 'Object Test', - properties: { - objectString: { - type: 'string', - title: 'Object String' - }, - objectNumber: { - type: 'number', - title: 'Object Number' - } - } - }, - number: { - type: 'number', - title: 'Number' - }, - geoLocation: { - type: 'geoPoint', - title: 'geoLocation' - }, - trueOrFalse: { - type: 'boolean', - title: 'Boolean' - }, - datetimeEnd: { - type: 'dateTime', - title: 'datetimeEnd' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema 2' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - }, - password: { - type: 'string' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - test: 'citest' - } - }, - { - id: 'schemaGuid2', - status: 'draft', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - } - } - } - } - ] - } - } - ] - } - } -}; - -function createTemplateData(dataSchemas) { - const templateSchemas = {}; - // array of data registries containing an array of schemas - dataSchemas.reduce((schemaStore, registryData) => { - registryData.schemas.records.forEach(schema => { - // only take schemas that are 'published' and also define field types - if ( - schema.status === 'published' && - has(schema.definition, 'properties') - ) { - schemaStore[schema.id] = { - name: registryData.name, - ...schema - }; - } - }); - }, templateSchemas); - - return templateSchemas; -} - -function createInitialTemplates(templateSources) { - const selectedTemplateSchemas = {}; - - const templateSchemas = createTemplateData( - dataSchemas.data.dataRegistries.records - ); - templateSources.forEach(template => { - if (has(templateSchemas, template.schemaId)) { - selectedTemplateSchemas[template.schemaId] = - templateSchemas[template.schemaId]; - if (template.data) { - // if we need to fill out the form with pre-data - selectedTemplateSchemas[template.schemaId].data = template.data; - } - } - }); - - return selectedTemplateSchemas; -} - -const templateData = createTemplateData( - dataSchemas.data.dataRegistries.records -); -const initialTemplates = createInitialTemplates( - templateSource.data.source.contentTemplates -); - -function logFormData(formData) { - console.log(formData); -} - -storiesOf('Content Templates', module) - .add('Null State', () => ) - .add('Template List', () => ( - - )) - .add('Form Cards', () => ( - - )) - .add('Form', () => ( - - )); diff --git a/packages/veritone-react-common/src/components/ContentTemplates/styles.scss b/packages/veritone-react-common/src/components/ContentTemplates/styles.scss deleted file mode 100644 index 60a4b178c..000000000 --- a/packages/veritone-react-common/src/components/ContentTemplates/styles.scss +++ /dev/null @@ -1,16 +0,0 @@ -.templatePage { - height: 100%; - width: 100%; - display: flex; - flex-direction: row; -} - -.template-list-container { - width: 30%; -} - -.content-templates { - width: 70%; - height: 100%; - overflow-y: auto; -} diff --git a/packages/veritone-react-common/src/components/DataTable/MenuColumn.js b/packages/veritone-react-common/src/components/DataTable/MenuColumn.js index cf30c4d04..ac37221fd 100644 --- a/packages/veritone-react-common/src/components/DataTable/MenuColumn.js +++ b/packages/veritone-react-common/src/components/DataTable/MenuColumn.js @@ -25,6 +25,7 @@ export default class MenuColumn extends React.Component { additionalActions: arrayOf(string), excludeActions: arrayOf(string), transformLabel: func, + transformActions: func, style: objectOf(any), dataKey: string }; @@ -33,6 +34,7 @@ export default class MenuColumn extends React.Component { onSelectItem: noop, protectedActions: ['delete'], transformLabel: l => l, + transformActions: a => a, additionalActions: [], excludeActions: [], dataKey: '' @@ -75,11 +77,14 @@ export default class MenuColumn extends React.Component { ].filter(a => !!a); } - renderMenuCell = (actions = [], ...rest) => { + renderMenuCell = (actions = [], data, ...rest) => { const allActions = - this.props.actions || + this.props.transformActions(this.props.actions, data) || difference( - [...actions, ...this.props.additionalActions], + [ + ...this.props.transformActions(actions, data), + ...this.props.additionalActions + ], this.props.excludeActions ); @@ -109,7 +114,7 @@ export default class MenuColumn extends React.Component { ) : ( {startCase(camelCase(this.props.transformLabel(s)))} diff --git a/packages/veritone-react-common/src/components/DataTable/styles/index.scss b/packages/veritone-react-common/src/components/DataTable/styles/index.scss index 73fded28e..1dd350220 100644 --- a/packages/veritone-react-common/src/components/DataTable/styles/index.scss +++ b/packages/veritone-react-common/src/components/DataTable/styles/index.scss @@ -17,6 +17,7 @@ } .table-cell { + white-space: normal; padding-right: 24px !important; } diff --git a/packages/veritone-react-common/src/components/FilePicker/FilePickerHeader/styles.scss b/packages/veritone-react-common/src/components/FilePicker/FilePickerHeader/styles.scss index 0bad7b519..0e04c3220 100644 --- a/packages/veritone-react-common/src/components/FilePicker/FilePickerHeader/styles.scss +++ b/packages/veritone-react-common/src/components/FilePicker/FilePickerHeader/styles.scss @@ -2,7 +2,7 @@ .filePickerHeader { width: 100%; - height: 88px; + min-height: 93px; display: flex; flex-direction: column; background-color: $grey-1; @@ -10,6 +10,7 @@ } .filePickerTitle { + flex: auto; font-size: 18px; padding-left: 20px; padding-top: 20px; diff --git a/packages/veritone-react-common/src/components/FilePicker/index.js b/packages/veritone-react-common/src/components/FilePicker/index.js index e1bf69b7a..4e6340b55 100644 --- a/packages/veritone-react-common/src/components/FilePicker/index.js +++ b/packages/veritone-react-common/src/components/FilePicker/index.js @@ -96,13 +96,15 @@ class FilePicker extends Component { }; handlePickFiles = () => { - this.props.onPickFiles(this.state.files); - - this.setState({ - files: [] - }); + const files = this.state.files; this.clearErrorMessage(); + this.setState( + { + files: [] + }, + () => this.props.onPickFiles(files) + ); }; clearErrorMessage() { diff --git a/packages/veritone-react-common/src/components/FullScreenDialog/index.js b/packages/veritone-react-common/src/components/FullScreenDialog/index.js index 5bcd0fec3..f683495b6 100644 --- a/packages/veritone-react-common/src/components/FullScreenDialog/index.js +++ b/packages/veritone-react-common/src/components/FullScreenDialog/index.js @@ -1,20 +1,22 @@ import React from 'react'; import cx from 'classnames'; -import { node, bool } from 'prop-types'; +import { node, bool, string } from 'prop-types'; import styles from './styles.scss'; export default class FullScreenDialog extends React.Component { static propTypes = { children: node, - open: bool + open: bool, + className: string }; static defaultProps = {}; render() { const containerClasses = cx( styles['dialog'], - this.props.open && styles['dialog--is-open'] + this.props.open && styles['dialog--is-open'], + this.props.className ); return
{this.props.children}
; diff --git a/packages/veritone-react-common/src/components/IngestionJobs/ListView/index.js b/packages/veritone-react-common/src/components/IngestionJobs/ListView/index.js deleted file mode 100644 index b14e63e96..000000000 --- a/packages/veritone-react-common/src/components/IngestionJobs/ListView/index.js +++ /dev/null @@ -1,121 +0,0 @@ -import React from 'react'; - -import { arrayOf, any, objectOf, bool, func } from 'prop-types'; - -import { Table, PaginatedTable, Column } from 'components/DataTable'; -import MenuColumn from 'components/DataTable/MenuColumn'; -import StatusPill from 'components/StatusPill'; -import { format } from 'date-fns'; -import { map, uniq, omit, noop } from 'lodash'; - -import styles from './styles.scss'; - -export default class IngestionJobTileView extends React.Component { - static propTypes = { - jobs: arrayOf(objectOf(any)).isRequired, // an array of source objects - onSelectJob: func, - onSelectMenuItem: func, - paginate: bool, - onFetchData: func - }; - - static defaultProps = { - onSelectJob: noop, - onSelectMenuItem: noop, - onFetchData: noop - }; - - getIngestionJobData = i => { - return this.props.jobs[i]; - }; - - renderEnginesIcons = taskTemplates => { - const icons = uniq(map(taskTemplates.records, 'engine.category.iconClass')); - - return ( - - {icons.length ? ( - icons.map( - icon => (icon ? : undefined) - ) - ) : ( - {'-'} - )} - - ); - }; - - renderAdapter = ingestionJobEngine => { - return ingestionJobEngine ? ingestionJobEngine.name : '-'; - }; - - renderIngestionType = ingestionJobEngine => { - return ingestionJobEngine ? ingestionJobEngine.category.name : '-'; - }; - - renderLastIngestion = mostRecentJob => { - return mostRecentJob - ? format(mostRecentJob.createdDateTime, 'M/D/YYYY h:mm A') - : '-'; - }; - - renderStatus = isActive => { - return ; - }; - - render() { - const TableComp = this.props.paginate ? PaginatedTable : Table; - const tableProps = omit(this.props, ['jobs', 'paginate', 'onFetchData']); - const ingestionJobKey = - 'ingestionJob.records[0].taskTemplates.records[0].engine'; - - if (this.props.paginate) { - tableProps.onShowCellRange = this.props.onFetchData; - } - - return ( - - - - - - - - - - ); - } -} diff --git a/packages/veritone-react-common/src/components/IngestionJobs/ListView/styles.scss b/packages/veritone-react-common/src/components/IngestionJobs/ListView/styles.scss deleted file mode 100644 index d7ad74ef2..000000000 --- a/packages/veritone-react-common/src/components/IngestionJobs/ListView/styles.scss +++ /dev/null @@ -1,40 +0,0 @@ -.tableTitleRow { - height: 62px; - width: 100%; - display: flex; - flex-direction: row; - border-bottom: 1px solid rgba(0, 0, 0, 0.12); - - .checkbox { - margin-left: 25px; - align-self: center; - } - - .titleTextGroup { - display: flex; - flex-direction: row; - justify-content: space-between; - width: 100%; - - .tableTitle { - height: 14px; - color: rgba(0, 0, 0, 0.54); - font-size: 12px; - font-weight: 500; - line-height: 14px; - align-self: center; - width: 17%; - padding-right: 5px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - } -} - -.engineIcons { - display: inline-flex; - justify-content: space-evenly; - align-content: center; - align-items: center; -} diff --git a/packages/veritone-react-common/src/components/IngestionJobs/NullState/index.js b/packages/veritone-react-common/src/components/IngestionJobs/NullState/index.js deleted file mode 100644 index 23d4281ce..000000000 --- a/packages/veritone-react-common/src/components/IngestionJobs/NullState/index.js +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; - -import { func } from 'prop-types'; - -import NullState from 'components/NullState'; -import NullstateImage from 'images/cms-ingestion-jobs-null.svg'; -import styles from './styles.scss'; - -export default class IngestionJobNullstate extends React.Component { - static propTypes = { - onClick: func.isRequired - }; - - render() { - return ( - -
- If you need help getting started, take a look at the -
-
How to Ingest a Data Set
-
- ); - } -} diff --git a/packages/veritone-react-common/src/components/IngestionJobs/NullState/styles.scss b/packages/veritone-react-common/src/components/IngestionJobs/NullState/styles.scss deleted file mode 100644 index be9284782..000000000 --- a/packages/veritone-react-common/src/components/IngestionJobs/NullState/styles.scss +++ /dev/null @@ -1,13 +0,0 @@ -@import 'src/styles/modules/variables'; - -.greyText { - color: $light-black; - font-size: 14px; - line-height: 18px; -} - -.linkText { - color: $blue-1; - font-size: 14px; - line-height: 18px; -} diff --git a/packages/veritone-react-common/src/components/IngestionJobs/index.js b/packages/veritone-react-common/src/components/IngestionJobs/index.js deleted file mode 100644 index c5aa06321..000000000 --- a/packages/veritone-react-common/src/components/IngestionJobs/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export ListView from './ListView'; -export NullState from './NullState'; diff --git a/packages/veritone-react-common/src/components/IngestionJobs/story.js b/packages/veritone-react-common/src/components/IngestionJobs/story.js deleted file mode 100644 index 716dd1324..000000000 --- a/packages/veritone-react-common/src/components/IngestionJobs/story.js +++ /dev/null @@ -1,220 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { noop } from 'lodash'; -import ListView from './ListView'; -import NullState from './NullState'; - -const jobInfo = { - data: { - scheduledJobs: { - records: [ - { - id: '35986', - isActive: true, - name: 'test time', - jobs: { - records: [ - { - id: '00b6b071-86b9-43f7-826b-9dd75aeb6e93', - createdDateTime: '2018-04-10T18:36:26.000Z' - }, - { - id: '3902249e-edd1-4296-9ba1-3a30b14eb2ac', - createdDateTime: '2018-04-10T05:04:23.000Z' - }, - { - id: 'c019cb93-2fbe-4a38-8640-a567aeefd574', - createdDateTime: '2018-04-10T04:53:35.000Z' - } - ] - }, - jobTemplates: { - records: [ - { - taskTemplates: { - records: [ - { - engineId: 'thumbnail-generator', - id: '600d313f-fc9b-4374-b8d7-e452a3c050af', - engine: { - name: 'Thumbnail generation', - category: { - name: 'Thumbnail', - id: 'f951fbf9-aa69-47a2-87c8-12dfb51a1f18', - type: { - name: 'Cognition' - }, - iconClass: 'icon-transcription' - }, - validStateActions: ['disable'] - } - }, - { - engineId: 'd1bc57fe-675d-435d-9f4d-2f074485ec55', - id: '33c454e5-308f-4752-ba01-5c283520b91f', - engine: { - name: 'Kurento Adapter', - category: { - name: 'Push', - id: '0b10da6b-3485-496c-a2cb-aabf59a6352d', - type: { - name: 'Ingestion' - }, - iconClass: null - }, - validStateActions: ['disable'] - } - } - ] - } - } - ] - }, - ingestionJob: { - records: [ - { - id: '592e2225-d97c-4dca-8b96-26b81adcd3a6', - taskTemplates: { - records: [ - { - id: 'ae7e7bd0-95a4-4cda-a42d-9e0c068ad4f6', - engine: { - id: 'b79d94cc-5b95-4bbd-ac01-f54b147f406f', - name: 'Google Drive Adapter', - category: { - name: 'Pull', - id: '4b150c85-82d0-4a18-b7fb-63e4a58dfcce', - type: { - name: 'Ingestion' - }, - iconClass: null - }, - validStateActions: ['disable'] - } - } - ] - } - } - ] - } - }, - { - id: '35982', - isActive: true, - name: 'give me my weather data pleasezzzz', - jobs: { - records: [ - { - id: '8fb9d671-b3a3-491a-8c54-1ce1a240f6ae', - createdDateTime: '2018-04-10T04:48:17.000Z' - }, - { - id: '4944ba03-9a27-40e5-b340-e2a6f2e63369', - createdDateTime: '2018-04-10T01:58:39.000Z' - }, - { - id: 'e749c250-28f1-48d9-9499-4912ade80be4', - createdDateTime: '2018-04-10T00:53:27.000Z' - } - ] - }, - jobTemplates: { - records: [ - { - taskTemplates: { - records: [ - { - engineId: 'transcode-ffmpeg', - id: '7d2f45bf-3606-4ec7-aaf8-c643db28cea2', - engine: { - name: 'Cerebral', - category: { - name: 'Transcode', - id: '581dbb32-ea5b-4458-bd15-8094942345e3', - type: { - name: 'Cognition' - }, - iconClass: 'icon-engine-transcode' - }, - validStateActions: ['disable'] - } - }, - { - engineId: '4d0b2407-f2af-4f19-bdfc-83f74981790a', - id: 'c65685fd-a0d6-481a-9596-9e4ce581747e', - engine: { - name: 'Open Weather Adapter', - category: { - name: 'Pull', - id: '4b150c85-82d0-4a18-b7fb-63e4a58dfcce', - type: { - name: 'Ingestion' - }, - iconClass: null - }, - validStateActions: ['disable'] - } - } - ] - } - } - ] - }, - ingestionJob: { - records: [ - { - id: '739a10d1-fb04-402a-aa0e-2db79088436a', - taskTemplates: { - records: [ - { - id: '6f0b3833-b7c1-415a-b3f1-ded7ffad86a1', - engine: { - id: 'd1bc57fe-675d-435d-9f4d-2f074485ec55', - name: 'Push Adapter', - category: { - name: 'Push', - id: '0b10da6b-3485-496c-a2cb-aabf59a6352d', - type: { - name: 'Ingestion' - }, - iconClass: null - }, - validStateActions: ['disable'] - } - } - ] - } - } - ] - } - } - ] - } - } -}; - -function handleSelectJob(row, dataKey, event) { - if (event && event.currentTarget.id === 'menu') { - return; - } - console.log('row, dataKey:', row, dataKey); -} - -function handleSelectMenuItem(menuAction, dataKeyValue, event) { - console.log( - 'menuAction, dataKeyValue, event:', - menuAction, - dataKeyValue, - event - ); -} - -storiesOf('IngestionJobs', module) - .add('List', () => ( - - )) - .add('NullState', () => ); diff --git a/packages/veritone-react-common/src/components/SDOTable/index.js b/packages/veritone-react-common/src/components/SDOTable/index.js deleted file mode 100644 index 99a579233..000000000 --- a/packages/veritone-react-common/src/components/SDOTable/index.js +++ /dev/null @@ -1,124 +0,0 @@ -import React from 'react'; -import { arrayOf, object, objectOf, bool, number, func } from 'prop-types'; -import { Table, PaginatedTable, Column } from 'components/DataTable'; -import { map, startCase, partial, omit } from 'lodash'; -import DotDotDot from 'react-dotdotdot'; -import { format } from 'date-fns'; - -const IntegerFormatter = new Intl.NumberFormat('en-US', { - maximumFractionDigits: 0 -}); - -const NumberFormatter = new Intl.NumberFormat('en-US', {}); - -export default class SDOTable extends React.Component { - static propTypes = { - data: arrayOf(object).isRequired, - schema: objectOf(object).isRequired, - paginate: bool, - onCellClick: func, - focusedRow: number, - renderFocusedRowDetails: func - }; - - static defaultProps = { - paginate: false - }; - - getRowData = i => { - return this.props.data[i]; - }; - - renderCell = (data, dataType) => { - let formattedData; - - switch (dataType) { - case 'dateTime': - formattedData = format(data, 'M/D/YYYY h:mm A'); - break; - case 'geoPoint': - formattedData = `[${data}]`; - break; - case 'integer': - formattedData = Number.isInteger(data) - ? IntegerFormatter.format(data) - : data; - break; - case 'number': - formattedData = !Number.isNaN(data) - ? NumberFormatter.format(data) - : data; - break; - default: - formattedData = data; - } - - return {formattedData}; - }; - - buildColumnsForObjectTypeProperty = (propDetails, propKey) => { - const allProps = {}; - this.flattenAllObjectTypeProperties(allProps, propDetails, propKey); - return map(allProps, (nestedPropDetails, nestedProp) => ( - - )); - }; - - flattenAllObjectTypeProperties = (allProps, propDetails, propKey) => { - for (let nestedPropKey in propDetails.properties) { - if (propDetails.properties[nestedPropKey].type === 'object') { - this.flattenAllObjectTypeProperties( - allProps, - propDetails.properties[nestedPropKey], - `${propKey}.${nestedPropKey}` - ); - } else { - allProps[`${propKey}.${nestedPropKey}`] = - propDetails.properties[nestedPropKey]; - } - } - }; - - render() { - const tableProps = omit(this.props, ['data', 'schema', 'paginate']); - const TableComponent = this.props.paginate ? PaginatedTable : Table; - const tableColumns = map(this.props.schema, (propDetails, prop) => { - if (propDetails.type === 'object') { - return this.buildColumnsForObjectTypeProperty(propDetails, prop); - } - return ( - - ); - }); - - return ( - - {tableColumns} - - ); - } -} diff --git a/packages/veritone-react-common/src/components/SDOTable/story.js b/packages/veritone-react-common/src/components/SDOTable/story.js deleted file mode 100644 index 2d443bb9d..000000000 --- a/packages/veritone-react-common/src/components/SDOTable/story.js +++ /dev/null @@ -1,260 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; - -import SDOTable from 'components/SDOTable'; - -const sdoData = [ - { - humidity: 54, - pressure: 1019, - windSpeed: 4.7, - visibility: 16093, - windDegree: 40, - datetimeEnd: '2018-02-21T23:00:00.000Z', - geoLocation: '34.05, -118.24', - temperature: 55.71, - locationName: 'Los Angeles', - datetimeStart: '2018-02-21T22:00:00.000Z', - temperatureMax: 59, - temperatureMin: 51.8 - }, - { - humidity: 100, - pressure: 1000, - windSpeed: 4.7, - visibility: 16093, - windDegree: 40, - datetimeEnd: '2018-02-21T23:00:00.000Z', - geoLocation: '34.05, -118.24', - temperature: 55.71, - locationName: 'Los Angeles', - datetimeStart: '2018-02-21T22:00:00.000Z', - temperatureMax: 59, - temperatureMin: 51.8 - } -]; - -const schemaData = { - humidity: { - $id: '/properties/humidity', - type: 'integer' - }, - pressure: { - $id: '/properties/pressure', - type: 'integer' - }, - windSpeed: { - $id: '/properties/windSpeed', - type: 'number' - }, - visibility: { - $id: '/properties/visibility', - type: 'integer' - }, - windDegree: { - $id: '/properties/windDegree', - type: 'number' - }, - datetimeEnd: { - $id: '/properties/datetimeEnd', - type: 'dateTime' - }, - geoLocation: { - $id: '/properties/geoLocation', - type: 'geoPoint' - }, - temperature: { - $id: '/properties/temperature', - type: 'number' - }, - locationName: { - $id: '/properties/locationName', - type: 'string', - title: 'City Name' - }, - datetimeStart: { - $id: '/properties/datetimeStart', - type: 'dateTime' - }, - temperatureMax: { - $id: '/properties/temperatureMax', - type: 'number' - }, - temperatureMin: { - $id: '/properties/temperatureMin', - type: 'number' - } -}; - -const nestedSdoData = [ - { - demographics: { - male: { - age65: 189290, - total: 367646, - age18_24: 0, - age25_34: 15464, - age35_49: 32655, - age50_54: 46684, - age55_64: 83553 - }, - total: 767342, - female: { - age65: 196927, - total: 399696, - age18_24: 13434, - age25_34: 19284, - age35_49: 42347, - age50_54: 50906, - age55_64: 76798 - } - }, - isAverage: true, - fileName: 'AVG Calculation', - networkCode: 'CNN', - programName: 'UNKNOWN', - datetimeStart: '2018-02-01T22:00:26.000Z', - datetimeEnd: '2018-02-01T22:02:28.000Z', - viewershipType: 'LV7', - uniqueCode: 'SDO 1' - }, - { - demographics: { - male: { - age65: 1, - total: 2, - age18_24: 3, - age25_34: 4, - age35_49: 5, - age50_54: 6, - age55_64: 7 - }, - total: 200, - female: { - age65: 9, - total: 10, - age18_24: 11, - age25_34: 12, - age35_49: 13, - age50_54: 14, - age55_64: 15 - } - }, - isAverage: true, - fileName: 'AVG Calculation', - networkCode: 'CNN', - programName: 'UNKNOWN', - datetimeStart: '2018-02-01T22:00:26.000Z', - datetimeEnd: '2018-02-01T22:02:28.000Z', - viewershipType: 'LV7', - uniqueCode: 'SDO 2' - } -]; - -const twoLevelDeepSchemaData = { - id: { $id: '/properties/id', type: 'string' }, - line: { $id: '/properties/line', type: 'string' }, - dataId: { $id: '/properties/dataId', type: 'string' }, - fileName: { $id: '/properties/fileName', type: 'string' }, - uniqueCode: { $id: '/properties/uniqueCode', type: 'string' }, - datetimeEnd: { $id: '/properties/datetimeEnd', type: 'string' }, - networkCode: { - $id: '/properties/decorators/properties/networkCode', - type: 'string' - }, - programName: { $id: '/properties/programName', type: 'string' }, - demographics: { - $id: '/properties/demographics', - type: 'object', - properties: { - male: { - $id: '/properties/demographics/properties/male', - type: 'object', - properties: { - age65: { - $id: '/properties/demographics/properties/male/properties/age65', - type: 'integer' - }, - total: { - $id: '/properties/demographics/properties/male/properties/total', - type: 'integer' - }, - age18_24: { - $id: '/properties/demographics/properties/male/properties/age18_24', - type: 'integer' - }, - age25_34: { - $id: '/properties/demographics/properties/male/properties/age25_34', - type: 'integer' - }, - age35_49: { - $id: '/properties/demographics/properties/male/properties/age35_44', - type: 'integer' - }, - age50_54: { - $id: '/properties/demographics/properties/male/properties/age50_54', - type: 'integer' - }, - age55_64: { - $id: '/properties/demographics/properties/male/properties/age55_64', - type: 'integer' - } - } - }, - total: { - $id: '/properties/demographics/properties/total', - type: 'integer' - }, - female: { - $id: '/properties/demographics/properties/female', - type: 'object', - properties: { - age65: { - $id: '/properties/demographics/properties/female/properties/age65', - type: 'integer' - }, - total: { - $id: '/properties/demographics/properties/female/properties/total', - type: 'integer' - }, - age18_24: { - $id: - '/properties/demographics/properties/female/properties/age18_24', - type: 'integer' - }, - age25_34: { - $id: - '/properties/demographics/properties/female/properties/age25_34', - type: 'integer' - }, - age35_49: { - $id: - '/properties/demographics/properties/female/properties/age35_49', - type: 'integer' - }, - age50_54: { - $id: - '/properties/demographics/properties/female/properties/age50_54', - type: 'integer' - }, - age55_64: { - $id: - '/properties/demographics/properties/female/properties/age55_64', - type: 'integer' - } - } - } - } - }, - datetimeStart: { $id: '/properties/datetimeStart', type: 'string' }, - dataRegistryId: { $id: '/properties/dataRegistryId', type: 'string' }, - viewershipType: { $id: '/properties/viewershipType', type: 'string' } -}; - -storiesOf('SDO', module).add('SDO Table', () => ( - -)); - -storiesOf('SDO', module).add('SDO Table multilevel schema', () => ( - -)); diff --git a/packages/veritone-react-common/src/components/Scheduler/ContinuousSection.js b/packages/veritone-react-common/src/components/Scheduler/ContinuousSection.js deleted file mode 100644 index 5b864660f..000000000 --- a/packages/veritone-react-common/src/components/Scheduler/ContinuousSection.js +++ /dev/null @@ -1,19 +0,0 @@ -import React, { Fragment } from 'react'; - -import DateTimeSelector from './DateTimeSelector'; -import styles from './styles.scss'; - -export default class ContinuousSection extends React.Component { - render() { - return ( - -
- -
-
- -
-
- ); - } -} diff --git a/packages/veritone-react-common/src/components/Scheduler/DateTimeSelector.js b/packages/veritone-react-common/src/components/Scheduler/DateTimeSelector.js deleted file mode 100644 index 1211af925..000000000 --- a/packages/veritone-react-common/src/components/Scheduler/DateTimeSelector.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; -import { string, bool } from 'prop-types'; -import { Field } from 'redux-form'; -import FormGroup from '@material-ui/core/FormGroup'; - -import DateTimePicker from '../formComponents/DateTimePicker'; -import LabeledInputGroup from './LabeledInputGroup'; -import styles from './styles.scss'; - -const DateTimeSelector = ({ name, label, showIcon }) => ( - - - - - -); - -DateTimeSelector.propTypes = { - name: string, - label: string, - showIcon: bool -}; - -export default DateTimeSelector; diff --git a/packages/veritone-react-common/src/components/Scheduler/ImmediateSection.js b/packages/veritone-react-common/src/components/Scheduler/ImmediateSection.js deleted file mode 100644 index 9e56aea8c..000000000 --- a/packages/veritone-react-common/src/components/Scheduler/ImmediateSection.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -export default class ImmediateSection extends React.Component { - render() { - return
; - } -} diff --git a/packages/veritone-react-common/src/components/Scheduler/LabeledInputGroup.js b/packages/veritone-react-common/src/components/Scheduler/LabeledInputGroup.js deleted file mode 100644 index bd321d26f..000000000 --- a/packages/veritone-react-common/src/components/Scheduler/LabeledInputGroup.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import cx from 'classnames'; -import { string, node, bool } from 'prop-types'; -import FormControl from '@material-ui/core/FormControl'; -import FormLabel from '@material-ui/core/FormLabel'; -import styles from './styles.scss'; - -const LabeledInputGroup = ({ label, hasIconOffset, children }) => ( - -
-
- {label} -
-
{children}
-
-
-); - -LabeledInputGroup.propTypes = { - label: string, - hasIconOffset: bool, - children: node -}; - -export default LabeledInputGroup; diff --git a/packages/veritone-react-common/src/components/Scheduler/OnDemandSection.js b/packages/veritone-react-common/src/components/Scheduler/OnDemandSection.js deleted file mode 100644 index 94025ac41..000000000 --- a/packages/veritone-react-common/src/components/Scheduler/OnDemandSection.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -export default class OnDemandSection extends React.Component { - render() { - return
; - } -} diff --git a/packages/veritone-react-common/src/components/Scheduler/RecurringSection.js b/packages/veritone-react-common/src/components/Scheduler/RecurringSection.js deleted file mode 100644 index 528791eb3..000000000 --- a/packages/veritone-react-common/src/components/Scheduler/RecurringSection.js +++ /dev/null @@ -1,130 +0,0 @@ -import React, { Fragment } from 'react'; -import { shape, string, objectOf, any } from 'prop-types'; -import cx from 'classnames'; -import { formValues, Field, FieldArray } from 'redux-form'; -import { capitalize } from 'lodash'; -import IconButton from '@material-ui/core/IconButton'; -import ClearIcon from '@material-ui/icons/Clear'; -import AddIcon from '@material-ui/icons/Add'; -import TimeIcon from '@material-ui/icons/AccessTime'; - -import Checkbox from '../formComponents/Checkbox'; -import TimeRangePicker from '../formComponents/TimeRangePicker'; -import DateTimeSelector from './DateTimeSelector'; -import TimePeriodSelector from './TimePeriodSelector'; -import styles from './styles.scss'; - -const days = [ - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday', - 'Sunday' -]; - -@formValues('repeatEvery') -@formValues({ selectedDays: 'weekly.selectedDays' }) -export default class RecurringSection extends React.Component { - static propTypes = { - repeatEvery: shape({ - number: string.isRequired, - period: string.isRequired - }).isRequired - }; - - render() { - return ( - -
- -
- -
- -
- - {this.props.repeatEvery.period === 'day' && ( -
-
- - -
-
- )} - -
- {this.props.repeatEvery.period === 'week' && - days.map(d => ( -
-
- -
- -
- ))} -
- -
- -
-
- ); - } -} - -const MultiTimeRange = ({ fields }) => { - /* eslint-disable react/jsx-no-bind */ - return ( -
- {fields.map((field, index) => ( -
- - {(index > 0 || fields.length > 1) && ( - fields.remove(index)} - className={styles.iconButton} - > - - - )} - {index === fields.length - 1 && ( - - fields.push({ - start: '', - end: '' - }) - } - className={styles.iconButton} - > - - - )} -
- ))} -
- ); -}; - -MultiTimeRange.propTypes = { - fields: objectOf(any) -}; diff --git a/packages/veritone-react-common/src/components/Scheduler/TimePeriodSelector.js b/packages/veritone-react-common/src/components/Scheduler/TimePeriodSelector.js deleted file mode 100644 index 10a40de08..000000000 --- a/packages/veritone-react-common/src/components/Scheduler/TimePeriodSelector.js +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react'; -import { string } from 'prop-types'; -import { Field, FormSection, formValues } from 'redux-form'; -import MenuItem from '@material-ui/core/MenuItem'; -import FormGroup from '@material-ui/core/FormGroup'; -import pluralize from 'pluralize'; - -import TextField from '../formComponents/TextField'; -import Select from '../formComponents/Select'; -import LabeledInputGroup from './LabeledInputGroup'; -import styles from './styles.scss'; - -const TimePeriodSelector = ({ name, label, number }) => ( - - - - - - {pluralize('Hours', Number(number))} - {pluralize('Days', Number(number))} - {pluralize('Weeks', Number(number))} - - - - -); - -TimePeriodSelector.propTypes = { - name: string, - label: string, - number: string -}; - -export default formValues(props => ({ - number: `${props.name}.number` -}))(TimePeriodSelector); diff --git a/packages/veritone-react-common/src/components/Scheduler/index.js b/packages/veritone-react-common/src/components/Scheduler/index.js deleted file mode 100644 index 7890ffb8c..000000000 --- a/packages/veritone-react-common/src/components/Scheduler/index.js +++ /dev/null @@ -1,267 +0,0 @@ -import React from 'react'; -import { oneOf, func, arrayOf } from 'prop-types'; -import { reduxForm, Field, formValues, Form } from 'redux-form'; -import { - noop, - pick, - get, - pickBy, - mapValues, - omit, - difference, - keys, - constant -} from 'lodash'; -import { withProps } from 'recompose'; -import FormControlLabel from '@material-ui/core/FormControlLabel'; -import Radio from '@material-ui/core/Radio'; -import { subDays } from 'date-fns'; - -import RadioGroup from '../formComponents/RadioGroup'; -import styles from './styles.scss'; -import ImmediateSection from './ImmediateSection'; -import RecurringSection from './RecurringSection'; -import OnDemandSection from './OnDemandSection'; -import ContinuousSection from './ContinuousSection'; - -const initDate = new Date(); - -function getDefaultScheduleType(props) { - // There may be inconsistencies in what scheduleType is currently selected and what's available - // This logic selects the schedule type that's valid - const scheduleType = props.initialValues && props.initialValues.scheduleType; - - // if scheduleType exists and is included in the list of supported types, - // we're good - if ( - scheduleType && - ((props.supportedScheduleTypes || []).includes('Any') || - (props.supportedScheduleTypes || []).includes(scheduleType)) - ) { - return scheduleType; - } - - if (!scheduleType) { - // default to first supported type if not set - return props.supportedScheduleTypes.includes('Any') - ? 'Recurring' // recurring is default - : props.supportedScheduleTypes[0]; // must specify at least one - } - - // ScheduleType isn't supported by the current - // supportedScheduleTypes list; fall back to the first supported type or - // recurring by default. - return get(props.supportedScheduleTypes, 0, 'Recurring'); -} - -@withProps(props => { - const scheduleType = getDefaultScheduleType(props); - - return { - // Handle empty array passed to supportedScheduleTypes - supportedScheduleTypes: - get(props.supportedScheduleTypes, 'length') === 0 - ? ['Any'] - : props.supportedScheduleTypes, - initialValues: { - // This provides defaults to the form. Shallow merged with - // props.initialValues to allow overriding. - scheduleType, - start: get(props, 'initialValues.start') - ? new Date(props.initialValues.start) - : subDays(initDate, 3), - end: get(props, 'initialValues.end') - ? new Date(props.initialValues.end) - : initDate, - repeatEvery: { - number: '1', - period: 'day' - }, - daily: [ - { - start: '00:00', - end: '01:00' - } - ], - weekly: { - // make sure we set a default start/end for any days which aren't given - // explicit default values in props.initialValues.weekly - ...difference( - // for days not given explicit initial values in props,.. - [ - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday', - 'Sunday' - ], - keys(get(props, 'initialValues.weekly')) - // ... provide them with default start/end ranges - ).reduce((r, day) => ({ ...r, [day]: [{ start: '', end: '' }] }), {}), - // and assume any days given explicit initial values should be selected - selectedDays: mapValues( - get(props, 'initialValues.weekly'), - constant(true) - ), - // then merge back with the days given explicit initial values in props - ...get(props, 'initialValues.weekly') - }, - // shallow-merge the properties we didn't have special merge logic for - ...omit(props.initialValues, ['start', 'end', 'weekly', 'scheduleType']) - } - }; -}) -@reduxForm({ - form: 'scheduler' -}) -@formValues('scheduleType') -class Scheduler extends React.Component { - static propTypes = { - scheduleType: oneOf(['Recurring', 'Continuous', 'Now', 'Once']).isRequired, - onSubmit: func, // user-provided callback for result values - handleSubmit: func.isRequired, // provided by redux-form - supportedScheduleTypes: arrayOf( - oneOf(['Recurring', 'Continuous', 'Now', 'Once', 'Any']) - ) - }; - - static defaultProps = { - onSubmit: noop, - supportedScheduleTypes: ['Any'] - }; - - prepareResultData(formResult) { - const recurringPeriod = get(formResult, 'repeatEvery.period'); - const selectedDays = Object.keys( - pickBy(get(formResult, 'weekly.selectedDays', {}), included => !!included) - ); - - const recurringRepeatSectionFields = { - hour: [], - day: ['daily'], - week: selectedDays.map(day => `weekly.${day}`) - }[recurringPeriod]; - - const wantedFields = { - Recurring: [ - 'scheduleType', - 'start', - 'end', - 'repeatEvery', - ...recurringRepeatSectionFields - ], - Continuous: ['scheduleType', 'start', 'end'], - Now: ['scheduleType'], - Once: ['scheduleType'] - }[formResult.scheduleType]; - - const result = pick(formResult, wantedFields); - return result.scheduleType === 'Recurring' - ? filterRecurringPeriods(result, recurringPeriod) - : result; - } - - handleSubmit = vals => { - this.props.onSubmit(this.prepareResultData(vals)); - }; - - render() { - const ActiveSectionComponent = { - Recurring: RecurringSection, - Continuous: ContinuousSection, - Now: ImmediateSection, - Once: OnDemandSection - }[this.props.scheduleType]; - - const showAllScheduleTypes = this.props.supportedScheduleTypes.includes( - 'Any' - ); - - return ( -
- - {(showAllScheduleTypes || - this.props.supportedScheduleTypes.includes('Recurring')) && ( - } - label="Recurring" - /> - )} - - {(showAllScheduleTypes || - this.props.supportedScheduleTypes.includes('Continuous')) && ( - } - label="Continuous" - /> - )} - - {(showAllScheduleTypes || - this.props.supportedScheduleTypes.includes('Now')) && ( - } - label="Immediate" - /> - )} - - {(showAllScheduleTypes || - this.props.supportedScheduleTypes.includes('Once')) && ( - } - label="On Demand" - /> - )} - -
- -
-
- ); - } -} - -function filterRecurringPeriods(result, recurringPeriod) { - if (recurringPeriod === 'hour') { - return result; - } - - if (recurringPeriod === 'day') { - // filter out incomplete ranges that don't have both start and end - return { - ...result, - daily: result.daily.filter(day => day.start && day.end) - }; - } - - if (recurringPeriod === 'week') { - return { - ...result, - weekly: pickBy( - // filter out incomplete ranges that don't have both start and end - mapValues(result.weekly, week => - week.filter(day => day.start && day.end) - ), - // remove days with no complete ranges - schedules => !!schedules.length - ) - }; - } - - return result; -} - -export default Scheduler; diff --git a/packages/veritone-react-common/src/components/Scheduler/story.js b/packages/veritone-react-common/src/components/Scheduler/story.js deleted file mode 100644 index 7e7007b53..000000000 --- a/packages/veritone-react-common/src/components/Scheduler/story.js +++ /dev/null @@ -1,85 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { Provider, connect } from 'react-redux'; -import { reducer as formReducer, submit } from 'redux-form'; -import { combineReducers, createStore } from 'redux'; - -import { createLogger } from 'redux-logger'; -import { applyMiddleware, compose } from 'redux'; - -import Scheduler from './'; - -const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; -const store = createStore( - combineReducers({ - form: formReducer - }), - composeEnhancers( - applyMiddleware( - createLogger({ - collapsed: true - }) - ) - ) -); - -@connect( - state => ({ - form: state.form.scheduler - }), - { submit } -) -class Story extends React.Component { - /* eslint-disable react/prop-types */ - state = { lastResult: {} }; - submit = () => { - this.props.submit('scheduler'); - }; - - handleSubmit = vals => { - this.setState({ - lastResult: vals - }); - }; - - render() { - return ( -
- -
- - -
- Last result: -
{JSON.stringify(this.state.lastResult, null, '\t')}
-
-
-
-
- ); - } -} - -storiesOf('Scheduler', module).add('Base', () => ); diff --git a/packages/veritone-react-common/src/components/Scheduler/styles.scss b/packages/veritone-react-common/src/components/Scheduler/styles.scss deleted file mode 100644 index 104a3d927..000000000 --- a/packages/veritone-react-common/src/components/Scheduler/styles.scss +++ /dev/null @@ -1,122 +0,0 @@ -@import 'src/styles/modules/muiTypography'; -@import 'src/styles/modules/variables'; - -$label-width: 150px; - -.header { - @include mui-text('headline'); -} - -.scheduleTypeContainer { - flex-direction: row !important; -} - -.activeSectionContainer { - display: flex; - flex-direction: column; - - .formSectionRow { - padding-top: 15px; - } - - label, - span, - input, - .periodSelect { - font-weight: inherit; - font-size: 0.8rem !important; - } - - .periodSelect > div > div { - padding-top: 8px; - } -} - -.repeatContainer { - display: flex; - flex-direction: column; - margin-left: $label-width; - margin-top: 30px; - width: 550px; - - .timeRangeContainer { - background-color: $grey-2; - padding: 0 10px; - } - - .weekSelectionContainer { - display: flex; - align-items: flex-start; - - &:not(:first-child) { - margin-top: 10px; - } - } - - .daySelectionContainer { - display: flex; - align-items: center; - padding-left: 15px; - - .timeIcon { - color: $light-black; - margin-right: 75px; - } - } - - .checkboxGroup { - width: 200px; - } -} - -.fieldsetGroup { - display: flex !important; - flex-direction: row !important; - width: 100% !important; - - .label { - width: $label-width; - display: flex; - align-items: flex-end; - } - - .hasIconOffset { - width: $label-width - 50px; - } - - .input { - flex-grow: 1; - } -} - -.inputsGroup { - flex-direction: row !important; - - .leftInput, - .rightInput { - width: 100px; - } - - .leftInput { - padding-right: 15px; - } - - .leftInput input { - text-align: right; - height: inherit; - } -} - -.multiTimeRange { - display: inline-flex; - flex-direction: column; - - .row { - display: flex; - align-items: center; - } - - .iconButton { - margin-left: -10px; - } -} diff --git a/packages/veritone-react-common/src/components/SourceConfiguration/SchemaDrivenSelectForm/index.js b/packages/veritone-react-common/src/components/SourceConfiguration/SchemaDrivenSelectForm/index.js deleted file mode 100644 index 6ed1028cf..000000000 --- a/packages/veritone-react-common/src/components/SourceConfiguration/SchemaDrivenSelectForm/index.js +++ /dev/null @@ -1,137 +0,0 @@ -import React from 'react'; -import { has, includes, get } from 'lodash'; - -import { any, arrayOf, objectOf, func, string, number } from 'prop-types'; - -import MenuItem from '@material-ui/core/MenuItem'; -import Select from '@material-ui/core/Select'; -import FormHelperText from '@material-ui/core/FormHelperText'; -import FormControl from '@material-ui/core/FormControl'; -import InputLabel from '@material-ui/core/InputLabel'; -import SourceTypeField from 'components/SourceTypeField'; - -import styles from './styles.scss'; - -export default class DynamicSelect extends React.Component { - static propTypes = { - sourceTypes: arrayOf(objectOf(any)).isRequired, //pass in the array of source types and their schemas - currentSourceType: number, // id of initial sourceType if there is a default - onSelectChange: func.isRequired, - onSourceDetailChange: func.isRequired, - fieldValues: objectOf(any), - errorFields: objectOf(any), - helperText: string, - selectLabel: string - }; - static defaultProps = { - fieldValues: {} - }; - - state = { - oneSourceType: false - }; - - // eslint-disable-next-line react/sort-comp - UNSAFE_componentWillMount() { - if (this.props.sourceTypes.length === 1) { - this.setState({ oneSourceType: true }); - } - } - - handleSourceTypeChange = event => { - const sourceTypeIndex = event.target.value; - this.props.onSelectChange(sourceTypeIndex); - }; - - handleDetailChange = fieldId => event => { - this.props.onSourceDetailChange({ - [fieldId]: event.target.value - }); - }; - - renderFields = () => { - const definition = get( - this.props.sourceTypes[this.props.currentSourceType], - 'sourceSchema.definition' - ); - const properties = definition && definition.properties; - const requiredFields = has(definition, 'required') - ? definition.required - : []; - - if (!definition || !properties) { - return []; - } - - return Object.keys(this.props.fieldValues).map((fieldId, index) => { - return ( - - ); - }); - }; - - render() { - const { sourceTypes, currentSourceType } = this.props; - const sourceTypesMenu = sourceTypes.map((type, index) => { - return ( - - {type.name} - - ); - }); - - return ( - - {this.props.selectLabel && - !this.state.oneSourceType && ( - - {this.props.selectLabel} - - )} - {!this.state.oneSourceType && ( - - )} - {this.state.oneSourceType && ( -
Source Type
- )} - {this.state.oneSourceType && ( -
-
- {sourceTypes[currentSourceType].name} -
-
- )} - {this.props.helperText && - !this.state.oneSourceType && ( - {this.props.helperText} - )} - {this.renderFields()} -
- ); - } -} diff --git a/packages/veritone-react-common/src/components/SourceConfiguration/SchemaDrivenSelectForm/styles.scss b/packages/veritone-react-common/src/components/SourceConfiguration/SchemaDrivenSelectForm/styles.scss deleted file mode 100644 index 4d88bce36..000000000 --- a/packages/veritone-react-common/src/components/SourceConfiguration/SchemaDrivenSelectForm/styles.scss +++ /dev/null @@ -1,67 +0,0 @@ -.dynamicFormStyle { - width: 100%; - - .inputLabel { - font-size: 12px; - line-height: 14px; - position: inherit; - } - - .textField { - margin-top: 30px; - } - - .selectField { - margin-top: inherit; - } - - .sourceTypeNameLabel { - color: rgba(0, 0, 0, 0.54); - font-size: 12px; - line-height: 14px; - } - - .sourceTypeNameContainer { - display: flex; - align-items: center; - flex-direction: row; - margin-top: 5px; - - .sourceTypeName { - color: rgba(0, 0, 0, 0.87); - font-size: 14px; - line-height: 16px; - } - - .sourceTypeNameTooltip { - color: #2196f3; - font-size: 10px; - line-height: 11px; - margin-left: 30px; - - &:hover { - cursor: pointer; - } - } - } -} - -.textFieldLabel { - font-weight: normal !important; -} - -.dateTimeContainer { - padding-top: 18px !important; -} - -.dateTimeLabel { - transform: translate(0, 1.5px) scale(0.75) !important; - transform-origin: top left !important; -} - -.unsupportedMsg { - padding-top: 20px; - color: rgba(0, 0, 0, 0.54); - font-size: 14px; - font-style: italic; -} diff --git a/packages/veritone-react-common/src/components/SourceConfiguration/index.js b/packages/veritone-react-common/src/components/SourceConfiguration/index.js deleted file mode 100644 index c90b4ce8e..000000000 --- a/packages/veritone-react-common/src/components/SourceConfiguration/index.js +++ /dev/null @@ -1,205 +0,0 @@ -import React from 'react'; -import { string, shape, any, arrayOf, objectOf, func } from 'prop-types'; -import { get } from 'lodash'; - -import TextField from '@material-ui/core/TextField'; -import FormControl from '@material-ui/core/FormControl'; -import Avatar from '@material-ui/core/Avatar'; -import Dialog from '@material-ui/core/Dialog'; -import FilePicker from 'components/FilePicker'; -import defaultThumbnail from 'images/cms-sources-null.svg'; -import DynamicSelect from './SchemaDrivenSelectForm'; -import styles from './styles.scss'; - -export default class SourceConfiguration extends React.Component { - static propTypes = { - sourceTypes: arrayOf(objectOf(any)).isRequired, - source: shape({ - sourceTypeId: string, - name: string, - details: objectOf(any) - }).isRequired, // the source if this is to edit a source - onInputChange: func.isRequired - }; - static defaultProps = {}; - - state = { - sourceTypeIndex: 0, - requiredFields: {}, - openFilePicker: false, - thumbnailUrl: '' - }; - - // eslint-disable-next-line react/sort-comp - UNSAFE_componentWillMount = () => { - const { sourceTypes, source } = this.props; - - // if editing a source, initialize the defaults - if (source && source.sourceTypeId) { - const newState = {}; - const sourceTypeIndex = sourceTypes.findIndex( - sourceType => sourceType.id === source.sourceTypeId - ); - - newState.sourceTypeIndex = Math.max( - sourceTypeIndex, - this.state.sourceTypeIndex - ); - - this.setState(newState); - } - }; - - // eslint-disable-next-line react/sort-comp - UNSAFE_componentWillReceiveProps(nextProps) { - if (nextProps.source.sourceTypeId !== this.props.source.sourceTypeId) { - // if editing a source, initialize the defaults - const sourceTypeIndex = nextProps.sourceTypes.findIndex( - sourceType => sourceType.id === nextProps.source.sourceTypeId - ); - - if (sourceTypeIndex > -1) { - this.setState({ sourceTypeIndex }); - } - } - } - - handleNameChange = event => { - this.props.onInputChange({ - name: event.target.value - }); - }; - - handleSourceChange = sourceTypeIndex => { - if (sourceTypeIndex !== this.state.sourceTypeIndex) { - const currentFields = {}; - const properties = get(this.props.sourceTypes, [ - sourceTypeIndex, - 'sourceSchema', - 'definition', - 'properties' - ]); - - if (properties) { - Object.keys(properties).forEach(field => { - currentFields[field] = ''; - }); - } - - return this.props.onInputChange({ - sourceTypeId: this.props.sourceTypes[sourceTypeIndex].id, - details: currentFields - }); - } - }; - - handleSourceDetailChange = formDetail => { - this.props.onInputChange({ - details: { - ...this.props.source.details, - ...formDetail - } - }); - }; - - handleThumbnailSelection = fileList => { - const file = fileList[0]; - const fileReader = new FileReader(); - - fileReader.onload = () => { - this.setState( - { - thumbnailUrl: fileReader.result, - openFilePicker: false - }, - () => this.props.onInputChange({ thumbnailFile: file }) - ); - }; - - fileReader.readAsDataURL(file); - }; - - openFilePicker = () => { - this.setState({ openFilePicker: true }); - }; - - closeFilePicker = () => { - this.setState({ openFilePicker: false }); - }; - - renderFilePicker = () => { - return ( - - - - ); - }; - - render() { - const { source } = this.props; - - return ( -
-
-
Configuration
-
- Configure your source below by selecting a source type and inputting - the associated data. -
-
- -
-
- -
- - Edit - -
-
- - {this.state.openFilePicker && this.renderFilePicker()} -
- -
-
-
-
- ); - } -} diff --git a/packages/veritone-react-common/src/components/SourceConfiguration/index.test.js b/packages/veritone-react-common/src/components/SourceConfiguration/index.test.js deleted file mode 100644 index 34e1a4168..000000000 --- a/packages/veritone-react-common/src/components/SourceConfiguration/index.test.js +++ /dev/null @@ -1,136 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import { noop } from 'lodash'; -import FilePicker from 'components/FilePicker'; - -import SourceConfiguration from './'; - -const sourceTypes = { - data: { - records: [ - { - name: 'Audio', - id: 'audio1', - sourceSchema: { - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name' - }, - password: { - type: 'string' - } - }, - required: ['url', 'username', 'password'] - } - } - }, - { - name: 'Audio2', - id: 'audio_2', - sourceSchema: { - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name 2' - }, - password: { - type: 'string' - }, - days: { - type: 'number' - } - }, - required: ['url', 'days'] - } - } - } - ] - } -}; - -describe('Source Configuration', function() { - const sourceRecords = sourceTypes.data.records; - const { properties } = sourceRecords[0].sourceSchema.definition; - const initialSource = { - sourceTypeId: sourceRecords[0].id, - name: '', - thumbnailUrl: '', - details: Object.keys(properties).reduce((detailObj, prop) => { - detailObj[prop] = 'Test Value'; - return detailObj; - }, {}), - thumbnailFile: null - }; - - describe('SchemaDrivenSelectForm', () => { - it("render's fields for a source schema", () => { - const wrapper = mount( - - ); - - Object.keys(properties).forEach(prop => { - expect(wrapper.find(`input#${prop}`)).toHaveLength(1); - }); - }); - it("render's fields on source change", () => { - const testProps = - sourceRecords[sourceRecords.length - 1].sourceSchema.definition - .properties; - const wrapper = mount( - - ); - - wrapper.setProps({ - source: { - sourceTypeId: sourceRecords[sourceRecords.length - 1].id, - name: sourceRecords[sourceRecords.length - 1].name, - thumbnailUrl: '', - thumbnailFile: null, - details: Object.keys(testProps).reduce((detailObj, prop) => { - detailObj[prop] = ''; - return detailObj; - }, {}) - } - }); - - wrapper.update(); - - Object.keys(testProps).forEach((prop, idx) => { - expect(wrapper.find(`input#${prop}`)).toHaveLength(1); - }); - }); - }); - - describe('FilePicker', () => { - it('opens FilePicker component', () => { - const wrapper = mount( - - ); - - expect(wrapper.find(FilePicker)).toHaveLength(0); - wrapper.find('#openFilePicker').simulate('click'); - expect(wrapper.find(FilePicker)).toHaveLength(1); - }); - }); -}); diff --git a/packages/veritone-react-common/src/components/SourceConfiguration/story.js b/packages/veritone-react-common/src/components/SourceConfiguration/story.js deleted file mode 100644 index 3a2406332..000000000 --- a/packages/veritone-react-common/src/components/SourceConfiguration/story.js +++ /dev/null @@ -1,99 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import SourceConfiguration from './'; - -const sourceTypes = { - data: { - records: [ - { - name: 'Audio', - id: 'audio1', - sourceSchema: { - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name' - }, - password: { - type: 'string' - } - }, - required: ['url', 'username', 'password'] - } - } - }, - { - name: 'Audio2', - id: 'audio_2', - sourceSchema: { - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name 2' - }, - password: { - type: 'string' - }, - days: { - type: 'number' - } - }, - required: ['url', 'days'] - } - } - } - ] - } -}; - -class SourceConfigWrapper extends React.Component { - state = { - sourceTypeId: sourceTypes.data.records[0].id, - name: '', - thumbnailUrl: '', - details: { - url: '', - username: '', - password: '' - }, - thumbnailFile: null - }; - - saveConfiguration = config => { - return this.setState(prevState => ({ - ...prevState.sourceConfig, - ...config - })); - }; - - handleSubmit = e => { - e.preventDefault(); - - console.log('Form Values:', this.state); - }; - - render() { - return ( -
- - - - ); - } -} - -storiesOf('Source Configuration', module).add('Base', () => ( - -)); diff --git a/packages/veritone-react-common/src/components/SourceConfiguration/styles.scss b/packages/veritone-react-common/src/components/SourceConfiguration/styles.scss deleted file mode 100644 index 90c0e294f..000000000 --- a/packages/veritone-react-common/src/components/SourceConfiguration/styles.scss +++ /dev/null @@ -1,87 +0,0 @@ -@import 'src/styles/modules/muiTypography'; -@import 'src/styles/modules/variables'; - -$avatar-size: 70px; - -.configuration-container { - height: 100%; - width: 60%; - padding: 30px; - - .configurationTitle { - color: rgba(0, 0, 0, 0.87); - font-size: 20px; - line-height: 24px; - } - - .configurationDescription { - opacity: 0.6; - color: rgba(0, 0, 0, 0.87); - font-size: 14px; - line-height: 16px; - } - - .sourceConfiguration { - .formStyle { - width: 80%; - min-width: 350px; - - .container { - flex-direction: row; - align-items: center; - display: flex; - justify-content: space-around; - margin-bottom: 20px; - margin-top: 20px; - - .sourceName { - margin-left: 20px; - margin-bottom: 30px; - } - } - } - } - - .avatar-container { - display: flex; - flex-direction: column; - align-items: center; - position: relative; - text-align: center; - } - - .avatar-img-container { - width: $avatar-size; - height: $avatar-size; - } - - .avatar-img { - height: 100%; - border-radius: 50%; - } - - .avatar-img-cta { - @include mui-text('caption'); - position: absolute; - top: 5px; - width: $avatar-size + 10; - height: $avatar-size; - border-radius: 50%; - background: linear-gradient( - to top, - $light-black 30%, - transparent 30%, - transparent 100% - ); - display: inline-flex; - flex-direction: column; - justify-content: flex-end; - color: $grey-1; - text-transform: uppercase; - padding-bottom: 5px; - - span { - cursor: pointer; - } - } -} diff --git a/packages/veritone-react-common/src/components/SourceManagement/NullState/index.js b/packages/veritone-react-common/src/components/SourceManagement/NullState/index.js deleted file mode 100644 index 4652c1519..000000000 --- a/packages/veritone-react-common/src/components/SourceManagement/NullState/index.js +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; -import { func } from 'prop-types'; -import NullstateImage from 'images/cms-sources-null.svg'; -import NullState from 'components/NullState'; - -import styles from './styles.scss'; - -export default class SourceManagementNullState extends React.Component { - static propTypes = { - onClick: func.isRequired - }; - - render() { - const { onClick } = this.props; - - return ( - -
- If you need help getting started, take a look at the -
-
How to Create a Source
-
- ); - } -} diff --git a/packages/veritone-react-common/src/components/SourceManagement/NullState/styles.scss b/packages/veritone-react-common/src/components/SourceManagement/NullState/styles.scss deleted file mode 100644 index be9284782..000000000 --- a/packages/veritone-react-common/src/components/SourceManagement/NullState/styles.scss +++ /dev/null @@ -1,13 +0,0 @@ -@import 'src/styles/modules/variables'; - -.greyText { - color: $light-black; - font-size: 14px; - line-height: 18px; -} - -.linkText { - color: $blue-1; - font-size: 14px; - line-height: 18px; -} diff --git a/packages/veritone-react-common/src/components/SourceManagement/SourceTileView/index.js b/packages/veritone-react-common/src/components/SourceManagement/SourceTileView/index.js deleted file mode 100644 index 660646ce7..000000000 --- a/packages/veritone-react-common/src/components/SourceManagement/SourceTileView/index.js +++ /dev/null @@ -1,101 +0,0 @@ -import React from 'react'; - -import { arrayOf, any, objectOf, func, bool } from 'prop-types'; - -import { Table, PaginatedTable, Column } from 'components/DataTable'; -import MenuColumn from 'components/DataTable/MenuColumn'; -import Avatar from '@material-ui/core/Avatar'; -import { format, distanceInWordsToNow } from 'date-fns'; -import { capitalize, omit, noop } from 'lodash'; - -export default class SourceTileView extends React.Component { - static propTypes = { - sources: arrayOf(objectOf(any)).isRequired, // an array of source objects - onSelectSource: func, - onSelectMenuItem: func, - paginate: bool, - onFetchData: func - }; - - static defaultProps = { - onSelectMenuItem: noop, - onFetchData: noop - }; - - getSourceData = i => { - return this.props.sources[i]; - }; - - renderThumbnail = thumbnailUrl => { - return ( - - ); - }; - - renderCreatedDate = date => { - return format(date, 'M/D/YYYY h:mm A'); - }; - - renderUpdatedDate = date => { - return capitalize(distanceInWordsToNow(date, { includeSeconds: true })); - }; - - render() { - const TableComp = this.props.paginate ? PaginatedTable : Table; - const tableProps = omit(this.props, [ - 'sources', - 'onSelectMenuItem', - 'paginate', - 'onFetchData' - ]); - - if (this.props.paginate) { - tableProps.onShowCellRange = this.props.onFetchData; - } - - return ( - - - - - - - - - ); - } -} diff --git a/packages/veritone-react-common/src/components/SourceManagement/index.js b/packages/veritone-react-common/src/components/SourceManagement/index.js deleted file mode 100644 index a0de813c4..000000000 --- a/packages/veritone-react-common/src/components/SourceManagement/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export NullState from './NullState'; -export SourceTileView from './SourceTileView'; diff --git a/packages/veritone-react-common/src/components/SourceManagement/story.js b/packages/veritone-react-common/src/components/SourceManagement/story.js deleted file mode 100644 index 40bf0b027..000000000 --- a/packages/veritone-react-common/src/components/SourceManagement/story.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import NullState from './NullState'; -import SourceTileView from './SourceTileView'; - -// a mock return result on a source from graphql -const sourceResult = { - data: { - source: { - id: '666', - name: 'KWOL--FM', - createdDateTime: '2014-12-01T18:17:20.675Z', - modifiedDateTime: '2015-12-01T18:17:20.675Z', - thumbnailUrl: 'https://image.flaticon.com/icons/svg/25/25305.svg', - details: { - url: 'twitter.com', - username: 'therealtrump', - password: 'password' - }, - sourceType: { - id: '1', - name: 'Audio', - sourceSchema: { - id: 'schemaId1', - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name' - }, - password: { - type: 'string', - title: 'Password' - } - } - }, - validActions: ['view', 'edit', 'deactivate', 'delete'] - } - } - } - } -}; - -const sourceResults = []; - -for (let i = 0; i < 15; i++) { - sourceResults.push(sourceResult.data.source); -} - -function btnClick() { - alert('Button Clicked!'); -} - -storiesOf('SourceManagement', module) - .add('NullState', () => ) - .add('Tile View', () => ); diff --git a/packages/veritone-react-common/src/components/SourceManagementForm/index.js b/packages/veritone-react-common/src/components/SourceManagementForm/index.js deleted file mode 100644 index 2fc11c42e..000000000 --- a/packages/veritone-react-common/src/components/SourceManagementForm/index.js +++ /dev/null @@ -1,266 +0,0 @@ -import React from 'react'; -import { arrayOf, objectOf, any, func, string, shape, bool } from 'prop-types'; -import { pick, has, get, noop } from 'lodash'; -import Tabs from '@material-ui/core/Tabs'; -import Tab from '@material-ui/core/Tab'; -import Icon from '@material-ui/core/Icon'; -import IconButton from '@material-ui/core/IconButton'; -import Button from '@material-ui/core/Button'; - -import FullScreenDialog from 'components/FullScreenDialog'; -import ModalHeader from 'components/ModalHeader'; -import SourceConfiguration from 'components/SourceConfiguration'; -import ContentTemplates from 'components/ContentTemplates'; - -import styles from './styles.scss'; - -export default class SourceManagementForm extends React.Component { - static propTypes = { - sourceTypes: arrayOf( - shape({ - id: string.isRequired, - name: string.isRequired, - sourceSchema: shape({ - definition: shape({ - properties: shape({ - type: string - }) - }) - }) - }) - ).isRequired, - templateData: objectOf( - shape({ - id: string, - name: string.isRequired, - status: string, - definition: objectOf(any) - }) - ).isRequired, - source: shape({ - name: string, - sourceType: objectOf(any), - details: objectOf(any), - thumbnailUrl: string - }), - initialTemplates: objectOf( - shape({ - id: string, - name: string.isRequired, - status: string, - definition: objectOf(any), - data: objectOf(any) - }) - ), - onSubmit: func.isRequired, - onClose: func, - open: bool - }; - - static defaultProps = { - initialTemplates: {}, - onClose: noop - }; - - state = { - selectedSource: null, - sourceConfig: { - sourceTypeId: '', - name: '', - thumbnailUrl: '', - details: {}, - thumbnailFile: null - }, - contentTemplates: {}, - activeTab: 0, - openDialog: true - }; - - // eslint-disable-next-line react/sort-comp - UNSAFE_componentWillMount() { - const { sourceTypes } = this.props; - const newState = { - contentTemplates: { ...this.props.initialTemplates } - }; - - if (has(this.props, 'open')) { - newState.openDialog = this.props.open; - } - if (this.props.source) { - // if editing a source, initialize the defaults - newState.sourceConfig = { - ...pick(this.props.source, ['name', 'thumbnailUrl', 'details']), - sourceTypeId: this.props.source.sourceType.id - }; - } else { - // If there is no source, then just pick the first available sourceType - const fieldValues = {}; - const sourceTypeIdx = 0; - const properties = get(sourceTypes, [ - sourceTypeIdx, - 'sourceSchema', - 'definition', - 'properties' - ]); - - if (properties) { - Object.keys(properties).forEach(field => { - fieldValues[field] = ''; - }); - } - - newState.sourceConfig = { - ...this.state.sourceConfig, - sourceTypeId: sourceTypes[sourceTypeIdx].id, - details: { - ...fieldValues - } - }; - } - - return this.setState(newState); - } - - handleCloseDialog = () => { - return this.setState({ openDialog: false }, () => { - this.props.onClose(); - }); - }; - - handleChangeTab = (e, tabIdx) => { - return this.setState({ activeTab: tabIdx }); - }; - - saveConfiguration = config => { - return this.setState(prevState => ({ - sourceConfig: { - ...prevState.sourceConfig, - ...config - } - })); - }; - - addToTemplateList = templateSchemaId => { - const { templateData, initialTemplates } = this.props; - const data = {}; - - Object.keys(templateData[templateSchemaId].definition.properties).reduce( - (fields, schemaDefProp) => { - data[schemaDefProp] = get( - initialTemplates, - [templateSchemaId, 'data', schemaDefProp], - '' - ); - }, - data - ); - - this.setState(prevState => ({ - contentTemplates: { - [templateSchemaId]: { - ...templateData[templateSchemaId], - data - }, - ...prevState.contentTemplates - } - })); - }; - - removeFromTemplateList = templateSchemaId => { - if (this.state.contentTemplates[templateSchemaId]) { - return this.setState(prevState => { - const contentTemplates = { ...prevState.contentTemplates }; - delete contentTemplates[templateSchemaId]; - - return { contentTemplates }; - }); - } - }; - - updateTemplateDetails = (templateSchemaId, fieldId, value) => { - const { contentTemplates } = this.state; - - this.setState({ - contentTemplates: { - ...contentTemplates, - [templateSchemaId]: { - ...contentTemplates[templateSchemaId], - data: { - ...contentTemplates[templateSchemaId].data, - [fieldId]: value - } - } - } - }); - }; - - handleSubmit = e => { - e.preventDefault(); - return this.props.onSubmit({ - sourceConfiguration: this.state.sourceConfig, - contentTemplates: this.state.contentTemplates - }); - }; - - render() { - const { activeTab } = this.state; - - return ( - -
- - - - ]} - > - - - - - -
- {activeTab === 0 && ( - - )} - {activeTab === 1 && ( - - )} -
- - -
- -
-
- ); - } -} diff --git a/packages/veritone-react-common/src/components/SourceManagementForm/story.js b/packages/veritone-react-common/src/components/SourceManagementForm/story.js deleted file mode 100644 index ca4e9881c..000000000 --- a/packages/veritone-react-common/src/components/SourceManagementForm/story.js +++ /dev/null @@ -1,314 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { has, noop } from 'lodash'; -import SourceManagementForm from './'; - -const sourceTypes = { - sourceTypes: { - records: [ - { - name: 'Audio', - id: 'audio_1', - sourceSchema: { - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'username' - }, - password: { - type: 'string' - } - }, - required: ['url', 'username', 'password'] - } - } - }, - { - name: 'Audio2', - id: 'audio_2', - sourceSchema: { - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'username 2' - }, - password: { - type: 'string' - }, - days: { - type: 'number' - } - } - } - } - } - ] - } -}; - -// a mock return result on a source from graphql -const sourceResult = { - data: { - source: { - id: '666', - name: 'KWOL--FM', - createdDateTime: '2014-12-01T18:17:20.675Z', - modifiedDateTime: '2015-12-01T18:17:20.675Z', - thumbnailUrl: 'https://image.flaticon.com/icons/svg/25/25305.svg', - details: { - url: 'twitter.com', - username: 'therealtrump', - password: 'password' - }, - sourceType: { - id: '1', - name: 'Audio', - sourceSchema: { - id: 'schemaId1', - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name' - }, - password: { - type: 'string', - title: 'Password' - } - } - }, - validActions: ['view', 'edit', 'deactivate', 'delete'] - } - } - } - } -}; - -const sourceResults = []; -for (let i = 0; i < 4; i++) { - sourceResults.push(sourceResult.data.source); -} - -// CONTENT TEMPLATES SETUP -const templateSource = { - data: { - source: { - id: '666', - name: 'KWOL--FM', - contentTemplates: [ - { - schemaId: 'schemaGuid1', - data: { - url: 'twitter.com', - username: 'THEREALTRUMP' - } - } - ] - } - } -}; - -const dataSchemas = { - data: { - dataRegistries: { - records: [ - { - name: 'Twitter Schema', - schemas: { - records: [ - { - id: 'schemaGuid1', - status: 'published', - definition: { - properties: { - url: { - type: 'string', - title: 'URL' - }, - username: { - type: 'string', - title: 'Username' - }, - testArray: { - type: 'array', - title: 'Array Test', - items: { - type: 'number', - title: 'Item Title' - } - }, - testObject: { - type: 'object', - title: 'Object Test', - properties: { - objectString: { - type: 'string', - title: 'Object String' - }, - objectNumber: { - type: 'number', - title: 'Object Number' - } - } - }, - number: { - type: 'number', - title: 'Number' - }, - geoLocation: { - type: 'geoPoint', - title: 'Geo Location' - }, - trueOrFalse: { - type: 'boolean', - title: 'Boolean' - }, - datetimeEnd: { - type: 'dateTime', - title: 'End Date' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema 2' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - }, - password: { - type: 'string' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - test: 'citest' - } - }, - { - id: 'schemaGuid2', - status: 'draft', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - } - } - } - } - ] - } - } - ] - } - } -}; - -function createTemplateData(dataSchemas) { - const templateSchemas = {}; - // array of data registries containing an array of schemas - dataSchemas.reduce((schemaStore, registryData) => { - registryData.schemas.records.forEach(schema => { - // only take schemas that are 'published' and also define field types - if ( - schema.status === 'published' && - has(schema.definition, 'properties') - ) { - schemaStore[schema.id] = { - name: registryData.name, - ...schema - }; - } - }); - }, templateSchemas); - - return templateSchemas; -} - -function createInitialTemplates(templateSources) { - const selectedTemplateSchemas = {}; - - const templateSchemas = createTemplateData( - dataSchemas.data.dataRegistries.records - ); - templateSources.forEach(template => { - if (has(templateSchemas, template.schemaId)) { - selectedTemplateSchemas[template.schemaId] = - templateSchemas[template.schemaId]; - if (template.data) { - // if we need to fill out the form with pre-data - selectedTemplateSchemas[template.schemaId].data = template.data; - } - } - }); - - return selectedTemplateSchemas; -} - -const templateData = createTemplateData( - dataSchemas.data.dataRegistries.records -); -const initialTemplates = createInitialTemplates( - templateSource.data.source.contentTemplates -); - -function displayForm(form) { - console.log(form); -} - -storiesOf('SourceManagementForm', module) - .add('Create Source', () => { - return ( - - ); - }) - .add('Edit Source', () => { - return ( - - ); - }); diff --git a/packages/veritone-react-common/src/components/SourceManagementForm/styles.scss b/packages/veritone-react-common/src/components/SourceManagementForm/styles.scss deleted file mode 100644 index 1d9784893..000000000 --- a/packages/veritone-react-common/src/components/SourceManagementForm/styles.scss +++ /dev/null @@ -1,40 +0,0 @@ -@import 'src/styles/modules/variables'; -@import 'src/styles/modules/muiTypography'; - -.source-config-wrapper { - width: 50%; -} - -.form-scroll { - height: calc(100vh - 106px); - overflow: scroll; -} - -.form-tab { - @include mui-text('body1'); -} - -.separator { - margin: 0 15px; - align-self: center; - border-right: 1px solid $grey-1; - height: 27px; -} - -.btn-container { - position: absolute; - bottom: 0; - right: 0; - display: flex; - justify-content: flex-end; - margin-right: 80px; - padding: 20px; - - & > *:not(:last-child) { - margin-right: 20px; - } -} - -.tab-indicator { - background-color: #f9a02c !important; -} diff --git a/packages/veritone-react-common/src/components/SourceTypeField/index.js b/packages/veritone-react-common/src/components/SourceTypeField/index.js deleted file mode 100644 index 91a7381c8..000000000 --- a/packages/veritone-react-common/src/components/SourceTypeField/index.js +++ /dev/null @@ -1,167 +0,0 @@ -import React from 'react'; -import FormControl from '@material-ui/core/FormControl'; -import FormControlLabel from '@material-ui/core/FormControlLabel'; -import InputLabel from '@material-ui/core/InputLabel'; -import TextField from '@material-ui/core/TextField'; -import Checkbox from '@material-ui/core/Checkbox'; -import { - string, - bool, - func, - any, - instanceOf, - oneOfType, - oneOf -} from 'prop-types'; -import { isFunction } from 'lodash'; -import DateTimePicker from 'components/formComponents/DateTimePicker'; - -import styles from './styles.scss'; - -// This functional component will handle field type render logic -// TODO: add fields here as needed for different field types -export default function SourceTypeField({ id, type, onChange, ...rest }) { - function handleChange(e) { - if (isFunction(onChange)) { - return onChange(e, id, { ...rest, type }); - } - } - - const supportedTypes = [ - 'object', - 'string', - 'number', - 'integer', - 'boolean', - 'array', - 'dateTime', - 'geoPoint' - ]; - - const foundSupportedType = supportedTypes.find(supportedType => - type.includes(supportedType) - ); - - if (!foundSupportedType) { - return ; - } - - let FieldTypeComponent = { - dateTime: DateTimeTypeField, - boolean: BoolTypeField, - geoPoint: GeoPointField, - number: NumberField, - integer: NumberField - }[foundSupportedType]; - - if (!FieldTypeComponent) { - FieldTypeComponent = BaseField; - } - - return ; -} - -SourceTypeField.propTypes = { - id: string.isRequired, - type: string.isRequired, - title: string, - value: any, // eslint-disable-line react/forbid-prop-types - onChange: func, - required: bool -}; - -const DateTimeTypeField = ({ id, title, value, onChange, ...rest }) => { - return ( - - - {title} - - - - ); -}; - -DateTimeTypeField.propTypes = { - id: string.isRequired, - title: string, - value: oneOfType([instanceOf(Date), oneOf([''])]), - onChange: func -}; - -const BoolTypeField = ({ id, title, value, onChange, ...rest }) => { - return ( - - } - /> - ); -}; - -BoolTypeField.propTypes = { - id: string.isRequired, - title: string, - value: oneOfType([bool, oneOf([''])]), - onChange: func -}; - -const GeoPointField = props => { - return ; -}; - -const NumberField = props => { - return ; -}; - -const BaseField = ({ id, title, ...rest }) => { - const inputProps = { - label: title || id, - fullWidth: true, - margin: 'normal', - type: id.toLowerCase().includes('password') ? 'password' : 'text' - }; - - return ( - - ); -}; - -BaseField.propTypes = { - id: string.isRequired, - title: string -}; - -const UnsupportedTypeField = ({ type, title }) => { - return ( -
- {`Unsupported Type: ${type}${title ? ` for ${title}` : ''}`} -
- ); -}; - -UnsupportedTypeField.propTypes = { - type: string.isRequired, - title: string -}; diff --git a/packages/veritone-react-common/src/components/SourceTypeField/index.test.js b/packages/veritone-react-common/src/components/SourceTypeField/index.test.js deleted file mode 100644 index b36c1061b..000000000 --- a/packages/veritone-react-common/src/components/SourceTypeField/index.test.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; - -import SourceTypeField from './'; - -describe('SourceTypeField', function() { - it('renders field for supported type', () => { - const wrapper = mount( - - ); - - expect(wrapper.find("input[id='username']")).toHaveLength(1); - }); - - it("doesn't render field for unsupported types", () => { - const wrapper = mount( - - ); - - expect(wrapper.find("input[id='username']")).toHaveLength(0); - expect(wrapper.text()).toContain('Unsupported Type'); - }); -}); diff --git a/packages/veritone-react-common/src/components/SourceTypeField/story.js b/packages/veritone-react-common/src/components/SourceTypeField/story.js deleted file mode 100644 index e7ce84c5b..000000000 --- a/packages/veritone-react-common/src/components/SourceTypeField/story.js +++ /dev/null @@ -1,107 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { map } from 'lodash'; - -import SourceTypeField from './'; - -const sourceSchema = { - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name' - }, - password: { - type: 'string' - }, - active: { - type: 'boolean', - title: 'Active' - }, - price: { - type: 'number' - }, - days: { - type: 'integer' - }, - location: { - type: 'geoPoint', - title: 'Geo Location' - }, - endDate: { - type: 'dateTime', - title: 'End Date' - }, - unsupported: { - type: 'enum', - title: 'Enum' - } - }, - required: ['url', 'username', 'password'] - } -}; - -const fieldTypes = { - url: 'http://www.google.com', - username: 'vtn1', - password: 'top-secret', - price: '1.50', - days: 10, - location: ['-101.0', '11.0'], - active: true, - endDate: new Date() -}; - -class SourceTypeFields extends React.Component { - constructor(props) { - super(props); - - this.state = fieldTypes; - } - - handleChange = (e, fld, def) => { - if (def.type === 'dateTime') { - const date = e; - - return this.setState(prevState => ({ - [fld]: date - })); - } - - e.persist(); - - this.setState(prevState => ({ - [fld]: def.type !== 'boolean' ? e.target.value : !prevState[fld] - })); - }; - - handleSubmit = (e, formValues) => { - e.preventDefault(); - - console.log('Form Values:', this.state); - }; - - render() { - return ( -
- {map(sourceSchema.definition.properties, (def, field) => ( - - ))} - - - ); - } -} - -storiesOf('SourceTypeField', module).add('Fields', () => ); diff --git a/packages/veritone-react-common/src/components/SourceTypeField/styles.scss b/packages/veritone-react-common/src/components/SourceTypeField/styles.scss deleted file mode 100644 index 9cbe42568..000000000 --- a/packages/veritone-react-common/src/components/SourceTypeField/styles.scss +++ /dev/null @@ -1,16 +0,0 @@ -@import 'src/styles/modules/variables'; - -.textFieldLabel { - font-weight: normal !important; -} - -.dateTimeContainer { - padding-top: 18px !important; -} - -.unsupportedMsg { - padding-top: 20px; - color: $light-black; - font-size: 14px; - font-style: italic; -} diff --git a/packages/veritone-react-common/src/components/TopBar/styles.scss b/packages/veritone-react-common/src/components/TopBar/styles.scss index 95c56cbdc..99bdef90f 100644 --- a/packages/veritone-react-common/src/components/TopBar/styles.scss +++ b/packages/veritone-react-common/src/components/TopBar/styles.scss @@ -7,6 +7,7 @@ justify-content: space-between; left: 0; right: 0; + margin-bottom: 20px; // copied from material-ui transition: margin 195ms cubic-bezier(0.4, 0, 0.6, 1) 0ms, width 195ms cubic-bezier(0.4, 0, 0.6, 1) 0ms; diff --git a/packages/veritone-react-common/src/components/formComponents/DateTimePicker.js b/packages/veritone-react-common/src/components/formComponents/DateTimePicker.js index 07a630219..24a11cce6 100644 --- a/packages/veritone-react-common/src/components/formComponents/DateTimePicker.js +++ b/packages/veritone-react-common/src/components/formComponents/DateTimePicker.js @@ -16,7 +16,8 @@ export default class DateTimePicker extends React.Component { input: shape({ value: instanceOf(Date).isRequired, onChange: func - }).isRequired + }).isRequired, + readOnly: bool }; handleDateChange = ({ target }) => { @@ -41,30 +42,33 @@ export default class DateTimePicker extends React.Component { }; render() { + const { input, min, max, ...rest } = this.props; return (
{this.props.showIcon && } {this.props.showTimezone && ( - + )}
); } } -const DateSelector = ({ value, min, max, onChange }) => { +const DateSelector = ({ value, min, max, onChange, readOnly, ...rest }) => { return ( { max={max} value={value} onChange={onChange} + InputProps={{ + readOnly: readOnly + }} /> ); }; @@ -80,10 +87,11 @@ DateSelector.propTypes = { min: instanceOf(Date), max: instanceOf(Date), value: string.isRequired, - onChange: func.isRequired + onChange: func.isRequired, + readOnly: bool }; -const TimeSelector = ({ value, min, max, onChange }) => { +const TimeSelector = ({ value, min, max, onChange, readOnly, ...rest }) => { return ( { InputLabelProps={{ shrink: true }} + InputProps={{ + readOnly: readOnly + }} /> ); }; @@ -102,22 +113,21 @@ TimeSelector.propTypes = { min: instanceOf(Date), max: instanceOf(Date), value: string.isRequired, - onChange: func.isRequired + onChange: func.isRequired, + readOnly: bool }; -const TimeZoneField = ({ value }) => { - return ( - value && ( - - ) - ); +const TimeZoneField = ({ value, ...rest }) => { + return value ? ( + + ) : null; }; TimeZoneField.propTypes = { @@ -138,12 +148,15 @@ function getTimeString(date) { function getTimeZone(date) { let tzDate = date; - if (isString(tzDate)) { - tzDate = new Date(); - } if (dateFns.isDate(tzDate)) { const tzMatch = tzDate.toTimeString().match(/\(([^)]+)\)$/); - - return tzMatch ? tzMatch[1] : ''; + if (tzMatch && tzMatch.length > 1) { + const tzParts = tzMatch[1].split(' '); + if (tzParts.length > 1) { + return tzParts.map(part => part[0]).join(''); + } + return tzMatch[1]; + } } + return ''; } diff --git a/packages/veritone-react-common/src/components/formComponents/TimeRangePicker.js b/packages/veritone-react-common/src/components/formComponents/TimeRangePicker.js index 36db92105..29661e731 100644 --- a/packages/veritone-react-common/src/components/formComponents/TimeRangePicker.js +++ b/packages/veritone-react-common/src/components/formComponents/TimeRangePicker.js @@ -1,5 +1,5 @@ import React from 'react'; -import { string, func, shape } from 'prop-types'; +import { string, func, shape, bool } from 'prop-types'; import dateFns from 'date-fns'; import TextField from '@material-ui/core/TextField'; @@ -10,23 +10,27 @@ export default class TimeRangePicker extends React.Component { input: shape({ value: shape({ start: string, - end: string + end: string, + timeZone: string }).isRequired, onChange: func.isRequired - }).isRequired + }).isRequired, + readOnly: bool }; handleChangeStart = ({ target: { value } }) => { this.props.input.onChange({ start: value, - end: this.props.input.value.end + end: this.props.input.value.end, + timeZone: this.props.input.value.timeZone }); }; handleChangeEnd = ({ target: { value } }) => { this.props.input.onChange({ start: this.props.input.value.start, - end: value + end: value, + timeZone: this.props.input.value.timeZone }); }; @@ -51,10 +55,11 @@ export default class TimeRangePicker extends React.Component { @@ -78,11 +85,19 @@ export default class TimeRangePicker extends React.Component { } } -const TimeSelector = ({ value, onChange }) => { - return ; +const TimeSelector = ({ value, onChange, readOnly }) => { + return ( + + ); }; TimeSelector.propTypes = { value: string, - onChange: func + onChange: func, + readOnly: bool }; diff --git a/packages/veritone-react-common/src/components/formComponents/index.js b/packages/veritone-react-common/src/components/formComponents/index.js index 1fd4dd84a..8b25910f3 100644 --- a/packages/veritone-react-common/src/components/formComponents/index.js +++ b/packages/veritone-react-common/src/components/formComponents/index.js @@ -6,4 +6,5 @@ export RadioGroup from './RadioGroup'; export Select from './Select'; export TextField from './TextField'; export DateTimePicker from './DateTimePicker'; +export TimeRangePicker from './TimeRangePicker'; export Switch from './Switch'; diff --git a/packages/veritone-react-common/src/components/formComponents/story.js b/packages/veritone-react-common/src/components/formComponents/story.js index e8bda7ef7..2a4ce08f9 100644 --- a/packages/veritone-react-common/src/components/formComponents/story.js +++ b/packages/veritone-react-common/src/components/formComponents/story.js @@ -1,7 +1,8 @@ import React from 'react'; -import { createStore, combineReducers } from 'redux'; +import { createStore, combineReducers, compose, applyMiddleware } from 'redux'; import { Provider } from 'react-redux'; import { reducer as formReducer, reduxForm, Field } from 'redux-form'; +import { createLogger } from 'redux-logger'; import { storiesOf } from '@storybook/react'; import InputLabel from '@material-ui/core/InputLabel'; import InputAdornment from '@material-ui/core/InputAdornment'; @@ -27,12 +28,20 @@ import DateIntervalSelect from './DateIntervalSelect'; import DateRangePicker from './DateRangePicker'; import DateTimePicker from './DateTimePicker'; import Switch from './Switch'; +import TimeRangePicker from './TimeRangePicker'; +const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const store = createStore( combineReducers({ form: formReducer }), - window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() + composeEnhancers( + applyMiddleware( + createLogger({ + collapsed: true + }) + ) + ) ); const StoryForm = reduxForm({ @@ -374,6 +383,23 @@ storiesOf('Form Components', module) ); }) + .add('TimeRangePicker', () => { + return ( + + alert(JSON.stringify(values))} + initialValues={{ + timeRange: { + start: '12:00', + end: '14:00' + } + }} + > + + + + ); + }) .add('Switch', () => ( alert(JSON.stringify(values))}> diff --git a/packages/veritone-react-common/src/index.js b/packages/veritone-react-common/src/index.js index 66415faae..5f271d13b 100644 --- a/packages/veritone-react-common/src/index.js +++ b/packages/veritone-react-common/src/index.js @@ -41,12 +41,5 @@ export ExpandableInputField from './components/ExpandableInputField'; export SearchBar from './components/SearchBar'; export BoundingPolyOverlay from './components/BoundingPolyOverlay/Overlay'; export OverlayPositioningProvider from './components/BoundingPolyOverlay/OverlayPositioningProvider'; -export SDOTable from './components/SDOTable'; -export * as IngestionJobs from './components/IngestionJobs'; -export ContentTemplateForm from './components/ContentTemplates/ContentTemplateForm'; -export ContentTemplate from './components/ContentTemplates'; -export SourceManagementForm from './components/SourceManagementForm'; -export * as SourceManagement from './components/SourceManagement'; export { Interval, defaultIntervals } from 'helpers/date'; -export Scheduler from './components/Scheduler'; export StatusPill from './components/StatusPill'; diff --git a/packages/veritone-react-common/src/styles/global.scss b/packages/veritone-react-common/src/styles/global.scss index 2df79430c..12ad9f7a6 100644 --- a/packages/veritone-react-common/src/styles/global.scss +++ b/packages/veritone-react-common/src/styles/global.scss @@ -3,7 +3,7 @@ // roboto font @import url('https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500'); // veritone icons -@import url('https://static.veritone.com/veritone-ui/veritone-icons-22/style.css'); +@import url('https://static.veritone.com/veritone-ui/veritone-icons-25/style.css'); // veritone engine icons @import url('https://static.veritone.com/engines/assets/v001/style.css'); diff --git a/packages/veritone-react-common/src/styles/modules/_variables.scss b/packages/veritone-react-common/src/styles/modules/_variables.scss index 59b50c0ff..aaee060bd 100644 --- a/packages/veritone-react-common/src/styles/modules/_variables.scss +++ b/packages/veritone-react-common/src/styles/modules/_variables.scss @@ -13,6 +13,7 @@ $grey-5: #727272; $grey-6: #666; $light-blue50: #e1f5fe; +$light-blue: #e3f2fd; $blue-1: #2196f3; $blue-2: darken(#2196f3, 15%); diff --git a/packages/veritone-redux-common/src/helpers/api/fetchGraphQLApi.js b/packages/veritone-redux-common/src/helpers/api/fetchGraphQLApi.js index dc1cd845d..1d073435e 100644 --- a/packages/veritone-redux-common/src/helpers/api/fetchGraphQLApi.js +++ b/packages/veritone-redux-common/src/helpers/api/fetchGraphQLApi.js @@ -5,7 +5,9 @@ export default function fetchGraphQLApi({ query, variables, operationName, - token + token, + dispatch, + getState }) { return fetch(endpoint, { method: 'post', diff --git a/packages/veritone-widgets/src/build-entry.js b/packages/veritone-widgets/src/build-entry.js index aa860438a..a3489d6cd 100644 --- a/packages/veritone-widgets/src/build-entry.js +++ b/packages/veritone-widgets/src/build-entry.js @@ -7,23 +7,20 @@ export OAuthLoginButton, { OAuthLoginButtonWidget } from './widgets/OAuthLoginButton'; export FilePicker, { FilePickerWidget } from './widgets/FilePicker'; +export filePickerReducer, * as filePickerModule from './redux/modules/filePicker'; +export filePickerSaga from './redux/modules/filePicker/filePickerSaga'; export { EngineSelectionWidget } from './widgets/EngineSelection'; -export { TableWidget } from './widgets/Table'; +export { TableWidget as Table, TableWidget } from './widgets/Table'; export { GlobalNotificationDialog, GlobalSnackBar } from './widgets/Notifications'; export notificationsReducer, * as notificationsModule from './redux/modules/notifications'; -// export ContentTemplate from './widgets/ContentTemplate'; -// export ContentTemplateForm from './widgets/ContentTemplateForm'; -// export SourceManagementForm from './widgets/SourceManagementForm'; -// export SourceList from './widgets/SourceList'; export { MediaPlayer } from './widgets/MediaPlayer'; export MediaPlayerControlBar from './widgets/MediaPlayer/DefaultControlBar'; export EngineOutputExport, { EngineOutputExportWidget } from './widgets/EngineOutputExport'; export engineOutputExportReducer, * as engineOutputExportModule from './redux/modules/engineOutputExport'; -// export SDOTable from './widgets/SDOTable'; -// export IngestionJobsList from './widgets/IngestionJobsList'; export { SchedulerWidget } from './widgets/Scheduler'; +export { UserProfileWidget } from './widgets/UserProfile'; \ No newline at end of file diff --git a/packages/veritone-widgets/src/redux/modules/engineOutputExport/index.js b/packages/veritone-widgets/src/redux/modules/engineOutputExport/index.js index b38ca5d7f..0a1007c8c 100644 --- a/packages/veritone-widgets/src/redux/modules/engineOutputExport/index.js +++ b/packages/veritone-widgets/src/redux/modules/engineOutputExport/index.js @@ -1,4 +1,4 @@ -import { forEach, get, uniqWith } from 'lodash'; +import { forEach, get, uniqWith, pick } from 'lodash'; import { helpers } from 'veritone-redux-common'; const { createReducer, callGraphQLApi } = helpers; @@ -17,6 +17,10 @@ export const UPDATE_SELECTED_FILE_TYPES = `vtn/${namespace}/UPDATE_SELECTED_FILE export const APPLY_SUBTITLE_CONFIGS = `vtn/${namespace}/APPLY_SUBTITLE_CONFIGS`; export const STORE_SUBTITLE_CONFIGS = `vtn/${namespace}/STORE_SUBTITLE_CONFIGS`; +export const APPLY_SPEAKER_TOGGLE = `vtn/${namespace}/APPLY_SPEAKER_TOGGLE`; +export const STORE_SPEAKER_TOGGLE = `vtn/${namespace}/STORE_SPEAKER_TOGGLE`; +export const STORE_HAS_SPEAKER_DATA = `vtn/${namespace}/STORE_HAS_SPEAKER_DATA`; + export const START_EXPORT_AND_DOWNLOAD = `vtn/${namespace}/START_EXPORT_AND_DOWNLOAD`; export const EXPORT_AND_DOWNLOAD_SUCCESS = `vtn/${namespace}/EXPORT_AND_DOWNLOAD_SUCCESS`; export const EXPORT_AND_DOWNLOAD_FAILURE = `vtn/${namespace}/EXPORT_AND_DOWNLOAD_FAILURE`; @@ -32,11 +36,17 @@ const defaultState = { categoryLookup: {}, expandedCategories: {}, subtitleConfigCache: {}, + speakerToggleCache: { + withSpeakerData: true // Default value across all categories + }, + hasSpeakerData: false, outputConfigurations: [], errorSnackBars: [], fetchEngineRunsFailed: false, exportAndDownloadFailed: false, - isBulkExport: false + isBulkExport: false, + transcriptCategoryType: 'transcript', + speakerCategoryType: 'speaker' }; export default createReducer(defaultState, { @@ -69,12 +79,14 @@ export default createReducer(defaultState, { if (!categoryLookup[engineRun.category.id]) { newOutputConfigurations.push({ categoryId: engineRun.category.id, + categoryType: engineRun.category.categoryType, formats: [] }); } } else { newOutputConfigurations.push({ engineId: engineRun.id, + categoryType: engineRun.category.categoryType, formats: [] }); } @@ -164,6 +176,14 @@ export default createReducer(defaultState, { 'subtitleConfigCache', categoryId ]); + const storedSpeakerToggle = state.hasSpeakerData + ? ( + get(state, [ + 'speakerToggleCache', + categoryId + ]) || get(state, 'speakerToggleCache') + ) + : {}; return { ...config, formats: selectedFileTypes.map(type => { @@ -171,9 +191,12 @@ export default createReducer(defaultState, { extension: type, options: storedSubtitleConfig ? { - ...storedSubtitleConfig + ...storedSubtitleConfig, + ...storedSpeakerToggle } - : {} + : { + ...storedSpeakerToggle + } }; }) }; @@ -182,6 +205,70 @@ export default createReducer(defaultState, { }) }; }, + [APPLY_SPEAKER_TOGGLE]( + state, + { + payload: { categoryId, values } + } + ) { + return { + ...state, + outputConfigurations: state.outputConfigurations.map(config => { + let engineCategoryId; + if (!config.categoryId && config.engineId) { + engineCategoryId = get(state, [ + 'enginesRan', + config.engineId, + 'category', + 'id' + ]); + } + if ( + config.categoryId === categoryId || + engineCategoryId === categoryId + ) { + return { + ...config, + formats: config.formats.map(format => { + return { + ...format, + options: { + ...format.options, + withSpeakerData: values + } + }; + }) + }; + } + return config; + }) + } + }, + [STORE_SPEAKER_TOGGLE]( + state, + { + payload: { categoryId, config } + } + ) { + return { + ...state, + speakerToggleCache: { + ...state.speakerToggleCache, + ...config + } + }; + }, + [STORE_HAS_SPEAKER_DATA]( + state, + { + payload: { hasSpeakerData } + } + ) { + return { + ...state, + hasSpeakerData + } + }, [APPLY_SUBTITLE_CONFIGS]( state, { @@ -285,7 +372,8 @@ function local(state) { export const getIncludeMedia = state => get(local(state), 'includeMedia'); export const outputConfigsByCategoryId = state => { const outputConfigsByCategoryId = {}; - forEach(get(local(state), 'outputConfigurations'), config => { + const outputConfigurations = get(local(state), 'outputConfigurations'); + forEach(outputConfigurations, config => { if (config.categoryId) { if (!outputConfigsByCategoryId[config.categoryId]) { outputConfigsByCategoryId[config.categoryId] = []; @@ -321,8 +409,20 @@ export const getOutputConfigurations = state => export const errorSnackBars = state => get(local(state), 'errorSnackBars'); export const fetchEngineRunsFailed = state => get(local(state), 'fetchEngineRunsFailed'); +export const speakerCategoryType = state => + get(local(state), 'speakerCategoryType'); +export const transcriptCategoryType = state => + get(local(state), 'transcriptCategoryType'); export const getSubtitleConfig = (state, categoryId) => get(local(state), ['subtitleConfigCache', categoryId]); +export const getSpeakerToggle = (state, categoryId) => { + // If the category speaker toggle is undefined, then + // fallback to the default across all categories + const speakerToggleCache = get(local(state), ['speakerToggleCache', categoryId]) || + get(local(state), 'speakerToggleCache'); + return speakerToggleCache; +}; +export const hasSpeakerData = (state) => get(local(state), 'hasSpeakerData'); export const isBulkExport = state => get(local(state), 'isBulkExport'); export const selectedFormats = state => get(local(state), 'outputConfigurations').reduce((accumulator, configObj) => { @@ -345,6 +445,7 @@ export const fetchEngineRuns = tdos => async (dispatch, getState) => { category { id name + categoryType iconClass exportFormats { format @@ -430,7 +531,8 @@ export const exportAndDownload = tdoData => async (dispatch, getState) => { query, variables: { includeMedia: getIncludeMedia(getState()), - outputConfigurations: getOutputConfigurations(getState()), + outputConfigurations: getOutputConfigurations(getState()) + .map(config => pick(config, ['engineId', 'categoryId', 'formats'])), tdoData }, dispatch, @@ -477,6 +579,35 @@ export const applySubtitleConfigs = (categoryId, values) => { }; }; +export const applySpeakerToggle = (categoryId, values) => { + return { + type: APPLY_SPEAKER_TOGGLE, + payload: { + categoryId, + values + } + }; +}; + +export const storeSpeakerToggle = (categoryId, config) => { + return { + type: STORE_SPEAKER_TOGGLE, + payload: { + categoryId, + config + } + }; +}; + +export const setHasSpeakerData = hasSpeakerData => { + return { + type: STORE_HAS_SPEAKER_DATA, + payload: { + hasSpeakerData + } + }; +}; + export const addSnackBar = snackBarConfig => { return { type: ADD_SNACK_BAR, @@ -503,4 +634,4 @@ export const storeSubtitleConfigs = (categoryId, config) => { config } }; -}; +}; \ No newline at end of file diff --git a/packages/veritone-widgets/src/widgets/ContentTemplate/index.js b/packages/veritone-widgets/src/widgets/ContentTemplate/index.js deleted file mode 100644 index b2b3005d7..000000000 --- a/packages/veritone-widgets/src/widgets/ContentTemplate/index.js +++ /dev/null @@ -1,125 +0,0 @@ -import React from 'react'; -import { get } from 'lodash'; -import { objectOf, any, func, number } from 'prop-types'; -import { ContentTemplate } from 'veritone-react-common'; - -import widget from '../../shared/widget'; - -class ContentTemplateWidget extends React.Component { - static propTypes = { - templateData: objectOf(any).isRequired, - initialTemplates: objectOf(any), - handleUpdateContentTemplates: func.isRequired, - textInputMaxRows: number - }; - - static defaultProps = { - initialTemplates: {} - }; - - state = { - contentTemplates: {} - }; - - // eslint-disable-next-line react/sort-comp - UNSAFE_componentWillMount() { - const newState = { - contentTemplates: { ...this.props.initialTemplates } - }; - - this.setState(newState); - } - - addToTemplateList = templateSchemaId => { - const { templateData, initialTemplates } = this.props; - const data = {}; - - Object.keys(templateData[templateSchemaId].definition.properties).reduce( - (fields, schemaDefProp) => { - const value = get(initialTemplates, [ - templateSchemaId, - 'data', - schemaDefProp - ]); - if (value) { - data[schemaDefProp] = value; - } - }, - data - ); - - const newState = { - contentTemplates: { - ...this.state.contentTemplates, - [templateSchemaId]: { - ...templateData[templateSchemaId], - data - } - } - }; - - this.setState(newState, () => { - this.props.handleUpdateContentTemplates(newState.contentTemplates); - }); - }; - - removeFromTemplateList = templateSchemaId => { - if (this.state.contentTemplates[templateSchemaId]) { - const contentTemplates = { ...this.state.contentTemplates }; - delete contentTemplates[templateSchemaId]; - - const newState = { contentTemplates }; - - this.setState(newState, () => { - this.props.handleUpdateContentTemplates(newState.contentTemplates); - }); - } - }; - - onInputChange = (templateSchemaId, fieldId, value) => { - let newState; - const { contentTemplates } = this.state; - - this.setState( - prevState => { - newState = { - contentTemplates: { - ...contentTemplates, - [templateSchemaId]: { - ...contentTemplates[templateSchemaId], - data: { - ...contentTemplates[templateSchemaId].data - } - } - } - }; - - if (value) { - newState.contentTemplates[templateSchemaId].data[fieldId] = value; - } else { - delete newState.contentTemplates[templateSchemaId].data[fieldId]; - } - - return newState; - }, - () => { - this.props.handleUpdateContentTemplates(newState.contentTemplates); - } - ); - }; - - render() { - return ( - - ); - } -} - -export default widget(ContentTemplateWidget); diff --git a/packages/veritone-widgets/src/widgets/ContentTemplate/story.js b/packages/veritone-widgets/src/widgets/ContentTemplate/story.js deleted file mode 100644 index af76b176a..000000000 --- a/packages/veritone-widgets/src/widgets/ContentTemplate/story.js +++ /dev/null @@ -1,186 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { text } from '@storybook/addon-knobs'; - -import VeritoneApp from '../../shared/VeritoneApp'; -import ContentTemplateWidget from './'; -import { has } from 'lodash'; - -// CONTENT TEMPLATES SETUP -const source = { - data: { - source: { - id: '666', - name: 'KWOL--FM', - contentTemplates: [ - { - schemaId: 'schemaGuid1', - data: { - url: 'twitter.com', - username: 'THEREALTRUMP' - } - } - ] - } - } -}; - -//// FORM CARDS LIST SETUP -const result = { - data: { - dataRegistries: { - records: [ - { - name: 'Twitter Schema', - schemas: { - records: [ - { - id: 'schemaGuid1', - status: 'published', - definition: { - properties: { - url: { - type: 'string', - title: 'URL' - }, - username: { - type: 'string' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema 2' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - }, - password: { - type: 'string' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - test: 'citest' - } - }, - { - id: 'schemaGuid2', - status: 'draft', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - } - } - } - } - ] - } - } - ] - } - } -}; - -function createTemplateData(dataSchemas) { - const templateSchemas = {}; - // array of data registries containing an array of schemas - dataSchemas.reduce((schemaStore, registryData) => { - registryData.schemas.records.forEach(schema => { - // only take schemas that are 'published' and also define field types - if ( - schema.status === 'published' && - has(schema.definition, 'properties') - ) { - schemaStore[schema.id] = { - name: registryData.name, - ...schema - }; - } - }); - }, templateSchemas); - - return templateSchemas; -} - -function createInitialTemplates(templateSources) { - const selectedTemplateSchemas = {}; - - const templateSchemas = createTemplateData( - result.data.dataRegistries.records - ); - templateSources.forEach(template => { - if (has(templateSchemas, template.schemaId)) { - selectedTemplateSchemas[template.schemaId] = - templateSchemas[template.schemaId]; - if (template.data) { - // if we need to fill out the form with pre-data - selectedTemplateSchemas[template.schemaId].data = template.data; - } - } - }); - - return selectedTemplateSchemas; -} - -const templateData = createTemplateData(result.data.dataRegistries.records); -const initialTemplates = createInitialTemplates( - source.data.source.contentTemplates -); - -class Story extends React.Component { - componentDidMount() { - this._ctWidget = new ContentTemplateWidget({ - elId: 'ct-widget', - title: 'Content Template Widget', - templateData, - initialTemplates, - handleUpdateContentTemplates: function(data) { - console.log('data:', data); - }, - textInputMaxRows: 10 - }); - } - - componentWillUnmount() { - this._ctWidget.destroy(); - } - - render() { - return ( -
- -
- ); - } -} - -const app = VeritoneApp(); - -storiesOf('Content Template', module).add('Base', () => { - const sessionToken = text('Api Session Token', ''); - - return ; -}); diff --git a/packages/veritone-widgets/src/widgets/ContentTemplateForm/index.js b/packages/veritone-widgets/src/widgets/ContentTemplateForm/index.js deleted file mode 100644 index 0a1fd25f5..000000000 --- a/packages/veritone-widgets/src/widgets/ContentTemplateForm/index.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import { objectOf, any, func, number } from 'prop-types'; -import { ContentTemplateForm } from 'veritone-react-common'; -import { pick } from 'lodash'; - -import widget from '../../shared/widget'; - -class ContentTemplateFormWidget extends React.Component { - static propTypes = { - templateData: objectOf(any).isRequired, - initialTemplates: objectOf(any), - onSubmit: func.isRequired, - textInputMaxRows: number - }; - - render() { - const templateFormProps = pick(this.props, [ - 'templateData', - 'initialTemplates', - 'textInputMaxRows' - ]); - return ( - - ); - } -} - -export default widget(ContentTemplateFormWidget); diff --git a/packages/veritone-widgets/src/widgets/ContentTemplateForm/story.js b/packages/veritone-widgets/src/widgets/ContentTemplateForm/story.js deleted file mode 100644 index f623812eb..000000000 --- a/packages/veritone-widgets/src/widgets/ContentTemplateForm/story.js +++ /dev/null @@ -1,186 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { text } from '@storybook/addon-knobs'; - -import VeritoneApp from '../../shared/VeritoneApp'; -import ContentTemplateFormWidget from './'; -import { has } from 'lodash'; - -// CONTENT TEMPLATES SETUP -const source = { - data: { - source: { - id: '666', - name: 'KWOL--FM', - contentTemplates: [ - { - schemaId: 'schemaGuid1', - data: { - url: 'twitter.com', - username: 'THEREALTRUMP' - } - } - ] - } - } -}; - -//// FORM CARDS LIST SETUP -const result = { - data: { - dataRegistries: { - records: [ - { - name: 'Twitter Schema', - schemas: { - records: [ - { - id: 'schemaGuid1', - status: 'published', - definition: { - properties: { - url: { - type: 'string', - title: 'URL' - }, - username: { - type: 'string' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema 2' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - }, - password: { - type: 'string' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - test: 'citest' - } - }, - { - id: 'schemaGuid2', - status: 'draft', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - } - } - } - } - ] - } - } - ] - } - } -}; - -function createTemplateData(dataSchemas) { - const templateSchemas = {}; - // array of data registries containing an array of schemas - dataSchemas.reduce((schemaStore, registryData) => { - registryData.schemas.records.forEach(schema => { - // only take schemas that are 'published' and also define field types - if ( - schema.status === 'published' && - has(schema.definition, 'properties') - ) { - schemaStore[schema.id] = { - name: registryData.name, - ...schema - }; - } - }); - }, templateSchemas); - - return templateSchemas; -} - -function createInitialTemplates(templateSources) { - const selectedTemplateSchemas = {}; - - const templateSchemas = createTemplateData( - result.data.dataRegistries.records - ); - templateSources.forEach(template => { - if (has(templateSchemas, template.schemaId)) { - selectedTemplateSchemas[template.schemaId] = - templateSchemas[template.schemaId]; - if (template.data) { - // if we need to fill out the form with pre-data - selectedTemplateSchemas[template.schemaId].data = template.data; - } - } - }); - - return selectedTemplateSchemas; -} - -const templateData = createTemplateData(result.data.dataRegistries.records); -const initialTemplates = createInitialTemplates( - source.data.source.contentTemplates -); - -class Story extends React.Component { - componentDidMount() { - this._ctFormWidget = new ContentTemplateFormWidget({ - elId: 'ct-form-widget', - title: 'Content Template Form Widget', - templateData, - initialTemplates, - onSubmit: function(data) { - console.log('data:', data); - }, - textInputMaxRows: 5 - }); - } - - componentWillUnmount() { - this._ctFormWidget.destroy(); - } - - render() { - return ( -
- -
- ); - } -} - -const app = VeritoneApp(); - -storiesOf('Content Template Form', module).add('Form', () => { - const sessionToken = text('Api Session Token', ''); - - return ; -}); diff --git a/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfig.js b/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfig.js index 39cb1cd12..eb44de255 100644 --- a/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfig.js +++ b/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfig.js @@ -15,9 +15,11 @@ import Dialog from '@material-ui/core/Dialog'; import DialogContent from '@material-ui/core/DialogContent'; import DialogTitle from '@material-ui/core/DialogTitle'; import DialogContentText from '@material-ui/core/DialogContentText'; +import Switch from '@material-ui/core/Switch'; import ExpandLessIcon from '@material-ui/icons/ExpandLess'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import ClosedCaptionIcon from '@material-ui/icons/ClosedCaption'; +import RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver'; import EngineConfigItem from './EngineConfigItem'; import SubtitleConfigForm from './SubtitleConfigForm'; @@ -28,19 +30,28 @@ import * as engineOutputExportModule from '../../redux/modules/engineOutputExpor @connect( (state, { categoryId }) => ({ category: engineOutputExportModule.getCategoryById(state, categoryId), + transcriptCategoryType: engineOutputExportModule.transcriptCategoryType(state), initialSubtitleConfig: engineOutputExportModule.getSubtitleConfig( state, categoryId - ) + ), + initialSpeakerToggle: engineOutputExportModule.getSpeakerToggle( + state, + categoryId + ), + hasSpeakerData: engineOutputExportModule.hasSpeakerData(state) }), { - applySubtitleConfigs: engineOutputExportModule.applySubtitleConfigs + applySubtitleConfigs: engineOutputExportModule.applySubtitleConfigs, + applySpeakerToggle: engineOutputExportModule.applySpeakerToggle, + storeSpeakerToggle: engineOutputExportModule.storeSpeakerToggle }, null, { withRef: true } ) export default class EngineCategoryConfig extends Component { static propTypes = { + transcriptCategoryType: string, category: shape({ id: string.isRequired, iconClass: string.isRequired, @@ -69,6 +80,11 @@ export default class EngineCategoryConfig extends Component { maxCharacterPerLine: number, newLineOnPunctuation: bool, linesPerScreen: number + }), + applySpeakerToggle: func, + storeSpeakerToggle: func, + initialSpeakerToggle: shape({ + withSpeakerData: bool }) }; @@ -95,14 +111,26 @@ export default class EngineCategoryConfig extends Component { }); }; + handleSpeakerToggle = (event, values) => { + this.props.applySpeakerToggle(this.props.category.id, values); + this.props.storeSpeakerToggle(this.props.category.id, { + [this.props.category.id]: { + withSpeakerData: values + } + }); + }; + render() { const { category, engineCategoryConfigs, onExpandConfigs, expanded, - initialSubtitleConfig + initialSubtitleConfig, + initialSpeakerToggle, + transcriptCategoryType } = this.props; + const isTranscriptionCategory = category.categoryType === transcriptCategoryType; let hasSubtitleFormatsSelected = false; forEach(engineCategoryConfigs, config => { @@ -117,6 +145,7 @@ export default class EngineCategoryConfig extends Component { }); } }); + const hasSpeakerData = get(this.props, 'hasSpeakerData'); const defaultSubtitleConfig = { linesPerScreen: 2, @@ -160,11 +189,28 @@ export default class EngineCategoryConfig extends Component { /> ); })} + {hasSpeakerData && isTranscriptionCategory && ( + +
+ + + Include speaker separation results + + +
+
+ )} {hasSubtitleFormatsSelected && (
- - + + Subtitle formats have been selected, adjust the format and display settings here @@ -205,4 +251,4 @@ export default class EngineCategoryConfig extends Component {
); } -} +} \ No newline at end of file diff --git a/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfigList.js b/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfigList.js index 308c1713e..47fcd4be4 100644 --- a/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfigList.js +++ b/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfigList.js @@ -25,11 +25,14 @@ import styles from './styles.scss'; state ), expandedCategories: engineOutputExportModule.expandedCategories(state), - fetchingEngineRuns: engineOutputExportModule.fetchingEngineRuns(state) + fetchingEngineRuns: engineOutputExportModule.fetchingEngineRuns(state), + speakerCategoryType: engineOutputExportModule.speakerCategoryType(state), + hasSpeakerData: engineOutputExportModule.hasSpeakerData(state) }), { fetchEngineRuns: engineOutputExportModule.fetchEngineRuns, - toggleConfigExpand: engineOutputExportModule.toggleConfigExpand + toggleConfigExpand: engineOutputExportModule.toggleConfigExpand, + setHasSpeakerData: engineOutputExportModule.setHasSpeakerData }, null, { withRef: true } @@ -55,26 +58,56 @@ export default class EngineCategoryConfigList extends Component { expandedCategories: objectOf(bool), fetchEngineRuns: func, fetchingEngineRuns: bool, - toggleConfigExpand: func + toggleConfigExpand: func, + setHasSpeakerData: func, + hasSpeakerData: bool, + speakerCategoryType: string }; componentDidMount() { this.props.fetchEngineRuns(this.props.tdos); } + componentDidUpdate() { + // Detect if speaker data is available + const { + speakerCategoryType, + outputConfigsByCategoryId + } = this.props; + let hasSpeakerDataBeenSet = this.props.hasSpeakerData; + Object.keys(outputConfigsByCategoryId).forEach(categoryId => { + const categoryEngines = outputConfigsByCategoryId[categoryId]; + categoryEngines.forEach(engine => { + const isSpeakerCategory = engine.categoryType === speakerCategoryType; + if (isSpeakerCategory && !hasSpeakerDataBeenSet) { + hasSpeakerDataBeenSet = true; + this.props.setHasSpeakerData(true); + } + }); + }); + } + render() { const { fetchingEngineRuns, outputConfigsByCategoryId, expandedCategories, - toggleConfigExpand + toggleConfigExpand, + speakerCategoryType } = this.props; + // Temporary bypass of speaker category since we are planning + // to separate it from transcription output in the future + const modifiedOutputConfigsByCategoryId = Object.keys(outputConfigsByCategoryId) + .filter(categoryId => + outputConfigsByCategoryId[categoryId].find(engine => engine.categoryType !== speakerCategoryType) + ); + return (
{!fetchingEngineRuns ? ( - {Object.keys(outputConfigsByCategoryId).map((key, index) => ( + {modifiedOutputConfigsByCategoryId.map((key, index) => ( ); } -} +} \ No newline at end of file diff --git a/packages/veritone-widgets/src/widgets/EngineOutputExport/index.test.js b/packages/veritone-widgets/src/widgets/EngineOutputExport/index.test.js index e45d098e4..c427606ed 100644 --- a/packages/veritone-widgets/src/widgets/EngineOutputExport/index.test.js +++ b/packages/veritone-widgets/src/widgets/EngineOutputExport/index.test.js @@ -12,6 +12,7 @@ import Button from '@material-ui/core/Button'; import Collapse from '@material-ui/core/Collapse'; import List from '@material-ui/core/List'; +import EngineCategoryConfigList from './EngineCategoryConfigList'; import EngineCategoryConfig from './EngineCategoryConfig'; import EngineConfigItem from './EngineConfigItem'; import SubtitleConfigForm from './SubtitleConfigForm'; @@ -21,6 +22,25 @@ import styles from './styles.scss'; const mockStore = configureMockStore(); +const testTDOs = [{ tdoId: 'fakeTDOId '}]; + +const testSpeakerEngine = { + id: 'speakerEngineId', + name: 'Test Speaker Engine', + category: { + id: 'a856c447-1030-4fb0-917f-08179f949c4e', + name: 'Test Speaker Category', + iconClass: 'icon-speaker-separation', + exportFormats: [ + { + label: 'Test Format', + format: 'test', + types: [] + } + ] + } +}; + const testEngine = { id: 'testEngineId', name: 'Test Engine', @@ -48,6 +68,14 @@ const testOutputConfigs = [ } ]; +const testSpeakerOutputConfigs = [ + { + engineId: testSpeakerEngine.id, + categoryId: testSpeakerEngine.category.id, + formats: [] + } +]; + const defaultStore = { engineOutputExport: { enginesRan: { @@ -63,6 +91,66 @@ const defaultStore = { } }; +const defaultSpeakerStore = { + engineOutputExport: { + enginesRan: { + [testSpeakerEngine.id]: testSpeakerEngine + }, + categoryLookup: { + [testSpeakerEngine.category.id]: testSpeakerEngine.category + }, + outputConfigurations: testSpeakerOutputConfigs, + expandedCategories: { + [testSpeakerEngine.category.id]: false + }, + speakerToggleCache: { + withSpeakerData: true + }, + hasSpeakerData: true + } +}; + +describe('EngineCategoryConfigList', () => { + let wrapper, store; + + //TODO: fix this test. It is throwing an error when trying to mount the component. + xdescribe('when speaker data is available', () => { + beforeEach(() => { + store = mockStore(defaultSpeakerStore); + + wrapper = mount( + + + + ); + }); + + afterEach(() => { + store = mockStore(defaultStore); + }); + + it('should not be displayed in the list', () => { + expect( + wrapper.find(EngineCategoryConfig) + .exists() + ).toEqual(false); + }); + }); +}); + describe('EngineCategoryConfig', () => { let wrapper, onExpandConfigs, store; @@ -351,4 +439,4 @@ describe('SubtitleConfigForm', () => { wrapper.find('form').simulate('submit'); expect(onSubmit).toHaveBeenCalled(); }); -}); +}); \ No newline at end of file diff --git a/packages/veritone-widgets/src/widgets/EngineOutputExport/styles.scss b/packages/veritone-widgets/src/widgets/EngineOutputExport/styles.scss index 45034c243..eb4887540 100644 --- a/packages/veritone-widgets/src/widgets/EngineOutputExport/styles.scss +++ b/packages/veritone-widgets/src/widgets/EngineOutputExport/styles.scss @@ -105,13 +105,13 @@ background-color: rgba(33, 150, 243, 0.1); padding: 15px 5px 15px 15px; - .closedCaptionIcon { + .customizeSettingsIcon { color: $grey-5; margin-right: 5px; flex: none; } - .customizeSubtitleText { + .customizeSettingsText { flex: auto; } @@ -156,4 +156,4 @@ .errorSnackBar { background-color: $red500 !important; -} +} \ No newline at end of file diff --git a/packages/veritone-widgets/src/widgets/EngineSelection/EngineListView/EngineListContainer/EngineSelectionRow/index.js b/packages/veritone-widgets/src/widgets/EngineSelection/EngineListView/EngineListContainer/EngineSelectionRow/index.js index 408f0b138..73e27d1ba 100644 --- a/packages/veritone-widgets/src/widgets/EngineSelection/EngineListView/EngineListContainer/EngineSelectionRow/index.js +++ b/packages/veritone-widgets/src/widgets/EngineSelection/EngineListView/EngineListContainer/EngineSelectionRow/index.js @@ -127,6 +127,7 @@ export default class EngineSelectionRow extends React.Component {
diff --git a/packages/veritone-widgets/src/widgets/IngestionJobsList/index.js b/packages/veritone-widgets/src/widgets/IngestionJobsList/index.js deleted file mode 100644 index 67c0f2204..000000000 --- a/packages/veritone-widgets/src/widgets/IngestionJobsList/index.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import { arrayOf, object, func, bool } from 'prop-types'; -import { IngestionJobs } from 'veritone-react-common'; -import { omit } from 'lodash'; - -import widget from '../../shared/widget'; - -const { NullState, ListView } = IngestionJobs; - -class IngestionJobListWidget extends React.Component { - static propTypes = { - jobs: arrayOf(object).isRequired, - onCreateJob: func.isRequired, - onSelectJob: func, - onSelectMenuItem: func, - paginate: bool, - fetchData: func - }; - - state = { - jobs: this.props.jobs - }; - - handleFetchData = ({ start, end }) => { - const perPage = end - start + 1; - const jobsCount = this.state.jobs.length; - - if ( - this.props.fetchData && - (!this.state.jobs[end + 1] || jobsCount - perPage < perPage) - ) { - const limit = !(jobsCount % perPage) ? perPage : jobsCount % perPage; - - this.props.fetchData(limit, jobsCount); - } - }; - - updateJobs = jobs => { - this.setState({ - jobs - }); - }; - - render() { - const viewProps = omit(this.props, ['onCreateJob', 'jobs', 'fetchData']); - - return !this.state.jobs.length ? ( - - ) : ( - - ); - } -} - -export default widget(IngestionJobListWidget); diff --git a/packages/veritone-widgets/src/widgets/IngestionJobsList/story.js b/packages/veritone-widgets/src/widgets/IngestionJobsList/story.js deleted file mode 100644 index 214381aca..000000000 --- a/packages/veritone-widgets/src/widgets/IngestionJobsList/story.js +++ /dev/null @@ -1,245 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { text } from '@storybook/addon-knobs'; - -import VeritoneApp from '../../shared/VeritoneApp'; -import IngestionJobsListWidget from './'; - -const ingestionJobs = { - data: { - scheduledJobs: { - records: [ - { - id: '35986', - isActive: true, - name: 'test time', - jobs: { - records: [ - { - id: '00b6b071-86b9-43f7-826b-9dd75aeb6e93', - createdDateTime: '2018-04-10T18:36:26.000Z' - }, - { - id: '3902249e-edd1-4296-9ba1-3a30b14eb2ac', - createdDateTime: '2018-04-10T05:04:23.000Z' - }, - { - id: 'c019cb93-2fbe-4a38-8640-a567aeefd574', - createdDateTime: '2018-04-10T04:53:35.000Z' - } - ] - }, - jobTemplates: { - records: [ - { - taskTemplates: { - records: [ - { - engineId: 'thumbnail-generator', - id: '600d313f-fc9b-4374-b8d7-e452a3c050af', - engine: { - name: 'Thumbnail generation', - category: { - name: 'Thumbnail', - id: 'f951fbf9-aa69-47a2-87c8-12dfb51a1f18', - type: { - name: 'Cognition' - }, - iconClass: 'icon-transcription' - }, - validStateActions: ['disable'] - } - }, - { - engineId: 'd1bc57fe-675d-435d-9f4d-2f074485ec55', - id: '33c454e5-308f-4752-ba01-5c283520b91f', - engine: { - name: 'Kurento Adapter', - category: { - name: 'Push', - id: '0b10da6b-3485-496c-a2cb-aabf59a6352d', - type: { - name: 'Ingestion' - }, - iconClass: null - }, - validStateActions: ['disable'] - } - } - ] - } - } - ] - }, - ingestionJob: { - records: [ - { - id: '592e2225-d97c-4dca-8b96-26b81adcd3a6', - taskTemplates: { - records: [ - { - id: 'ae7e7bd0-95a4-4cda-a42d-9e0c068ad4f6', - engine: { - id: 'b79d94cc-5b95-4bbd-ac01-f54b147f406f', - name: 'Google Drive Adapter', - category: { - name: 'Pull', - id: '4b150c85-82d0-4a18-b7fb-63e4a58dfcce', - type: { - name: 'Ingestion' - }, - iconClass: null - }, - validStateActions: ['disable'] - } - } - ] - } - } - ] - } - }, - { - id: '35982', - isActive: true, - name: 'give me my weather data pleasezzzz', - jobs: { - records: [ - { - id: '8fb9d671-b3a3-491a-8c54-1ce1a240f6ae', - createdDateTime: '2018-04-10T04:48:17.000Z' - }, - { - id: '4944ba03-9a27-40e5-b340-e2a6f2e63369', - createdDateTime: '2018-04-10T01:58:39.000Z' - }, - { - id: 'e749c250-28f1-48d9-9499-4912ade80be4', - createdDateTime: '2018-04-10T00:53:27.000Z' - } - ] - }, - jobTemplates: { - records: [ - { - taskTemplates: { - records: [ - { - engineId: 'transcode-ffmpeg', - id: '7d2f45bf-3606-4ec7-aaf8-c643db28cea2', - engine: { - name: 'Cerebral', - category: { - name: 'Transcode', - id: '581dbb32-ea5b-4458-bd15-8094942345e3', - type: { - name: 'Cognition' - }, - iconClass: 'icon-engine-transcode' - }, - validStateActions: ['disable'] - } - }, - { - engineId: '4d0b2407-f2af-4f19-bdfc-83f74981790a', - id: 'c65685fd-a0d6-481a-9596-9e4ce581747e', - engine: { - name: 'Open Weather Adapter', - category: { - name: 'Pull', - id: '4b150c85-82d0-4a18-b7fb-63e4a58dfcce', - type: { - name: 'Ingestion' - }, - iconClass: null - }, - validStateActions: ['disable'] - } - } - ] - } - } - ] - }, - ingestionJob: { - records: [ - { - id: '739a10d1-fb04-402a-aa0e-2db79088436a', - taskTemplates: { - records: [ - { - id: '6f0b3833-b7c1-415a-b3f1-ded7ffad86a1', - engine: { - id: 'd1bc57fe-675d-435d-9f4d-2f074485ec55', - name: 'Push Adapter', - category: { - name: 'Push', - id: '0b10da6b-3485-496c-a2cb-aabf59a6352d', - type: { - name: 'Ingestion' - }, - iconClass: null - }, - validStateActions: ['disable'] - } - } - ] - } - } - ] - } - } - ] - } - } -}; - -function handleCreateJob() { - console.log('Create Job Button clicked'); -} - -function handleSelectJob(rowIdx, dataKey, dataKeyValue) { - console.log(`Row ${rowIdx} clicked`); -} - -function handleSelectMenuItem(menuAction, dataKeyValue, event) { - console.log( - 'menuAction, dataKeyValue, event:', - menuAction, - dataKeyValue, - event - ); -} - -class Story extends React.Component { - componentDidMount() { - this._ijWidget = new IngestionJobsListWidget({ - elId: 'ij-widget', - title: 'Ingestion Jobs List Widget', - jobs: ingestionJobs.data.scheduledJobs.records, - onCreateJob: handleCreateJob, - onSelectJob: handleSelectJob, - onSelectMenuItem: handleSelectMenuItem - }); - } - - componentWillUnmount() { - this._ijWidget.destroy(); - } - - render() { - return ( -
- -
- ); - } -} - -const app = VeritoneApp(); - -storiesOf('Ingestion Jobs List', module).add('Base', () => { - const sessionToken = text('Api Session Token', ''); - - return ; -}); diff --git a/packages/veritone-widgets/src/widgets/SDOTable/index.js b/packages/veritone-widgets/src/widgets/SDOTable/index.js deleted file mode 100644 index 7aca2c7f1..000000000 --- a/packages/veritone-widgets/src/widgets/SDOTable/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import { arrayOf, bool, objectOf, object } from 'prop-types'; -import { SDOTable } from 'veritone-react-common'; -import widget from '../../shared/widget'; - -class SDOTableWidget extends React.Component { - static propTypes = { - data: arrayOf(object).isRequired, - schema: objectOf(object).isRequired, - paginate: bool - }; - - static defaultProps = { - paginate: false - }; - - render() { - return ; - } -} - -export default widget(SDOTableWidget); diff --git a/packages/veritone-widgets/src/widgets/SDOTable/story.js b/packages/veritone-widgets/src/widgets/SDOTable/story.js deleted file mode 100644 index 87916c395..000000000 --- a/packages/veritone-widgets/src/widgets/SDOTable/story.js +++ /dev/null @@ -1,120 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { text } from '@storybook/addon-knobs'; - -import VeritoneApp from '../../shared/VeritoneApp'; -import SDOTableWidget from './'; - -const data = [ - { - humidity: 54, - pressure: 1019, - windSpeed: 4.7, - visibility: 16093, - windDegree: 40, - datetimeEnd: '2018-02-21T23:00:00.000Z', - geoLocation: '34.05, -118.24', - temperature: 55.71, - locationName: 'Los Angeles', - datetimeStart: '2018-02-21T22:00:00.000Z', - temperatureMax: 59, - temperatureMin: 51.8 - }, - { - humidity: 100, - pressure: 1000, - windSpeed: 4.7, - visibility: 16093, - windDegree: 40, - datetimeEnd: '2018-02-21T23:00:00.000Z', - geoLocation: '34.05, -118.24', - temperature: 55.71, - locationName: 'Los Angeles', - datetimeStart: '2018-02-21T22:00:00.000Z', - temperatureMax: 59, - temperatureMin: 51.8 - } -]; - -const schema = { - humidity: { - $id: '/properties/humidity', - type: 'integer' - }, - pressure: { - $id: '/properties/pressure', - type: 'integer' - }, - windSpeed: { - $id: '/properties/windSpeed', - type: 'number' - }, - visibility: { - $id: '/properties/visibility', - type: 'integer' - }, - windDegree: { - $id: '/properties/windDegree', - type: 'number' - }, - datetimeEnd: { - $id: '/properties/datetimeEnd', - type: 'dateTime' - }, - geoLocation: { - $id: '/properties/geoLocation', - type: 'geoPoint' - }, - temperature: { - $id: '/properties/temperature', - type: 'number' - }, - locationName: { - $id: '/properties/locationName', - type: 'string', - title: 'City Name' - }, - datetimeStart: { - $id: '/properties/datetimeStart', - type: 'dateTime' - }, - temperatureMax: { - $id: '/properties/temperatureMax', - type: 'number' - }, - temperatureMin: { - $id: '/properties/temperatureMin', - type: 'number' - } -}; - -class Story extends React.Component { - componentDidMount() { - this._sdoTableWidget = new SDOTableWidget({ - elId: 'sdo-table-widget', - title: 'SDOTableWidget Widget', - data, - schema - }); - } - - componentWillUnmount() { - this._sdoTableWidget.destroy(); - } - - render() { - return ( -
- -
- ); - } -} - -const app = VeritoneApp(); - -storiesOf('SDO Table', module).add('Base', () => { - const sessionToken = text('Api Session Token', ''); - - return ; -}); diff --git a/packages/veritone-widgets/src/widgets/Scheduler/index.js b/packages/veritone-widgets/src/widgets/Scheduler/index.js deleted file mode 100644 index 10683d39e..000000000 --- a/packages/veritone-widgets/src/widgets/Scheduler/index.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { func } from 'prop-types'; -import { noop } from 'lodash'; -import { submit } from 'redux-form'; -import { connect } from 'react-redux'; -import { Scheduler as LibScheduler } from 'veritone-react-common'; - -import widget from '../../shared/widget'; - -@connect(null, { submit }, null, { withRef: true }) -class Scheduler extends React.Component { - static propTypes = { - submit: func.isRequired - }; - - state = { - submitCallback: noop - }; - - submit = (submitCallback = noop) => { - this.setState( - { - submitCallback - }, - () => this.props.submit('scheduler') - ); - }; - - render() { - return ( - - ); - } -} - -export const SchedulerWidget = widget(Scheduler); diff --git a/packages/veritone-widgets/src/widgets/Scheduler/story.js b/packages/veritone-widgets/src/widgets/Scheduler/story.js deleted file mode 100644 index de546c5fc..000000000 --- a/packages/veritone-widgets/src/widgets/Scheduler/story.js +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; - -import BaseStory from '../../shared/BaseStory'; -import VeritoneApp from '../../shared/VeritoneApp'; -import { SchedulerWidget } from '.'; - -class Story extends React.Component { - state = { - lastResult: {} - }; - - handleSubmit = vals => { - this.setState({ - lastResult: vals - }); - }; - - render() { - return ( -
-
- Last result: -
{JSON.stringify(this.state.lastResult, null, '\t')}
-
- - - instance.submit(vals => { - this.handleSubmit(vals); - }) - }} - /> -
- ); - } -} - -const app = VeritoneApp(); - -storiesOf('Scheduler', module).add('Base', () => { - return ; -}); diff --git a/packages/veritone-widgets/src/widgets/SourceList/index.js b/packages/veritone-widgets/src/widgets/SourceList/index.js deleted file mode 100644 index 3edd238ad..000000000 --- a/packages/veritone-widgets/src/widgets/SourceList/index.js +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react'; -import { arrayOf, object, func, bool } from 'prop-types'; -import { SourceManagement } from 'veritone-react-common'; -import { omit } from 'lodash'; - -import widget from '../../shared/widget'; - -const { NullState, SourceTileView } = SourceManagement; - -class SourceListWidget extends React.Component { - static propTypes = { - sources: arrayOf(object).isRequired, - onSelectMenuItem: func.isRequired, - onCreateSource: func.isRequired, - onSelectSource: func.isRequired, - paginate: bool, - fetchData: func - }; - - state = { - sources: this.props.sources - }; - - handleFetchData = ({ start, end }) => { - const perPage = end - start + 1; - const sourcesCount = this.state.sources.length; - - if ( - this.props.fetchData && - (!this.state.sources[end + 1] || sourcesCount - perPage < perPage) - ) { - const limit = !(sourcesCount % perPage) - ? perPage - : sourcesCount % perPage; - - this.props.fetchData(limit, sourcesCount); - } - }; - - updateSources = sources => { - this.setState({ - sources - }); - }; - - render() { - const viewProps = omit(this.props, [ - 'onCreateSource', - 'sources', - 'fetchData' - ]); - - return !this.state.sources.length ? ( - - ) : ( - - ); - } -} - -export default widget(SourceListWidget); diff --git a/packages/veritone-widgets/src/widgets/SourceList/story.js b/packages/veritone-widgets/src/widgets/SourceList/story.js deleted file mode 100644 index a00478198..000000000 --- a/packages/veritone-widgets/src/widgets/SourceList/story.js +++ /dev/null @@ -1,84 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { text } from '@storybook/addon-knobs'; -import { noop } from 'lodash'; -import VeritoneApp from '../../shared/VeritoneApp'; -import SourceListWidget from './'; - -// a mock return result on a source from graphql -const sourceResult = { - data: { - source: { - id: '666', - name: 'KWOL--FM', - createdDateTime: '2014-12-01T18:17:20.675Z', - modifiedDateTime: '2015-12-01T18:17:20.675Z', - thumbnailUrl: 'https://image.flaticon.com/icons/svg/25/25305.svg', - details: { - url: 'twitter.com', - username: 'therealtrump', - password: 'password' - }, - sourceType: { - id: '1', - name: 'Audio', - sourceSchema: { - id: 'schemaId1', - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name' - }, - password: { - type: 'string', - title: 'Password' - } - } - } - } - } - } - } -}; - -const sources = []; -for (let i = 0; i < 4; i++) { - sources.push(sourceResult.data.source); -} - -class Story extends React.Component { - componentDidMount() { - this._srcList = new SourceListWidget({ - elId: 'src-list-widget', - title: 'Source Management Widget', - sources, - onSelectMenuItem: noop, - onCreateSource: noop, - onSelectSource: noop - }); - } - - componentWillUnmount() { - this._srcList.destroy(); - } - - render() { - return ( -
- -
- ); - } -} - -const app = VeritoneApp(); - -storiesOf('Source List', module).add('Base', () => { - const sessionToken = text('Api Session Token', ''); - - return ; -}); diff --git a/packages/veritone-widgets/src/widgets/SourceManagementForm/index.js b/packages/veritone-widgets/src/widgets/SourceManagementForm/index.js deleted file mode 100644 index 3f695f9bc..000000000 --- a/packages/veritone-widgets/src/widgets/SourceManagementForm/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import { arrayOf, object, objectOf, any, func } from 'prop-types'; -import { SourceManagementForm } from 'veritone-react-common'; - -import widget from '../../shared/widget'; - -class SourceManagementFormWidget extends React.Component { - static propTypes = { - sourceTypes: arrayOf(object).isRequired, - templateData: objectOf(any).isRequired, - source: objectOf(any), - initialTemplates: objectOf(any), - onSubmit: func.isRequired, - onClose: func - }; - - render() { - return ; - } -} - -export default widget(SourceManagementFormWidget); diff --git a/packages/veritone-widgets/src/widgets/SourceManagementForm/story.js b/packages/veritone-widgets/src/widgets/SourceManagementForm/story.js deleted file mode 100644 index d3e8224e4..000000000 --- a/packages/veritone-widgets/src/widgets/SourceManagementForm/story.js +++ /dev/null @@ -1,284 +0,0 @@ -import React from 'react'; -import { storiesOf } from '@storybook/react'; -import { text } from '@storybook/addon-knobs'; - -import VeritoneApp from '../../shared/VeritoneApp'; -import SourceManagementFormWidget from './'; -import { has, noop } from 'lodash'; - -const sourceTypes = { - sourceTypes: { - records: [ - { - name: 'Audio', - id: 'audio_1', - sourceSchema: { - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name' - }, - password: { - type: 'string' - } - }, - required: ['url', 'username', 'password'] - } - } - }, - { - name: 'Audio2', - id: 'audio_2', - sourceSchema: { - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name 2' - }, - password: { - type: 'string' - }, - days: { - type: 'number' - } - } - } - } - } - ] - } -}; - -// a mock return result on a source from graphql -const sourceResult = { - data: { - source: { - id: '666', - name: 'KWOL--FM', - createdDateTime: '2014-12-01T18:17:20.675Z', - modifiedDateTime: '2015-12-01T18:17:20.675Z', - thumbnail: 'https://image.flaticon.com/icons/svg/25/25305.svg', - details: { - url: 'twitter.com', - username: 'therealtrump', - password: 'password' - }, - sourceType: { - id: '1', - name: 'Audio', - sourceSchema: { - id: 'schemaId1', - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string', - title: 'User Name' - }, - password: { - type: 'string', - title: 'Password' - } - } - } - } - } - } - } -}; - -let sources = []; -for (let i = 0; i < 4; i++) { - sources.push(sourceResult.data.source); -} - -// CONTENT TEMPLATES SETUP -const source = { - data: { - source: { - id: '666', - name: 'KWOL--FM', - contentTemplates: [ - { - schemaId: 'schemaGuid1', - data: { - url: 'twitter.com', - username: 'THEREALTRUMP' - } - } - ] - } - } -}; - -// FORM CARDS LIST SETUP -const result = { - data: { - dataRegistries: { - records: [ - { - name: 'Twitter Schema', - schemas: { - records: [ - { - id: 'schemaGuid1', - status: 'published', - definition: { - properties: { - url: { - type: 'string', - title: 'URL' - }, - username: { - type: 'string' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema 2' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - }, - password: { - type: 'string' - } - } - } - }, - { - id: 'schemaGuid2', - status: 'published', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - test: 'citest' - } - }, - { - id: 'schemaGuid2', - status: 'draft', - // dataRegistry: { - // name: 'Twitter Schema' - // }, - definition: { - properties: { - url: { - type: 'string' - }, - username: { - type: 'string' - } - } - } - } - ] - } - } - ] - } - } -}; - -function createTemplateData(dataSchemas) { - const templateSchemas = {}; - // array of data registries containing an array of schemas - dataSchemas.reduce((schemaStore, registryData) => { - registryData.schemas.records.forEach(schema => { - // only take schemas that are 'published' and also define field types - if ( - schema.status === 'published' && - has(schema.definition, 'properties') - ) { - schemaStore[schema.id] = { - name: registryData.name, - ...schema - }; - } - }); - }, templateSchemas); - - return templateSchemas; -} - -function createInitialTemplates(templateSources) { - const selectedTemplateSchemas = {}; - - const templateSchemas = createTemplateData( - result.data.dataRegistries.records - ); - templateSources.forEach(template => { - if (has(templateSchemas, template.schemaId)) { - selectedTemplateSchemas[template.schemaId] = - templateSchemas[template.schemaId]; - if (template.data) { - // if we need to fill out the form with pre-data - selectedTemplateSchemas[template.schemaId].data = template.data; - } - } - }); - - return selectedTemplateSchemas; -} - -const templateData = createTemplateData(result.data.dataRegistries.records); -const initialTemplates = createInitialTemplates( - source.data.source.contentTemplates -); - -class Story extends React.Component { - componentDidMount() { - this._smFormWidget = new SourceManagementFormWidget({ - elId: 'sm-form-widget', - title: 'Source Management Form Widget', - sourceTypes: sourceTypes.sourceTypes.records, - sources, - templateData, - initialTemplates, - onClose: noop, - onSubmit: data => { - console.log('data:', data); - } - }); - } - - componentWillUnmount() { - this._smFormWidget.destroy(); - } - - render() { - return ( -
- -
- ); - } -} - -const app = VeritoneApp(); - -storiesOf('Source Management Form', module).add('Base', () => { - const sessionToken = text('Api Session Token', ''); - - return ; -}); diff --git a/packages/veritone-widgets/src/widgets/UserProfile/index.js b/packages/veritone-widgets/src/widgets/UserProfile/index.js index 9b8ba0e54..873783d41 100644 --- a/packages/veritone-widgets/src/widgets/UserProfile/index.js +++ b/packages/veritone-widgets/src/widgets/UserProfile/index.js @@ -1,6 +1,6 @@ import React from 'react'; import { connect } from 'react-redux'; -import { startCase, noop, isEmpty } from 'lodash'; +import { startCase, noop, isEmpty, get } from 'lodash'; import { string, func, bool, shape } from 'prop-types'; import { withProps, branch, renderNothing } from 'recompose'; import { @@ -31,6 +31,7 @@ import ChangeNameModal from './Modals/ChangeName'; import ResetPasswordModal from './Modals/ResetPassword'; import styles from './styles.scss'; +const defaultAvatarImg = 'https://static.veritone.com/veritone-ui/default-avatar.png'; @connect( state => ({ @@ -87,11 +88,16 @@ export class UserProfile extends React.Component { handleSubmit: func.isRequired, resetUserPassword: func.isRequired, updateCurrentUserProfile: func.isRequired, + onUserUpdated: func, invalid: bool, pristine: bool, submitting: bool }; + static defaultProps = { + onUserUpdated: noop + }; + state = { currentModal: null }; @@ -160,7 +166,11 @@ export class UserProfile extends React.Component { }); }; - afterChange = () => { + afterChange = userResponse => { + const updatedUser = get(userResponse, 'updateCurrentUser'); + if (updatedUser) { + this.props.onUserUpdated(updatedUser); + } this.closeModal(); }; @@ -186,7 +196,7 @@ export class UserProfile extends React.Component { // eslint-disable-next-line renderButton={({ handlePickFiles }) => ( @@ -268,7 +278,8 @@ class UserProfileDialog extends React.Component { static propTypes = { open: bool, title: string, - onClose: func + onClose: func, + onUserUpdated: func }; static defaultProps = { @@ -322,4 +333,4 @@ class UserProfileDialog extends React.Component { } const UserProfileWidget = widget(UserProfileDialog); -export { UserProfileDialog as default, UserProfileWidget }; +export { UserProfileDialog as default, UserProfileWidget }; \ No newline at end of file From 7ba50bba644ae2a954a4c52d867ed7a10dd61e9e Mon Sep 17 00:00:00 2001 From: Alex Bu Date: Tue, 22 Jan 2019 16:51:21 -0800 Subject: [PATCH 03/11] add veritone-app changes from sdo-integration --- .../src/shared/VeritoneApp.js | 61 ++++++++++--------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/packages/veritone-widgets/src/shared/VeritoneApp.js b/packages/veritone-widgets/src/shared/VeritoneApp.js index c20393d59..35fd7b144 100644 --- a/packages/veritone-widgets/src/shared/VeritoneApp.js +++ b/packages/veritone-widgets/src/shared/VeritoneApp.js @@ -5,7 +5,7 @@ import { Provider } from 'react-redux'; import * as appModule from '../redux/modules/veritoneApp'; import appConfig from '../../config.json'; import configureStore from '../redux/configureStore'; -import { modules, helpers } from 'veritone-redux-common'; +import { modules, util, helpers } from 'veritone-redux-common'; import { VeritoneSDKThemeProvider } from 'veritone-react-common'; const { auth: authModule, config: configModule, user: userModule } = modules; @@ -16,6 +16,7 @@ const { CALLBACK_ERROR_ARGUMENT } = promiseMiddleware; +const Sagas = util.reactReduxSaga.Sagas; class _VeritoneApp { _store = configureStore(); _containerEl = null; @@ -108,33 +109,35 @@ class _VeritoneApp { ReactDOM.render( - -
- {appModule.widgets(this._store.getState()).map(w => { - if (!w._elId) { - console.warn( - 'The widget', - w, - 'needs to specify an elId that references an existing dom node.' - ); - return null; - } - - if (document.getElementById(w._elId)) { - return ReactDOM.createPortal( - , - document.getElementById(w._elId) - ); - } - })} -
-
+ + +
+ {appModule.widgets(this._store.getState()).map(w => { + if (!w._elId) { + console.warn( + 'The widget', + w, + 'needs to specify an elId that references an existing dom node.' + ); + return null; + } + + if (document.getElementById(w._elId)) { + return ReactDOM.createPortal( + , + document.getElementById(w._elId) + ); + } + })} +
+
+
, this._containerEl ); @@ -158,4 +161,4 @@ export default function VeritoneApp(config, { _isWidget } = {}) { } return global.__veritoneAppSingleton; -} +} \ No newline at end of file From 9446aaee2b097997f1ce210e8a33e133b58c1852 Mon Sep 17 00:00:00 2001 From: Alex Bu Date: Tue, 22 Jan 2019 16:54:38 -0800 Subject: [PATCH 04/11] lint --- .../src/components/formComponents/DateTimePicker.js | 1 - .../veritone-widgets/src/widgets/EngineOutputExport/styles.scss | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/veritone-react-common/src/components/formComponents/DateTimePicker.js b/packages/veritone-react-common/src/components/formComponents/DateTimePicker.js index 24a11cce6..d8da7ad01 100644 --- a/packages/veritone-react-common/src/components/formComponents/DateTimePicker.js +++ b/packages/veritone-react-common/src/components/formComponents/DateTimePicker.js @@ -1,7 +1,6 @@ import React from 'react'; import Today from '@material-ui/icons/Today'; import dateFns from 'date-fns'; -import { isString } from 'lodash'; import TextField from '@material-ui/core/TextField'; import { instanceOf, func, shape, string, bool } from 'prop-types'; diff --git a/packages/veritone-widgets/src/widgets/EngineOutputExport/styles.scss b/packages/veritone-widgets/src/widgets/EngineOutputExport/styles.scss index eb4887540..a0a4fa67b 100644 --- a/packages/veritone-widgets/src/widgets/EngineOutputExport/styles.scss +++ b/packages/veritone-widgets/src/widgets/EngineOutputExport/styles.scss @@ -156,4 +156,4 @@ .errorSnackBar { background-color: $red500 !important; -} \ No newline at end of file +} From 80ea0052e9137382d7912fc239f749dc071e899a Mon Sep 17 00:00:00 2001 From: Alex Bu Date: Tue, 22 Jan 2019 17:00:18 -0800 Subject: [PATCH 05/11] fix prop error --- .../veritone-react-common/src/components/DataTable/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/veritone-react-common/src/components/DataTable/index.js b/packages/veritone-react-common/src/components/DataTable/index.js index 7e5d3ab95..be50f507b 100644 --- a/packages/veritone-react-common/src/components/DataTable/index.js +++ b/packages/veritone-react-common/src/components/DataTable/index.js @@ -340,7 +340,7 @@ export const Column = ({ return ( Date: Tue, 22 Jan 2019 17:50:15 -0800 Subject: [PATCH 06/11] rm unused params --- .../veritone-redux-common/src/helpers/api/fetchGraphQLApi.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/veritone-redux-common/src/helpers/api/fetchGraphQLApi.js b/packages/veritone-redux-common/src/helpers/api/fetchGraphQLApi.js index 1d073435e..dc1cd845d 100644 --- a/packages/veritone-redux-common/src/helpers/api/fetchGraphQLApi.js +++ b/packages/veritone-redux-common/src/helpers/api/fetchGraphQLApi.js @@ -5,9 +5,7 @@ export default function fetchGraphQLApi({ query, variables, operationName, - token, - dispatch, - getState + token }) { return fetch(endpoint, { method: 'post', From 6f079e8165464ad92bc0ab77e7dca532a9f02ca2 Mon Sep 17 00:00:00 2001 From: Alex Bu Date: Tue, 22 Jan 2019 17:59:15 -0800 Subject: [PATCH 07/11] revert weird table export --- packages/veritone-widgets/src/build-entry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/veritone-widgets/src/build-entry.js b/packages/veritone-widgets/src/build-entry.js index a3489d6cd..7d59bf474 100644 --- a/packages/veritone-widgets/src/build-entry.js +++ b/packages/veritone-widgets/src/build-entry.js @@ -10,7 +10,7 @@ export FilePicker, { FilePickerWidget } from './widgets/FilePicker'; export filePickerReducer, * as filePickerModule from './redux/modules/filePicker'; export filePickerSaga from './redux/modules/filePicker/filePickerSaga'; export { EngineSelectionWidget } from './widgets/EngineSelection'; -export { TableWidget as Table, TableWidget } from './widgets/Table'; +export { TableWidget } from './widgets/Table'; export { GlobalNotificationDialog, GlobalSnackBar From ba822977aa40026df6b70ad4d44aed9c0de97234 Mon Sep 17 00:00:00 2001 From: Alex Bu Date: Tue, 22 Jan 2019 18:01:24 -0800 Subject: [PATCH 08/11] rm topbar styling --- packages/veritone-react-common/src/components/TopBar/styles.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/veritone-react-common/src/components/TopBar/styles.scss b/packages/veritone-react-common/src/components/TopBar/styles.scss index 99bdef90f..95c56cbdc 100644 --- a/packages/veritone-react-common/src/components/TopBar/styles.scss +++ b/packages/veritone-react-common/src/components/TopBar/styles.scss @@ -7,7 +7,6 @@ justify-content: space-between; left: 0; right: 0; - margin-bottom: 20px; // copied from material-ui transition: margin 195ms cubic-bezier(0.4, 0, 0.6, 1) 0ms, width 195ms cubic-bezier(0.4, 0, 0.6, 1) 0ms; From d82b662fcb7856426059d59f09fff87e685a9b2b Mon Sep 17 00:00:00 2001 From: Chris Pelletier Date: Tue, 22 Jan 2019 18:03:15 -0800 Subject: [PATCH 09/11] The logic in the componentDidUpdate was causing long test runs so I moved it into the reducer of FETCH_ENGINE_RUNS_SUCCESS action --- .../redux/modules/engineOutputExport/index.js | 56 +++++++------------ .../EngineCategoryConfig.js | 46 ++++++++------- .../EngineCategoryConfigList.js | 40 ++++--------- .../widgets/EngineOutputExport/index.test.js | 34 +++++------ 4 files changed, 70 insertions(+), 106 deletions(-) diff --git a/packages/veritone-widgets/src/redux/modules/engineOutputExport/index.js b/packages/veritone-widgets/src/redux/modules/engineOutputExport/index.js index 0a1007c8c..99240e72d 100644 --- a/packages/veritone-widgets/src/redux/modules/engineOutputExport/index.js +++ b/packages/veritone-widgets/src/redux/modules/engineOutputExport/index.js @@ -19,7 +19,6 @@ export const STORE_SUBTITLE_CONFIGS = `vtn/${namespace}/STORE_SUBTITLE_CONFIGS`; export const APPLY_SPEAKER_TOGGLE = `vtn/${namespace}/APPLY_SPEAKER_TOGGLE`; export const STORE_SPEAKER_TOGGLE = `vtn/${namespace}/STORE_SPEAKER_TOGGLE`; -export const STORE_HAS_SPEAKER_DATA = `vtn/${namespace}/STORE_HAS_SPEAKER_DATA`; export const START_EXPORT_AND_DOWNLOAD = `vtn/${namespace}/START_EXPORT_AND_DOWNLOAD`; export const EXPORT_AND_DOWNLOAD_SUCCESS = `vtn/${namespace}/EXPORT_AND_DOWNLOAD_SUCCESS`; @@ -73,6 +72,7 @@ export default createReducer(defaultState, { } return accumulator; }, {}); + let hasSpeakerData = false; forEach(enginesRan, engineRun => { if (get(engineRun, 'category.exportFormats.length')) { if (isBulkExport) { @@ -92,6 +92,9 @@ export default createReducer(defaultState, { } categoryLookup[engineRun.category.id] = engineRun.category; expandedCategories[engineRun.category.id] = false; + if (get(engineRun, 'category.categoryType') === 'speaker') { + hasSpeakerData = true; + } } }); newOutputConfigurations = uniqWith( @@ -120,7 +123,8 @@ export default createReducer(defaultState, { expandedCategories: expandedCategories, isBulkExport, fetchEngineRunsFailed: false, - includeMedia: false + includeMedia: false, + hasSpeakerData }; }, [FETCH_ENGINE_RUNS_FAILURE](state) { @@ -177,12 +181,8 @@ export default createReducer(defaultState, { categoryId ]); const storedSpeakerToggle = state.hasSpeakerData - ? ( - get(state, [ - 'speakerToggleCache', - categoryId - ]) || get(state, 'speakerToggleCache') - ) + ? get(state, ['speakerToggleCache', categoryId]) || + get(state, 'speakerToggleCache') : {}; return { ...config, @@ -195,8 +195,8 @@ export default createReducer(defaultState, { ...storedSpeakerToggle } : { - ...storedSpeakerToggle - } + ...storedSpeakerToggle + } }; }) }; @@ -232,7 +232,7 @@ export default createReducer(defaultState, { formats: config.formats.map(format => { return { ...format, - options: { + options: { ...format.options, withSpeakerData: values } @@ -242,7 +242,7 @@ export default createReducer(defaultState, { } return config; }) - } + }; }, [STORE_SPEAKER_TOGGLE]( state, @@ -258,17 +258,6 @@ export default createReducer(defaultState, { } }; }, - [STORE_HAS_SPEAKER_DATA]( - state, - { - payload: { hasSpeakerData } - } - ) { - return { - ...state, - hasSpeakerData - } - }, [APPLY_SUBTITLE_CONFIGS]( state, { @@ -418,11 +407,12 @@ export const getSubtitleConfig = (state, categoryId) => export const getSpeakerToggle = (state, categoryId) => { // If the category speaker toggle is undefined, then // fallback to the default across all categories - const speakerToggleCache = get(local(state), ['speakerToggleCache', categoryId]) || + const speakerToggleCache = + get(local(state), ['speakerToggleCache', categoryId]) || get(local(state), 'speakerToggleCache'); return speakerToggleCache; }; -export const hasSpeakerData = (state) => get(local(state), 'hasSpeakerData'); +export const hasSpeakerData = state => get(local(state), 'hasSpeakerData'); export const isBulkExport = state => get(local(state), 'isBulkExport'); export const selectedFormats = state => get(local(state), 'outputConfigurations').reduce((accumulator, configObj) => { @@ -531,8 +521,9 @@ export const exportAndDownload = tdoData => async (dispatch, getState) => { query, variables: { includeMedia: getIncludeMedia(getState()), - outputConfigurations: getOutputConfigurations(getState()) - .map(config => pick(config, ['engineId', 'categoryId', 'formats'])), + outputConfigurations: getOutputConfigurations(getState()).map(config => + pick(config, ['engineId', 'categoryId', 'formats']) + ), tdoData }, dispatch, @@ -599,15 +590,6 @@ export const storeSpeakerToggle = (categoryId, config) => { }; }; -export const setHasSpeakerData = hasSpeakerData => { - return { - type: STORE_HAS_SPEAKER_DATA, - payload: { - hasSpeakerData - } - }; -}; - export const addSnackBar = snackBarConfig => { return { type: ADD_SNACK_BAR, @@ -634,4 +616,4 @@ export const storeSubtitleConfigs = (categoryId, config) => { config } }; -}; \ No newline at end of file +}; diff --git a/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfig.js b/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfig.js index eb44de255..30742906a 100644 --- a/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfig.js +++ b/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfig.js @@ -30,7 +30,9 @@ import * as engineOutputExportModule from '../../redux/modules/engineOutputExpor @connect( (state, { categoryId }) => ({ category: engineOutputExportModule.getCategoryById(state, categoryId), - transcriptCategoryType: engineOutputExportModule.transcriptCategoryType(state), + transcriptCategoryType: engineOutputExportModule.transcriptCategoryType( + state + ), initialSubtitleConfig: engineOutputExportModule.getSubtitleConfig( state, categoryId @@ -130,7 +132,8 @@ export default class EngineCategoryConfig extends Component { initialSpeakerToggle, transcriptCategoryType } = this.props; - const isTranscriptionCategory = category.categoryType === transcriptCategoryType; + const isTranscriptionCategory = + category.categoryType === transcriptCategoryType; let hasSubtitleFormatsSelected = false; forEach(engineCategoryConfigs, config => { @@ -189,23 +192,26 @@ export default class EngineCategoryConfig extends Component { /> ); })} - {hasSpeakerData && isTranscriptionCategory && ( - -
- - - Include speaker separation results - - -
-
- )} + {hasSpeakerData && + isTranscriptionCategory && ( + +
+ + + Include speaker separation results + + +
+
+ )} {hasSubtitleFormatsSelected && (
@@ -251,4 +257,4 @@ export default class EngineCategoryConfig extends Component {
); } -} \ No newline at end of file +} diff --git a/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfigList.js b/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfigList.js index 47fcd4be4..7612144ea 100644 --- a/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfigList.js +++ b/packages/veritone-widgets/src/widgets/EngineOutputExport/EngineCategoryConfigList.js @@ -26,13 +26,11 @@ import styles from './styles.scss'; ), expandedCategories: engineOutputExportModule.expandedCategories(state), fetchingEngineRuns: engineOutputExportModule.fetchingEngineRuns(state), - speakerCategoryType: engineOutputExportModule.speakerCategoryType(state), - hasSpeakerData: engineOutputExportModule.hasSpeakerData(state) + speakerCategoryType: engineOutputExportModule.speakerCategoryType(state) }), { fetchEngineRuns: engineOutputExportModule.fetchEngineRuns, - toggleConfigExpand: engineOutputExportModule.toggleConfigExpand, - setHasSpeakerData: engineOutputExportModule.setHasSpeakerData + toggleConfigExpand: engineOutputExportModule.toggleConfigExpand }, null, { withRef: true } @@ -59,8 +57,6 @@ export default class EngineCategoryConfigList extends Component { fetchEngineRuns: func, fetchingEngineRuns: bool, toggleConfigExpand: func, - setHasSpeakerData: func, - hasSpeakerData: bool, speakerCategoryType: string }; @@ -68,25 +64,6 @@ export default class EngineCategoryConfigList extends Component { this.props.fetchEngineRuns(this.props.tdos); } - componentDidUpdate() { - // Detect if speaker data is available - const { - speakerCategoryType, - outputConfigsByCategoryId - } = this.props; - let hasSpeakerDataBeenSet = this.props.hasSpeakerData; - Object.keys(outputConfigsByCategoryId).forEach(categoryId => { - const categoryEngines = outputConfigsByCategoryId[categoryId]; - categoryEngines.forEach(engine => { - const isSpeakerCategory = engine.categoryType === speakerCategoryType; - if (isSpeakerCategory && !hasSpeakerDataBeenSet) { - hasSpeakerDataBeenSet = true; - this.props.setHasSpeakerData(true); - } - }); - }); - } - render() { const { fetchingEngineRuns, @@ -98,10 +75,13 @@ export default class EngineCategoryConfigList extends Component { // Temporary bypass of speaker category since we are planning // to separate it from transcription output in the future - const modifiedOutputConfigsByCategoryId = Object.keys(outputConfigsByCategoryId) - .filter(categoryId => - outputConfigsByCategoryId[categoryId].find(engine => engine.categoryType !== speakerCategoryType) - ); + const modifiedOutputConfigsByCategoryId = Object.keys( + outputConfigsByCategoryId + ).filter(categoryId => + outputConfigsByCategoryId[categoryId].find( + engine => engine.categoryType !== speakerCategoryType + ) + ); return (
@@ -130,4 +110,4 @@ export default class EngineCategoryConfigList extends Component {
); } -} \ No newline at end of file +} diff --git a/packages/veritone-widgets/src/widgets/EngineOutputExport/index.test.js b/packages/veritone-widgets/src/widgets/EngineOutputExport/index.test.js index c427606ed..ba6007f65 100644 --- a/packages/veritone-widgets/src/widgets/EngineOutputExport/index.test.js +++ b/packages/veritone-widgets/src/widgets/EngineOutputExport/index.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { mount } from 'enzyme'; import { Provider } from 'react-redux'; +import thunk from 'redux-thunk'; import configureMockStore from 'redux-mock-store'; import Select from '@material-ui/core/Select'; @@ -20,9 +21,10 @@ import * as engineOutputExportModule from '../../redux/modules/engineOutputExpor import styles from './styles.scss'; -const mockStore = configureMockStore(); +const middlewares = [thunk]; +const mockStore = configureMockStore(middlewares); -const testTDOs = [{ tdoId: 'fakeTDOId '}]; +const testTDOs = [{ tdoId: 'fakeTDOId ' }]; const testSpeakerEngine = { id: 'speakerEngineId', @@ -31,6 +33,7 @@ const testSpeakerEngine = { id: 'a856c447-1030-4fb0-917f-08179f949c4e', name: 'Test Speaker Category', iconClass: 'icon-speaker-separation', + categoryType: 'speaker', exportFormats: [ { label: 'Test Format', @@ -50,6 +53,7 @@ const testEngine = { id: 'testCategoryId', name: 'Test Category', iconClass: 'test-class', + categoryType: 'transcript', exportFormats: [ { label: 'Test Format', @@ -113,8 +117,7 @@ const defaultSpeakerStore = { describe('EngineCategoryConfigList', () => { let wrapper, store; - //TODO: fix this test. It is throwing an error when trying to mount the component. - xdescribe('when speaker data is available', () => { + describe('when speaker data is available', () => { beforeEach(() => { store = mockStore(defaultSpeakerStore); @@ -122,16 +125,12 @@ describe('EngineCategoryConfigList', () => { @@ -143,10 +142,7 @@ describe('EngineCategoryConfigList', () => { }); it('should not be displayed in the list', () => { - expect( - wrapper.find(EngineCategoryConfig) - .exists() - ).toEqual(false); + expect(wrapper.find(EngineCategoryConfig).exists()).toEqual(false); }); }); }); @@ -439,4 +435,4 @@ describe('SubtitleConfigForm', () => { wrapper.find('form').simulate('submit'); expect(onSubmit).toHaveBeenCalled(); }); -}); \ No newline at end of file +}); From 451595c6a77f6bf3b361329a562055dd73652fc0 Mon Sep 17 00:00:00 2001 From: Alex Bu Date: Tue, 22 Jan 2019 18:08:38 -0800 Subject: [PATCH 10/11] export modal header --- packages/veritone-react-common/src/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/veritone-react-common/src/index.js b/packages/veritone-react-common/src/index.js index 5f271d13b..4e243082d 100644 --- a/packages/veritone-react-common/src/index.js +++ b/packages/veritone-react-common/src/index.js @@ -43,3 +43,4 @@ export BoundingPolyOverlay from './components/BoundingPolyOverlay/Overlay'; export OverlayPositioningProvider from './components/BoundingPolyOverlay/OverlayPositioningProvider'; export { Interval, defaultIntervals } from 'helpers/date'; export StatusPill from './components/StatusPill'; +export ModalHeader from './components/ModalHeader'; From ff75b15e490d927c707875d38ac24ed8bdcd7a03 Mon Sep 17 00:00:00 2001 From: Mitch Robb Date: Thu, 24 Jan 2019 14:41:46 -0800 Subject: [PATCH 11/11] run formatall script --- .../src/components/BoundingPolyOverlay/Overlay.js | 4 +++- .../src/components/formComponents/TimeRangePicker.js | 2 +- .../veritone-redux-common/src/helpers/api/callGraphQLApi.js | 2 +- packages/veritone-widgets/src/build-entry.js | 5 ++--- packages/veritone-widgets/src/shared/VeritoneApp.js | 2 +- .../src/widgets/MediaPlayer/RestartMediaButton.js | 2 +- packages/veritone-widgets/src/widgets/UserProfile/index.js | 5 +++-- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/veritone-react-common/src/components/BoundingPolyOverlay/Overlay.js b/packages/veritone-react-common/src/components/BoundingPolyOverlay/Overlay.js index 2e69cefcf..0a00cd9da 100644 --- a/packages/veritone-react-common/src/components/BoundingPolyOverlay/Overlay.js +++ b/packages/veritone-react-common/src/components/BoundingPolyOverlay/Overlay.js @@ -400,7 +400,9 @@ export default class Overlay extends React.Component { isString(this.state.focusedBoundingBoxId) && !this.state.userActingOnBoundingBox && !this.state.userMinimizedConfirmMenu && - this.state.boundingBoxPositions.some(el => el.id === this.state.focusedBoundingBoxId); + this.state.boundingBoxPositions.some( + el => el.id === this.state.focusedBoundingBoxId + ); const boundingBoxCommonStyles = { // this seems to fix some rendering jank diff --git a/packages/veritone-react-common/src/components/formComponents/TimeRangePicker.js b/packages/veritone-react-common/src/components/formComponents/TimeRangePicker.js index 29661e731..63de3cda5 100644 --- a/packages/veritone-react-common/src/components/formComponents/TimeRangePicker.js +++ b/packages/veritone-react-common/src/components/formComponents/TimeRangePicker.js @@ -73,7 +73,7 @@ export default class TimeRangePicker extends React.Component { /> ); } diff --git a/packages/veritone-widgets/src/widgets/UserProfile/index.js b/packages/veritone-widgets/src/widgets/UserProfile/index.js index 873783d41..33738edb1 100644 --- a/packages/veritone-widgets/src/widgets/UserProfile/index.js +++ b/packages/veritone-widgets/src/widgets/UserProfile/index.js @@ -31,7 +31,8 @@ import ChangeNameModal from './Modals/ChangeName'; import ResetPasswordModal from './Modals/ResetPassword'; import styles from './styles.scss'; -const defaultAvatarImg = 'https://static.veritone.com/veritone-ui/default-avatar.png'; +const defaultAvatarImg = + 'https://static.veritone.com/veritone-ui/default-avatar.png'; @connect( state => ({ @@ -333,4 +334,4 @@ class UserProfileDialog extends React.Component { } const UserProfileWidget = widget(UserProfileDialog); -export { UserProfileDialog as default, UserProfileWidget }; \ No newline at end of file +export { UserProfileDialog as default, UserProfileWidget };