diff --git a/app/api_topologies.go b/app/api_topologies.go index bb16836fe..29e6b64ca 100644 --- a/app/api_topologies.go +++ b/app/api_topologies.go @@ -53,7 +53,7 @@ var ( // namespaceFilters generates a namespace selector option group based on the given namespaces func namespaceFilters(namespaces []string, noneLabel string) APITopologyOptionGroup { - options := APITopologyOptionGroup{ID: "namespace", Default: "none", SelectType: "union", NoneLabel: noneLabel} + options := APITopologyOptionGroup{ID: "namespace", Default: "", SelectType: "union", NoneLabel: noneLabel} for _, namespace := range namespaces { options.Options = append(options.Options, APITopologyOption{ Value: namespace, Label: namespace, filter: render.IsNamespace(namespace), filterPseudo: false, @@ -343,7 +343,7 @@ func (a byName) Less(i, j int) bool { return a[i].Name < a[j].Name } type APITopologyOptionGroup struct { ID string `json:"id"` // Default value for the UI to adopt. NOT used as the default if the value is omitted, allowing "" as a distinct value. - Default string `json:"defaultValue,omitempty"` + Default string `json:"defaultValue"` Options []APITopologyOption `json:"options,omitempty"` // SelectType describes how options can be picked. Currently defined values: // "one": Default if empty. Exactly one option may be picked from the list. diff --git a/client/app/scripts/components/topology-options.js b/client/app/scripts/components/topology-options.js index 448b355ec..a184fa88a 100644 --- a/client/app/scripts/components/topology-options.js +++ b/client/app/scripts/components/topology-options.js @@ -49,12 +49,15 @@ class TopologyOptions extends React.Component { // Add it to the array if it's not selected nextOptions = selectedActiveOptions.concat(value); } - // Since the user is clicking an option, remove the highlighting from the 'none' option, - // unless they are removing the last option. In that case, default to the 'none' label. + // Since the user is clicking an option, remove the highlighting from the none option, + // unless they are removing the last option. In that case, default to the none label. + // Note that since the other ids are potentially user-controlled (eg. k8s namespaces), + // the only string we can use for the none option is the empty string '', + // since that can't collide. if (nextOptions.length === 0) { - nextOptions = ['none']; + nextOptions = ['']; } else { - nextOptions = nextOptions.filter(o => o !== 'none'); + nextOptions = nextOptions.filter(o => o !== ''); } } this.trackOptionClick(optionId, nextOptions); @@ -62,7 +65,7 @@ class TopologyOptions extends React.Component { } handleNoneClick(optionId, value, topologyId) { - const nextOptions = ['none']; + const nextOptions = ['']; this.trackOptionClick(optionId, nextOptions); this.props.changeTopologyOption(optionId, nextOptions, topologyId); } @@ -74,7 +77,7 @@ class TopologyOptions extends React.Component { ? activeOptions.get(optionId) : option.get('defaultValue'); const noneItem = makeMap({ - value: 'none', + value: '', label: option.get('noneLabel') }); return (