Skip to content

Commit 3c6836f

Browse files
committed
Fixed ibutsu-header and dashboard context loading
context is now synced from params, and params are accounted for in componentDidMount scope functions. Page refreshes now set both the project and dashboard selection from URL params!
1 parent 8710a1c commit 3c6836f

File tree

3 files changed

+102
-77
lines changed

3 files changed

+102
-77
lines changed

frontend/src/components/ibutsu-header.js

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,44 @@ export class IbutsuHeader extends React.Component {
8383
};
8484
}
8585

86+
sync_context = () => {
87+
// TODO handle portal_id
88+
// Primary object
89+
const { primaryObject, setPrimaryObject, setPrimaryType } = this.context;
90+
const { selectedProject } = this.state;
91+
const paramProject = this.props.params?.project_id;
92+
let updatedPrimary = undefined;
93+
94+
// API fetch and set the context
95+
if (paramProject && primaryObject?.id !== paramProject) {
96+
HttpClient.get([Settings.serverUrl, 'project', paramProject])
97+
.then(response => HttpClient.handleResponse(response))
98+
.then(data => {
99+
updatedPrimary = data;
100+
setPrimaryObject(data)
101+
setPrimaryType('project')
102+
// update state
103+
this.setState({
104+
selectedProject: data,
105+
isProjectSelectorOpen: false,
106+
inputValue: data?.title,
107+
filterValue: ''
108+
});
109+
});
110+
}
111+
112+
// update selector state
113+
if (updatedPrimary && !selectedProject) {
114+
this.setState({
115+
selectedProject: updatedPrimary,
116+
inputValue: updatedPrimary.title
117+
})
118+
}
119+
120+
if ( updatedPrimary ) {
121+
this.emitProjectChange(updatedPrimary);
122+
}
123+
}
86124

