chrome-devtools-frontend
Version:
Chrome DevTools UI
155 lines (132 loc) • 5.08 kB
text/typescript
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Common from '../../common/common.js';
import * as Host from '../../host/host.js'; // eslint-disable-line no-unused-vars
import * as LitHtml from '../../third_party/lit-html/lit-html.js';
import type {IconData} from './Icon.js';
const ls = Common.ls;
export type CanShowSurveyCallback = (result: Host.InspectorFrontendHostAPI.CanShowSurveyResult) => void;
export type ShowSurveyCallback = (result: Host.InspectorFrontendHostAPI.ShowSurveyResult) => void;
export interface SurveyLinkData {
trigger: string;
promptText: Common.UIString.LocalizedString;
canShowSurvey: (trigger: string, callback: CanShowSurveyCallback) => void;
showSurvey: (trigger: string, callback: ShowSurveyCallback) => void;
}
const enum State {
Checking = 'Checking', // (begin state) -> ShowLink | DontShowLink
ShowLink = 'ShowLink', // -> Sending
Sending = 'Sending', // -> SurveyShown | Failed
SurveyShown = 'SurveyShown',
Failed = 'Failed',
DontShowLink = 'DontShowLink',
}
// A link to a survey. The link is rendered aysnchronously because we need to first check if
// canShowSurvey succeeds.
export class SurveyLink extends HTMLElement {
private readonly shadow = this.attachShadow({mode: 'open'});
private trigger = '';
private promptText = Common.UIString.LocalizedEmptyString;
private canShowSurvey: (trigger: string, callback: CanShowSurveyCallback) => void = () => {};
private showSurvey: (trigger: string, callback: ShowSurveyCallback) => void = () => {};
private state: State = State.Checking;
// Re-setting data will cause the state to go back to 'Checking' which hides the link.
set data(data: SurveyLinkData) {
this.trigger = data.trigger;
this.promptText = data.promptText;
this.canShowSurvey = data.canShowSurvey;
this.showSurvey = data.showSurvey;
this.checkSurvey();
}
private checkSurvey(): void {
this.state = State.Checking;
this.canShowSurvey(this.trigger, ({canShowSurvey}) => {
if (!canShowSurvey) {
this.state = State.DontShowLink;
} else {
this.state = State.ShowLink;
}
this.render();
});
}
private sendSurvey(): void {
this.state = State.Sending;
this.render();
this.showSurvey(this.trigger, ({surveyShown}) => {
if (!surveyShown) {
this.state = State.Failed;
} else {
this.state = State.SurveyShown;
}
this.render();
});
}
private render(): void {
if (this.state === State.Checking || this.state === State.DontShowLink) {
return;
}
let linkText = this.promptText;
if (this.state === State.Sending) {
linkText = ls`Opening survey …`;
} else if (this.state === State.SurveyShown) {
linkText = ls`Thank you for your feedback`;
} else if (this.state === State.Failed) {
linkText = ls`An error occurred with the survey`;
}
let linkState = '';
if (this.state === State.Sending) {
linkState = 'pending-link';
} else if (this.state === State.Failed || this.state === State.SurveyShown) {
linkState = 'disabled-link';
}
const ariaDisabled = this.state !== State.ShowLink;
// clang-format off
const output = LitHtml.html`
<style>
.link-icon {
vertical-align: sub;
margin-right: 0.5ch;
}
.link {
padding: var(--issue-link-padding, 4px 0 0 0);
text-decoration: var(--issue-link-text-decoration, underline);
cursor: pointer;
font-size: var(--issue-link-font-size, 14px);
color: var(--issue-link); /* stylelint-disable-line plugin/use_theme_colors */
/* See: crbug.com/1152736 for color variable migration. */
border: none;
background: none;
font-family: inherit;
}
.link:focus:not(:focus-visible) {
outline: none;
}
.pending-link {
opacity: 75%;
pointer-events: none;
cursor: default;
text-decoration: none;
}
.disabled-link {
pointer-events: none;
cursor: default;
text-decoration: none;
}
</style>
<button class="link ${linkState}" tabindex=${ariaDisabled ? '-1' : '0'} aria-disabled=${ariaDisabled} @click=${this.sendSurvey}>
<devtools-icon class="link-icon" .data=${{iconName: 'feedback_thin_16x16_icon', color: 'var(--issue-link)', width: 'var(--issue-link-icon-size, 16px)', height: 'var(--issue-link-icon-size, 16px)'} as IconData}></devtools-icon><!--
-->${linkText}
</button>
`;
// clang-format on
LitHtml.render(output, this.shadow, {eventContext: this});
}
}
customElements.define('devtools-survey-link', SurveyLink);
declare global {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface HTMLElementTagNameMap {
'devtools-survey-link': SurveyLink;
}
}