Skip to content
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

AD-169 - preserve configured labels on Jira page #286

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ You can set your user's settings by clicking in (your user name) -> Settings.

Available options:
- set default team
- set labels for Jira plugin

### Teams
All data is organized by Teams: a team groups a set of repositories to show data more concisely and acts as a global filter.
Expand Down
2 changes: 1 addition & 1 deletion backend/api/server/router/jira/jira.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (s *jiraRouter) listBugsAffectingCI(ctx context.Context, w http.ResponseWri

team, err := s.Storage.GetTeamByName(teamName[0])
if err != nil {
s.Logger.Error("Failed to fetch bugs")
s.Logger.Error("Failed to fetch team")

return httputils.WriteJSON(w, http.StatusInternalServerError, &types.ErrorResponse{
Message: err.Error(),
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/Github/Github.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ let GitHub = () => {
<Spinner isSVG diameter="80px" aria-label="Contents of the custom size example" style={{ margin: "100px auto" }} />
</div>
}
{!loadingState &&
{!isInvalid && !loadingState &&
(
<GridItem>
<Card>
Expand Down
155 changes: 100 additions & 55 deletions frontend/src/app/Jira/Jira.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import {
ToggleGroup,
ToggleGroupItem,
Spinner,
FormGroup,
Form,
TextInput,
ButtonVariant,
Button,
Modal,
FormGroup,
Popover,
TextInput,
Form,
} from '@patternfly/react-core';
import {
TableComposable,
Expand All @@ -28,7 +29,7 @@ import {
ThProps
} from '@patternfly/react-table';
import { Chart, ChartAxis, ChartGroup, ChartLine, createContainer, ChartThemeColor } from '@patternfly/react-charts';
import { getJirasResolutionTime, getJirasOpen, listBugsAffectingCI } from '@app/utils/APIService';
import { getJirasResolutionTime, getJirasOpen, listBugsAffectingCI, createUser } from '@app/utils/APIService';
import { ReactReduxContext, useSelector } from 'react-redux';
import { formatDate, getRangeDates } from '@app/Reports/utils';
import { DateTimeRangePicker } from '@app/utils/DateTimeRangePicker';
Expand All @@ -39,7 +40,8 @@ import { CustomStackChart } from './CustomStackChart';
import { ListIssues } from './ListIssuesTable';
import { getIssuesByFields, getIssuesByLabels, getLegend } from './utils';
import { getLabels } from '@app/utils/utils';
import { HelpIcon } from '@patternfly/react-icons';
import { UserConfig } from '@app/Teams/User';
import { CogIcon, HelpIcon, PlusIcon } from '@patternfly/react-icons';

interface Bugs {
jira_key: string;
Expand Down Expand Up @@ -71,10 +73,21 @@ export const Jira = () => {
const [rangeDateTime, setRangeDateTime] = useState(getRangeDates(30));
const priorities = ["Global", "Major", "Critical", "Blocker", "Normal", "Undefined", "Minor"]
const [loadingState, setLoadingState] = useState(false);
const [labels, setLabels] = useState<string[]>(defaultLabels);
const [labels, setLabels] = useState<string[]>([]);
const [openIssuesTable, setOpenIssuesTable] = useState<any>({});
const [closedIssuesTable, setClosedIssuesTable] = useState<any>({});


useEffect(() => {
if (state.auth.USER_CONFIG != "" && state.auth.USER_CONFIG != undefined) {
let userConfig = JSON.parse(state.auth.USER_CONFIG) as UserConfig;
const userConfigJiraLabels = userConfig.jira_config.labels
if (userConfigJiraLabels != "") {
setLabelsValue(userConfigJiraLabels)
}
}
}, []);

const getJiraData = (ID) => {
setLoadingState(true)
const newData = {}
Expand Down Expand Up @@ -107,7 +120,9 @@ export const Jira = () => {
}

useEffect(() => {
if (currentTeam != "" && currentTeam != undefined) {
const team = params.get('team');

if (team == currentTeam || team == null) {
listBugsAffectingCI(currentTeam).then(res => {
setBugsKnown(res.data)
})
Expand All @@ -122,16 +137,28 @@ export const Jira = () => {
const labelParam = params.get("label_selected")

if (start == null || end == null || labelsParam == null || labelParam == null) {
setIsLabelSelected(labels[0])
let lbs = defaultLabels

if (state.auth.USER_CONFIG != "" && state.auth.USER_CONFIG != undefined) {
var userConfig = JSON.parse(state.auth.USER_CONFIG) as UserConfig;
if (userConfig.jira_config.labels != "") {
setLabels(userConfig.jira_config.labels.split(","))
lbs = userConfig.jira_config.labels.split(",")
}
}

setLabels(lbs)
setIsLabelSelected(lbs[0])

history.push(
'/home/jira?team=' + currentTeam +
'&selected=' + ID +
'&start=' + formatDate(rangeDateTime[0]) +
'&end=' + formatDate(rangeDateTime[1]) +
'&labels=' + labels +
'&label_selected=' + labels[0]
'&labels=' + lbs.toString() +
'&label_selected=' + lbs[0]
)

} else {
setRangeDateTime([new Date(start), new Date(end)])
const lbls = labelsParam.split(",")
Expand All @@ -143,7 +170,7 @@ export const Jira = () => {
'&selected=' + ID +
'&start=' + start +
'&end=' + end +
'&labels=' + labels +
'&labels=' + labelsParam +
'&label_selected=' + labelParam
)
}
Expand All @@ -164,12 +191,6 @@ export const Jira = () => {
const [isSelected, setIsSelected] = React.useState('open');
const [isLabelSelected, setIsLabelSelected] = React.useState('');

const handleItemClick = (isSelected: boolean, event: React.MouseEvent<any> | React.KeyboardEvent | MouseEvent) => {
const id = event.currentTarget.id;
setBugsTable([])
setIsSelected(id);
};

useEffect(() => {
const selected = params.get("selected")
const target = selected != null ? selected : "Global"
Expand Down Expand Up @@ -303,9 +324,9 @@ export const Jira = () => {
};

const [isModalOpen, setIsModalOpen] = React.useState(false);
const [labelsValue, setLabelsValue] = React.useState("");
const [labelsValue, setLabelsValue] = React.useState(defaultLabels.join(","));
type validate = 'success' | 'warning' | 'error' | 'default';
const [labelsValidated, setLabelsValidated] = React.useState<validate>('error');
const [labelsValidated, setLabelsValidated] = React.useState<validate>();
const regexp = new RegExp('^[a-zA-Z_-]+(,[0-9a-zA-Z_-]+)*$')


Expand All @@ -314,6 +335,7 @@ export const Jira = () => {
};

const handleLabelsInput = async (value) => {
console.log("value")
setLabelsValidated('error');
setLabelsValue(value);
if (regexp.test(value)) {
Expand All @@ -329,9 +351,26 @@ export const Jira = () => {
setLabels(ls)
setIsLabelSelected(ls[0])

if (state.auth.USER_CONFIG != "" && state.auth.USER_CONFIG != undefined) {
// get user config
let userConfig = JSON.parse(state.auth.USER_CONFIG) as UserConfig;
userConfig.jira_config.labels = labelsValue

// get user email
const userClaims = JSON.parse(window.atob(state.auth.IDT.split('.')[1]))

// update user config
const config = JSON.stringify(userConfig)
createUser(userClaims.email, config)
const redux_dispatch = store.dispatch;
redux_dispatch({ type: "SET_USER_CONFIG", data: config });
}

// update params and reload page
params.set("labels", labelsValue)
params.set("label_selected", ls[0])
history.push(window.location.pathname + '?' + params.toString());
window.location.reload();
};

return (
Expand All @@ -345,12 +384,21 @@ export const Jira = () => {
{!loadingState && <React.Fragment>
<Grid hasGutter>
<GridItem>
<DateTimeRangePicker
startDate={rangeDateTime[0]}
endDate={rangeDateTime[1]}
handleChange={(event, from, to) => handleChange(event, from, to)}
>
</DateTimeRangePicker>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<DateTimeRangePicker
startDate={rangeDateTime[0]}
endDate={rangeDateTime[1]}
handleChange={(event, from, to) => handleChange(event, from, to)}
>
</DateTimeRangePicker>
<Button
style={{ float: 'right' }}
variant={ButtonVariant.secondary}
onClick={handleModalToggle}
>
<CogIcon /> &nbsp; Labels Configuration
</Button>
</div>
</GridItem>
<GridItem>
<Grid hasGutter span={3}>
Expand Down Expand Up @@ -493,9 +541,6 @@ export const Jira = () => {
</GridItem>
</Grid>
</GridItem>}
<Button variant="primary" onClick={handleModalToggle}>
Configure labels
</Button>
<Modal
width={800}
title="Configure your own tables"
Expand Down Expand Up @@ -557,13 +602,13 @@ export const Jira = () => {
</GridItem>
}
{(openIssuesTable.length > 0) && getIssuesByFields(openIssuesTable, labels, "component")?.filter((x) => {
let exists = false
x.filter((x) => {
let exists = false
x.filter((x) => {
if (x.y != 0) {
exists = true
}
})
return exists
return exists
}).length > 0 &&
<GridItem span={4} rows={12}>
<Card style={{ textAlign: 'center', alignContent: 'center' }}>
Expand All @@ -574,7 +619,7 @@ export const Jira = () => {
</CardBody>
</GridItem>
}

{(openIssuesTable.length > 0) && getIssuesByFields(openIssuesTable, labels, "status").filter((x) => {
let exists = false
x.filter((x) => {
Expand All @@ -583,7 +628,7 @@ export const Jira = () => {
}
})
return exists
}).length > 0 &&
}).length > 0 &&
<GridItem span={4} rows={12}>
<Card style={{ textAlign: 'center', alignContent: 'center' }}>
<CardTitle style={{ backgroundColor: "grey", color: 'white' }}>Open Issues by Labels and Status</CardTitle>
Expand Down Expand Up @@ -624,28 +669,28 @@ export const Jira = () => {
</GridItem>
}
<Card>
<CardTitle style={{ backgroundColor: "grey", color: 'white' }}>
List of open issues
</CardTitle>
<CardBody style={{ backgroundColor: 'white' }}>
<div style={{ marginTop: 10 }}>
<ToggleGroup aria-label="Default with single selectable">
{labels?.map((label, idx) => {
return (
<ToggleGroupItem
key={idx}
text={label}
buttonId={label}
isSelected={isLabelSelected === label}
onChange={handleLabelClick}
/>
)
})}
</ToggleGroup>
</div>
<ListIssues issues={openIssuesTable}></ListIssues>
</CardBody>
</Card>
<CardTitle style={{ backgroundColor: "grey", color: 'white' }}>
List of open issues
</CardTitle>
<CardBody style={{ backgroundColor: 'white' }}>
<div style={{ marginTop: 10 }}>
<ToggleGroup aria-label="Default with single selectable">
{labels?.map((label, idx) => {
return (
<ToggleGroupItem
key={idx}
text={label}
buttonId={label}
isSelected={isLabelSelected === label}
onChange={handleLabelClick}
/>
)
})}
</ToggleGroup>
</div>
<ListIssues issues={openIssuesTable}></ListIssues>
</CardBody>
</Card>
{(closedIssuesTable.length > 0) &&
<Card>
<CardTitle style={{ backgroundColor: "grey", color: 'white' }}>
Expand Down
13 changes: 10 additions & 3 deletions frontend/src/app/Login/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { ReactReduxContext } from 'react-redux';
import { initOauthFlow, completeOauthFlow, OauthData } from '@app/utils/oauth'
import { JwtPayload, jwtDecode } from "jwt-decode";
import { createUser, getUser } from '@app/utils/APIService';
import { GetUserConfig } from '@app/Teams/User';
import { defaultLabels } from '@app/Jira/Jira';
let authorizationUrl: URL
async function callLogin() {
document.location.href = authorizationUrl.toString()
Expand Down Expand Up @@ -67,12 +69,17 @@ let Login = () => {
const sessionInfo = jwtDecode<JwtPayload & { name: string, email: string }>(data.IDT);
const user = await getUser(sessionInfo.email)

if (user.data == null) {
await createUser(sessionInfo.email, "")
if (user.data == null) { // user does not exist yet
// get user config
const config = GetUserConfig("n/a", defaultLabels.join(","))

// update user config
await createUser(sessionInfo.email, config)
redux_dispatch({ type: "SET_USER_CONFIG", data: config });
} else {
redux_dispatch({ type: "SET_USER_CONFIG", data: user.data.config });
}

setTimeout(function () {
setCallbackError("")
const API_URL = process.env.REACT_APP_API_SERVER_URL || 'http://localhost:9898'
Expand Down
1 change: 0 additions & 1 deletion frontend/src/app/Reports/Reports.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ let Reports = () => {

// Called onChange of the repository dropdown element. This set repository name and organization state variables, or clears them when placeholder is selected
const setRepoNameOnChange = (event, selection, isPlaceholder) => {
console.log(selection, repositories[selection])
if (isPlaceholder) {
clearRepo()
}
Expand Down
Loading