Skip to content

Commit

Permalink
Merge pull request #711 from getguesstimate/05-08-release-fixes
Browse files Browse the repository at this point in the history
08/06 Release Fixes
  • Loading branch information
OAGr authored Aug 7, 2016
2 parents ebd0aad + 1f0e0ea commit c818031
Show file tree
Hide file tree
Showing 14 changed files with 70 additions and 43 deletions.
15 changes: 7 additions & 8 deletions src/components/calculators/show/calculator-space-selector.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { createSelector } from 'reselect'
import e from 'gEngine/engine'

function _sameId(idA, idB){
return idA.toString() === idB.toString()
}

function calculatorSelector(state, {calculatorId}) { return state.calculators.find(c => _sameId(c.id, calculatorId)) }
function spaceGraphSelector(state) { return _.pick(state, ['spaces', 'metrics', 'guesstimates', 'simulations', 'users', 'me', 'organizations']) }
const _sameId = (idA, idB) => idA.toString() === idB.toString()
const spaceGraphSelector = state => _.pick(state, ['spaces', 'metrics', 'guesstimates', 'simulations', 'users', 'me', 'organizations'])
const organizationFactsSelector = state => _.get(state, 'facts.organizationFacts')
const calculatorSelector = (state, {calculatorId}) => state.calculators.find(c => _sameId(c.id, calculatorId))

