-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bulk update separation #356
Changes from 7 commits
8bf80a8
35f260d
ea5baf7
2b1837e
f3ba48b
d5bc709
9a0d150
19b9c9f
cedf122
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,13 +32,12 @@ import { | |
ObservabilityPanelAttrs, | ||
PanelType, | ||
} from '../../../common/types/custom_panels'; | ||
import { ObservabilitySideBar } from '../common/side_nav'; | ||
import { CustomPanelTable } from './custom_panel_table'; | ||
import { CustomPanelView } from './custom_panel_view'; | ||
import { isNameValid } from './helpers/utils'; | ||
import { CustomPanelViewSO } from './custom_panel_view_so'; | ||
import { coreRefs } from '../../framework/core_refs'; | ||
import { fetchPanels } from './redux/panel_slice'; | ||
import { deletePanel, fetchPanels, uuidRx } from './redux/panel_slice'; | ||
|
||
// import { ObjectFetcher } from '../common/objectFetcher'; | ||
|
||
|
@@ -143,8 +142,6 @@ export const Home = ({ | |
}); | ||
}; | ||
|
||
const uuidRx = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/; | ||
|
||
const isUuid = (id) => !!id.match(uuidRx); | ||
|
||
const fetchSavedObjectPanel = async (id: string) => { | ||
|
@@ -226,44 +223,46 @@ export const Home = ({ | |
|
||
// Deletes multiple existing Operational Panels | ||
const deleteCustomPanelList = (customPanelIdList: string[], toastMessage: string) => { | ||
// Promise.all([ | ||
// deletePanelSO(customPanelIdList), | ||
// deletePanels(customPanelIdList) | ||
// ]).then((res) => { | ||
// setcustomPanelData((prevCustomPanelData) => { | ||
// return prevCustomPanelData.filter( | ||
// (customPanel) => !customPanelIdList.includes(customPanel.id) | ||
// ); | ||
// }); | ||
// setToast(toastMessage); | ||
// }) | ||
// .catch((err) => { | ||
// setToast( | ||
// 'Error deleting Operational Panels, please make sure you have the correct permission.', | ||
// 'danger' | ||
// ); | ||
// console.error(err.body.message); | ||
// }); | ||
Promise.all([deletePanelSO(customPanelIdList), deletePanels(customPanelIdList)]) | ||
.then((res) => { | ||
// setcustomPanelData((prevCustomPanelData) => { | ||
// return prevCustomPanelData.filter( | ||
// (customPanel) => !customPanelIdList.includes(customPanel.id) | ||
// ); | ||
// }); | ||
// setToast(toastMessage); | ||
}) | ||
.catch((err) => { | ||
setToast( | ||
'Error deleting Operational Panels, please make sure you have the correct permission.', | ||
'danger' | ||
); | ||
console.error(err.body.message); | ||
}); | ||
}; | ||
|
||
// Deletes an existing Operational Panel | ||
const deleteCustomPanel = async (customPanelId: string, customPanelName: string) => { | ||
// return http | ||
// .delete(`${CUSTOM_PANELS_API_PREFIX}/panels/` + customPanelId) | ||
// .then((res) => { | ||
// setcustomPanelData((prevCustomPanelData) => { | ||
// return prevCustomPanelData.filter((customPanel) => customPanel.id !== customPanelId); | ||
// }); | ||
// setToast(`Operational Panel "${customPanelName}" successfully deleted!`); | ||
// return res; | ||
// }) | ||
// .catch((err) => { | ||
// setToast( | ||
// 'Error deleting Operational Panel, please make sure you have the correct permission.', | ||
// 'danger' | ||
// ); | ||
// console.error(err.body.message); | ||
// }); | ||
return http | ||
.delete(`${CUSTOM_PANELS_API_PREFIX}/panels/` + customPanelId) | ||
.then((res) => { | ||
dispatch(fetchPanels()); | ||
setToast(`Operational Panel "${customPanelName}" successfully deleted!`); | ||
return res; | ||
}) | ||
.catch((err) => { | ||
setToast( | ||
'Error deleting Operational Panel, please make sure you have the correct permission.', | ||
'danger' | ||
); | ||
console.error(err.body.message); | ||
}); | ||
}; | ||
|
||
// Deletes an existing SO Operational Panel | ||
const deleteCustomPanelSO = async (customPanelId: string, customPanelName: string) => { | ||
dispatch(deletePanel(customPanelId)); | ||
// TODO: toast here | ||
}; | ||
|
||
const addSamplePanels = async () => { | ||
|
@@ -306,7 +305,6 @@ export const Home = ({ | |
}) | ||
.then((res) => { | ||
dispatch(fetchPanels()); | ||
// setcustomPanelData([...customPanelData, ...res.demoPanelsData]); | ||
}); | ||
setToast(`Sample panels successfully added.`); | ||
} catch (err: any) { | ||
|
@@ -358,7 +356,7 @@ export const Home = ({ | |
chrome={chrome} | ||
parentBreadcrumbs={customPanelBreadCrumbs} | ||
cloneCustomPanel={cloneCustomPanel} | ||
deleteCustomPanel={deleteCustomPanel} | ||
deleteCustomPanel={deleteCustomPanelSO} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. delete savedobject should be in panel_slice. Therefore, we should collapse a reference and just call We're trying to eliminate all prop-drilling, especially functions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can modify this in a follow up PR |
||
setToast={setToast} | ||
onEditClick={onEditClick} | ||
page="operationalPanels" | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -1,6 +1,7 @@ | ||||
import { createSelector, createSlice } from '@reduxjs/toolkit'; | ||||
import { concat, from, Observable, of } from 'rxjs'; | ||||
import { async, concat, from, Observable, of } from 'rxjs'; | ||||
import { map, mergeMap, tap, toArray } from 'rxjs/operators'; | ||||
import { forEach } from 'lodash'; | ||||
import { | ||||
CUSTOM_PANELS_API_PREFIX, | ||||
CUSTOM_PANELS_SAVED_OBJECT_TYPE, | ||||
|
@@ -16,6 +17,7 @@ import { | |||
import { coreRefs } from '../../../framework/core_refs'; | ||||
import { SavedObject, SimpleSavedObject } from '../../../../../../src/core/public'; | ||||
import { isNameValid } from '../helpers/utils'; | ||||
import { addVisualizationPanel } from '../helpers/add_visualization_helper'; | ||||
|
||||
interface InitialState { | ||||
id: string; | ||||
|
@@ -56,10 +58,7 @@ export const panelReducer = panelSlice.reducer; | |||
|
||||
export const selectPanel = (rootState): CustomPanelType => rootState.customPanel.panel; | ||||
|
||||
export const selectPanelList = (rootState): CustomPanelType[] => { | ||||
// console.log('selectPanelList', { rootState, panelList: rootState.customPanel.panelList }); | ||||
return rootState.customPanel.panelList; | ||||
}; | ||||
export const selectPanelList = (rootState): CustomPanelType[] => rootState.customPanel.panelList; | ||||
|
||||
// export const selectPanelList = createSelector( | ||||
// rootState => { console.log("selectPanelList", { rootState }); return rootState.customPanel.panelList }, | ||||
|
@@ -90,16 +89,18 @@ const fetchCustomPanels = async () => { | |||
const panels$: Observable<CustomPanelListType> = concat( | ||||
fetchSavedObjectPanels$(), | ||||
fetchObservabilityPanels$() | ||||
).pipe(map((res) => { | ||||
console.log("fetchCustomPanels", res); | ||||
return res as CustomPanelListType | ||||
})); | ||||
).pipe( | ||||
map((res) => { | ||||
console.log('fetchCustomPanels', res); | ||||
return res as CustomPanelListType; | ||||
}) | ||||
); | ||||
|
||||
return panels$.pipe(toArray()).toPromise(); | ||||
}; | ||||
|
||||
export const fetchPanels = () => async (dispatch, getState) => { | ||||
const panels = await fetchCustomPanels() | ||||
const panels = await fetchCustomPanels(); | ||||
console.log('fetchPanels', { panels }); | ||||
dispatch(setPanelList(panels)); | ||||
}; | ||||
|
@@ -112,34 +113,49 @@ export const fetchPanel = (id) => async (dispatch, getState) => { | |||
|
||||
export const fetchVisualization = () => (dispatch, getState) => {}; | ||||
|
||||
const updateLegacyPanel = (panel: CustomPanelType) => coreRefs.http! | ||||
.post(`${CUSTOM_PANELS_API_PREFIX}/panels/update`, { | ||||
const updateLegacyPanel = (panel: CustomPanelType) => | ||||
coreRefs.http!.post(`${CUSTOM_PANELS_API_PREFIX}/panels/update`, { | ||||
body: JSON.stringify({ panelId: panel.id, panel: panel as PanelType }), | ||||
}); | ||||
|
||||
const updateSavedObjectPanel = (panel: CustomPanelType) => savedObjectPanelsClient.update(panel); | ||||
|
||||
|
||||
const uuidRx = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/; | ||||
export const uuidRx = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/; | ||||
|
||||
const isUuid = (id) => !!id.match(uuidRx); | ||||
|
||||
|
||||
export const updatePanel = (panel: CustomPanelType) => async (dispatch, getState) => { | ||||
try { | ||||
if (isUuid(panel.id)) | ||||
await updateSavedObjectPanel(panel) | ||||
else | ||||
await updateLegacyPanel(panel) | ||||
if (isUuid(panel.id)) await updateSavedObjectPanel(panel); | ||||
else await updateLegacyPanel(panel); | ||||
|
||||
dispatch(setPanel(panel)); | ||||
const panelList = getState().customPanel.panelList.map((p) => (p.id === panel.id ? panel : p)); | ||||
dispatch(setPanelList(panelList)); | ||||
} catch (err) { | ||||
console.log("Error updating panel", { err, panel }) | ||||
console.log('Error updating panel', { err, panel }); | ||||
} | ||||
}; | ||||
|
||||
export const addVizToPanels = (panels, vizId) => async (dispatch, getState) => { | ||||
forEach(panels, (oldPanel) => { | ||||
console.log(oldPanel); | ||||
console.log(getState().customPanel.panelList); | ||||
derek-ho marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
const panel = getState().customPanel.panelList.find((p) => p.id === oldPanel.panel.id); | ||||
|
||||
const allVisualizations = panel!.visualizations; | ||||
|
||||
const visualizationsWithNewPanel = addVisualizationPanel(vizId, undefined, allVisualizations); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ps48 @joshuali925 can you verify this line makes sense? Since we want to add a viz to panel as a new one, pass in undefined into this function: dashboards-observability/public/components/custom_panels/helpers/add_visualization_helper.ts Line 57 in 5f2b777
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is correct for adding panels to a visualization. For replace workflow, you can use the same function and pass OldVisualizationId. |
||||
|
||||
const updatedPanel = { ...panel, visualizations: visualizationsWithNewPanel }; | ||||
try { | ||||
dispatch(updatePanel(updatedPanel)); | ||||
} catch (err) { | ||||
console.error(err?.body?.message || err); | ||||
} | ||||
}); | ||||
}; | ||||
|
||||
export const deletePanel = (id) => async (dispatch, getState) => { | ||||
await savedObjectPanelsClient.delete(id); | ||||
const panelList: CustomPanelType[] = getState().panelList.filter((p) => p.id !== id); | ||||
|
@@ -152,7 +168,6 @@ export const createPanel = (panel) => async (dispatch, getState) => { | |||
dispatch(setPanelList([...panelList, newPanel])); | ||||
}; | ||||
|
||||
|
||||
const saveRenamedPanel = async (id, name) => { | ||||
const renamePanelObject = { | ||||
panelId: id, | ||||
|
@@ -174,17 +189,20 @@ const saveRenamedPanelSO = async (id, name) => { | |||
}; | ||||
|
||||
// Renames an existing CustomPanel | ||||
export const renameCustomPanel = (editedCustomPanelName: string, id: string) => async (dispatch, getState) => { | ||||
console.log("renameCustomPanel dispatched", { editedCustomPanelName, id }) | ||||
export const renameCustomPanel = (editedCustomPanelName: string, id: string) => async ( | ||||
dispatch, | ||||
getState | ||||
) => { | ||||
console.log('renameCustomPanel dispatched', { editedCustomPanelName, id }); | ||||
|
||||
if (!isNameValid(editedCustomPanelName)) { | ||||
console.log('Invalid Custom Panel name', 'danger'); | ||||
return Promise.reject(); | ||||
} | ||||
|
||||
const panel = getState().customPanel.panelList.find(p => p.id === id) | ||||
const updatedPanel = { ...panel, title: editedCustomPanelName } | ||||
dispatch(updatePanel(updatedPanel)) | ||||
const panel = getState().customPanel.panelList.find((p) => p.id === id); | ||||
const updatedPanel = { ...panel, title: editedCustomPanelName }; | ||||
dispatch(updatePanel(updatedPanel)); | ||||
|
||||
// try { | ||||
// // await savePanelFn(editedCustomPanelId, editedCustomPanelName); | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,13 +3,20 @@ | |
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { forEach } from 'lodash'; | ||
import { | ||
addVizToPanels, | ||
fetchPanel, | ||
uuidRx, | ||
} from '../../../../../public/components/custom_panels/redux/panel_slice'; | ||
import { | ||
SAVED_OBJECT_ID, | ||
SAVED_OBJECT_TYPE, | ||
SAVED_VISUALIZATION, | ||
} from '../../../../../common/constants/explorer'; | ||
import { ISavedObjectsClient } from '../../saved_object_client/client_interface'; | ||
import { SavedQuerySaver } from './saved_query_saver'; | ||
import { addVisualizationPanel } from '../../../../../public/components/custom_panels/helpers/add_visualization_helper'; | ||
|
||
export class SaveAsNewVisualization extends SavedQuerySaver { | ||
constructor( | ||
|
@@ -76,9 +83,14 @@ export class SaveAsNewVisualization extends SavedQuerySaver { | |
} | ||
|
||
addToPanel({ selectedPanels, saveTitle, notifications, visId }) { | ||
const { dispatch } = this.dispatchers; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please consider context here, as well as SRP-SingleResponsibilityPrinciple. Wer are inside "saved_objects/saved_object_savers".... This, despite it's name, is the Observability index re-invention of saved objects. Also, wrt. SRP, although "saving things" sounds like a single responsibliity, we can see from the code that saving to SavedObject-Core (via Redux/Dispatch) is very different from using SavedObjectSavers. Recommendation : There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Why does this happen? I didn't look into impl details but essentially the difference between saving SO vs. observability object is the client. If the client can be abstracted, then the same operation should work for both cases There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @joshuali925 @pjfitzgibbons can we merge this in as is? I understand it may not be right but theres a few other p0 items today, once we make the final go-no go call I can refactor to be correct |
||
const soPanels = selectedPanels.filter((panel) => panel.panel.id.test(uuidRx)); | ||
const opsPanels = selectedPanels.filter((panel) => !panel.panel.id.test(uuidRx)); | ||
|
||
dispatch(addVizToPanels(soPanels, visId)); | ||
this.panelClient | ||
.updateBulk({ | ||
selectedCustomPanels: selectedPanels, | ||
selectedCustomPanels: opsPanels, | ||
savedVisualizationId: visId, | ||
}) | ||
.then((res: any) => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought
var?: string
meantstring | undefined
exactly?I've even "fixed" my own bugs many times with the
?
syntax.Thuoghts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe... I think what it is doing is makes it optional, which it cannot be since a required parameter comes after. This gets rid of it but maybe the more right thing is to put it at the end...