Fix browser profile origins sidebar overlap (#530)

This commit is contained in:
sua yoo 2023-01-31 13:44:17 -08:00 committed by GitHub
parent 7d25565ef4
commit f94be79364
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 205 additions and 186 deletions

View File

@ -1,12 +1,12 @@
// import { LitElement, html } from "lit";
import { property, state } from "lit/decorators.js";
import { ref } from "lit/directives/ref.js";
import { property, state, query } from "lit/decorators.js";
import { msg, localized, str } from "@lit/localize";
import type { AuthState } from "../utils/AuthService";
import LiteElement, { html } from "../utils/LiteElement";
const POLL_INTERVAL_SECONDS = 2;
const hiddenClassList = ["translate-x-2/3", "opacity-0", "pointer-events-none"];
/**
* View embedded profile browser
@ -26,10 +26,6 @@ const POLL_INTERVAL_SECONDS = 2;
*/
@localized()
export class ProfileBrowser extends LiteElement {
// TODO remove sidebar constaint once devtools panel
// is hidden on the backend
static SIDE_BAR_WIDTH = 288;
@property({ type: Object })
authState!: AuthState;
@ -57,9 +53,21 @@ export class ProfileBrowser extends LiteElement {
@state()
private isFullscreen = false;
@state()
private showOriginSidebar = false;
@state()
private newOrigins: string[] = [];
@query("#profileBrowserSidebar")
private sidebar?: HTMLElement;
@query("#iframeWrapper")
private iframeWrapper?: HTMLElement;
@query("iframe")
private iframe?: HTMLIFrameElement;
private pollTimerId?: number;
connectedCallback() {
@ -73,7 +81,7 @@ export class ProfileBrowser extends LiteElement {
document.removeEventListener("fullscreenchange", this.onFullscreenChange);
}
updated(changedProperties: Map<string, any>) {
willUpdate(changedProperties: Map<string, any>) {
if (changedProperties.has("browserId")) {
if (this.browserId) {
window.clearTimeout(this.pollTimerId);
@ -85,40 +93,84 @@ export class ProfileBrowser extends LiteElement {
window.clearTimeout(this.pollTimerId);
}
}
if (
changedProperties.has("showOriginSidebar") &&
changedProperties.get("showOriginSidebar") !== undefined
) {
this.animateSidebar();
}
}
private animateSidebar() {
if (!this.sidebar) return;
if (this.showOriginSidebar) {
this.sidebar.classList.remove(...hiddenClassList);
} else {
this.sidebar.classList.add(...hiddenClassList);
}
}
render() {
return html`
<div id="interactive-browser" class="lg:flex relative">
<div class="grow lg:rounded-lg border overflow-hidden bg-slate-50">
<div id="interactive-browser" class="w-full h-full flex flex-col">
${this.renderControlBar()}
<div
id="iframeWrapper"
class="${this.isFullscreen
? "w-screen h-screen"
: "border-t"} flex-1 relative bg-neutral-50 overflow-hidden"
aria-live="polite"
>
${this.renderBrowser()}
<div
class="w-full ${this.isFullscreen ? "h-screen" : "h-96"}"
aria-live="polite"
id="profileBrowserSidebar"
class="${hiddenClassList.join(
" "
)} lg:absolute top-0 right-0 bottom-0 lg:w-80 lg:p-3 flex transition-all duration-300 ease-out"
>
${this.renderBrowser()}
</div>
<div
class="rounded-b lg:rounded-b-none lg:rounded-r border w-72 bg-white absolute h-full top-0 right-0"
>
${document.fullscreenEnabled ? this.renderFullscreenButton() : ""}
${this.renderOrigins()} ${this.renderNewOrigins()}
<div
class="shadow-lg overflow-auto border rounded-lg bg-white flex-1"
>
${this.renderOrigins()} ${this.renderNewOrigins()}
</div>
</div>
</div>
</div>
`;
}
private renderControlBar() {
if (this.isFullscreen) {
return html`
<div
class="fixed top-2 left-1/2 bg-white rounded-lg shadow z-50 -translate-x-1/2 flex items-center text-base"
>
${this.renderSidebarButton()}
<sl-icon-button
name="fullscreen-exit"
@click=${() => document.exitFullscreen()}
></sl-icon-button>
</div>
`;
}
return html`
<div class="text-right text-base p-1">
${this.renderSidebarButton()}
<sl-icon-button
name="arrows-fullscreen"
@click=${() => this.enterFullscreen("interactive-browser")}
></sl-icon-button>
</div>
`;
}
private renderBrowser() {
if (this.hasFetchError) {
return html`
<div style="padding-right: ${ProfileBrowser.SIDE_BAR_WIDTH}px;">
<btrix-alert
variant="danger"
style="padding-right: ${ProfileBrowser.SIDE_BAR_WIDTH}px;"
>
${msg(`The interactive browser is not available.`)}
</btrix-alert>
</div>
<btrix-alert variant="danger">
${msg(`The interactive browser is not available.`)}
</btrix-alert>
`;
}
@ -128,16 +180,12 @@ export class ProfileBrowser extends LiteElement {
title=${msg("Interactive browser for creating browser profile")}
src=${this.iframeSrc}
@load=${this.onIframeLoad}
${ref((el) => this.onIframeRef(el as HTMLIFrameElement))}
></iframe>`;
}
if (this.browserId && !this.isIframeLoaded) {
return html`
<div
class="w-full h-full flex items-center justify-center text-3xl"
style="padding-right: ${ProfileBrowser.SIDE_BAR_WIDTH}px;"
>
<div class="w-full h-full flex items-center justify-center text-3xl">
<sl-spinner></sl-spinner>
</div>
`;
@ -146,37 +194,13 @@ export class ProfileBrowser extends LiteElement {
return "";
}
private renderFullscreenButton() {
if (!this.browserId) return;
private renderSidebarButton() {
return html`
<div class="p-2 text-right">
<sl-button
size="small"
@click=${() =>
this.isFullscreen
? document.exitFullscreen()
: this.enterFullscreen("interactive-browser")}
>
${this.isFullscreen
? html`
<sl-icon
slot="prefix"
name="fullscreen-exit"
label=${msg("Exit fullscreen")}
></sl-icon>
${msg("Exit")}
`
: html`
<sl-icon
slot="prefix"
name="arrows-fullscreen"
label=${msg("Enter fullscreen")}
></sl-icon>
${msg("Fullscreen")}
`}
</sl-button>
</div>
<sl-icon-button
name="layout-sidebar-reverse"
class="${this.showOriginSidebar ? "text-blue-600" : ""}"
@click=${() => (this.showOriginSidebar = !this.showOriginSidebar)}
></sl-icon-button>
`;
}
@ -353,8 +377,8 @@ export class ProfileBrowser extends LiteElement {
private async enterFullscreen(id: string) {
try {
document.getElementById(id)!.requestFullscreen({
// Show browser navigation controls
navigationUI: "show",
// Hide browser navigation controls
navigationUI: "hide",
});
} catch (err) {
console.error(err);
@ -363,31 +387,17 @@ export class ProfileBrowser extends LiteElement {
private onIframeLoad() {
this.isIframeLoaded = true;
try {
this.iframe?.contentWindow?.localStorage.setItem("uiTheme", '"default"');
} catch (e) {}
this.dispatchEvent(new CustomEvent("load", { detail: this.iframeSrc }));
}
private onFullscreenChange = () => {
private onFullscreenChange = async () => {
if (document.fullscreenElement) {
this.isFullscreen = true;
} else {
this.isFullscreen = false;
}
};
private onIframeRef(el: HTMLIFrameElement) {
if (!el) return;
el.addEventListener("load", () => {
// TODO see if we can make this work locally without CORs errors
try {
//el.style.width = "132%";
el.contentWindow?.localStorage.setItem("uiTheme", '"default"');
el.contentWindow?.localStorage.setItem(
"InspectorView.screencastSplitViewState",
`{"vertical":{"size":${ProfileBrowser.SIDE_BAR_WIDTH}}}`
);
} catch (e) {}
});
}
}

View File

@ -1,10 +1,10 @@
import { state, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { when } from "lit/directives/when.js";
import { msg, localized, str } from "@lit/localize";
import type { AuthState } from "../../utils/AuthService";
import LiteElement, { html } from "../../utils/LiteElement";
import { ProfileBrowser } from "../../components/profile-browser";
import { Profile } from "./types";
/**
@ -80,7 +80,7 @@ export class BrowserProfilesDetail extends LiteElement {
</div>
<header class="md:flex items-center justify-between mb-3">
<h2 class="text-xl md:text-2xl font-semibold md:h-9 mb-1">
<h2 class="text-xl font-semibold md:h-9 mb-1">
${this.profile?.name
? html`${this.profile?.name}
<sl-button
@ -169,87 +169,51 @@ export class BrowserProfilesDetail extends LiteElement {
</dl>
</section>
<section>
<header>
<h3 class="text-lg font-medium">${msg("Browser Profile")}</h3>
</header>
<div class="rounded p-2 bg-slate-50">
<div class="mb-2 flex justify-between items-center">
<div class="text-sm text-neutral-500 mx-1">
${this.browserId
? html`
${msg(
"Interact with the browsing tool to make changes to your browser profile."
)}
`
: ""}
</div>
<div>
${this.browserId && !this.isBrowserLoading
? html`
<sl-button size="small" @click=${this.cancelEditBrowser}
>${msg("Cancel")}</sl-button
>
<sl-button
variant="primary"
size="small"
?loading=${this.isSubmittingBrowserChange}
?disabled=${this.isSubmittingBrowserChange ||
!this.isBrowserLoaded}
@click=${this.saveBrowser}
>${msg("Save")}</sl-button
>
`
: html`
<sl-button
size="small"
?loading=${this.isBrowserLoading}
?disabled=${this.isBrowserLoading}
@click=${this.duplicateProfile}
>${msg("Duplicate")}</sl-button
>
`}
</div>
</div>
<main class="relative">
<btrix-profile-browser
.authState=${this.authState}
orgId=${this.orgId}
browserId=${ifDefined(this.browserId)}
.origins=${this.profile?.origins}
@load=${() => (this.isBrowserLoaded = true)}
></btrix-profile-browser>
${this.browserId || this.isBrowserLoading
? ""
: html`
<div
class="absolute top-0 left-0 h-full flex flex-col items-center justify-center"
style="right: ${ProfileBrowser.SIDE_BAR_WIDTH}px;"
>
<p class="mb-4 text-neutral-600 max-w-prose">
${msg(
"Load browser to view or edit websites in the profile."
)}
</p>
<sl-button
variant="primary"
outline
@click=${this.startBrowserPreview}
><sl-icon
slot="prefix"
name="collection-play-fill"
></sl-icon>
${msg("Load Browser")}</sl-button
>
</div>
`}
</main>
</div>
</section>
<div class="flex">
<section class="flex-1">
<header class="mb-2">
<h3 class="text-lg font-medium">${msg("Browser Profile")}</h3>
</header>
${when(
this.browserId || this.isBrowserLoading,
() => html`
<div
class="border rounded-lg overflow-hidden h-screen flex flex-col"
>
<btrix-profile-browser
class="flex-1"
.authState=${this.authState}
orgId=${this.orgId}
browserId=${ifDefined(this.browserId)}
.origins=${this.profile?.origins}
@load=${() => (this.isBrowserLoaded = true)}
></btrix-profile-browser>
<div class="flex-0 border-t">
${this.renderBrowserProfileControls()}
</div>
</div>
`,
() => html`<div
class="border rounded-lg bg-neutral-50 aspect-4/3 flex flex-col items-center justify-center"
>
<p class="mb-4 text-neutral-600 max-w-prose">
${msg(
"Edit the profile to make changes or view its present configuration"
)}
</p>
<sl-button @click=${this.startBrowserPreview}
><sl-icon slot="prefix" name="pencil-square"></sl-icon> ${msg(
"Edit Browser Profile"
)}</sl-button
>
</div>`
)}
</section>
${when(
!(this.browserId || this.isBrowserLoading),
this.renderVisitedSites
)}
</div>
<sl-dialog
label=${msg(str`Edit Profile`)}
@ -262,6 +226,48 @@ export class BrowserProfilesDetail extends LiteElement {
</sl-dialog> `;
}
private renderVisitedSites = () => {
return html`
<section class="flex-grow-1 lg:w-80 lg:pl-6 flex flex-col">
<header class="flex-0 mb-2">
<h3 class="text-lg font-medium">${msg("Visited Sites")}</h3>
</header>
<div class="border rounded-lg p-4 flex-1 overflow-auto">
<ul class="font-monostyle text-neutral-800">
${this.profile?.origins.map((origin) => html`<li>${origin}</li>`)}
</ul>
</div>
</section>
`;
};
private renderBrowserProfileControls() {
return html`
<div class="flex justify-between p-4">
<div class="max-w-prose">
<p class="text-xs text-neutral-500 mx-1">
${msg(
"Interact with the browsing tool to set up the browser profile. Crawl configs that use this browser profile will behave as if they have logged into the same websites and have the same cookies that have been set here."
)}
</p>
</div>
<div>
<sl-button size="small" @click=${this.cancelEditBrowser}
>${msg("Cancel")}</sl-button
>
<sl-button
variant="primary"
size="small"
?loading=${this.isSubmittingBrowserChange}
?disabled=${this.isSubmittingBrowserChange || !this.isBrowserLoaded}
@click=${this.saveBrowser}
>${msg("Save Browser Profile")}</sl-button
>
</div>
</div>
`;
}
private renderMenu() {
return html`
<sl-dropdown placement="bottom-end" distance="4">

View File

@ -88,27 +88,32 @@ export class BrowserProfilesNew extends LiteElement {
`
: ""}
<div class="flex items-center justify-between mb-3 p-2 bg-slate-50">
<p class="text-sm text-slate-600 mr-3 p-1">
${msg(
"Interact with the browsing tool to record your browser profile. You will complete and save your profile in the next step."
)}
</p>
<sl-button
variant="primary"
@click=${() => (this.isDialogVisible = true)}
<div class="h-screen flex flex-col">
<div
class="flex-0 flex items-center justify-between mb-3 p-2 bg-slate-50"
>
${msg("Next")}
</sl-button>
</div>
<p class="text-sm text-slate-600 mr-3 p-1">
${msg(
"Interact with the browsing tool to record your browser profile. You will complete and save your profile in the next step."
)}
</p>
<btrix-profile-browser
.authState=${this.authState}
orgId=${this.orgId}
browserId=${this.browserId}
initialNavigateUrl=${ifDefined(this.params.navigateUrl)}
></btrix-profile-browser>
<sl-button
variant="primary"
@click=${() => (this.isDialogVisible = true)}
>
${msg("Next")}
</sl-button>
</div>
<btrix-profile-browser
class="flex-1 border rounded-lg overflow-hidden"
.authState=${this.authState}
orgId=${this.orgId}
browserId=${this.browserId}
initialNavigateUrl=${ifDefined(this.params.navigateUrl)}
></btrix-profile-browser>
</div>
<sl-dialog
label=${msg(str`Save Browser Profile`)}
@ -196,9 +201,7 @@ export class BrowserProfilesNew extends LiteElement {
icon: "check2-circle",
});
this.navTo(
`/orgs/${this.orgId}/browser-profiles/profile/${data.id}`
);
this.navTo(`/orgs/${this.orgId}/browser-profiles/profile/${data.id}`);
} catch (e) {
this.isSubmitting = false;