blob: 54458f5d5bc704438682e2de7630adecc2c60b25 [file] [log] [blame]
import { LitElement, TemplateResult, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { LoggedIn } from '../../../infra-sk/modules/alogin-sk/alogin-sk';
import { AnomalySk } from '../anomaly-sk/anomaly-sk';
import { errorMessage } from '../errorMessage';
import { Status as LoginStatus } from '../../../infra-sk/modules/json';
import '../../../elements-sk/modules/icons/close-icon-sk';
import '../../../elements-sk/modules/icons/check-icon-sk';
@customElement('user-issue-sk')
export class UserIssueSk extends LitElement {
static styles = css`
.showLinkContainer {
display: flex;
align-items: center;
.label {
text-decoration: underline;
}
.linkContainer {
color: var(--primary);
font-size: 14px;
display: flex;
align-items: center;
a {
color: var(--primary);
margin: 0 8px;
}
close-icon-sk {
fill: var(--negative);
cursor: pointer;
height: 24px;
width: 24px;
}
}
}
.new-issue-label {
background: none;
background: none !important;
border: none;
padding: 0 !important;
color: var(--primary);
text-decoration: underline;
cursor: pointer;
font-size: 14px;
}
.new-issue-text-container {
display: flex;
align-items: center;
input {
color: var(--on-surface);
background: var(--surface);
border: solid 1px var(--on-surface);
}
span {
margin-left: 12px;
check-icon-sk {
fill: var(--positive);
cursor: pointer;
height: 24px;
width: 24px;
}
close-icon-sk {
fill: var(--negative);
cursor: pointer;
height: 24px;
width: 24px;
}
}
}
`;
// Email of the logged in user. Empty string otherwise
_user_id: string = '';
// Used for capturing number input values
_input_val: number = 0;
// Indicates if the text input is active typically when adding a new issue.
@property({ attribute: false })
_text_input_active: boolean = false;
// bug_id = 0 signifies no buganizer issue available in the database for the
// data point. bug_id > 0 means we have an existing buganizer issue.
@property({ attribute: true })
bug_id: number = 0;
// The trace_key of the selected data point. Format: ,a=1,b=2,c=3,
@property({ attribute: true })
trace_key: string = '';
// Commit position of the data point
@property({ attribute: true })
commit_position: number = 0;
connectedCallback() {
super.connectedCallback();
LoggedIn().then((status: LoginStatus) => {
this._user_id = status.email;
});
}
render() {
if (this.bug_id === -1) {
return html``;
}
return html`
<div style="margin-bottom: 12px;">
${this.bug_id === 0 ? this.addIssueTemplate() : this.showLinkTemplate()}
</div>
`;
}
/* Template manipulation functions */
private activateTextInput() {
this._text_input_active = true;
this.render();
}
private changeHandler(e: InputEvent) {
this._input_val = +(e.target! as HTMLInputElement).value;
}
hideTextInput() {
this._input_val = 0;
this._text_input_active = false;
this.render();
}
/* Templates */
// Template for showing option to add an issue on the datapoint
// Only shown when the user is logged in
addIssueTemplate(): TemplateResult {
if (this._user_id === '') {
return html``;
}
if (this._text_input_active) {
return html`
<div class="new-issue-text-container">
<input placeholder="eg: 91345" type="number" min="0" @input=${this.changeHandler} />
<span>
<check-icon-sk
@click=${() => {
this.addIssue();
}}></check-icon-sk>
<close-icon-sk @click=${this.hideTextInput}></close-icon-sk>
</span>
</div>
`;
}
return html`
<button class="new-issue-label" @click=${this.activateTextInput}>
Start a user thread (buganizer issue)
</button>
`;
}
// If a bug is already associated with the data point show them the link.
// The delete action for this bug will only be shown if the user is logged in.
showLinkTemplate(): TemplateResult {
if (this._user_id === '') {
return html`
<div class="showLinkContainer">
<span class="label"> User Thread: </span>
<span class="linkContainer">
${AnomalySk.formatBug(window.perf.bug_host_url, this.bug_id)}
</span>
</div>
`;
}
return html`
<div class="showLinkContainer">
<span class="label"> User Thread: </span>
<span class="linkContainer">
${AnomalySk.formatBug(window.perf.bug_host_url, this.bug_id)}
<close-icon-sk @click=${this.removeIssue} ?hidden=${this.bug_id === 0}> </close-icon-sk>
</span>
</div>
`;
}
/* API CALLS */
// Makes an api call to save a buganizer issue
// Also emits an event to refresh the existing list of user issues
// with the newly added object.
private async addIssue() {
const traceKey = this.trace_key;
const commitPosition = this.commit_position;
if (this._input_val === 0) {
errorMessage(`Input a valid bug id. For example, 34243`);
return;
}
const req = {
trace_key: traceKey,
commit_position: commitPosition,
issue_id: this._input_val,
};
const resp = await fetch('/_/user_issue/save', {
method: 'POST',
body: JSON.stringify(req),
headers: {
'Content-Type': 'application/json',
},
});
if (!resp.ok) {
this.hideTextInput();
const msg = await resp.text();
errorMessage(`${resp.statusText}: ${msg}`);
return;
}
this.bug_id = this._input_val;
this._input_val = 0;
this._text_input_active = false;
this.dispatchEvent(
new CustomEvent('user-issue-changed', {
detail: {
trace_key: this.trace_key,
commit_position: this.commit_position,
bug_id: this.bug_id,
},
bubbles: true,
})
);
this.render();
}
// Makes an api call to delete a buganizer issue
// Also emits an event to refresh the existing list of user issues
// with the newly deleted object.
private async removeIssue() {
const traceKey = this.trace_key;
const commitPosition = this.commit_position;
const req = {
trace_key: traceKey,
commit_position: commitPosition,
};
const resp = await fetch('/_/user_issue/delete', {
method: 'POST',
body: JSON.stringify(req),
headers: {
'Content-Type': 'application/json',
},
});
if (!resp.ok) {
const msg = await resp.text();
errorMessage(`${resp.statusText}: ${msg}`);
return;
}
// Since the bug is deleted now, we set the bug_id to 0 for showing the
// Add buganizer issue template
this.bug_id = 0;
this._input_val = 0;
this._text_input_active = false;
this.dispatchEvent(
new CustomEvent('user-issue-changed', {
detail: {
trace_key: this.trace_key,
commit_position: this.commit_position,
bug_id: this.bug_id,
},
bubbles: true,
})
);
this.render();
}
}