diff --git a/mock/mock.go b/mock/mock.go index 37bf4424f..c5445b85a 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -25,7 +25,7 @@ func NewExplorationStore(nowFunc func() time.Time) mrfusion.ExplorationStore { UpdatedAt: nowFunc(), } e.db[1] = &mrfusion.Exploration{ - Name: "Ferdinand Magellan", + Name: "Your Mom", Data: "{\"panels\":{\"123\":{\"id\":\"123\",\"queryIds\":[\"456\"]}},\"queryConfigs\":{\"456\":{\"id\":\"456\",\"database\":null,\"measurement\":null,\"retentionPolicy\":null,\"fields\":[],\"tags\":{},\"groupBy\":{\"time\":null,\"tags\":[]},\"areTagsAccepted\":true,\"rawText\":null}}}", CreatedAt: nowFunc(), UpdatedAt: nowFunc(), diff --git a/ui/src/chronograf/actions/view/index.js b/ui/src/chronograf/actions/view/index.js index 6ffadd9ee..9e85e9973 100644 --- a/ui/src/chronograf/actions/view/index.js +++ b/ui/src/chronograf/actions/view/index.js @@ -142,14 +142,13 @@ export function toggleTagAcceptance(queryId) { }; } -export function createExplorer(clusterID, push) { +export function createExploration(source, push) { return (dispatch) => { const initialState = getInitialState(); AJAX({ - url: '/api/int/v1/explorers', + url: `${source.links.self}/users/1/explorations`, // TODO: change this to use actual user link once users are introduced method: 'POST', data: JSON.stringify({ - cluster_id: clusterID, data: JSON.stringify(initialState), }), headers: { @@ -157,8 +156,8 @@ export function createExplorer(clusterID, push) { }, }).then((resp) => { const explorer = parseRawExplorer(resp.data); - dispatch(loadExplorer(explorer)); - push(`/chronograf/data_explorer/${explorer.id}`); + dispatch(loadExploration(explorer)); + push(`/sources/${source.id}/chronograf/data_explorer/${btoa(explorer.link.href)}`); // Base64 encode explorer URI }); }; } @@ -178,10 +177,10 @@ export function deleteExplorer(clusterID, explorerID, push) { // If we don't have an explorer to navigate to, it means we're deleting the last // explorer and should create a new one. if (explorer) { - dispatch(loadExplorer(explorer)); + dispatch(loadExploration(explorer)); push(`/chronograf/data_explorer/${explorer.id}`); } else { - dispatch(createExplorer(clusterID, push)); + dispatch(createExploration(clusterID, push)); } } @@ -220,14 +219,14 @@ function loadExplorers(explorers) { }; } -function loadExplorer(explorer) { +function loadExploration(explorer) { return { type: 'LOAD_EXPLORER', payload: {explorer}, }; } -export function fetchExplorers({source, userID, explorerID, push}) { +export function fetchExplorers({source, userID, explorerURI, push}) { return (dispatch) => { dispatch({type: 'FETCH_EXPLORERS'}); AJAX({ @@ -239,29 +238,29 @@ export function fetchExplorers({source, userID, explorerID, push}) { // Create a new explorer session for a user if they don't have any // saved (e.g. when they visit for the first time). if (!explorers.length) { - dispatch(createExplorer(push)); + dispatch(createExploration(push)); return; } - // If no explorerID is provided, it means the user wasn't attempting to visit + // If no explorerURI is provided, it means the user wasn't attempting to visit // a specific explorer (i.e. `/data_explorer/:id`). In this case, pick the // most recently updated explorer and navigate to it. - if (!explorerID) { + if (!explorerURI) { const explorer = _.maxBy(explorers, (ex) => ex.updated_at); - dispatch(loadExplorer(explorer)); + dispatch(loadExploration(explorer)); push(`/sources/${source.id}/chronograf/data_explorer/${btoa(explorer.link.href)}`); return; } - // We have an explorerID, meaning a specific explorer was requested. - const explorer = explorers.find((ex) => ex.id === explorerID); + // We have an explorerURI, meaning a specific explorer was requested. + const explorer = explorers.find((ex) => ex.id === explorerURI); // Attempting to request a non-existent explorer if (!explorer) { return; } - dispatch(loadExplorer(explorer)); + dispatch(loadExploration(explorer)); }); }; } @@ -284,12 +283,13 @@ function saveExplorer(error) { }; } -export function chooseExplorer(clusterID, explorerID, push) { +export function chooseExploration(explorerURI, source, push) { return (dispatch, getState) => { // Save the previous session explicitly in case an auto-save was unable to complete. const {panels, queryConfigs, activeExplorer} = getState(); api.saveExplorer({ explorerID: activeExplorer.id, + name: activeExplorer.name, panels, queryConfigs, }).then(() => { @@ -302,11 +302,11 @@ export function chooseExplorer(clusterID, explorerID, push) { dispatch(fetchExplorer()); AJAX({ - url: `/api/int/v1/explorers/${explorerID}`, + url: explorerURI, }).then((resp) => { const explorer = parseRawExplorer(resp.data); - dispatch(loadExplorer(explorer)); - push(`/chronograf/data_explorer/${explorerID}`); + dispatch(loadExploration(explorer)); + push(`/sources/${source.id}/chronograf/data_explorer/${btoa(explorerURI)}`); }); }; } diff --git a/ui/src/chronograf/api/index.js b/ui/src/chronograf/api/index.js index 93a2d5d94..70018e968 100644 --- a/ui/src/chronograf/api/index.js +++ b/ui/src/chronograf/api/index.js @@ -1,15 +1,15 @@ import AJAX from 'utils/ajax'; -export function saveExplorer({panels, queryConfigs, explorerID}) { +export function saveExplorer({name, panels, queryConfigs, explorerID}) { return AJAX({ - url: `/api/int/v1/explorers/${explorerID}`, - method: 'PUT', + url: explorerID, + method: 'PATCH', headers: { 'Content-Type': 'application/json', }, data: JSON.stringify({ data: JSON.stringify({panels, queryConfigs}), + name, }), }); } - diff --git a/ui/src/chronograf/containers/DataExplorer.js b/ui/src/chronograf/containers/DataExplorer.js index 342af6ff1..8498dce0d 100644 --- a/ui/src/chronograf/containers/DataExplorer.js +++ b/ui/src/chronograf/containers/DataExplorer.js @@ -7,8 +7,8 @@ import ResizeContainer from 'shared/components/ResizeContainer'; import {FETCHING} from '../reducers/explorers'; import { setTimeRange as setTimeRangeAction, - createExplorer as createExplorerAction, - chooseExplorer as chooseExplorerAction, + createExploration as createExplorationAction, + chooseExploration as chooseExplorationAction, deleteExplorer as deleteExplorerAction, editExplorer as editExplorerAction, } from '../actions/view'; @@ -28,8 +28,8 @@ const DataExplorer = React.createClass({ lower: PropTypes.string, }).isRequired, setTimeRange: PropTypes.func.isRequired, - createExplorer: PropTypes.func.isRequired, - chooseExplorer: PropTypes.func.isRequired, + createExploration: PropTypes.func.isRequired, + chooseExploration: PropTypes.func.isRequired, deleteExplorer: PropTypes.func.isRequired, editExplorer: PropTypes.func.isRequired, }, @@ -60,7 +60,7 @@ const DataExplorer = React.createClass({ }, render() { - const {timeRange, explorers, explorerID, setTimeRange, createExplorer, chooseExplorer, deleteExplorer, editExplorer} = this.props; + const {timeRange, explorers, explorerID, setTimeRange, createExploration, chooseExploration, deleteExplorer, editExplorer} = this.props; if (explorers === FETCHING) { // TODO: page-wide spinner @@ -69,13 +69,13 @@ const DataExplorer = React.createClass({ const activeExplorer = explorers[explorerID]; if (!activeExplorer) { - return null; // TODO: handle no explorers; + return