From 0ebc8fa45a2b7d95158c8246ae0180346c34bd88 Mon Sep 17 00:00:00 2001 From: Neil Vohra Date: Thu, 30 Apr 2026 06:04:43 +0000 Subject: [PATCH] feat: Add share dialog with QR code and support auto-subscriptions Introduces a new share dialog with QR code generation for saved searches. Also adds handling for a `subscribe=true` URL parameter that prompts users to log in if needed, or automatically opens the subscription dialog. --- ...-channels-authenticated-chromium-linux.png | Bin 28287 -> 28298 bytes ...nels-authenticated-dark-chromium-linux.png | Bin 27435 -> 27444 bytes e2e/tests/saved-searches.spec.ts | 12 +- e2e/tests/utils.ts | 2 +- .../static/img/shoelace/assets/icons/link.svg | 4 + .../webstatus-login-prompt-dialog.test.ts | 98 +++++++ .../test/webstatus-overview-content.test.ts | 17 ++ .../webstatus-saved-search-controls.test.ts | 61 +++-- ...ebstatus-saved-search-share-dialog.test.ts | 117 +++++++++ .../test/webstatus-subscribe-button.test.ts | 15 ++ .../webstatus-login-prompt-dialog.ts | 103 ++++++++ .../components/webstatus-overview-content.ts | 28 +- .../webstatus-overview-data-loader.ts | 4 +- .../webstatus-overview-pagination.ts | 6 +- .../webstatus-saved-search-controls.ts | 26 +- .../webstatus-saved-search-share-dialog.ts | 239 ++++++++++++++++++ .../components/webstatus-subscribe-button.ts | 17 +- frontend/src/static/js/index.ts | 1 + frontend/src/static/js/utils/urls.ts | 10 + 19 files changed, 717 insertions(+), 43 deletions(-) create mode 100644 frontend/src/static/img/shoelace/assets/icons/link.svg create mode 100644 frontend/src/static/js/components/test/webstatus-login-prompt-dialog.test.ts create mode 100644 frontend/src/static/js/components/test/webstatus-saved-search-share-dialog.test.ts create mode 100644 frontend/src/static/js/components/webstatus-login-prompt-dialog.ts create mode 100644 frontend/src/static/js/components/webstatus-saved-search-share-dialog.ts diff --git a/e2e/tests/notification-channels.spec.ts-snapshots/notification-channels-authenticated-chromium-linux.png b/e2e/tests/notification-channels.spec.ts-snapshots/notification-channels-authenticated-chromium-linux.png index f616632041e0dbdcbea01a42dd18e536c05ca870..ee76113a31b97d8ae2807bfce09c661306acf79b 100644 GIT binary patch literal 28298 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 P;Ua1Os+IT4Z-4wZeOdh( diff --git a/e2e/tests/notification-channels.spec.ts-snapshots/notification-channels-authenticated-dark-chromium-linux.png b/e2e/tests/notification-channels.spec.ts-snapshots/notification-channels-authenticated-dark-chromium-linux.png index 437367629fa21da13521426bcf1a7f040d0bcbf0..88461b84a9e617d420ee117ba7efc420440f406e 100644 GIT binary patch literal 27444 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 literal 27435 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 diff --git a/e2e/tests/saved-searches.spec.ts b/e2e/tests/saved-searches.spec.ts index ffd3f6fd5..c323381be 100644 --- a/e2e/tests/saved-searches.spec.ts +++ b/e2e/tests/saved-searches.spec.ts @@ -77,7 +77,7 @@ const saveButtonLocator = (page: Page) => .getByTestId('saved-search-save-button') .getByRole('button', {name: 'Save'}); const shareButtonLocator = (page: Page) => - controlsLocator(page).getByLabel('Copy', {exact: true}); + controlsLocator(page).getByLabel('Share', {exact: true}); const bookmarkEmptyIconLocator = (page: Page) => controlsLocator(page).getByRole('button', {name: 'Bookmark', exact: true}); const bookmarkFilledIconLocator = (page: Page) => @@ -404,11 +404,19 @@ test.describe('Saved Searches on Overview Page', () => { // Click the share icon await shareButtonLocator(page).click(); + // Wait for the share dialog to appear + const dialog = page.getByRole('dialog', {name: 'Share bookmark'}); + await expect(dialog).toBeVisible(); + console.log('Dialog HTML:', await dialog.innerHTML()); + + // Click the "Copy link" button inside the dialog + await page.getByTestId('copy-link-button').click(); + // Verify clipboard content const clipboardText = await page.evaluate(() => navigator.clipboard.readText(), ); - expectUrlsEqual(clipboardText, page.url()); + expectUrlsEqual(clipboardText, `${page.url()}&subscribe=true`); }); test('Edit dialog opens automatically with edit_saved_search=true URL parameter', async ({ diff --git a/e2e/tests/utils.ts b/e2e/tests/utils.ts index a287b2f59..b4345f452 100644 --- a/e2e/tests/utils.ts +++ b/e2e/tests/utils.ts @@ -202,7 +202,7 @@ export async function loginAsUser( const popupPromise = page.waitForEvent('popup'); await page.goto('http://localhost:5555/'); await waitForSidebarLoaded(page); - await page.getByText('Log in').click(); + await page.getByRole('banner').getByText('Log in').click(); const popup = await popupPromise; await popup.waitForLoadState(); diff --git a/frontend/src/static/img/shoelace/assets/icons/link.svg b/frontend/src/static/img/shoelace/assets/icons/link.svg new file mode 100644 index 000000000..823e4cd69 --- /dev/null +++ b/frontend/src/static/img/shoelace/assets/icons/link.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/src/static/js/components/test/webstatus-login-prompt-dialog.test.ts b/frontend/src/static/js/components/test/webstatus-login-prompt-dialog.test.ts new file mode 100644 index 000000000..87aeb7847 --- /dev/null +++ b/frontend/src/static/js/components/test/webstatus-login-prompt-dialog.test.ts @@ -0,0 +1,98 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {fixture, html, expect, oneEvent} from '@open-wc/testing'; +import sinon from 'sinon'; +import {WebstatusLoginPromptDialog} from '../webstatus-login-prompt-dialog.js'; +import { + AuthConfig, + firebaseAuthContext, +} from '../../contexts/firebase-auth-context.js'; +import {provide} from '@lit/context'; +import {LitElement} from 'lit'; +import {customElement, property} from 'lit/decorators.js'; + +import '../webstatus-login-prompt-dialog.js'; + +@customElement('test-auth-provider') +class TestAuthProvider extends LitElement { + @property({type: Object}) + @provide({context: firebaseAuthContext}) + authConfig!: AuthConfig; + + render() { + return html``; + } +} + +describe('webstatus-login-prompt-dialog', () => { + let mockAuthConfig: AuthConfig; + let signInStub: sinon.SinonStub; + + beforeEach(() => { + signInStub = sinon.stub().resolves(); + mockAuthConfig = { + auth: {} as any, + provider: {} as any, + icon: 'github', + signIn: signInStub, + }; + }); + + it('renders nothing when closed', async () => { + const el = await fixture(html` + + `); + const dialog = el.shadowRoot?.querySelector('sl-dialog'); + expect(dialog?.open).to.be.false; + }); + + it('renders dialog when open', async () => { + const el = await fixture(html` + + `); + const dialog = el.shadowRoot?.querySelector('sl-dialog'); + expect(dialog?.open).to.be.true; + expect(el.shadowRoot?.textContent).to.contain('My Search'); + }); + + it('calls signIn on button click and dispatches login-success', async () => { + const wrapper = await fixture(html` + + + + `); + const el = wrapper.querySelector( + 'webstatus-login-prompt-dialog', + )!; + const button = el.shadowRoot?.querySelector('sl-button[variant="primary"]'); + expect(button).to.exist; + + const eventPromise = oneEvent(el, 'login-success'); + (button as HTMLElement).click(); + + await eventPromise; + expect(signInStub.calledOnce).to.be.true; + expect(el.open).to.be.false; + }); +}); diff --git a/frontend/src/static/js/components/test/webstatus-overview-content.test.ts b/frontend/src/static/js/components/test/webstatus-overview-content.test.ts index 34229500e..59662cdf0 100644 --- a/frontend/src/static/js/components/test/webstatus-overview-content.test.ts +++ b/frontend/src/static/js/components/test/webstatus-overview-content.test.ts @@ -17,6 +17,7 @@ import {WebstatusOverviewContent} from '../webstatus-overview-content.js'; import '../webstatus-overview-content.js'; import {expect, fixture, html} from '@open-wc/testing'; +import {WebstatusLoginPromptDialog} from '../webstatus-login-prompt-dialog.js'; import { savedSearchHelpers, @@ -50,6 +51,7 @@ describe('WebstatusOverviewContent', () => { element = await fixture(html` `); + element.location = {search: ''}; element._getOrigin = () => 'http://localhost'; sinon.stub(element, '_getEditSavedSearch').returns(false); sinon.stub(element, '_updatePageUrl'); @@ -280,6 +282,21 @@ describe('WebstatusOverviewContent', () => { expect(openSpy).to.have.been.calledOnce; }); + it('automatically opens the login prompt when subscribe param is true and user is logged out', async () => { + element.location = {search: '?subscribe=true'}; + element.userContext = null; + element.savedSearch = mockUserSearch; + + element.requestUpdate(); + await element.updateComplete; + + const promptDialog = + element.shadowRoot?.querySelector( + 'webstatus-login-prompt-dialog', + ); + expect(promptDialog).to.exist; + expect(promptDialog?.open).to.be.true; + }); }); describe('Events & Interactions', () => { diff --git a/frontend/src/static/js/components/test/webstatus-saved-search-controls.test.ts b/frontend/src/static/js/components/test/webstatus-saved-search-controls.test.ts index bbda696cf..08d675243 100644 --- a/frontend/src/static/js/components/test/webstatus-saved-search-controls.test.ts +++ b/frontend/src/static/js/components/test/webstatus-saved-search-controls.test.ts @@ -141,7 +141,9 @@ describe('WebstatusSavedSearchControls', () => { }); it('does not render active search controls when no savedSearch is provided', () => { - const shareButton = element.shadowRoot!.querySelector('sl-copy-button'); + const shareButton = element.shadowRoot!.querySelector( + 'sl-icon-button[name="share"]', + ); const bookmarkButton = element.shadowRoot!.querySelector( 'sl-icon-button[name^="star"]', ); @@ -182,7 +184,9 @@ describe('WebstatusSavedSearchControls', () => { const saveButton = element.shadowRoot!.querySelector( 'sl-icon-button[name="floppy"]', ); - const shareButton = element.shadowRoot!.querySelector('sl-copy-button'); + const shareButton = element.shadowRoot!.querySelector( + 'sl-icon-button[name="share"]', + ); const bookmarkButton = element.shadowRoot!.querySelector( 'sl-icon-button[name="star"]', ); @@ -205,13 +209,33 @@ describe('WebstatusSavedSearchControls', () => { expect(deleteButton).to.not.exist; }); - it('configures share button correctly', () => { - const copyButton = element.shadowRoot!.querySelector('sl-copy-button'); - const expectedUrl = `http://localhost:8080/features?q=saved%3A${mockSavedSearchViewerNotBookmarked.id}`; - expect(copyButton).to.have.attribute('value', expectedUrl); - expect(formatOverviewPageUrlStub).to.have.been.calledWith(mockLocation, { - q: `saved:${mockSavedSearchViewerNotBookmarked.id}`, - }); + it('opens modal when share button is clicked and renders QR code', async () => { + const shareButton = element.shadowRoot!.querySelector( + 'sl-icon-button[name="share"]', + )!; + shareButton.click(); + await element.updateComplete; + + // Wait for dialog to appear in body. + await waitUntil( + () => + document.body.querySelector('webstatus-saved-search-share-dialog') !== + null, + ); + + const shareDialog = document.body.querySelector( + 'webstatus-saved-search-share-dialog', + )!; + expect(shareDialog).to.exist; + + const dialog = shareDialog.shadowRoot!.querySelector('sl-dialog'); + expect(dialog).to.exist; + + const qrCode = dialog!.querySelector('sl-qr-code'); + expect(qrCode).to.exist; + + const copyButton = dialog!.querySelector('sl-button[variant="primary"]'); + expect(copyButton).to.exist; }); it('calls handleBookmarkSavedSearch to bookmark when bookmark button is clicked', async () => { @@ -332,7 +356,9 @@ describe('WebstatusSavedSearchControls', () => { const saveButton = element.shadowRoot!.querySelector( 'sl-icon-button[name="floppy"]', ); - const shareButton = element.shadowRoot!.querySelector('sl-copy-button'); + const shareButton = element.shadowRoot!.querySelector( + 'sl-icon-button[name="share"]', + ); const bookmarkButton = element.shadowRoot!.querySelector( 'sl-icon-button[name="star"]', ); @@ -446,7 +472,9 @@ describe('WebstatusSavedSearchControls', () => { const saveButton = element.shadowRoot!.querySelector( 'sl-icon-button[name="floppy"]', ); - const shareButton = element.shadowRoot!.querySelector('sl-copy-button'); + const shareButton = element.shadowRoot!.querySelector( + 'sl-icon-button[name="share"]', + ); const bookmarkButton = element.shadowRoot!.querySelector( 'sl-icon-button[name="star"]', ); @@ -469,10 +497,13 @@ describe('WebstatusSavedSearchControls', () => { expect(deleteButton).to.exist; }); - it('configures share button correctly for owner', () => { - const copyButton = element.shadowRoot!.querySelector('sl-copy-button'); - const expectedUrl = `http://localhost:8080/features?q=saved%3A${mockSavedSearchOwner.id}`; - expect(copyButton).to.have.attribute('value', expectedUrl); + it('configures share button correctly for owner', async () => { + const shareButton = element.shadowRoot!.querySelector( + 'sl-icon-button[name="share"]', + )!; + shareButton.click(); + await element.updateComplete; + expect(formatOverviewPageUrlStub).to.have.been.calledWith(mockLocation, { q: `saved:${mockSavedSearchOwner.id}`, }); diff --git a/frontend/src/static/js/components/test/webstatus-saved-search-share-dialog.test.ts b/frontend/src/static/js/components/test/webstatus-saved-search-share-dialog.test.ts new file mode 100644 index 000000000..1c90b85fd --- /dev/null +++ b/frontend/src/static/js/components/test/webstatus-saved-search-share-dialog.test.ts @@ -0,0 +1,117 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {fixture, html, expect, waitUntil} from '@open-wc/testing'; +import sinon from 'sinon'; +import {WebstatusSavedSearchShareDialog} from '../webstatus-saved-search-share-dialog.js'; +import {UserSavedSearch} from '../../utils/constants.js'; +import {Toast} from '../../utils/toast.js'; + +import '../webstatus-saved-search-share-dialog.js'; + +describe('webstatus-saved-search-share-dialog', () => { + let el: WebstatusSavedSearchShareDialog; + let toastStub: sinon.SinonStub; + let clipboardStub: sinon.SinonStub; + + const mockSavedSearch: UserSavedSearch = { + id: 'test-id', + name: 'Test Search', + query: 'feature:css', + description: 'A test search', + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + }; + + beforeEach(async () => { + toastStub = sinon.stub(Toast.prototype, 'toast').resolves(); + + if (!navigator.clipboard) { + Object.defineProperty(navigator, 'clipboard', { + value: { + writeText: async () => {}, + }, + writable: true, + }); + } + clipboardStub = sinon.stub(navigator.clipboard, 'writeText').resolves(); + + el = await fixture(html` + + `); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('computes effectiveUrl correctly', async () => { + el.shareableUrl = 'http://localhost:8080/features?q=saved:test-id'; + await el.updateComplete; + expect(el.effectiveUrl).to.equal( + 'http://localhost:8080/features?q=saved%3Atest-id&subscribe=true', + ); + }); + + it('computes effectiveUrl correctly when fallback is needed', async () => { + el.shareableUrl = 'http://localhost:8080/features'; + await el.updateComplete; + expect(el.effectiveUrl).to.equal( + 'http://localhost:8080/features?subscribe=true', + ); + }); + + it('copies effectiveUrl to clipboard on button click', async () => { + el.shareableUrl = 'http://localhost:8080/features?q=saved:test-id'; + await el.updateComplete; + + await el.openWithContext(mockSavedSearch, el.shareableUrl); + await el.updateComplete; + + const dialog = el.shadowRoot?.querySelector('sl-dialog'); + expect(dialog).to.exist; + + const copyButton = dialog?.querySelector( + 'sl-button[variant="primary"]', + ); + expect(copyButton).to.exist; + + copyButton!.click(); + + await waitUntil(() => toastStub.calledOnce); + + expect( + clipboardStub.calledOnceWith( + 'http://localhost:8080/features?q=saved%3Atest-id&subscribe=true', + ), + ).to.be.true; + expect(toastStub.calledOnce).to.be.true; + }); + + it('renders QR code when open', async () => { + el.shareableUrl = 'http://localhost:8080/features?q=saved:test-id'; + await el.updateComplete; + + await el.openWithContext(mockSavedSearch, el.shareableUrl); + await el.updateComplete; + + const qrCode = el.shadowRoot?.querySelector('sl-qr-code'); + expect(qrCode).to.exist; + expect(qrCode?.getAttribute('value')).to.equal( + 'http://localhost:8080/features?q=saved%3Atest-id&subscribe=true', + ); + }); +}); diff --git a/frontend/src/static/js/components/test/webstatus-subscribe-button.test.ts b/frontend/src/static/js/components/test/webstatus-subscribe-button.test.ts index 07ce4cbde..66fe61229 100644 --- a/frontend/src/static/js/components/test/webstatus-subscribe-button.test.ts +++ b/frontend/src/static/js/components/test/webstatus-subscribe-button.test.ts @@ -82,6 +82,21 @@ describe('webstatus-subscribe-button', () => { expect(dialog?.open).to.be.true; }); + it('opens dialog automatically when autoOpen is true and user is logged in', async () => { + const el = await fixture(html` + + `); + const dialog = el.shadowRoot?.querySelector( + 'webstatus-manage-subscriptions-dialog', + ); + expect(dialog).to.exist; + expect(dialog?.open).to.be.true; + }); + it('calls toaster on successful save', async () => { const toasterSpy = sinon.spy(); const el = await fixture(html` diff --git a/frontend/src/static/js/components/webstatus-login-prompt-dialog.ts b/frontend/src/static/js/components/webstatus-login-prompt-dialog.ts new file mode 100644 index 000000000..dd191eef0 --- /dev/null +++ b/frontend/src/static/js/components/webstatus-login-prompt-dialog.ts @@ -0,0 +1,103 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {LitElement, TemplateResult, css, html} from 'lit'; +import {customElement, property, state} from 'lit/decorators.js'; +import {consume} from '@lit/context'; +import { + firebaseAuthContext, + AuthConfig, +} from '../contexts/firebase-auth-context.js'; +import {toast} from '../utils/toast.js'; +import {SHARED_STYLES} from '../css/shared-css.js'; + +@customElement('webstatus-login-prompt-dialog') +export class WebstatusLoginPromptDialog extends LitElement { + @property({type: Boolean}) + open = false; + + @property({type: String}) + savedSearchName = ''; + + @consume({context: firebaseAuthContext, subscribe: true}) + @state() + firebaseAuthConfig?: AuthConfig; + + static styles = [ + SHARED_STYLES, + css` + .content { + display: flex; + flex-direction: column; + gap: var(--content-padding); + } + .footer { + display: flex; + justify-content: flex-end; + } + `, + ]; + + async _handleLogin() { + if (this.firebaseAuthConfig) { + try { + await this.firebaseAuthConfig.signIn(); + this.dispatchEvent( + new CustomEvent('login-success', {bubbles: true, composed: true}), + ); + this.open = false; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'unknown'; + await toast( + `Failed to login: ${errorMessage}`, + 'danger', + 'exclamation-triangle', + ); + } + } + } + + _handleClose() { + this.open = false; + this.dispatchEvent( + new CustomEvent('prompt-close', {bubbles: true, composed: true}), + ); + } + + render(): TemplateResult { + return html` + +
+

+ You need an account to subscribe to + ${this.savedSearchName} and receive the latest + updates. +

+
+ +
+ `; + } +} diff --git a/frontend/src/static/js/components/webstatus-overview-content.ts b/frontend/src/static/js/components/webstatus-overview-content.ts index b8746e14c..efbac04d5 100644 --- a/frontend/src/static/js/components/webstatus-overview-content.ts +++ b/frontend/src/static/js/components/webstatus-overview-content.ts @@ -30,6 +30,7 @@ import './webstatus-overview-data-loader.js'; import './webstatus-overview-filters.js'; import './webstatus-overview-pagination.js'; import './webstatus-subscribe-button.js'; +import './webstatus-login-prompt-dialog.js'; import {SHARED_STYLES} from '../css/shared-css.js'; import {TaskTracker} from '../utils/task-tracker.js'; import {ApiError} from '../api/errors.js'; @@ -55,6 +56,7 @@ import { formatOverviewPageUrl, getEditSavedSearch, getOrigin, + getSubscribeToSavedSearch, QueryStringOverrides, updatePageUrl, } from '../utils/urls.js'; @@ -244,7 +246,7 @@ export class WebstatusOverviewContent extends LitElement { _updatePageUrl: ( pathname: string, location: {search: string}, - overrides: {edit_saved_search?: boolean}, + overrides: QueryStringOverrides, ) => void = updatePageUrl; _formatOverviewPageUrl: ( location?: {search: string}, @@ -255,6 +257,7 @@ export class WebstatusOverviewContent extends LitElement { _changedProperties: PropertyValueMap, ): Promise { if ( + this.location && this._getEditSavedSearch(this.location) && !this.savedSearchEditor.isOpen() && this.savedSearch @@ -266,6 +269,15 @@ export class WebstatusOverviewContent extends LitElement { ); this._updatePageUrl('', this.location, {edit_saved_search: false}); } + + if ( + this.location && + getSubscribeToSavedSearch(this.location) && + this.userContext && + this.savedSearch + ) { + this._updatePageUrl('', this.location, {subscribe: false}); + } } render(): TemplateResult { @@ -279,6 +291,9 @@ export class WebstatusOverviewContent extends LitElement { ? savedSearch : undefined; const config = this.subscribeButtonConfig; + const shouldSubscribe = this.location + ? getSubscribeToSavedSearch(this.location) + : false; return html`
@@ -287,6 +302,7 @@ export class WebstatusOverviewContent extends LitElement { ? html`` : nothing}
@@ -323,6 +339,14 @@ export class WebstatusOverviewContent extends LitElement { .userContext=${this.userContext!} .savedSearch=${userSavedSearch?.value} .location=${this.location} - >`; + > + + this._updatePageUrl('', this.location, {subscribe: false})} + >`; } } diff --git a/frontend/src/static/js/components/webstatus-overview-data-loader.ts b/frontend/src/static/js/components/webstatus-overview-data-loader.ts index 035a3e402..9076e6c41 100644 --- a/frontend/src/static/js/components/webstatus-overview-data-loader.ts +++ b/frontend/src/static/js/components/webstatus-overview-data-loader.ts @@ -54,11 +54,9 @@ export class WebstatusOverviewDataLoader extends LitElement { savedSearch: CurrentSavedSearch; render(): TemplateResult { - const columns: ColumnKey[] = parseColumnsSpec( - getColumnsSpec(this.location), - ); const location = this.location; if (!location) return html``; + const columns: ColumnKey[] = parseColumnsSpec(getColumnsSpec(location)); const sortSpec = getSortSpec(location) || DEFAULT_SORT_SPEC; const groupCells = renderGroupCells(location, columns, sortSpec!); let headerCells: TemplateResult[] = []; diff --git a/frontend/src/static/js/components/webstatus-overview-pagination.ts b/frontend/src/static/js/components/webstatus-overview-pagination.ts index 3b75f58d7..6515c1a78 100644 --- a/frontend/src/static/js/components/webstatus-overview-pagination.ts +++ b/frontend/src/static/js/components/webstatus-overview-pagination.ts @@ -208,8 +208,10 @@ export class WebstatusOverviewPagination extends LitElement { return html``; } - this.start = getPaginationStart(this.location); - this.pageSize = getPageSize(this.location); + this.start = this.location ? getPaginationStart(this.location) : 0; + this.pageSize = this.location + ? getPageSize(this.location) + : DEFAULT_ITEMS_PER_PAGE; const prevUrl = this.formatUrlForRelativeOffset(-this.pageSize); const nextUrl = this.formatUrlForRelativeOffset(this.pageSize); diff --git a/frontend/src/static/js/components/webstatus-saved-search-controls.ts b/frontend/src/static/js/components/webstatus-saved-search-controls.ts index c17f968f4..856349461 100644 --- a/frontend/src/static/js/components/webstatus-saved-search-controls.ts +++ b/frontend/src/static/js/components/webstatus-saved-search-controls.ts @@ -16,6 +16,7 @@ import {LitElement, TemplateResult, css, html, nothing} from 'lit'; import {customElement, property, query, state} from 'lit/decorators.js'; +import {openShareDialog} from './webstatus-saved-search-share-dialog.js'; import {APIClient} from '../contexts/api-client-context.js'; import {UserContext} from '../contexts/firebase-user-context.js'; import { @@ -207,24 +208,15 @@ export class WebstatusSavedSearchControls extends LitElement { savedSearch: UserSavedSearch, ): TemplateResult { const isOwner = savedSearch.permissions?.role === BookmarkOwnerRole; - const shareableUrl = `${this._getOrigin()}${this._formatOverviewPageUrl(this.location, {q: `saved:${savedSearch.id}`})}`; return html` - - + { + const shareableUrl = `${this._getOrigin()}${this._formatOverviewPageUrl(this.location, {q: `saved:${savedSearch.id}`})}`; + void openShareDialog(savedSearch, shareableUrl); + }} + > ${this.renderBookmarkControl(savedSearch, isOwner)} ${isOwner ? html` diff --git a/frontend/src/static/js/components/webstatus-saved-search-share-dialog.ts b/frontend/src/static/js/components/webstatus-saved-search-share-dialog.ts new file mode 100644 index 000000000..8e02c6873 --- /dev/null +++ b/frontend/src/static/js/components/webstatus-saved-search-share-dialog.ts @@ -0,0 +1,239 @@ +/** + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {LitElement, TemplateResult, css, html} from 'lit'; +import {customElement, property} from 'lit/decorators.js'; +import {UserSavedSearch} from '../utils/constants.js'; +import {Toast} from '../utils/toast.js'; +import {SHARED_STYLES} from '../css/shared-css.js'; + +@customElement('webstatus-saved-search-share-dialog') +export class WebstatusSavedSearchShareDialog extends LitElement { + @property({type: Object}) + savedSearch?: UserSavedSearch; + + @property({type: String}) + shareableUrl: string = ''; + + get effectiveUrl(): string { + try { + const url = new URL(this.shareableUrl); + url.searchParams.set('subscribe', 'true'); + return url.toString(); + } catch { + // Fallback if shareableUrl is relative or invalid. + const separator = this.shareableUrl.includes('?') ? '&' : '?'; + return `${this.shareableUrl}${separator}subscribe=true`; + } + } + + static styles = [ + SHARED_STYLES, + css` + sl-dialog::part(body) { + padding-top: 0; + } + + .qr-code-box { + border: 1px solid var(--border-color, #ccc); + border-radius: var(--border-radius, 4px); + padding: var(--content-padding-half) var(--content-padding) + var(--content-padding-quarter) var(--content-padding); + display: flex; + flex-direction: column; + align-items: center; + gap: var(--content-padding); + margin: 0 auto; + margin-bottom: var(--content-padding-quarter); + width: 25em; + } + + .qr-code-box h3 { + margin: 0.5em; + font-weight: bold; + font-size: 1rem; + } + + .qr-code-box sl-button::part(base) { + padding-bottom: var(--content-padding-quarter); + font-weight: normal; + } + + .link-share-box { + display: grid; + grid-template-columns: 1fr auto; + grid-template-rows: auto auto; + gap: 0; + width: 100%; + border-radius: var(--border-radius); + align-items: stretch; + margin-top: 1em; + } + + .link-share-box h3 { + grid-column: 1; + grid-row: 1; + margin: 0; + font-size: 1rem; + font-weight: bold; + } + + .link-share-box sl-input { + grid-column: 1; + grid-row: 2; + } + + .link-share-box sl-input::part(base) { + border: none; + background-color: transparent; + box-shadow: none; + } + + .link-share-box sl-input::part(input) { + padding-left: 0; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + font-size: 0.875rem; + } + + .link-share-box sl-button { + grid-column: 2; + grid-row: 1 / span 2; + align-self: stretch; + } + `, + ]; + + async openWithContext(savedSearch: UserSavedSearch, shareableUrl: string) { + this.savedSearch = savedSearch; + this.shareableUrl = shareableUrl; + const dialog = this.shadowRoot?.querySelector('sl-dialog'); + if (dialog?.show) await dialog.show(); + } + + async hide() { + const dialog = this.shadowRoot?.querySelector('sl-dialog'); + if (dialog?.hide) await dialog.hide(); + } + + async drawLogoOnCanvas(qrCodeElement: Element) { + if (!qrCodeElement.shadowRoot) return; + const canvas = qrCodeElement.shadowRoot.querySelector('canvas'); + if (!canvas) return; + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + const logo = new Image(); + logo.src = '/public/img/cross.svg'; + await logo.decode(); + + const logoSize = canvas.width * 0.2; + const x = (canvas.width - logoSize) / 2; + const y = (canvas.height - logoSize) / 2; + + ctx.drawImage(logo, x, y, logoSize, logoSize); + } + + saveQRCode() { + const canvas = this.shadowRoot + ?.querySelector('sl-qr-code') + ?.shadowRoot?.querySelector('canvas'); + if (!canvas) return; + const dataURL = canvas.toDataURL('image/png'); + const a = document.createElement('a'); + a.href = dataURL; + a.download = `qr-code-${this.savedSearch?.id}.png`; + a.click(); + } + + async copyToClipboard() { + try { + await navigator.clipboard.writeText(this.effectiveUrl); + await new Toast().toast( + 'Link copied to clipboard', + 'success', + 'info-circle', + ); + } catch (err) { + console.error('Failed to copy: ', err); + await new Toast().toast( + 'Failed to copy link', + 'danger', + 'exclamation-triangle', + ); + } + } + + render(): TemplateResult { + return html` + +
+
+

Share via QR code

+ { + if (e.target instanceof Element) { + void this.drawLogoOnCanvas(e.target); + } + }} + > + + Save QR code + +
+ + +
+
+ `; + } +} + +let shareDialogEl: WebstatusSavedSearchShareDialog | null = null; + +export async function openShareDialog( + savedSearch: UserSavedSearch, + shareableUrl: string, +): Promise { + if (!shareDialogEl) { + shareDialogEl = new WebstatusSavedSearchShareDialog(); + document.body.appendChild(shareDialogEl); + await shareDialogEl.updateComplete; + } + await shareDialogEl.openWithContext(savedSearch, shareableUrl); + return shareDialogEl; +} diff --git a/frontend/src/static/js/components/webstatus-subscribe-button.ts b/frontend/src/static/js/components/webstatus-subscribe-button.ts index a80b00c90..7e0286746 100644 --- a/frontend/src/static/js/components/webstatus-subscribe-button.ts +++ b/frontend/src/static/js/components/webstatus-subscribe-button.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import {LitElement, html, TemplateResult} from 'lit'; +import {LitElement, html, TemplateResult, PropertyValueMap} from 'lit'; import {customElement, property, state} from 'lit/decorators.js'; import {consume} from '@lit/context'; import { @@ -45,9 +45,24 @@ export class SubscribeButton extends LitElement { @property({attribute: false}) toaster = toast; + @property({type: Boolean}) + autoOpen = false; + @state() private _isSubscriptionDialogOpen = false; + protected updated(changedProperties: PropertyValueMap): void { + super.updated(changedProperties); + if ( + (changedProperties.has('autoOpen') || + changedProperties.has('userContext')) && + this.autoOpen && + this.userContext + ) { + this._isSubscriptionDialogOpen = true; + } + } + render(): TemplateResult { if (!this.userContext || !this.savedSearchId) { return html``; diff --git a/frontend/src/static/js/index.ts b/frontend/src/static/js/index.ts index 6ec2910f5..ecd329396 100644 --- a/frontend/src/static/js/index.ts +++ b/frontend/src/static/js/index.ts @@ -29,6 +29,7 @@ import '@shoelace-style/shoelace/dist/components/input/input.js'; import '@shoelace-style/shoelace/dist/components/menu/menu.js'; import '@shoelace-style/shoelace/dist/components/menu-item/menu-item.js'; import '@shoelace-style/shoelace/dist/components/option/option.js'; +import '@shoelace-style/shoelace/dist/components/qr-code/qr-code.js'; import '@shoelace-style/shoelace/dist/components/radio-button/radio-button.js'; import '@shoelace-style/shoelace/dist/components/radio-group/radio-group.js'; import '@shoelace-style/shoelace/dist/components/select/select.js'; diff --git a/frontend/src/static/js/utils/urls.ts b/frontend/src/static/js/utils/urls.ts index 1429be07b..e9cf09c67 100644 --- a/frontend/src/static/js/utils/urls.ts +++ b/frontend/src/static/js/utils/urls.ts @@ -51,6 +51,10 @@ export function getEditSavedSearch(location: {search: string}): boolean { return Boolean(getQueryParam(location.search, 'edit_saved_search')); } +export function getSubscribeToSavedSearch(location: {search: string}): boolean { + return Boolean(getQueryParam(location.search, 'subscribe')); +} + export interface DateRange { start?: Date; end?: Date; @@ -85,6 +89,7 @@ export type QueryStringOverrides = { dateRange?: DateRange; column_options?: string[]; edit_saved_search?: boolean; + subscribe?: boolean; }; /* Given the router location object, return a query string with @@ -161,6 +166,11 @@ function getContextualQueryStringParams( searchParams.set('edit_saved_search', '' + editBookmark); } + const subscribe = 'subscribe' in overrides ? overrides.subscribe : undefined; + if (subscribe) { + searchParams.set('subscribe', '' + subscribe); + } + return searchParams.toString() ? '?' + searchParams.toString() : ''; }