export const calculatorSpaceSelector = createSelector(
spaceGraphSelector,
organizationFactsSelector,
calculatorSelector,
(graph, calculator) => {
(graph, organizationFacts, calculator) => {
if (!_.has(calculator, 'space_id')) { return {} }
const {metrics, is_private} = e.space.toDSpace(calculator.space_id, graph)
const {metrics, is_private} = e.space.toDSpace(calculator.space_id, graph, organizationFacts)

const findById = id => metrics.find(m => _sameId(m.id, id))

Expand Down
4 changes: 3 additions & 1 deletion src/components/distributions/editor/TextForm/TextForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class TextForm extends Component{
size: PropTypes.string
}

focus() { this.refs.TextInput.focus() }
focus() { this.refs.TextInput.getWrappedInstance().focus() }

onChangeInput(input) {
this.props.onChangeInput(input)
Expand All @@ -47,6 +47,7 @@ export class TextForm extends Component{
size,
errors,
organizationId,
organizationHasFacts,
onChangeInput,
onAddData,
onChangeGuesstimateType,
Expand Down Expand Up @@ -81,6 +82,7 @@ export class TextForm extends Component{
errors={errors}
width={shouldBeWide ? 'NARROW' : "WIDE"}
organizationId={organizationId}
organizationHasFacts={organizationHasFacts}
/>

{ shouldDisplayType &&
Expand Down
37 changes: 26 additions & 11 deletions src/components/distributions/editor/TextForm/TextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {EditorState, Editor, ContentState, Modifier, CompositeDecorator} from 'd

import {clearSuggestion, getSuggestion} from 'gModules/facts/actions'

import {HANDLE_REGEX, resolveToSelector} from 'gEngine/facts'
import {HANDLE_REGEX, GLOBALS_ONLY_REGEX, resolveToSelector} from 'gEngine/facts'

import {isData, formatData} from 'lib/guesstimator/formatter/formatters/Data'

Expand All @@ -25,19 +25,12 @@ const Suggestion = stylizedSpan('suggestion')
const ValidInput = stylizedSpan('valid input')
const ErrorInput = stylizedSpan('error input')

const FACT_DECORATOR_LIST = [
{
strategy: (contentBlock, callback) => { findWithRegex(HANDLE_REGEX, contentBlock, callback) },
component: Fact,
},
]

const positionDecorator = (start, end, component) => ({
strategy: (contentBlock, callback) => {if (end <= contentBlock.text.length) {callback(start, end)}},
component,
})

@connect(state => ({suggestion: state.facts.currentSuggestion}))
@connect(state => ({suggestion: state.facts.currentSuggestion}), null, null, {withRef: true})
export class TextInput extends Component{
displayName: 'Guesstimate-TextInput'

Expand All @@ -55,7 +48,16 @@ export class TextInput extends Component{
decoratorList(extraDecorators=[]) {
const {validInputs, errorInputs} = this.props

let decorators = [...extraDecorators, ...FACT_DECORATOR_LIST]
const canUseOrganizationFacts = (!!this.props.organizationHasFacts && (__DEV__ || this.props.organizationId.toString() === '1'))
const fact_regex = canUseOrganizationFacts ? HANDLE_REGEX : GLOBALS_ONLY_REGEX
const fact_decorators = [
{
strategy: (contentBlock, callback) => { findWithRegex(fact_regex, contentBlock, callback) },
component: Fact,
},
]

let decorators = [...extraDecorators, ...fact_decorators]

if (!_.isEmpty(validInputs)) {
const validInputsRegex = new RegExp(`(${validInputs.join('|')})`, 'g')
Expand Down Expand Up @@ -99,6 +101,7 @@ export class TextInput extends Component{
withExtraDecorators(editorState, extraDecorators) {
return EditorState.set(editorState, {decorator: new CompositeDecorator(this.decoratorList(extraDecorators))})
}
updateDecorators() { this.setState({editorState: this.withExtraDecorators(this.state.editorState)}) }

deleteOldSuggestion(oldSuggestion) {
const freshEditorState = this.addText('', true, oldSuggestion.length)
Expand All @@ -125,6 +128,8 @@ export class TextInput extends Component{
} else {
this.addSuggestion()
}
} else if (!_.isEqual(prevProps.validInputs, this.props.validInputs) || !_.isEqual(prevProps.errorInputs, this.props.errorInputs)) {
this.updateDecorators()
}
}

Expand Down Expand Up @@ -153,13 +158,22 @@ export class TextInput extends Component{
}
}

changeData(text) { this.props.onChangeData(formatData(text)) }

handlePastedText(text) {
if (text === this.props.value || !isData(text)) { return false }

this.changeData(text)
return true
}

onChange(editorState) {
this.fetchSuggestion(editorState)
this.setState({editorState})

const text = this.text(editorState)
if (text !== this.props.value) {
isData(text) ? this.props.onChangeData(formatData(text)) : this.props.onChange(text)
isData(text) ? this.changeData(text) : this.props.onChange(text)
}
}

Expand Down Expand Up @@ -201,6 +215,7 @@ export class TextInput extends Component{
onEscape={this.props.onEscape}
editorState={editorState}
handleReturn={e => this.props.onReturn(e.shiftKey)}
handlePastedText={this.handlePastedText.bind(this)}
onTab={this.handleTab.bind(this)}
onBlur={this.handleBlur.bind(this)}
onChange={this.onChange.bind(this)}
Expand Down
3 changes: 2 additions & 1 deletion src/components/distributions/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default class Guesstimate extends Component{
}

render () {
const {size, guesstimate, inputMetrics, onOpen, errors, organizationId} = this.props
const {size, guesstimate, inputMetrics, onOpen, errors, organizationId, organizationHasFacts} = this.props
if(guesstimate.metric !== this.props.metricId) { return false }

const hasData = !!guesstimate.data
Expand Down Expand Up @@ -124,6 +124,7 @@ export default class Guesstimate extends Component{
size={size}
errors={errors}
organizationId={organizationId}
organizationHasFacts={organizationHasFacts}
ref='TextForm'
/>
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/metrics/card/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ export default class MetricCard extends Component {
inSelectedCell,
metric,
organizationId,
organizationHasFacts,
canvasState,
hovered,
connectDragSource,
Expand Down Expand Up @@ -272,6 +273,7 @@ export default class MetricCard extends Component {
inputMetrics={metric.edges.inputMetrics}
metricId={metric.id}
organizationId={organizationId}
organizationHasFacts={organizationHasFacts}
metricFocus={this.focus.bind(this)}
jumpSection={() => {this.refs.MetricCardViewSection.focusName()}}
onOpen={this.openModal.bind(this)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/organizations/show/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export default class OrganizationShow extends Component{

if (!organization) { return false }
let tabs = [{name: 'Models', key: MODEL_TAB}, {name: 'Members', key: MEMBERS_TAB}]
if (__DEV__ || organizationId === 1) { tabs = [{name: 'Models', key: MODEL_TAB}, {name: 'Facts', key: FACT_BOOK_TAB}, {name: 'Members', key: MEMBERS_TAB}] }
if (__DEV__ || organizationId.toString() === '1') { tabs = [{name: 'Models', key: MODEL_TAB}, {name: 'Facts', key: FACT_BOOK_TAB}, {name: 'Members', key: MEMBERS_TAB}] }
const portalUrl = _.get(organization, 'account._links.payment_portal.href')
if (!!portalUrl) { tabs = [...tabs, {name: 'Billing', key: 'BILLING', href: portalUrl, onMouseUp: this.refreshData.bind(this)}] }

Expand Down
2 changes: 1 addition & 1 deletion src/components/spaces/canvas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ function mapStateToProps(state) {
copied: state.copied,
selectedCell: state.selectedCell,
selectedRegion: state.selectedRegion,
organizationFacts: state.facts.organizationFacts,
}
}

Expand Down Expand Up @@ -146,6 +145,7 @@ export default class Canvas extends Component{
location={location}
metric={metric}
organizationId={this.props.denormalizedSpace.organization_id}
organizationHasFacts={this.props.organizationHasFacts}
selectedMetric={passSelected && selected}
/>
)
Expand Down
11 changes: 9 additions & 2 deletions src/components/spaces/denormalized-space-selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,21 @@ export const denormalizedSpaceSelector = createSelector(
spaceIdSelector,
canvasStateSelector,
(graph, spaceId, canvasState) => {
let denormalizedSpace = e.space.toDSpace(spaceId, graph, graph.facts.organizationFacts)
const {facts: {organizationFacts}} = graph
let denormalizedSpace = e.space.toDSpace(spaceId, graph, organizationFacts)

if (denormalizedSpace) {
denormalizedSpace.canvasState = canvasState
denormalizedSpace.checkpointMetadata = checkpointMetadata(spaceId, graph.checkpoints)
}

const {organization_id} = denormalizedSpace
const organization = graph.organizations.find(o => o.id == organization_id)
const organizationHasFacts = !!organization && _.some(
organizationFacts, e.facts.byVariableName(e.organization.organizationReadableId(organization))
)

window.recorder.recordSelectorStop(NAME, {denormalizedSpace})
return { denormalizedSpace }
return { denormalizedSpace, organizationHasFacts }
}
)
2 changes: 1 addition & 1 deletion src/components/spaces/show/Toolbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export class SpaceToolbar extends Component {
<CardListElement
key={c.id}
header={c.title}
onMouseDown={() => {this.props.showCalculator(c.id)}}
onMouseDown={() => {this.props.showCalculator(c)}}
closeOnClick={true}
icon={'calculator'}
/>
Expand Down
14 changes: 11 additions & 3 deletions src/components/spaces/show/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const ShowCalculatorHeader = ({id, editableByMe, onEdit, onDelete, onClose}) =>
<div className='row'>
<div className='col-xs-12'>
<div className='button-close-text'>
<ButtonExpandText onClick={navigateFn(`/calculators/${showCalculatorId}`)}/>
<ButtonExpandText onClick={navigateFn(`/calculators/${id}`)}/>
{editableByMe && <ButtonEditText onClick={onEdit}/>}
{editableByMe && <ButtonDeleteText onClick={onDelete}/>}
<ButtonCloseText onClick={onClose}/>
Expand Down Expand Up @@ -104,14 +104,15 @@ export default class SpacesShow extends Component {
rightSidebar: {
type: !!this.props.showCalculatorId ? SHOW_CALCULATOR : CLOSED,
showCalculatorResults: this.props.showCalculatorResults,
showCalculatorId: this.props.showCalculatorId,
},
}

componentWillMount() {
window.recorder.recordMountEvent(this)

this.considerFetch(this.props)
if (!(this.props.embed || this.state.showCalculatorId)) { elev.show() }
if (!(this.props.embed || this.state.rightSidebar.type !== CLOSED)) { elev.show() }

if (_.has(this.props, 'denormalizedSpace.editableByMe')) {
this.setDefaultEditPermission(_.get(this.props, 'denormalizedSpace.editableByMe'))
Expand Down Expand Up @@ -261,6 +262,10 @@ export default class SpacesShow extends Component {
}
showCalculator({id}) { this.openRightSidebar({type: SHOW_CALCULATOR, showCalculatorId: id}) }
editCalculator(id) { this.openRightSidebar({type: EDIT_CALCULATOR_FORM, editCalculatorId: id}) }
deleteCalculator(id) {
this.props.dispatch(calculatorActions.destroy(id))
this.closeRightSidebar()
}
makeNewCalculator() { this.openRightSidebar({type: NEW_CALCULATOR_FORM}) }
showFactSidebar() { if (this.canShowFactSidebar()) { this.openRightSidebar({type: FACT_SIDEBAR}) } }

Expand All @@ -276,6 +281,7 @@ export default class SpacesShow extends Component {
header: (
<ShowCalculatorHeader
editableByMe={editableByMe}
id={showCalculatorId}
onEdit={this.editCalculator.bind(this, showCalculatorId)}
onDelete={this.deleteCalculator.bind(this, showCalculatorId)}
onClose={this.closeRightSidebar.bind(this)}
Expand Down Expand Up @@ -334,6 +340,7 @@ export default class SpacesShow extends Component {

render() {
const space = this.props.denormalizedSpace
const {organizationHasFacts} = this.props
if (!spacePrepared(space)) { return <div className='spaceShow'></div> }

const sidebarIsViseable = space.editableByMe || !_.isEmpty(space.description)
Expand All @@ -342,7 +349,7 @@ export default class SpacesShow extends Component {
if (this.props.embed) {
return (
<div className='spaceShow screenshot'>
<Canvas denormalizedSpace={space} overflow={'hidden'} screenshot={true}/>
<Canvas denormalizedSpace={space} organizationHasFacts={organizationHasFacts} overflow={'hidden'} screenshot={true}/>
</div>
)
}
Expand Down Expand Up @@ -441,6 +448,7 @@ export default class SpacesShow extends Component {
<ClosedSpaceSidebar onOpen={this.openLeftSidebar.bind(this)}/>
}
<Canvas
organizationHasFacts={organizationHasFacts}
denormalizedSpace={space}
onCopy={this.onCopy.bind(this, true)}
onPaste={this.onPaste.bind(this, true)}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/engine/dgraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function runSimulation(dGraph:DGraph, metricId:string, n:number) {
return Promise.resolve({sample: {errors: [{type: INTERNAL_ERROR, message: 'Unknown metric referenced'}]}})
} else if (_facts.HANDLE_REGEX.test(m.guesstimate.input)) {
const unresolvedFacts = m.guesstimate.input.match(_facts.HANDLE_REGEX)
const message = `Unknown Fact${unresolvedFacts.length > 1 ? 's' : ''} Referenced: ${unresolvedFacts.join(', ')}`
const message = `Unknown fact${unresolvedFacts.length > 1 ? 's' : ''} referenced: ${unresolvedFacts.join(', ')}`
return Promise.resolve({sample: {errors: [{type: MATH_ERROR, message}]}})
}
return _guesstimate.sample(m.guesstimate, dGraph, n)
Expand Down
4 changes: 2 additions & 2 deletions src/lib/engine/facts.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ export const FactPT = PropTypes.shape({
}).isRequired,
})

export const GLOBALS_ONLY_REGEX = /@\w+(?:\.\w+)?/
export const HANDLE_REGEX = /(?:@\w+(?:\.\w+)?|#\w+)/g

export const getVar = f => _.get(f, 'variable_name') || ''
export const byVariableName = name => f => getVar(f) === name
const namedLike = partial => f => getVar(f).startsWith(partial)
const variableNameIntersection = (f1, f2) => _.intersection(f1.split(''), f2.split('')).join('')

export function withSortedValues(rawFact) {
let fact = Object.assign({}, rawFact)
Expand All @@ -51,7 +51,7 @@ export function selectorSearch(selector, facts) {
const matches = possibleFacts.filter(namedLike(partial))
if (_.isEmpty(matches)) { return {partial, suggestion: ''} }

const suggestion = _.map(matches, getVar).reduce(variableNameIntersection)
const suggestion = getVar(matches[0])
return {partial, suggestion}
}

Expand Down
3 changes: 2 additions & 1 deletion src/lib/engine/guesstimate.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function translateReadableIds(input, idMap) {
const ids = _.sortBy(Object.keys(idMap), id => -id.length)

let translatedInput = input
ids.forEach(id => {translatedInput = translatedInput.replace(id, idMap[id])})
ids.forEach(id => {translatedInput = translatedInput.replace(new RegExp(id, 'g'), idMap[id])})

return translatedInput
}
Expand Down Expand Up @@ -131,5 +131,6 @@ export function expressionToInputFn(metrics=[], facts=[]) {

// Returns an expression based on the passed input and idMap.
export function inputToExpression(input, idMap) {
if (_.isEmpty(input) || _.isEmpty(idMap)) { return input }
return input.replace(RegExp(Object.keys(idMap).join('|'), 'g'), match => expressionSyntaxPad(idMap[match].id, idMap[match].isMetric))
}
12 changes: 2 additions & 10 deletions src/modules/facts/cities.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@
"expression": "8405837",
"simulation": {
"sample": {
"simulation": {
"sample": {
"values": [8405837]
}
}
"values": [8405837]
}
}
}
Expand All @@ -25,11 +21,7 @@
"expression": "3884307",
"simulation": {
"sample": {
"simulation": {
"sample": {
"values": [3884307]
}
}
"values": [3884307]
}
}
}
Expand Down

0 comments on commit c818031

Please sign in to comment.