Frontend browser profile editor enhancements (#288)
- add button to duplicate profile from main view - add save / cancel button when editing - change location of 'full screen' button
This commit is contained in:
parent
b11a5f136a
commit
ee6161ad43
@ -21,6 +21,8 @@ const POLL_INTERVAL_SECONDS = 2;
|
||||
* origins=${origins}
|
||||
* ></btrix-profile-browser>
|
||||
* ```
|
||||
*
|
||||
* @event load Event on iframe load, with src URL
|
||||
*/
|
||||
@localized()
|
||||
export class ProfileBrowser extends LiteElement {
|
||||
@ -49,6 +51,9 @@ export class ProfileBrowser extends LiteElement {
|
||||
@state()
|
||||
private iframeSrc?: string;
|
||||
|
||||
@state()
|
||||
private isIframeLoaded = false;
|
||||
|
||||
@state()
|
||||
private hasFetchError = false;
|
||||
|
||||
@ -74,9 +79,11 @@ export class ProfileBrowser extends LiteElement {
|
||||
updated(changedProperties: Map<string, any>) {
|
||||
if (changedProperties.has("browserId")) {
|
||||
if (this.browserId) {
|
||||
window.clearTimeout(this.pollTimerId);
|
||||
this.fetchBrowser();
|
||||
} else if (changedProperties.get("browserId")) {
|
||||
this.iframeSrc = undefined;
|
||||
this.isIframeLoaded = false;
|
||||
|
||||
window.clearTimeout(this.pollTimerId);
|
||||
}
|
||||
@ -96,8 +103,8 @@ export class ProfileBrowser extends LiteElement {
|
||||
<div
|
||||
class="rounded-b lg:rounded-b-none lg:rounded-r border w-72 bg-white absolute h-full top-0 right-0"
|
||||
>
|
||||
${this.renderFullscreenButton()} ${this.renderOrigins()}
|
||||
${this.renderNewOrigins()}
|
||||
${document.fullscreenEnabled ? this.renderFullscreenButton() : ""}
|
||||
${this.renderOrigins()} ${this.renderNewOrigins()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -135,11 +142,12 @@ export class ProfileBrowser extends LiteElement {
|
||||
class="w-full h-full"
|
||||
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.iframeSrc) {
|
||||
if (this.browserId && !this.isIframeLoaded) {
|
||||
return html`
|
||||
<div
|
||||
class="w-full h-full flex items-center justify-center text-4xl"
|
||||
@ -154,37 +162,37 @@ export class ProfileBrowser extends LiteElement {
|
||||
}
|
||||
|
||||
private renderFullscreenButton() {
|
||||
return html`${document.fullscreenEnabled
|
||||
? 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>
|
||||
`
|
||||
: ""}`;
|
||||
if (!this.browserId) return;
|
||||
|
||||
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>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderOrigins() {
|
||||
@ -244,9 +252,14 @@ export class ProfileBrowser extends LiteElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch browser profiles and update internal state
|
||||
* Fetch browser profile and update internal state
|
||||
*/
|
||||
private async fetchBrowser(): Promise<void> {
|
||||
await this.updateComplete;
|
||||
|
||||
this.iframeSrc = undefined;
|
||||
this.isIframeLoaded = false;
|
||||
|
||||
try {
|
||||
await this.checkBrowserStatus();
|
||||
} catch (e) {
|
||||
@ -280,6 +293,10 @@ export class ProfileBrowser extends LiteElement {
|
||||
|
||||
this.iframeSrc = result.url;
|
||||
|
||||
await this.updateComplete;
|
||||
|
||||
this.dispatchEvent(new CustomEvent("load", { detail: result.url }));
|
||||
|
||||
this.pingBrowser();
|
||||
} else {
|
||||
console.debug("Unknown checkBrowserStatus state");
|
||||
@ -333,7 +350,7 @@ export class ProfileBrowser extends LiteElement {
|
||||
if (!this.origins) {
|
||||
this.origins = data.origins;
|
||||
} else {
|
||||
this.newOrigins = data.origins.filter(
|
||||
this.newOrigins = data.origins?.filter(
|
||||
(url: string) => !this.origins?.includes(url)
|
||||
);
|
||||
}
|
||||
@ -359,6 +376,12 @@ export class ProfileBrowser extends LiteElement {
|
||||
}
|
||||
}
|
||||
|
||||
private onIframeLoad() {
|
||||
this.isIframeLoaded = true;
|
||||
|
||||
this.dispatchEvent(new CustomEvent("load", { detail: this.iframeSrc }));
|
||||
}
|
||||
|
||||
private onFullscreenChange = () => {
|
||||
if (document.fullscreenElement) {
|
||||
this.isFullscreen = true;
|
||||
|
||||
@ -33,7 +33,10 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
private profile?: Profile;
|
||||
|
||||
@state()
|
||||
private isLoading = false;
|
||||
private isBrowserLoading = false;
|
||||
|
||||
@state()
|
||||
private isBrowserLoaded = false;
|
||||
|
||||
@state()
|
||||
private isSubmittingBrowserChange = false;
|
||||
@ -41,9 +44,6 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
@state()
|
||||
private isSubmittingProfileChange = false;
|
||||
|
||||
@state()
|
||||
private showSaveButton = false;
|
||||
|
||||
@state()
|
||||
private browserId?: string;
|
||||
|
||||
@ -53,10 +53,10 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
@state()
|
||||
private isEditDialogContentVisible = false;
|
||||
|
||||
private showSaveButtonTimerId?: number;
|
||||
|
||||
disconnectedCallback() {
|
||||
window.clearTimeout(this.showSaveButtonTimerId);
|
||||
if (this.browserId) {
|
||||
this.deleteBrowser(this.browserId);
|
||||
}
|
||||
}
|
||||
|
||||
firstUpdated() {
|
||||
@ -172,72 +172,85 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
|
||||
<section>
|
||||
<header>
|
||||
<h3 class="text-lg font-medium mb-2">
|
||||
${msg("Browser Profile Editor")}
|
||||
</h3>
|
||||
<h3 class="text-lg font-medium">${msg("Browser Profile")}</h3>
|
||||
</header>
|
||||
|
||||
<main class="relative">
|
||||
<btrix-profile-browser
|
||||
.authState=${this.authState}
|
||||
archiveId=${this.archiveId}
|
||||
browserId=${ifDefined(this.browserId)}
|
||||
.origins=${this.profile?.origins}
|
||||
></btrix-profile-browser>
|
||||
|
||||
${this.browserId && !this.isLoading
|
||||
? html`
|
||||
<!-- Hide browser area with overlay -->
|
||||
<!-- TODO remove when browser no longer shows dev tools -->
|
||||
${this.isSubmittingBrowserChange
|
||||
? html`<div
|
||||
class="absolute top-0 left-0 h-full flex items-center justify-center text-4xl bg-slate-50 lg:rounded-l-lg border border-r-0"
|
||||
style="right: ${ProfileBrowser.SIDE_BAR_WIDTH}px;"
|
||||
>
|
||||
<sl-spinner></sl-spinner>
|
||||
</div>`
|
||||
: ""}
|
||||
${this.showSaveButton
|
||||
? html`<div
|
||||
class="absolute top-0 p-2"
|
||||
style="right: ${ProfileBrowser.SIDE_BAR_WIDTH}px;"
|
||||
>
|
||||
<sl-button
|
||||
class="shadow"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click=${this.saveBrowser}
|
||||
>${msg("Done Editing")}</sl-button
|
||||
>
|
||||
</div>`
|
||||
: ""}
|
||||
`
|
||||
: 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">
|
||||
<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(
|
||||
"Load browser to view or edit websites in the profile."
|
||||
"Interact with the browsing tool to make changes to your browser profile."
|
||||
)}
|
||||
</p>
|
||||
<sl-button
|
||||
type="primary"
|
||||
outline
|
||||
?disabled=${this.isLoading ||
|
||||
!ProfileBrowser.isBrowserCompatible}
|
||||
?loading=${this.isLoading}
|
||||
@click=${this.startBrowserPreview}
|
||||
><sl-icon
|
||||
slot="prefix"
|
||||
name="collection-play-fill"
|
||||
></sl-icon>
|
||||
${msg("Load Browser")}</sl-button
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
${this.browserId && !this.isBrowserLoading
|
||||
? html`
|
||||
<sl-button size="small" @click=${this.cancelEditBrowser}
|
||||
>${msg("Cancel")}</sl-button
|
||||
>
|
||||
<sl-button
|
||||
type="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}
|
||||
archiveId=${this.archiveId}
|
||||
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;"
|
||||
>
|
||||
</div>
|
||||
`}
|
||||
</main>
|
||||
<p class="mb-4 text-neutral-600 max-w-prose">
|
||||
${msg(
|
||||
"Load browser to view or edit websites in the profile."
|
||||
)}
|
||||
</p>
|
||||
<sl-button
|
||||
type="primary"
|
||||
outline
|
||||
?disabled=${!ProfileBrowser.isBrowserCompatible}
|
||||
@click=${this.startBrowserPreview}
|
||||
><sl-icon
|
||||
slot="prefix"
|
||||
name="collection-play-fill"
|
||||
></sl-icon>
|
||||
${msg("Load Browser")}</sl-button
|
||||
>
|
||||
</div>
|
||||
`}
|
||||
</main>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<sl-dialog
|
||||
@ -254,7 +267,7 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
private renderMenu() {
|
||||
return html`
|
||||
<sl-dropdown placement="bottom-end" distance="4">
|
||||
<sl-button slot="trigger" type="primary" size="small" caret
|
||||
<sl-button slot="trigger" size="small" caret
|
||||
>${msg("Actions")}</sl-button
|
||||
>
|
||||
|
||||
@ -351,27 +364,17 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
private async startBrowserPreview() {
|
||||
if (!this.profile) return;
|
||||
|
||||
this.isLoading = true;
|
||||
this.isBrowserLoading = true;
|
||||
|
||||
const url = this.profile.origins[0];
|
||||
|
||||
try {
|
||||
const data = await this.createBrowser({ url });
|
||||
|
||||
this.notify({
|
||||
message: msg("Starting up browser..."),
|
||||
type: "success",
|
||||
icon: "check2-circle",
|
||||
});
|
||||
|
||||
this.browserId = data.browserid;
|
||||
|
||||
// Slightly delay showing the save button while browser loads
|
||||
this.showSaveButtonTimerId = window.setTimeout(() => {
|
||||
this.showSaveButton = true;
|
||||
}, 3 * 1000);
|
||||
this.isBrowserLoading = false;
|
||||
} catch (e) {
|
||||
this.isLoading = false;
|
||||
this.isBrowserLoading = false;
|
||||
|
||||
this.notify({
|
||||
message: msg("Sorry, couldn't preview browser profile at this time."),
|
||||
@ -379,14 +382,28 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
icon: "exclamation-octagon",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.isLoading = false;
|
||||
private async cancelEditBrowser() {
|
||||
const prevBrowserId = this.browserId;
|
||||
|
||||
this.isBrowserLoaded = false;
|
||||
this.browserId = undefined;
|
||||
|
||||
if (prevBrowserId) {
|
||||
try {
|
||||
await this.deleteBrowser(prevBrowserId);
|
||||
} catch (e) {
|
||||
// TODO Investigate DELETE is returning 404
|
||||
console.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async duplicateProfile() {
|
||||
if (!this.profile) return;
|
||||
|
||||
this.isLoading = true;
|
||||
this.isBrowserLoading = true;
|
||||
|
||||
const url = this.profile.origins[0];
|
||||
|
||||
@ -409,7 +426,7 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
)}&profileId=${window.encodeURIComponent(this.profile.id)}&navigateUrl=`
|
||||
);
|
||||
} catch (e) {
|
||||
this.isLoading = false;
|
||||
this.isBrowserLoading = false;
|
||||
|
||||
this.notify({
|
||||
message: msg("Sorry, couldn't create browser profile at this time."),
|
||||
@ -479,6 +496,16 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
);
|
||||
}
|
||||
|
||||
private deleteBrowser(id: string) {
|
||||
return this.apiFetch(
|
||||
`/archives/${this.archiveId}/profiles/browser/${id}`,
|
||||
this.authState!,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch browser profile and update internal state
|
||||
*/
|
||||
@ -511,7 +538,7 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
if (
|
||||
!window.confirm(
|
||||
msg(
|
||||
"Save browser changes to profile? You will need to reload the editor to make additional changes."
|
||||
"Save browser changes to profile? You will need to re-load the browsing tool to make additional changes."
|
||||
)
|
||||
)
|
||||
) {
|
||||
@ -519,7 +546,6 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
}
|
||||
|
||||
this.isSubmittingBrowserChange = true;
|
||||
this.showSaveButton = false;
|
||||
|
||||
const params = {
|
||||
name: this.profile!.name,
|
||||
@ -553,8 +579,6 @@ export class BrowserProfilesDetail extends LiteElement {
|
||||
type: "danger",
|
||||
icon: "exclamation-octagon",
|
||||
});
|
||||
|
||||
this.showSaveButton = true;
|
||||
}
|
||||
|
||||
this.isSubmittingBrowserChange = false;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user