From ba148cedebd189d65c2cfcddefe7564215c87b2c Mon Sep 17 00:00:00 2001 From: "jinhyeong.kim@snetsystems.co.kr" Date: Fri, 17 Mar 2023 14:12:18 +0900 Subject: [PATCH 1/5] At #363 Modify format when creating OSP telegraf config --- backend/server/csp.go | 21 +++++---- .../cloudhub/ProviderOpenStackConfigs.tsx | 9 ++-- .../containers/cloudhub/ProviderConfPage.tsx | 6 +-- .../components/CollectorConfig.tsx | 7 ++- .../agent_admin/containers/ServiceConfig.tsx | 45 +++++++------------ 5 files changed, 40 insertions(+), 48 deletions(-) diff --git a/backend/server/csp.go b/backend/server/csp.go index 36b9506e..0d8be010 100644 --- a/backend/server/csp.go +++ b/backend/server/csp.go @@ -424,17 +424,20 @@ func (s *Service) generateTelegrafConfigForOSP(ctx context.Context, csp *cloudhu return http.StatusInternalServerError, nil, fmt.Errorf("Output plugin(something like influxdb) urls for telegraf are empty or invalid") } + var influxdbs []influxdb + for _, url := range outputURLs { + influxdbs = append(influxdbs, influxdb{ + Urls: []string{url}, + Database: csp.NameSpace, + Tagpass: tagpass{ + Tenant: []string{csp.NameSpace}, + }, + }) + } + telegrafConfig := &telegrafConfig{ Outputs: outputs{ - Influxdb: []influxdb{ - { - Urls: outputURLs, - Database: csp.NameSpace, - Tagpass: tagpass{ - Tenant: []string{csp.NameSpace}, - }, - }, - }, + Influxdb: influxdbs, }, Inputs: inputs{ Openstack: []openstack{ diff --git a/frontend/src/admin/components/cloudhub/ProviderOpenStackConfigs.tsx b/frontend/src/admin/components/cloudhub/ProviderOpenStackConfigs.tsx index 7be72ac4..8435da65 100644 --- a/frontend/src/admin/components/cloudhub/ProviderOpenStackConfigs.tsx +++ b/frontend/src/admin/components/cloudhub/ProviderOpenStackConfigs.tsx @@ -150,7 +150,7 @@ export class ProviderOpenStackConfigs extends PureComponent { type="button" > - {id ? HandleType.Delete : HandleType.Create} + {_.isEmpty(id) ? HandleType.Create : HandleType.Delete}
@@ -182,8 +182,7 @@ export class ProviderOpenStackConfigs extends PureComponent { private handleSubmit = async e => { e.preventDefault() - const {id} = this.props.cspInput - + const {id, hasProjectOption} = this.props.cspInput const properties = { id: id || '', projectName: this.projectName.value, @@ -196,5 +195,9 @@ export class ProviderOpenStackConfigs extends PureComponent { } const handleType = id ? HandleType.Delete : HandleType.Create await this.props.onHandleSubmit(properties, handleType) + this.setState(prevState => ({ + ...prevState, + isActiveToggle: hasProjectOption, + })) } } diff --git a/frontend/src/admin/containers/cloudhub/ProviderConfPage.tsx b/frontend/src/admin/containers/cloudhub/ProviderConfPage.tsx index 3243f48b..a5088b01 100644 --- a/frontend/src/admin/containers/cloudhub/ProviderConfPage.tsx +++ b/frontend/src/admin/containers/cloudhub/ProviderConfPage.tsx @@ -84,7 +84,7 @@ export class ProviderConfPage extends PureComponent { password: storeData['admin-pw'], projectDomain: storeData['pj-domain-id'], userDomain: storeData['user-domain-id'], - hasProjectOption: true, + hasProjectOption: false, }, } return convertProperties[provider] @@ -337,9 +337,8 @@ export class ProviderConfPage extends PureComponent { return { ...preState, cspInput: { - ...properties, + ...this.defaultProperties(ProviderTypes.OpenStack), id: cspRes.id, - hasProjectOption: true, }, } }) @@ -415,7 +414,6 @@ export class ProviderConfPage extends PureComponent { [ProviderTypes.OpenStack]: { ...defaultProperties, id: cspId, - hasProjectOption: true, } as OpenStackCspInput, } diff --git a/frontend/src/agent_admin/components/CollectorConfig.tsx b/frontend/src/agent_admin/components/CollectorConfig.tsx index 6d2ba1ba..300bb06c 100644 --- a/frontend/src/agent_admin/components/CollectorConfig.tsx +++ b/frontend/src/agent_admin/components/CollectorConfig.tsx @@ -23,8 +23,7 @@ import AgentCodeEditor from 'src/agent_admin/components/AgentCodeEditor' interface Props { isCollectorInstalled: boolean focusedCollectorConfigTab: CollectorConfigTabName | '' - configScript: string - inputConfigScript: string + tomlConfigScript: string selectedService: string[] collectorConfigTableTabs: CollectorConfigTabName[] collectorConfigTableData: CollectorConfigTableData @@ -112,7 +111,7 @@ class CollectorConfig extends PureComponent { private get CodeEditor() { const { - inputConfigScript, + tomlConfigScript, handleBeforeChangeScript, handleChangeScript, } = this.props @@ -129,7 +128,7 @@ class CollectorConfig extends PureComponent { }} > diff --git a/frontend/src/agent_admin/containers/ServiceConfig.tsx b/frontend/src/agent_admin/containers/ServiceConfig.tsx index 7cd19430..9e02b0a6 100644 --- a/frontend/src/agent_admin/containers/ServiceConfig.tsx +++ b/frontend/src/agent_admin/containers/ServiceConfig.tsx @@ -112,7 +112,7 @@ interface State { collectorServerObject: MinionsObject isCollectorInstalled: boolean configScript: string - inputConfigScript: string + tomlConfigScript: string configEditStyle: 'basic' | 'toml' focusedMinion: string focusedTenant: string @@ -131,7 +131,7 @@ export class ServiceConfig extends PureComponent { this.state = { collectorServerObject: {}, focusedCollectorConfigTab: '', - inputConfigScript: '', + tomlConfigScript: '', configScript: '', configEditStyle: 'basic', isCollectorInstalled: false, @@ -236,7 +236,7 @@ export class ServiceConfig extends PureComponent { selectedService: [], projectFileList: {files: [], isLoading: true}, configScript: '', - inputConfigScript: '', + tomlConfigScript: '', }) try { @@ -354,7 +354,7 @@ export class ServiceConfig extends PureComponent { script: string ) => { this.setState({ - inputConfigScript: script, + tomlConfigScript: script, }) } @@ -403,7 +403,7 @@ export class ServiceConfig extends PureComponent { } = this.state if (configEditStyle === 'toml') { - return this.updateCollectorConfigTableDataByTOM(configScript) + return this.updateCollectorConfigTableDataByTOM() } const configObj = TOML.parse(configScript) @@ -418,23 +418,17 @@ export class ServiceConfig extends PureComponent { inputPlugins.interval = collectorConfigTableData.interval inputPlugins.enabled_services = selectedService - const inputConfigObj = _.cloneDeep(configObj) - - delete inputConfigObj.outputs this.setState({ - inputConfigScript: TOML.stringify(inputConfigObj), + tomlConfigScript: TOML.stringify(configObj), }) return TOML.stringify(configObj) } - public updateCollectorConfigTableDataByTOM(configScript) { - const {focusedCollectorConfigTab, inputConfigScript} = this.state - const configObj = TOML.parse(configScript) - const inputConfigObj = TOML.parse(inputConfigScript) - const inputPlugins = inputConfigObj['inputs'][focusedCollectorConfigTab][0] - - configObj.inputs = inputConfigObj.inputs + public updateCollectorConfigTableDataByTOM() { + const {focusedCollectorConfigTab, tomlConfigScript} = this.state + const tomlConfigObj = TOML.parse(tomlConfigScript) + const inputPlugins = tomlConfigObj['inputs'][focusedCollectorConfigTab][0] this.setState({ collectorConfigTableData: { @@ -448,7 +442,7 @@ export class ServiceConfig extends PureComponent { selectedService: inputPlugins.enabled_services, }) - return TOML.stringify(configObj) + return TOML.stringify(tomlConfigObj) } public debugTelegrafCloudPlugin(configScript) { @@ -626,12 +620,9 @@ export class ServiceConfig extends PureComponent { ) const configObj = TOML.parse(hostLocalFileReadData) const inputPlugins = this.getInputPlugins(configObj) - const inputConfigObj = _.cloneDeep(configObj) - - delete inputConfigObj.outputs this.setState({ - inputConfigScript: TOML.stringify(inputConfigObj), + tomlConfigScript: TOML.stringify(configObj), configScript: TOML.stringify(configObj), serviceConfigStatus: RemoteDataState.Done, focusedTenant: selectedTenant, @@ -671,7 +662,7 @@ export class ServiceConfig extends PureComponent { }, selectedService: [], configScript: '', - inputConfigScript: '', + tomlConfigScript: '', }) notify(notifyConfigFileReadFailed(tomlParsingErrorMessage)) @@ -747,7 +738,7 @@ export class ServiceConfig extends PureComponent { focusedCollectorConfigTab: selectedCollectorConfigTab, serviceConfigStatus: RemoteDataState.Loading, configScript: '', - inputConfigScript: '', + tomlConfigScript: '', }) try { @@ -796,7 +787,7 @@ export class ServiceConfig extends PureComponent { projectFileList: {files: [], isLoading: true}, serviceConfigStatus: RemoteDataState.Done, configScript: '', - inputConfigScript: '', + tomlConfigScript: '', }) notify(notifyGetProjectFileFailed(error)) @@ -815,8 +806,7 @@ export class ServiceConfig extends PureComponent { collectorConfigTableData, focusedCollectorConfigTab, selectedService, - configScript, - inputConfigScript, + tomlConfigScript, configEditStyle, } = this.state @@ -854,8 +844,7 @@ export class ServiceConfig extends PureComponent {
Date: Fri, 17 Mar 2023 14:21:46 +0900 Subject: [PATCH 2/5] At #392 FIx reactdev-tools Error handling for uninstalled browsers --- frontend/src/store/configureStore.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/store/configureStore.js b/frontend/src/store/configureStore.js index f303b942..172c8b71 100644 --- a/frontend/src/store/configureStore.js +++ b/frontend/src/store/configureStore.js @@ -52,9 +52,11 @@ const composeEnhancers = : window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose if (process.env.NODE_ENV === 'production') { - window.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = function () {} - window.__REACT_DEVTOOLS_GLOBAL_HOOK__.onCommitFiberRoot = function () {} - window.__REACT_DEVTOOLS_GLOBAL_HOOK__.onCommitFiberUnmount = function () {} + if (typeof window.__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'object') { + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = function () {} + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.onCommitFiberRoot = function () {} + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.onCommitFiberUnmount = function () {} + } } export default function configureStore(initialState, browserHistory) { From 6478ca453aaf0f29c731484ada33c3efcafac75b Mon Sep 17 00:00:00 2001 From: jaegeun Date: Mon, 20 Mar 2023 13:58:29 +0900 Subject: [PATCH 3/5] At #393 Add Support OS ToolTip in Collector Control Tab --- .../src/agent_admin/components/Agent.scss | 5 ++ .../AgentControlSupportOSVersionToolTip.tsx | 65 +++++++++++++++++++ .../components/AgentControlTable.tsx | 13 ++-- .../agentControlTableSupportedOsVersion.ts | 11 ++++ frontend/src/agent_admin/constants/index.ts | 7 ++ 5 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 frontend/src/agent_admin/components/AgentControlSupportOSVersionToolTip.tsx create mode 100644 frontend/src/agent_admin/constants/agentControlTableSupportedOsVersion.ts diff --git a/frontend/src/agent_admin/components/Agent.scss b/frontend/src/agent_admin/components/Agent.scss index c3eca06b..a0ae3849 100644 --- a/frontend/src/agent_admin/components/Agent.scss +++ b/frontend/src/agent_admin/components/Agent.scss @@ -107,6 +107,11 @@ cursor: pointer; } + .tooltip--agent-control { + line-height: 30px; + padding-right: 0.1rem; + } + .panel-body--agent-control { display: flex; flex-direction: row; diff --git a/frontend/src/agent_admin/components/AgentControlSupportOSVersionToolTip.tsx b/frontend/src/agent_admin/components/AgentControlSupportOSVersionToolTip.tsx new file mode 100644 index 00000000..ae2607a2 --- /dev/null +++ b/frontend/src/agent_admin/components/AgentControlSupportOSVersionToolTip.tsx @@ -0,0 +1,65 @@ +// Libraries +import _ from 'lodash' +import React, {PureComponent} from 'react' +import ReactTooltip from 'react-tooltip' + +// Constants +import { + SUPPORTED_OS_VERSION_ORDER, + SUPPORTED_OS_VERSION, +} from 'src/agent_admin/constants' + +// Decorators +import {ErrorHandling} from 'src/shared/decorators/errors' + +interface Props {} + +@ErrorHandling +class AgentControlSupportOSVersionToolTip extends PureComponent { + constructor(props: Props) { + super(props) + } + + public generateSupportedOSVersionText = osName => { + const supportedOSVersions: string[] = SUPPORTED_OS_VERSION[osName] + let supportVersionText = '' + + _.map(supportedOSVersions, osVersion => { + supportVersionText += `${osVersion}
` + }) + + return supportVersionText + } + + render() { + const centosSupportVersionText = this.generateSupportedOSVersionText( + SUPPORTED_OS_VERSION_ORDER[0] + ) + // const ubuntuSupportVersionText = this.generateSupportedOSVersionText( + // SUPPORTED_OS_VERSION_ORDER[1] + // ) + const redhatSupportVersionText = this.generateSupportedOSVersionText( + SUPPORTED_OS_VERSION_ORDER[1] + ) + const agentControlSupportedOSVersionText = `

CentOS:

${centosSupportVersionText}

RedHat:

${redhatSupportVersionText}

` + + return ( +
+ ? + +
+ ) + } +} + +export default AgentControlSupportOSVersionToolTip diff --git a/frontend/src/agent_admin/components/AgentControlTable.tsx b/frontend/src/agent_admin/components/AgentControlTable.tsx index 5c0a820d..5d8d67d8 100644 --- a/frontend/src/agent_admin/components/AgentControlTable.tsx +++ b/frontend/src/agent_admin/components/AgentControlTable.tsx @@ -12,6 +12,7 @@ import AgentControlModal from 'src/agent_admin/components/AgentControlModal' import Dropdown from 'src/shared/components/Dropdown' import LoadingSpinner from 'src/flux/components/LoadingSpinner' import AgentMinionsToolTip from 'src/agent_admin/components/AgentMinionsToolTip' +import AgentControlSupportOSVersionToolTip from 'src/agent_admin/components/AgentControlSupportOSVersionToolTip' // Contants import { @@ -218,10 +219,14 @@ class AgentControlTable extends PureComponent { This feature is{' '} not supported yet for Windows. - + + OS Support + + +
{this.AgentTableContents}
diff --git a/frontend/src/agent_admin/constants/agentControlTableSupportedOsVersion.ts b/frontend/src/agent_admin/constants/agentControlTableSupportedOsVersion.ts new file mode 100644 index 00000000..a2c1b801 --- /dev/null +++ b/frontend/src/agent_admin/constants/agentControlTableSupportedOsVersion.ts @@ -0,0 +1,11 @@ +export const SUPPORTED_OS_VERSION = { + SUPPORTED_CENTOS_VERSION: ['CentOS 7.X'], + // SUPPORTED_UBUNTU_VERSION: ['Ubuntu 16.04', 'Ubuntu 18.04'], + SUPPORTED_REDHAT_VERSION: ['RedHat 7.X'], +} + +export const SUPPORTED_OS_VERSION_ORDER = [ + 'SUPPORTED_CENTOS_VERSION', + // 'SUPPORTED_UBUNTU_VERSION', + 'SUPPORTED_REDHAT_VERSION', +] diff --git a/frontend/src/agent_admin/constants/index.ts b/frontend/src/agent_admin/constants/index.ts index 5d2ae97f..7331e35f 100644 --- a/frontend/src/agent_admin/constants/index.ts +++ b/frontend/src/agent_admin/constants/index.ts @@ -24,6 +24,11 @@ import { COLLECTOR_CONFIG_TAB_ORDER, } from 'src/agent_admin/constants/CollectorConfigTable' +import { + SUPPORTED_OS_VERSION, + SUPPORTED_OS_VERSION_ORDER, +} from 'src/agent_admin/constants/agentControlTableSupportedOsVersion' + export { NETWORK_ACCESS, GET_STATUS, @@ -39,4 +44,6 @@ export { COLLECTOR_DROPDOWN_DATA, COLLECTOR_CONFIG_TAB_ABBREVIATION, COLLECTOR_CONFIG_TAB_ORDER, + SUPPORTED_OS_VERSION, + SUPPORTED_OS_VERSION_ORDER, } From cf38a051a547e0495382931625e642a254588189 Mon Sep 17 00:00:00 2001 From: "jinhyeong.kim@snetsystems.co.kr" Date: Tue, 21 Mar 2023 09:47:42 +0900 Subject: [PATCH 4/5] At #394 Update OpenStack Dashboard AutoRefresh intervals and add separate feature for Telegraf data --- frontend/src/clouds/actions/clouds.ts | 11 + frontend/src/clouds/actions/index.ts | 2 + .../components/OpenStackInstanceGraph.tsx | 241 ++++++++++++++++++ .../clouds/components/OpenStackPageHeader.tsx | 9 +- frontend/src/clouds/constants/autoRefresh.ts | 59 +++++ frontend/src/clouds/containers/Clouds.tsx | 49 +++- .../src/clouds/containers/OpenStackPage.tsx | 103 ++------ frontend/src/clouds/types/actions/clouds.ts | 22 ++ frontend/src/clouds/types/type.ts | 4 + .../AutoRefreshDropdown.tsx | 89 +++++-- .../autoRefreshOptions.ts | 17 +- frontend/src/shared/reducers/app.ts | 22 +- 12 files changed, 498 insertions(+), 130 deletions(-) create mode 100644 frontend/src/clouds/actions/clouds.ts create mode 100644 frontend/src/clouds/components/OpenStackInstanceGraph.tsx create mode 100644 frontend/src/clouds/types/actions/clouds.ts diff --git a/frontend/src/clouds/actions/clouds.ts b/frontend/src/clouds/actions/clouds.ts new file mode 100644 index 00000000..f005af34 --- /dev/null +++ b/frontend/src/clouds/actions/clouds.ts @@ -0,0 +1,11 @@ +import { + CloudActionTypes, + SetCloudAutoRefreshActionCreator, +} from 'src/clouds/types/actions/clouds' + +export const setCloudAutoRefresh: SetCloudAutoRefreshActionCreator = cloudAutoRefresh => ({ + type: CloudActionTypes.SetCloudAutoRefresh, + payload: { + cloudAutoRefresh, + }, +}) diff --git a/frontend/src/clouds/actions/index.ts b/frontend/src/clouds/actions/index.ts index 791781ab..f06540ce 100644 --- a/frontend/src/clouds/actions/index.ts +++ b/frontend/src/clouds/actions/index.ts @@ -20,6 +20,7 @@ import { RequestPauseVcenterAction, RequestRunVcenterAction, } from 'src/clouds/actions/vspheres' +import {setCloudAutoRefresh} from 'src/clouds/actions/clouds' export { Action, @@ -42,4 +43,5 @@ export { ResponseVcenterAction, RequestPauseVcenterAction, RequestRunVcenterAction, + setCloudAutoRefresh, } diff --git a/frontend/src/clouds/components/OpenStackInstanceGraph.tsx b/frontend/src/clouds/components/OpenStackInstanceGraph.tsx new file mode 100644 index 00000000..bc739b2d --- /dev/null +++ b/frontend/src/clouds/components/OpenStackInstanceGraph.tsx @@ -0,0 +1,241 @@ +// library +import _ from 'lodash' +import React from 'react' +import {Component} from 'react' +import {connect} from 'react-redux' +import {bindActionCreators} from 'redux' +import ReactObserver from 'react-resize-observer' + +// constants +import { + DEFAULT_CELL_BG_COLOR, + DEFAULT_CELL_TEXT_COLOR, + GRAPH_BG_COLOR, +} from 'src/dashboards/constants' +import {getCells} from 'src/hosts/utils/getCells' + +// actions +import {setAutoRefresh} from 'src/shared/actions/app' + +// components +import AutoRefreshDropdown from 'src/shared/components/dropdown_auto_refresh/AutoRefreshDropdown' +import LayoutRenderer from 'src/shared/components/LayoutRenderer' +import TimeRangeDropdown from 'src/shared/components/TimeRangeDropdown' +import {ErrorHandling} from 'src/shared/decorators/errors' +import OpenStackPageHeader from 'src/clouds/components/OpenStackPageHeader' + +// types +import {timeRanges} from 'src/shared/data/timeRanges' +import {Layout, RefreshRate, Source, TimeRange} from 'src/types' +import {FocusedInstance, OpenStackInstance} from 'src/clouds/types/openstack' + +// utils +import {WindowResizeEventTrigger} from 'src/shared/utils/trigger' +import {generateForHosts} from 'src/utils/tempVars' +import {GlobalAutoRefresher} from 'src/utils/AutoRefresher' + +interface Props { + filteredLayouts: Layout[] + source: Source + instance: OpenStackInstance + focusedInstance: Partial + selfAutoRefrsh?: number + autoRefresh?: number + manualRefresh: number + timeRange?: TimeRange + onChooseAutoRefresh?: (milliseconds: RefreshRate) => void +} +interface State { + selfTimeRange: TimeRange + selfManulRefresh: number +} +@ErrorHandling +class OpenStackInstanceGraph extends Component { + public intervalID: number + constructor(props: Props) { + super(props) + const {timeRange} = this.props + + this.state = { + selfTimeRange: timeRange + ? timeRange + : timeRanges.find(tr => tr.lower === 'now() - 1h'), + selfManulRefresh: 0, + } + } + componentDidMount(): void { + const {selfAutoRefrsh, autoRefresh} = this.props + + GlobalAutoRefresher.poll(selfAutoRefrsh) + GlobalAutoRefresher.poll(autoRefresh) + } + componentDidUpdate(prevProps: Readonly): void { + const { + manualRefresh: prevManulRefresh, + selfAutoRefrsh: prevSelfAutorefresh, + timeRange: prevTimeRange, + autoRefresh: prevAutoRefresh, + } = prevProps + const {manualRefresh, selfAutoRefrsh, autoRefresh, timeRange} = this.props + if (prevManulRefresh !== manualRefresh) { + this.setState({selfManulRefresh: manualRefresh}) + } + if (prevAutoRefresh !== autoRefresh) { + GlobalAutoRefresher.poll(autoRefresh) + } + if (prevSelfAutorefresh !== selfAutoRefrsh) { + GlobalAutoRefresher.poll(selfAutoRefrsh) + } + if (prevTimeRange !== timeRange) { + this.setState({selfTimeRange: timeRange}) + } + } + + public async UNSAFE_componentWillReceiveProps(nextProps: Props) { + const {filteredLayouts, selfAutoRefrsh, autoRefresh} = this.props + if (filteredLayouts.length) { + if (selfAutoRefrsh !== nextProps.selfAutoRefrsh) { + GlobalAutoRefresher.poll(nextProps.selfAutoRefrsh) + } + if (autoRefresh !== nextProps.autoRefresh) { + GlobalAutoRefresher.poll(nextProps.autoRefresh) + } + } + } + + public componentWillUnmount() { + GlobalAutoRefresher.stopPolling() + } + + render() { + const { + filteredLayouts, + source, + instance, + focusedInstance, + selfAutoRefrsh, + } = this.props + const {selfTimeRange, selfManulRefresh} = this.state + const layoutCells = getCells(filteredLayouts, source) + const tempVars = generateForHosts(source) + const renderInstance = { + instancename: instance?.instanceName, + instanceid: instance?.instanceId, + namespace: instance?.projectName, + } + const debouncedFit = _.debounce(() => { + WindowResizeEventTrigger() + }, 150) + const handleOnResize = (): void => { + debouncedFit() + } + + return ( +
+ +
+ + +
+
+ {_.isEmpty(instance) ? ( +
+
+

No Instances found

+
+
+ ) : ( + <> +
+
+ + +
+
+
+
+
+
+
+
+ + )} +
+ ) + } + + private handleChooseAutoRefresh = (option: { + milliseconds: RefreshRate + group?: string + }) => { + const {onChooseAutoRefresh} = this.props + const {milliseconds} = option + onChooseAutoRefresh(milliseconds) + } + + private handleChooseTimeRange = ({lower, upper}) => { + if (upper) { + this.setState({selfTimeRange: {lower, upper}}) + } else { + const timeRange = timeRanges.find(range => range.lower === lower) + this.setState({selfTimeRange: timeRange}) + } + } + private handleManualRefresh = (): void => { + this.setState({ + selfManulRefresh: Date.now(), + }) + } +} + +const mstp = state => { + const { + app: { + persisted: {autoRefresh}, + }, + links, + } = state + + return { + links, + selfAutoRefrsh: autoRefresh, + } +} + +const mdtp = dispatch => ({ + onChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch), +}) +export default connect(mstp, mdtp, null)(OpenStackInstanceGraph) diff --git a/frontend/src/clouds/components/OpenStackPageHeader.tsx b/frontend/src/clouds/components/OpenStackPageHeader.tsx index 384a22bc..35088372 100644 --- a/frontend/src/clouds/components/OpenStackPageHeader.tsx +++ b/frontend/src/clouds/components/OpenStackPageHeader.tsx @@ -2,7 +2,7 @@ import React, {Component} from 'react' import chroma from 'chroma-js' -// constents +// constants import {DEFAULT_CELL_BG_COLOR} from 'src/dashboards/constants' // error handler @@ -22,7 +22,12 @@ class OpenStackPageHeader extends Component { className={ 'dash-graph--heading dash-graph--heading-draggable openstacck-dash-graph--draggable' } - style={{margin: 0, height: '40px', backgroundColor: '#292933'}} + style={{ + margin: 0, + height: '40px', + backgroundColor: '#292933', + zIndex: 6, + }} > {this.cellName} {this.props.children} diff --git a/frontend/src/clouds/constants/autoRefresh.ts b/frontend/src/clouds/constants/autoRefresh.ts index 25e95eef..4de09725 100644 --- a/frontend/src/clouds/constants/autoRefresh.ts +++ b/frontend/src/clouds/constants/autoRefresh.ts @@ -1,8 +1,17 @@ +// library +import _ from 'lodash' + +// constants import { AutoRefreshOptionType, AutoRefreshOption, + defaultAutoRefreshOptions, + autoRefreshHeader, + autoRefreshOptionPaused, } from 'src/shared/components/dropdown_auto_refresh/autoRefreshOptions' +export const CLOUD_AUTO_REFRESH = {default: 0} + export const autoRefreshOptions: AutoRefreshOption[] = [ { id: 'auto-refresh-header', @@ -35,3 +44,53 @@ export const autoRefreshOptions: AutoRefreshOption[] = [ type: AutoRefreshOptionType.Option, }, ] + +export function getTimeOptionByGroup(groupName: string | undefined) { + return ( + { + openstack: [ + {...autoRefreshHeader, group: groupName}, + {...autoRefreshOptionPaused, group: groupName}, + { + id: 'auto-refresh-5m-osp', + milliseconds: 300000, + label: '5m', + type: AutoRefreshOptionType.Option, + group: groupName, + }, + { + id: 'auto-refresh-10-osp', + milliseconds: 600000, + label: '10m', + type: AutoRefreshOptionType.Option, + group: groupName, + }, + { + id: 'auto-refresh-15m-osp', + milliseconds: 900000, + label: '15m', + type: AutoRefreshOptionType.Option, + group: groupName, + }, + { + id: 'auto-refresh-30m-osp', + milliseconds: 1800000, + label: '30m', + type: AutoRefreshOptionType.Option, + group: groupName, + }, + { + id: 'auto-refresh-60m-osp', + milliseconds: 3600000, + label: '60m', + type: AutoRefreshOptionType.Option, + group: groupName, + }, + ], + default: _.map(defaultAutoRefreshOptions, autoRefreshOption => ({ + ...autoRefreshOption, + group: groupName, + })), + }[groupName] || null + ) +} diff --git a/frontend/src/clouds/containers/Clouds.tsx b/frontend/src/clouds/containers/Clouds.tsx index f4a6d682..a699fdf0 100644 --- a/frontend/src/clouds/containers/Clouds.tsx +++ b/frontend/src/clouds/containers/Clouds.tsx @@ -24,6 +24,7 @@ import { delayEnablePresentationMode, } from 'src/shared/actions/app' import {notify as notifyAction} from 'src/shared/actions/notifications' +import {setCloudAutoRefresh} from 'src/clouds/actions' // Types import { @@ -35,10 +36,15 @@ import { } from 'src/types' import {timeRanges} from 'src/shared/data/timeRanges' import * as AppActions from 'src/types/actions/app' +import {CloudAutoRefresh} from 'src/clouds/types/type' // Utils import {RouterState, InjectedRouter} from 'react-router' +// Constants +import {AutoRefreshOption} from 'src/shared/components/dropdown_auto_refresh/autoRefreshOptions' +import {getTimeOptionByGroup} from 'src/clouds/constants/autoRefresh' + interface RouterProps extends InjectedRouter { params: RouterState['params'] } @@ -47,9 +53,11 @@ interface Props extends ManualRefreshProps { source: Source links: Links autoRefresh: number + cloudAutoRefresh: CloudAutoRefresh inPresentationMode: boolean notify: NotificationAction onChooseAutoRefresh: (milliseconds: RefreshRate) => void + onChooseCloudAutoRefresh: (autoRefreshGroup: CloudAutoRefresh) => void handleClearTimeout: (key: string) => void handleClickPresentationButton: AppActions.DelayEnablePresentationModeDispatcher handleChooseAutoRefresh: AppActions.SetAutoRefreshActionCreator @@ -58,28 +66,50 @@ interface Props extends ManualRefreshProps { interface State { timeRange: TimeRange + autoRefreshOptions: AutoRefreshOption[] | null + currentRoute: string | null } @ErrorHandling class Clouds extends PureComponent { constructor(props: Props) { super(props) + const currentRoute = this.props.router.params?.cloud this.state = { timeRange: timeRanges.find(tr => tr.lower === 'now() - 1h'), + autoRefreshOptions: getTimeOptionByGroup(currentRoute), + currentRoute, } } - public handleChooseAutoRefresh = (option: {milliseconds: RefreshRate}) => { - const {onChooseAutoRefresh} = this.props - const {milliseconds} = option + componentDidUpdate(): void { + if (this.state.currentRoute !== this.props.router.params?.cloud) { + const currentRoute = this.props.router.params?.cloud + + this.setState(prevState => ({ + ...prevState, + autoRefreshOptions: getTimeOptionByGroup(currentRoute), + currentRoute, + })) + } + } - onChooseAutoRefresh(milliseconds) + public handleChooseAutoRefresh = (option: { + milliseconds: RefreshRate + group?: string + }) => { + const {onChooseAutoRefresh, onChooseCloudAutoRefresh} = this.props + const {milliseconds, group} = option + group + ? onChooseCloudAutoRefresh({[group]: milliseconds}) + : onChooseAutoRefresh(milliseconds) } public render() { const { autoRefresh, + cloudAutoRefresh, manualRefresh, onManualRefresh, inPresentationMode, @@ -87,7 +117,7 @@ class Clouds extends PureComponent { handleClearTimeout, router, } = this.props - const {timeRange} = this.state + const {timeRange, autoRefreshOptions} = this.state return ( @@ -111,6 +141,8 @@ class Clouds extends PureComponent { selected={autoRefresh} onChoose={this.handleChooseAutoRefresh} onManualRefresh={onManualRefresh} + customAutoRefreshOptions={autoRefreshOptions} + customAutoRefreshSelected={cloudAutoRefresh} /> { source={source} manualRefresh={manualRefresh} timeRange={timeRange} - autoRefresh={autoRefresh} + autoRefresh={cloudAutoRefresh?.openstack || 0} /> )} @@ -178,20 +210,23 @@ class Clouds extends PureComponent { const mstp = state => { const { app: { - persisted: {autoRefresh}, + persisted: {autoRefresh, cloudAutoRefresh}, ephemeral: {inPresentationMode}, }, links, } = state + return { links, autoRefresh, + cloudAutoRefresh, inPresentationMode, } } const mdtp = dispatch => ({ onChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch), + onChooseCloudAutoRefresh: bindActionCreators(setCloudAutoRefresh, dispatch), handleClickPresentationButton: bindActionCreators( delayEnablePresentationMode, dispatch diff --git a/frontend/src/clouds/containers/OpenStackPage.tsx b/frontend/src/clouds/containers/OpenStackPage.tsx index db37ea46..730d7fa8 100644 --- a/frontend/src/clouds/containers/OpenStackPage.tsx +++ b/frontend/src/clouds/containers/OpenStackPage.tsx @@ -4,7 +4,6 @@ import {connect} from 'react-redux' import _ from 'lodash' import ReactGridLayout, {WidthProvider} from 'react-grid-layout' import {bindActionCreators} from 'redux' -import ReactObserver from 'react-resize-observer' // middleware const GridLayout = WidthProvider(ReactGridLayout) @@ -43,18 +42,15 @@ import PageSpinner from 'src/shared/components/PageSpinner' import {AddonType, LAYOUT_MARGIN} from 'src/shared/constants' import FancyScrollbar from 'src/shared/components/FancyScrollbar' import OpenStackPageInstanceOverview from 'src/clouds/components/OpenStackPageInstanceOverview' -import LayoutRenderer from 'src/shared/components/LayoutRenderer' import OpenStackPageInstanceTable from 'src/clouds/components/OpenStackPageInstanceTable' import OpenStackProjectGaugeChartLayout from 'src/clouds/components/OpenStackProjectGaugeChartLayout' import OpenStackPageProjectTable from 'src/clouds/components/OpenStackPageProjectTable' -import OpenStackPageHeader from 'src/clouds/components/OpenStackPageHeader' +import OpenStackInstanceGraph from 'src/clouds/components/OpenStackInstanceGraph' // utils import {GlobalAutoRefresher} from 'src/utils/AutoRefresher' -import {getCells} from 'src/hosts/utils/getCells' import {generateForHosts} from 'src/utils/tempVars' import {getDeep} from 'src/utils/wrappers' -import {WindowResizeEventTrigger} from 'src/shared/utils/trigger' // api import { @@ -67,11 +63,6 @@ import {adminSaltCall, superAdminSaltCall} from 'src/clouds/apis/openstack' // constants import {getOpenStackPageLayouts} from 'src/clouds/constants/layout' import {notIncludeAppsOsp} from 'src/hosts/constants/apps' -import { - DEFAULT_CELL_BG_COLOR, - DEFAULT_CELL_TEXT_COLOR, - GRAPH_BG_COLOR, -} from 'src/dashboards/constants' import {SUPERADMIN_ROLE} from 'src/auth/Authorized' interface Props extends ManualRefreshProps { @@ -113,7 +104,6 @@ export class OpenStackPage extends PureComponent { private adminProvider = this.props.links.osp['admin-provider'] constructor(props: Props) { super(props) - this.setState = (args, callback) => { if (!this.isComponentMounted) return PureComponent.prototype.setState.bind(this)(args, callback) @@ -188,9 +178,9 @@ export class OpenStackPage extends PureComponent { GlobalAutoRefresher.poll(autoRefresh) - this.setState(state => { + this.setState(prevState => { return { - ...state, + ...prevState, layouts, filteredLayouts: focusedLayout, openStackPageStatus: RemoteDataState.Done, @@ -198,11 +188,12 @@ export class OpenStackPage extends PureComponent { } }) } catch (error) { - this.setState({ + this.setState(prevState => ({ + ...prevState, openStackPageStatus: RemoteDataState.Done, saltRemoteDataState: RemoteDataState.Done, openStackLayouts: openstackLayoutsByRole, - }) + })) } } @@ -319,7 +310,7 @@ export class OpenStackPage extends PureComponent { filteredLayouts, saltRemoteDataState, } = this.state - const {source, manualRefresh, timeRange} = this.props + const {source, manualRefresh, autoRefresh, timeRange} = this.props const updateFocusedProject = _.filter( projects, @@ -381,74 +372,16 @@ export class OpenStackPage extends PureComponent { } case 'instanceGraph': { - const layoutCells = getCells(filteredLayouts, source) - const tempVars = generateForHosts(source) - const instance = { - instancename: updateInstance?.instanceName, - instanceid: updateInstance?.instanceId, - namespace: updateInstance?.projectName, - } - const debouncedFit = _.debounce(() => { - WindowResizeEventTrigger() - }, 150) - const handleOnResize = (): void => { - debouncedFit() - } - return ( -
- - {_.isEmpty(updateInstance) ? ( -
-
-

No Instances found

-
-
- ) : ( - <> -
-
- - -
-
-
-
-
-
-
-
- - )} -
+ ) } } @@ -676,9 +609,6 @@ export class OpenStackPage extends PureComponent { const mstp = state => { const { - app: { - persisted: {autoRefresh}, - }, links, auth: {me}, } = state @@ -692,7 +622,6 @@ const mstp = state => { meCurrentOrganization, meOrganizations, links, - autoRefresh, } } diff --git a/frontend/src/clouds/types/actions/clouds.ts b/frontend/src/clouds/types/actions/clouds.ts new file mode 100644 index 00000000..282a745d --- /dev/null +++ b/frontend/src/clouds/types/actions/clouds.ts @@ -0,0 +1,22 @@ +type CloudAutoRefresh = { + autoRefreshGroup: { + [x: string]: number + } +} + +export enum CloudActionTypes { + SetCloudAutoRefresh = 'SET_CLOUD_AUTOREFRESH', +} + +export type CloudAction = SetCloudAutoRefreshAction + +export type SetCloudAutoRefreshActionCreator = ( + cloudAutoRefresh: CloudAutoRefresh +) => SetCloudAutoRefreshAction + +export interface SetCloudAutoRefreshAction { + type: CloudActionTypes.SetCloudAutoRefresh + payload: { + cloudAutoRefresh: CloudAutoRefresh + } +} diff --git a/frontend/src/clouds/types/type.ts b/frontend/src/clouds/types/type.ts index ca80cadd..e03f73d0 100644 --- a/frontend/src/clouds/types/type.ts +++ b/frontend/src/clouds/types/type.ts @@ -150,3 +150,7 @@ export interface reducerVSphere { } status: VcenterStatus } + +export type CloudAutoRefresh = { + [x: string]: number +} diff --git a/frontend/src/shared/components/dropdown_auto_refresh/AutoRefreshDropdown.tsx b/frontend/src/shared/components/dropdown_auto_refresh/AutoRefreshDropdown.tsx index 34df3c94..df842c7a 100644 --- a/frontend/src/shared/components/dropdown_auto_refresh/AutoRefreshDropdown.tsx +++ b/frontend/src/shared/components/dropdown_auto_refresh/AutoRefreshDropdown.tsx @@ -15,16 +15,23 @@ import { import {ErrorHandling} from 'src/shared/decorators/errors' +// Types +import {CloudAutoRefresh} from 'src/clouds/types/type' + interface Props { selected: number onChoose: (autoRefreshOption: AutoRefreshOption) => void showManualRefresh?: boolean onManualRefresh?: () => void userAutoRefreshOptions?: AutoRefreshOption[] + customAutoRefreshOptions?: AutoRefreshOption[] + customAutoRefreshSelected?: CloudAutoRefresh +} +interface State { + isOpen: boolean } - @ErrorHandling -class AutoRefreshDropdown extends Component { +class AutoRefreshDropdown extends Component { public static defaultProps: Partial = { showManualRefresh: true, } @@ -46,23 +53,7 @@ class AutoRefreshDropdown extends Component { onChange={this.handleDropdownChange} selectedID={this.selectedID} > - {getAutoRefreshOptions().map(option => { - if (option.type === AutoRefreshOptionType.Header) { - return ( - - ) - } - - return ( - - {option.label} - - ) - })} + {this.autoRefreshDropdownItems} {this.manualRefreshButton}
@@ -77,9 +68,15 @@ class AutoRefreshDropdown extends Component { } private get isPaused(): boolean { - const {selected} = this.props - - return selected === 0 + const { + selected, + customAutoRefreshOptions, + customAutoRefreshSelected, + } = this.props + const checkSelected = customAutoRefreshOptions + ? customAutoRefreshSelected?.[customAutoRefreshOptions[0].group] === 0 + : selected === 0 + return checkSelected } private get className(): string { @@ -103,14 +100,30 @@ class AutoRefreshDropdown extends Component { } private get selectedID(): string { - const {selected} = this.props - const autoRefreshOptions = getAutoRefreshOptions() + const { + selected, + customAutoRefreshOptions, + customAutoRefreshSelected, + } = this.props + + if (customAutoRefreshOptions) { + const autoRefreshOptions = this.getCombinedAutoRefreshOptions() + + const selectedOption = _.find( + autoRefreshOptions, + option => + option.milliseconds === + (customAutoRefreshSelected?.[option.group] || + customAutoRefreshSelected.default) + ) + return selectedOption?.id || 'auto-refresh-paused' + } + const autoRefreshOptions = getAutoRefreshOptions() const selectedOption = _.find( autoRefreshOptions, option => option.milliseconds === selected ) - return selectedOption.id } @@ -133,6 +146,32 @@ class AutoRefreshDropdown extends Component { return null } + private getCombinedAutoRefreshOptions() { + const {customAutoRefreshOptions} = this.props + + return customAutoRefreshOptions || getAutoRefreshOptions() + } + + private get autoRefreshDropdownItems(): JSX.Element[] { + const autoRefreshDropdownItems = this.getCombinedAutoRefreshOptions() + return autoRefreshDropdownItems.map(option => { + if (option.type === AutoRefreshOptionType.Header) { + return ( + + ) + } + + return ( + + {option.label} + + ) + }) + } } export default AutoRefreshDropdown diff --git a/frontend/src/shared/components/dropdown_auto_refresh/autoRefreshOptions.ts b/frontend/src/shared/components/dropdown_auto_refresh/autoRefreshOptions.ts index 6da41518..914b1aaa 100644 --- a/frontend/src/shared/components/dropdown_auto_refresh/autoRefreshOptions.ts +++ b/frontend/src/shared/components/dropdown_auto_refresh/autoRefreshOptions.ts @@ -8,6 +8,7 @@ export interface AutoRefreshOption { milliseconds: number label: string type: AutoRefreshOptionType + group?: string } export const autoRefreshOptionPaused: AutoRefreshOption = { @@ -16,14 +17,14 @@ export const autoRefreshOptionPaused: AutoRefreshOption = { label: 'Paused', type: AutoRefreshOptionType.Option, } - -const defaultAutoRefreshOptions: AutoRefreshOption[] = [ - { - id: 'auto-refresh-header', - milliseconds: 9999, - label: 'Refresh', - type: AutoRefreshOptionType.Header, - }, +export const autoRefreshHeader: AutoRefreshOption = { + id: 'auto-refresh-header', + milliseconds: 9999, + label: 'Refresh', + type: AutoRefreshOptionType.Header, +} +export const defaultAutoRefreshOptions: AutoRefreshOption[] = [ + autoRefreshHeader, autoRefreshOptionPaused, { id: 'auto-refresh-5s', diff --git a/frontend/src/shared/reducers/app.ts b/frontend/src/shared/reducers/app.ts index 7dab47cc..93ec9300 100644 --- a/frontend/src/shared/reducers/app.ts +++ b/frontend/src/shared/reducers/app.ts @@ -1,11 +1,20 @@ +// library import {combineReducers} from 'redux' +// constants import { AUTOREFRESH_DEFAULT, SHOW_TEMP_VAR_CONTROL_BAR_DEFAULT, } from 'src/shared/constants' +import {CLOUD_AUTO_REFRESH} from 'src/clouds/constants/autoRefresh' + +// actions import {ActionTypes, Action} from 'src/types/actions/app' +import {CloudAction, CloudActionTypes} from 'src/clouds/types/actions/clouds' + +// types import {TimeZones} from 'src/types' +import {CloudAutoRefresh} from 'src/clouds/types/type' interface State { ephemeral: { @@ -13,6 +22,7 @@ interface State { } persisted: { autoRefresh: number + cloudAutoRefresh: CloudAutoRefresh showTemplateVariableControlBar: boolean timeZone: TimeZones } @@ -24,6 +34,7 @@ const initialState: State = { }, persisted: { autoRefresh: AUTOREFRESH_DEFAULT, + cloudAutoRefresh: CLOUD_AUTO_REFRESH, showTemplateVariableControlBar: SHOW_TEMP_VAR_CONTROL_BAR_DEFAULT, timeZone: TimeZones.Local, }, @@ -60,7 +71,7 @@ const appEphemeralReducer = ( const appPersistedReducer = ( state = initialAppPersistedState, - action: Action + action: Action | CloudAction ) => { switch (action.type) { case ActionTypes.SetAutoRefresh: { @@ -86,6 +97,15 @@ const appPersistedReducer = ( timeZone, } } + case CloudActionTypes.SetCloudAutoRefresh: { + return { + ...state, + cloudAutoRefresh: { + ...state.cloudAutoRefresh, + ...action.payload.cloudAutoRefresh, + }, + } + } default: return state From c1a59d6760cf00b53038410f02175f47b9d43159 Mon Sep 17 00:00:00 2001 From: "jinhyeong.kim@snetsystems.co.kr" Date: Tue, 21 Mar 2023 11:18:24 +0900 Subject: [PATCH 5/5] At #394 Fix error when Redux persist store already exists in local storage --- frontend/src/clouds/containers/Clouds.tsx | 14 ++++++++------ .../AutoRefreshDropdown.tsx | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/frontend/src/clouds/containers/Clouds.tsx b/frontend/src/clouds/containers/Clouds.tsx index a699fdf0..e627688e 100644 --- a/frontend/src/clouds/containers/Clouds.tsx +++ b/frontend/src/clouds/containers/Clouds.tsx @@ -117,7 +117,7 @@ class Clouds extends PureComponent { handleClearTimeout, router, } = this.props - const {timeRange, autoRefreshOptions} = this.state + const {timeRange, autoRefreshOptions, currentRoute} = this.state return ( @@ -144,11 +144,13 @@ class Clouds extends PureComponent { customAutoRefreshOptions={autoRefreshOptions} customAutoRefreshSelected={cloudAutoRefresh} /> - + {currentRoute !== 'openstack' && ( + + )}