87125
showNotification(type, title, message, action = null, timeout = null, key = null) {
88126
if (!this.eventEmitter) {
@@ -132,45 +170,22 @@ export class IbutsuHeader extends React.Component {
132170
}
133171

134172
getSelectorOptions = (endpoint = "project") => {
173+
// adding s here seems dumb, but this scope is small, it's only abstracted for 2 things
174+
const pluralEndpoint = endpoint+'s';
135175
const params = {pageSize: 10};
136176
if (this.state.filterValue) {
137177
params['filter'] = ['title%' + this.state.filterValue];
138178
}
139-
140-
const {setPrimaryObject} = this.context;
141-
142-
// adding s here seems dumb, but this scope is small, it's only abstracted for 2 things
143179
HttpClient.get([Settings.serverUrl, endpoint], params)
144180
.then(response => HttpClient.handleResponse(response))
145181
.then(data => {
146-
// populate context and current input value if passed
147-
for ( let item of data[endpoint+'s'] ) {
148-
if (item.id === this.props.params?.project_id) {
149-
this.setState({
150-
inputValue: item.title,
151-
filterValue: ''
152-
});
153-
setPrimaryObject(item);
154-
}
182+
this.setState(
183+
{
184+
projects: data[pluralEndpoint],
185+
filteredProjects: data[pluralEndpoint],
186+
})
155187
}
156-
this.setState(
157-
{
158-
projects: data[endpoint+'s'],
159-
filteredProjects: data[endpoint+'s'],
160-
161-
})
162-
}
163188
);
164-
165-
166-
}
167-
168-
findPrimary = (endpoint, name) => {
169-
HttpClient.get([Settings.serverUrl, endpoint], {'name': name})
170-
.then(response => HttpClient.handleResponse(response))
171-
.then(data => {return( data[endpoint+'s'] )}
172-
)
173-
174189
}
175190

176191
onBeforeUpload = (files) => {
@@ -290,10 +305,9 @@ export class IbutsuHeader extends React.Component {
290305

291306
componentDidMount() {
292307
this.getSelectorOptions("project");
308+
this.sync_context();
293309
this.checkVersion();
294310
this.versionCheckId = setInterval(() => this.checkVersion(), VERSION_CHECK_TIMEOUT);
295-
296-
297311
}
298312

299313
componentDidUpdate(prevProps, prevState) {
@@ -350,8 +364,6 @@ export class IbutsuHeader extends React.Component {
350364
</MenuToggle>
351365
);
352366

353-
354-
355367
render() {
356368
document.title = 'Ibutsu';
357369
const apiUiUrl = Settings.serverUrl + '/ui/';

frontend/src/components/ibutsu-page.js

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,9 @@ import {
1515
import ElementWrapper from './elementWrapper';
1616
import { IbutsuHeader } from '../components';
1717
import { ALERT_TIMEOUT } from '../constants';
18-
import { HttpClient } from '../services/http';
1918
import { getDateString, getTheme } from '../utilities';
2019
import { IbutsuContext } from '../services/context';
2120
import IbutsuSidebar from './sidebar';
22-
import { Settings } from '../settings';
2321

2422

2523
export class IbutsuPage extends React.Component {
@@ -90,43 +88,13 @@ export class IbutsuPage extends React.Component {
9088
}
9189
}
9290

93-
sync_context() {
94-
// TODO handle portal_id
95-
// Primary object
96-
const { primaryObject, setPrimaryType, setPrimaryObject } = this.context;
97-
let param_project = this.props.params?.project_id;
98-
99-
if (param_project && primaryObject?.id !== param_project) {
100-
HttpClient.get([Settings.serverUrl, 'project', param_project])
101-
.then(response => HttpClient.handleResponse(response))
102-
.then(data => {
103-
setPrimaryObject(data);
104-
setPrimaryType('project')
105-
});
106-
107-
}
108-
109-
// Active dashboard
110-
const { activeDashboard, setActiveDashboard } = this.context;
111-
let param_dash = this.props.params?.dashboard_id;
112-
if ( param_dash && activeDashboard?.id !== param_dash) {
113-
HttpClient.get([Settings.serverUrl, 'dashboard', param_dash])
114-
.then(response => HttpClient.handleResponse(response))
115-
.then(data => {
116-
setActiveDashboard(data);
117-
});
118-
119-
}
120-
}
121-
12291
componentDidMount() {
12392
this.setTheme();
12493
}
12594

12695
render() {
12796
document.title = this.props.title || 'Ibutsu';
12897
// TODO: render project or portal depending on menutoggle + select event
129-
this.sync_context();
13098
return (
13199
<React.Fragment>
132100
<AlertGroup isToast>

frontend/src/dashboard.js

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,57 @@ export class Dashboard extends React.Component {
7474
};
7575
props.eventEmitter.on('projectChange', (value) => {
7676
this.getDashboards(value);
77-
this.checkDefaultDashboard(value);
77+
this.getDefaultDashboard(value);
7878
});
7979
}
8080

81+
sync_context = () => {
82+
// Active dashboard
83+
const { activeDashboard } = this.context;
84+
const { selectedDashboard } = this.state;
85+
const paramDash = this.props.params?.dashboard_id;
86+
let updatedDash = undefined;
87+
// API call to update context
88+
if ( paramDash && activeDashboard?.id !== paramDash) {
89+
HttpClient.get([Settings.serverUrl, 'dashboard', paramDash])
90+
.then(response => HttpClient.handleResponse(response))
91+
.then(data => {
92+
const { setActiveDashboard } = this.context;
93+
setActiveDashboard(data);
94+
updatedDash = data;
95+
this.setState({
96+
selectedDashboard: data,
97+
isDashboardSelectorOpen: false,
98+
filterValueDashboard: '',
99+
dashboardInputValue: data.title,
100+
}); // callback within class component won't have updated context
101+
// TODO don't pass value when converting to functional component
102+
this.getWidgets(data);
103+
});
104+
}
105+
106+
if (updatedDash && !selectedDashboard ) {
107+
this.setState({
108+
selectedDashboard: updatedDash,
109+
dashboardInputValue: updatedDash.title
110+
})
111+
}
112+
}
113+
81114
getDashboards = (handledOject = null) => {
82115
// value is checked because of handler scope not seeing context state updates
116+
// TODO: react-router loaders would be way better
83117
const { primaryObject } = this.context;
84-
const targetObject = handledOject ?? primaryObject;
85-
console.log("getting dashboards");
86-
if (!targetObject) {
118+
const paramProject = this.props.params?.project_id;
119+
const primaryObjectId = handledOject?.id ?? primaryObject?.id ?? paramProject;
120+
121+
if (!primaryObjectId) {
87122
this.setState({dashboardInputValue: ''})
88123
return;
89124
}
90125
// TODO: set based on primaryType
91126
let params = {
92-
'project_id': targetObject.id,
127+
'project_id': primaryObjectId,
93128
'pageSize': 10
94129
};
95130

@@ -99,14 +134,24 @@ export class Dashboard extends React.Component {
99134
HttpClient.get([Settings.serverUrl, 'dashboard'], params)
100135
.then(response => HttpClient.handleResponse(response))
101136
.then(data => {
102-
this.setState({dashboards: data['dashboards'], filteredDashboards: data['dashboards']}, this.getWidgets);
137+
this.setState({dashboards: data['dashboards'], filteredDashboards: data['dashboards']});
103138
});
104139
}
105140

106-
checkDefaultDashboard = (handledObject = null) => {
141+
getDefaultDashboard = (handledObject = null) => {
107142
const { primaryObject, activeDashboard, setActiveDashboard } = this.context;
108-
const targetObject = handledObject ?? primaryObject;
109-
console.log("checking default dash");
143+
const paramProject = this.props.params?.project_id;
144+
145+
let targetObject = handledObject ?? primaryObject ?? paramProject;
146+
147+
if (typeof(targetObject) === 'string') {
148+
HttpClient.get([Settings.serverUrl, 'project', paramProject])
149+
.then(response => HttpClient.handleResponse(response))
150+
.then(data => {
151+
targetObject = data;
152+
});
153+
154+
}
110155

111156
if ( !activeDashboard && targetObject?.defaultDashboard ){
112157
setActiveDashboard(targetObject.defaultDashboard);
@@ -125,7 +170,6 @@ export class Dashboard extends React.Component {
125170
getWidgets = (dashboard) => {
126171
let params = {'type': 'widget'};
127172
const { activeDashboard } = this.context;
128-
console.log('getting widgets');
129173
// TODO don't pass value when converting to functional component
130174
let target_dash = null;
131175
if (dashboard === undefined) {
@@ -305,8 +349,9 @@ export class Dashboard extends React.Component {
305349
}
306350

307351
componentDidMount() {
352+
this.sync_context();
308353
this.getDashboards();
309-
this.checkDefaultDashboard();
354+
this.getDefaultDashboard();
310355
this.getWidgets();
311356
}
312357

0 commit comments

Comments
 (0)