render() { const changesButton = this.props.recordsChanged === null ? null : HTML.button({ onClick: this.download('data/changed'), disabled: this.props.recordsChanged === 0 }, ...[ 'Download changed rows', HTML.span({}, this.changesFor(this.props.recordsChanged)) ]) const body = [ HTML.h5({}, Moment(this.props.date).format('LLL')), HTML.button({ onClick: this.download('data') }, ...[ 'Download all data', HTML.span({}, this.changesFor(this.props.records)) ]), HTML.button({ onClick: this.download('data/added'), disabled: this.props.recordsAdded === 0 }, ...[ 'Download added rows', HTML.span({}, this.changesFor(this.props.recordsAdded)) ]), HTML.button({ onClick: this.download('data/removed'), disabled: this.props.recordsRemoved === 0 }, ...[ 'Download removed rows', HTML.span({}, this.changesFor(this.props.recordsRemoved)) ]), changesButton ] const dialog = React.createElement(Dialog, { body, cancel: this.props.close }) return HTML.div({ className: 'run-data-download' }, dialog) }
render() { const schedule = 'Runs ' + PrettyCron.toString(this.props.recipe.schedule).toLowerCase() + '.' const next = this.props.state === 'started' ? ' Next run is ' + PrettyCron.getNext(this.props.recipe.schedule).toLowerCase() + '.' : '' const elements = [ HTML.p({}, this.props.recipe.schedule === '' ? 'Not scheduled to run.' : schedule + next), HTML.h4({}, 'Setup commands'), this.props.recipe.setup.length > 0 ? HTML.code({}, HTML.ol({}, ...this.props.recipe.setup.map(step => HTML.li({ className: 'stdin' }, step)))) : HTML.span({ className: 'note' }, 'This agent has no setup.'), HTML.h4({}, 'Run commands'), HTML.code({}, HTML.ol({}, ...this.props.recipe.run.map(step => HTML.li({ className: 'stdin' }, step)))), HTML.h4({}, 'Result file'), HTML.span({ className: 'field filename' }, this.props.recipe.result), HTML.h4({}, 'ID field'), this.props.recipe.key ? HTML.span({ className: 'field' }, this.props.recipe.key) : HTML.span({ className: 'note' }, 'This agent has no ID field defined.'), HTML.h4({}, 'Triggers'), this.props.recipe.triggers.length > 0 ? HTML.ul({ className: 'triggers' }, ...this.props.recipe.triggers.map(trigger => HTML.li({}, trigger.recipient))) : HTML.span({ className: 'note' }, 'This agent has no triggers.'), ] return HTML.div({ className: 'agent-page-recipe' }, ...elements) }
function GripMap(props) { const { mode, object } = props; const config = { "data-link-actor-id": object.actor, className: "objectBox objectBox-object" }; const title = getTitle(props, object); const isEmpty = getLength(object) === 0; if (isEmpty || mode === MODE.TINY) { return span(config, title); } const propsArray = safeEntriesIterator(props, object, maxLengthMap.get(mode)); return span( config, title, span( { className: "objectLeftBrace" }, " { " ), ...interleave(propsArray, ", "), span( { className: "objectRightBrace" }, " }" ) ); }
render() { const body = [ HTML.h5({}, 'Edit agent'), this.state.validation['name'] ? HTML.span({ className: 'validation' }, 'You must give this agent a name') : null, HTML.h4({}, 'Name'), HTML.input({ value: this.state.recipe.name, onChange: this.set('name') }), HTML.h4({}, 'Description'), HTML.input({ value: this.state.recipe.description, onChange: this.set('description') }), HTML.h4({}, 'Run schedule'), React.createElement(CronEntry, { value: this.state.recipe.schedule, onChange: this.set('schedule') }), this.state.validation['run'] ? HTML.span({ className: 'validation' }, 'At least one command needs to be entered') : null, HTML.h4({}, 'Run commands'), React.createElement(CommandEntry, { value: this.state.recipe.run, onChange: this.set('run') }), this.state.validation['result'] ? HTML.span({ className: 'validation' }, 'You must give the name of the file that gets created by this agent') : null, HTML.h4({}, 'Result file'), HTML.input({ className: 'filename', value: this.state.recipe.result, onChange: this.set('result') }), HTML.h4({}, 'ID field'), HTML.input({ value: this.state.recipe.key || '', onChange: this.set('key') }), HTML.h4({}, 'Triggers'), React.createElement(TriggerEntry, { value: this.state.recipe.triggers, onChange: this.set('triggers') }) ] const dialog = !this.state.confirming ? null : React.createElement(Dialog, { body, acceptText: 'Save changes', accept: this.send, validate: this.validate, cancel: () => this.setState({ confirming: false }) }) const editButton = HTML.button({ onClick: () => this.setState({ confirming: true }) }, 'Edit') return HTML.div({ className: 'agent-page-edit', ref: node => this.node = node }, editButton, dialog) }
render() { const title = HTML.h2({}, 'Create a new agent') const hr = HTML.hr({}) if (this.state.error) { const error = HTML.h2({}, 'Something went wrong') const info = HTML.p({}, 'An error occured whilst creating this agent.') const message = HTML.p({}, this.state.error) return HTML.div({ className: 'new-agent-page', ref: node => this.node = node }, ...[ title, hr, HTML.div({ className: 'error' }, error, info, message) ]) } if (this.state.loading) return HTML.div({ className: 'new-agent-page', ref: node => this.node = node }, ...[ HTML.div({ className: 'loading' }) ]) const elements = [ this.state.validation['name'] ? HTML.span({ className: 'validation' }, 'You must give this agent a name') : null, HTML.h4({}, 'Agent name'), HTML.input({ onChange: this.set('name') }), HTML.h4({}, 'Description'), HTML.input({ onChange: this.set('description') }), HTML.hr({}), HTML.h4({}, 'Setup commands'), React.createElement(CommandEntry, { onChange: this.set('setup') }), HTML.p({}, 'These commands will only be executed once, when the agent is being built. Use ', HTML.code({}, 'requires'), ' to declare what packages are going to be used.'), HTML.hr({}), HTML.h4({}, 'When should this agent run?'), React.createElement(CronEntry, { defaultValue: this.state.recipe.schedule, onChange: this.set('schedule') }), this.state.validation['run'] ? HTML.span({ className: 'validation' }, 'At least one command needs to be entered') : null, HTML.h4({}, 'Run commands'), React.createElement(CommandEntry, { onChange: this.set('run') }), HTML.p({}, 'These commands will be executed every time the agent runs.'), this.state.validation['result'] ? HTML.span({ className: 'validation' }, 'You must give the name of the file that gets created by this agent') : null, HTML.h4({}, 'What file gets created?'), HTML.input({ className: 'filename', onChange: this.set('result') }), HTML.h4({}, 'If there is an ID column, what is it called? '), HTML.input({ className: 'key', onChange: this.set('key') }), HTML.p({}, 'An ID column it can be used to discover changes, otherwise only additions and deletions can be determined.'), HTML.hr({}), HTML.h4({}, 'What should happen next?'), React.createElement(TriggerEntry, { onChange: this.set('triggers') }), HTML.hr({}), HTML.button({ onClick: this.create }, 'Create agent') ] return HTML.div({ className: 'new-agent-page', ref: node => this.node = node }, ...[ title, hr, HTML.div({}, ...elements) ]) }
renderTreeItem( item: Node, depth: number, focused: boolean, arrow: Object, expanded: boolean ) { const { label, value } = this.getTreeItemLabelAndValue( item, depth, expanded ); const labelElement = this.renderTreeItemLabel( label, item, depth, focused, expanded ); const delimiter = value && labelElement ? dom.span({ className: "object-delimiter" }, ": ") : null; return dom.div( this.getTreeTopElementProps(item, depth, focused, expanded), arrow, labelElement, delimiter, value ); }
renderGroup: function(item, key) { return DOM.span({ key: item.label || key, className:'ql-formats' }, item.items.map(this.renderItem) ); },
renderLabel(label: string) { if (label === null || typeof label === "undefined") { return null; } const { item, depth, focused, expanded, onLabelClick } = this.props; return dom.span( { className: "object-label", onClick: onLabelClick ? event => { event.stopPropagation(); // If the user selected text, bail out. if (Utils.selection.documentHasSelection()) { return; } onLabelClick(item, { depth, focused, expanded, setExpanded: this.props.setExpanded }); } : undefined }, label ); }
getDisplayString: function(){ if( this.getDisplayModeString ) return this.getDisplayModeString(); if( this.props.value === '' ) return DOM.span( {className: 'jsonNovalue'}, 'No value' ); return this.props.value; },
function getElements(grip, nameMaxLength, separatorText = ": ") { const { name, role } = grip.preview; const elements = []; elements.push(span({ className: "accessible-role" }, role)); if (name) { elements.push( span({ className: "separator" }, separatorText), StringRep({ className: "accessible-name", object: name, cropLimit: nameMaxLength }) ); } return elements; }
function Accessible(props) { const { object, inspectIconTitle, nameMaxLength, onAccessibleClick, onAccessibleMouseOver, onAccessibleMouseOut, onInspectIconClick, separatorText } = props; const elements = getElements(object, nameMaxLength, separatorText); const isInTree = object.preview && object.preview.isConnected === true; const baseConfig = { "data-link-actor-id": object.actor, className: "objectBox objectBox-accessible" }; let inspectIcon; if (isInTree) { if (onAccessibleClick) { Object.assign(baseConfig, { onClick: _ => onAccessibleClick(object), className: `${baseConfig.className} clickable` }); } if (onAccessibleMouseOver) { Object.assign(baseConfig, { onMouseOver: _ => onAccessibleMouseOver(object) }); } if (onAccessibleMouseOut) { Object.assign(baseConfig, { onMouseOut: onAccessibleMouseOut }); } if (onInspectIconClick) { inspectIcon = button({ className: "open-accessibility-inspector", title: inspectIconTitle, onClick: e => { if (onAccessibleClick) { e.stopPropagation(); } onInspectIconClick(object, e); } }); } } return span(baseConfig, ...elements, inspectIcon); }
const execution = this.state.execution.map(line => { const command = HTML.li({ className: 'stdin' }, line.command + '\n') if (line.code === undefined && this.props.state !== 'running') { // run failed on this line const code = HTML.code({}, HTML.ol({}, command)) return HTML.div({ className: 'execution' }, code) } else { // line has run or is running const maxLogLength = 500 const outputs = line.log.slice(0, maxLogLength).map(entry => HTML.li({ className: entry.type }, entry.value)) const unseen = line.log.length > maxLogLength ? HTML.span({ className: 'unseen' }, 'Output too large to display: ' + (line.log.length - maxLogLength).toLocaleString() + ' rows hidden.') : null const exit = line.code > 0 ? HTML.span({ className: 'exit' }, 'Exited with code ' + line.code + '.') : null const durationNow = line.duration || new Date() - new Date(line.dateStarted) const durationText = Moment.duration(durationNow, 'ms').format('h[h] m[m] s[s]') const duration = HTML.span({ className: 'duration' }, durationText) const state = line.code === undefined ? 'running' : line.code === 0 ? 'success' : 'failure' const code = HTML.code({}, HTML.ol({}, command, ...outputs)) return HTML.div({ className: 'execution ' + state }, code, duration, unseen, exit) } })
const agents = this.state.agentsFiltered.map(agent => { const fields = [ agent.state === 'started' && agent.recipe.schedule ? HTML.div({ className: 'schedule' }, 'runs ' + PrettyCron.toString(agent.recipe.schedule).toLowerCase()) : null, agent.state !== 'started' ? HTML.div({ className: 'state ' + agent.state }, agent.state) : null, HTML.h5({}, agent.recipe ? agent.recipe.name : '[' + agent.id + ']'), HTML.div({ className: 'description' }, agent.recipe ? agent.recipe.description : null) ] const inner = agent.state !== 'unresponsive' ? HTML.a({ href: '/agents/' + agent.id }, ...fields) : HTML.span({}, ...fields) return HTML.li({ className: agent.state }, inner) })
function getTitle(props, object) { const title = props.title || (object && object.class ? object.class : "Map"); return span( { className: "objectTitle" }, title, lengthBubble({ object, mode: props.mode, maxLengthMap, getLength, showZeroLength: true }) ); }
render() { const title = HTML.h2({}, HTML.a({ href: '/' }, 'Agents')) const hr = HTML.hr({}) const createButton = HTML.button({ onClick: this.create }, 'Create new agent') const importButton = HTML.button({ onClick: this.import }, 'Import') const exportButton = HTML.button({ onClick: this.export }, 'Export') if (this.state.agents === null) { const buttons = HTML.div({ className: 'buttons' }, importButton, createButton) const loading = HTML.div({ className: 'loading' }) return HTML.div({ className: 'dashboard-page', ref: node => this.node = node }, title, buttons, hr, loading) } else if (this.state.agents.length === 0) { const buttons = HTML.div({ className: 'buttons' }, importButton, createButton) const message = HTML.p({}, 'No agents have been created.') return HTML.div({ className: 'dashboard-page', ref: node => this.node = node }, title, buttons, hr, message) } else { const count = HTML.span({ className: 'count' }, this.state.agentsFiltered.length === 1 ? '1 agent' : this.state.agentsFiltered.length + ' agents') const filter = HTML.input({ placeholder: 'Filter agents...', className: 'filter', onInput: this.onFilter }) const buttons = HTML.div({ className: 'buttons' }, exportButton, importButton, createButton) const agents = this.state.agentsFiltered.map(agent => { const fields = [ agent.state === 'started' && agent.recipe.schedule ? HTML.div({ className: 'schedule' }, 'runs ' + PrettyCron.toString(agent.recipe.schedule).toLowerCase()) : null, agent.state !== 'started' ? HTML.div({ className: 'state ' + agent.state }, agent.state) : null, HTML.h5({}, agent.recipe ? agent.recipe.name : '[' + agent.id + ']'), HTML.div({ className: 'description' }, agent.recipe ? agent.recipe.description : null) ] const inner = agent.state !== 'unresponsive' ? HTML.a({ href: '/agents/' + agent.id }, ...fields) : HTML.span({}, ...fields) return HTML.li({ className: agent.state }, inner) }) const list = HTML.ol({}, ...agents) return HTML.div({ className: 'dashboard-page', ref: node => this.node = node }, ...[ title, buttons, hr, filter, count, list ]) } }
render() { const { arrow } = this.props; const { label, value } = this.getLabelAndValue(); const labelElement = this.renderLabel(label); const delimiter = value && labelElement ? dom.span({ className: "object-delimiter" }, ": ") : null; return dom.div( this.getTreeItemProps(), arrow, labelElement, delimiter, value ); }
renderInput: function(){ var className = this.typeClass; if( !this.state.editing ) return DOM.span( {onClick: this.setEditMode, className: className, readOnly: this.props.settings.readOnly}, this.getDisplayString() ); if (this.props.settings.dateTime) { this.inputType = 'datetime-local'; } return DOM.input({ type: this.inputType, value: this.state.value, readOnly: this.props.settings.readOnly, id: this.props.id, placeholder: this.props.settings.placeholder || '', onChange: this.updateValue, onBlur: this.setValue, ref: 'input', onKeyDown: this.handleKeyDown }); },
// eslint-disable-next-line complexity getLabelAndValue(): { value?: string | Element, label?: string } { const { item, depth, expanded, mode } = this.props; const label = item.name; const isPrimitive = nodeIsPrimitive(item); if (nodeIsOptimizedOut(item)) { return { label, value: dom.span({ className: "unavailable" }, "(optimized away)") }; } if (nodeIsUninitializedBinding(item)) { return { label, value: dom.span({ className: "unavailable" }, "(uninitialized)") }; } if (nodeIsUnmappedBinding(item)) { return { label, value: dom.span({ className: "unavailable" }, "(unmapped)") }; } if (nodeIsUnscopedBinding(item)) { return { label, value: dom.span({ className: "unavailable" }, "(unscoped)") }; } const itemValue = getValue(item); const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable"); if (nodeIsMissingArguments(item) || unavailable) { return { label, value: dom.span({ className: "unavailable" }, "(unavailable)") }; } if ( nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item) && (mode === MODE.TINY || !mode) ) { return { label: Utils.renderRep(item, { ...this.props, functionName: label }) }; } if ( nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || nodeIsLongString(item) || isPrimitive ) { const repProps = { ...this.props }; if (depth > 0) { repProps.mode = mode === MODE.LONG ? MODE.SHORT : MODE.TINY; } if (expanded) { repProps.mode = MODE.TINY; } if (nodeIsLongString(item)) { repProps.member = { open: nodeHasFullText(item) && expanded }; } if (nodeHasGetter(item)) { const targetGrip = getParentGripValue(item); const receiverGrip = getNonPrototypeParentGripValue(item); if (targetGrip && receiverGrip) { Object.assign(repProps, { onInvokeGetterButtonClick: () => this.props.invokeGetter( item, targetGrip, receiverGrip.actor, item.name ) }); } } return { label, value: Utils.renderRep(item, repProps) }; } return { label }; }
} render() { const { expanded } = this.props; const classNames = ["arrow"]; if (expanded) { classNames.push("expanded"); } return dom.button({ className: classNames.join(" ") }); } } const treeIndent = dom.span({ className: "tree-indent" }, "\u200B"); class TreeNode extends Component { static get propTypes() { return { id: PropTypes.any.isRequired, index: PropTypes.number.isRequired, depth: PropTypes.number.isRequired, focused: PropTypes.bool.isRequired, expanded: PropTypes.bool.isRequired, item: PropTypes.any.isRequired, isExpandable: PropTypes.bool.isRequired, onClick: PropTypes.func, renderItem: PropTypes.func.isRequired }; }
const summarise = (title, value) => HTML.span({ className: 'summary' }, HTML.span({ className: 'title' }, title), value)
// eslint-disable-next-line complexity getTreeItemLabelAndValue( item: Node, depth: number, expanded: boolean ): { value?: string | Element, label?: string } { const label = item.name; const isPrimitive = nodeIsPrimitive(item); if (nodeIsOptimizedOut(item)) { return { label, value: dom.span({ className: "unavailable" }, "(optimized away)") }; } if (nodeIsUninitializedBinding(item)) { return { label, value: dom.span({ className: "unavailable" }, "(uninitialized)") }; } if (nodeIsUnmappedBinding(item)) { return { label, value: dom.span({ className: "unavailable" }, "(unmapped)") }; } if (nodeIsUnscopedBinding(item)) { return { label, value: dom.span({ className: "unavailable" }, "(unscoped)") }; } const itemValue = getValue(item); const unavailable = isPrimitive && itemValue && itemValue.hasOwnProperty && itemValue.hasOwnProperty("unavailable"); if (nodeIsMissingArguments(item) || unavailable) { return { label, value: dom.span({ className: "unavailable" }, "(unavailable)") }; } if ( nodeIsFunction(item) && !nodeIsGetter(item) && !nodeIsSetter(item) && (this.props.mode === MODE.TINY || !this.props.mode) ) { return { label: Utils.renderRep(item, { ...this.props, functionName: label }) }; } if ( nodeHasProperties(item) || nodeHasAccessors(item) || nodeIsMapEntry(item) || nodeIsLongString(item) || isPrimitive ) { const repProps = { ...this.props }; if (depth > 0) { repProps.mode = this.props.mode === MODE.LONG ? MODE.SHORT : MODE.TINY; } if (expanded) { repProps.mode = MODE.TINY; } if (nodeIsLongString(item)) { repProps.member = { open: nodeHasFullText(item) && expanded }; } return { label, value: Utils.renderRep(item, repProps) }; } return { label }; }