Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions e2e/scripts/st_set_favicon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2018-2020 Streamlit Inc.
#
# 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 streamlit as st

st.beta_set_favicon(":shark:")
17 changes: 17 additions & 0 deletions e2e/scripts/st_set_page_title.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2018-2020 Streamlit Inc.
#
# 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 streamlit as st

st.beta_set_page_title("Heya, world?")
30 changes: 30 additions & 0 deletions e2e/specs/st_set_favicon.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @license
* Copyright 2018-2020 Streamlit Inc.
*
* 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.
*/

/// <reference types="cypress" />

describe("st.set_favicon", () => {
before(() => {
cy.visit("http://localhost:3000/");
});

it("sets the page favicon", () => {
cy.get("link[rel='shortcut icon']")
.invoke("attr", "href")
.should("eq", "https://twemoji.maxcdn.com/2/72x72/1f988.png");
});
});
28 changes: 28 additions & 0 deletions e2e/specs/st_set_page_title.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @license
* Copyright 2018-2020 Streamlit Inc.
*
* 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.
*/

/// <reference types="cypress" />

describe("st.set_page_title", () => {
before(() => {
cy.visit("http://localhost:3000/");
});

it("sets the page title", () => {
cy.title().should("eq", "Heya, world? · Streamlit");
});
});
14 changes: 14 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import {
Initialize,
ISessionState,
NewReport,
ReportProperties,
SessionEvent,
} from "autogen/proto"

Expand All @@ -72,6 +73,8 @@ import "assets/css/header.scss"
import { UserSettings } from "components/core/StreamlitDialog/UserSettings"
import { ComponentRegistry } from "./components/widgets/CustomComponent"

import { handleFavicon } from "components/elements/Favicon"

import withScreencast, {
ScreenCastHOC,
} from "./hocs/withScreencast/withScreencast"
Expand Down Expand Up @@ -265,6 +268,8 @@ export class App extends PureComponent<Props, State> {
this.handleNewReport(newReportMsg),
delta: (deltaMsg: Delta) =>
this.handleDeltaMsg(deltaMsg, msgProto.metadata),
updateReportProperties: (propertiesMsg: ReportProperties) =>
this.handleReportProperties(propertiesMsg),
reportFinished: (status: ForwardMsg.ReportFinishedStatus) =>
this.handleReportFinished(status),
uploadReportProgress: (progress: string | number) =>
Expand Down Expand Up @@ -646,6 +651,15 @@ export class App extends PureComponent<Props, State> {
}
}

handleReportProperties(propertiesMsg: ReportProperties): void {
if (propertiesMsg.title) {
document.title = `${propertiesMsg.title} · Streamlit`
}
if (propertiesMsg.favicon) {
handleFavicon(propertiesMsg.favicon)
}
}

/**
* Used by e2e tests to test disabling widgets
*/
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/components/core/Block/Block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ const DeckGlChart = React.lazy(() =>
const DeckGlJsonChart = React.lazy(() =>
import("components/elements/DeckGlJsonChart/")
)
const Favicon = React.lazy(() => import("components/elements/Favicon/"))
const GraphVizChart = React.lazy(() =>
import("components/elements/GraphVizChart/")
)
Expand Down Expand Up @@ -193,7 +192,7 @@ class Block extends PureComponent<Props> {
)

const elementType = element.get("type")
const isHidden = elementType === "empty" || elementType === "favicon"
const isHidden = elementType === "empty"
const enable = this.shouldComponentBeEnabled(isHidden)
const isStale = this.isComponentStale(enable, reportElement)
const className = Block.getClassNames(isStale, isHidden)
Expand Down Expand Up @@ -280,7 +279,6 @@ class Block extends PureComponent<Props> {
exception: (el: SimpleElement) => (
<ExceptionElement element={el} width={width} />
),
favicon: (el: SimpleElement) => <Favicon element={el} />,
graphvizChart: (el: SimpleElement) => (
<GraphVizChart element={el} index={index} width={width} />
),
Expand Down
78 changes: 13 additions & 65 deletions frontend/src/components/elements/Favicon/Favicon.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,7 @@
* limitations under the License.
*/

import React from "react"
import { mount } from "enzyme"
import { fromJS } from "immutable"

import { Favicon, Props } from "./Favicon"

const getProps = (elementProps: Record<string, unknown> = {}): Props => ({
element: fromJS({
url: "https://streamlit.io/path/to/favicon.png",
...elementProps,
}),
})

// Overwrite bounding box code for testing (https://stackoverflow.com/a/52146902)
const mockedRect = {
x: 0,
y: 0,
bottom: 0,
left: 0,
right: 0,
top: 0,
width: 10,
height: 10,
toJSON: () => "",
}
const originalGetBBox = SVGElement.prototype.getBBox
beforeEach(() => (SVGElement.prototype.getBBox = () => mockedRect))
afterEach(() => (SVGElement.prototype.getBBox = originalGetBBox))
import { handleFavicon } from "./Favicon"

function getFaviconHref(): string {
const faviconElement: HTMLLinkElement | null = document.querySelector(
Expand All @@ -53,61 +26,36 @@ function getFaviconHref(): string {

document.head.innerHTML = `<link rel="shortcut icon" href="default.png">`

const PIZZA_TWEMOJI_URL = "https://twemoji.maxcdn.com/2/72x72/1f355.png"

test("is set up with the default favicon", () => {
expect(getFaviconHref()).toBe("http://localhost/default.png")
})

describe("Favicon element", () => {
it("renders without crashing", () => {
const props = getProps()
const wrapper = mount(<Favicon {...props} />)

expect(wrapper.find(".stHidden")).toBeTruthy()
})

it("should set the favicon in the DOM", () => {
const props = getProps()
mount(<Favicon {...props} />)

handleFavicon("https://streamlit.io/path/to/favicon.png")
expect(getFaviconHref()).toBe("https://streamlit.io/path/to/favicon.png")
})

it("should accept /media urls from backend", () => {
const props = getProps({ url: "/media/1234567890.png" })
mount(<Favicon {...props} />)

handleFavicon("/media/1234567890.png")
expect(getFaviconHref()).toBe("http://localhost/media/1234567890.png")
})

const PIZZA_EMOJI_SVG = `data:image/svg+xml,
<svg version="1.2" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<text
style="transform: translate(50%, 50%) scale(10)"
dominant-baseline="central"
text-anchor="middle">
%F0%9F%8D%95
</text>
</svg>`.replace(/\n/g, "")

it("should accept emojis directly", () => {
const props = getProps({ url: "🍕" })
mount(<Favicon {...props} />)

expect(getFaviconHref()).toBe(PIZZA_EMOJI_SVG)
handleFavicon("🍕")
expect(getFaviconHref()).toBe(PIZZA_TWEMOJI_URL)
})

it("should accept emoji shortcodes", () => {
const props = getProps({ url: ":pizza:" })
mount(<Favicon {...props} />)

expect(getFaviconHref()).toBe(PIZZA_EMOJI_SVG)
handleFavicon(":pizza:")
expect(getFaviconHref()).toBe(PIZZA_TWEMOJI_URL)
})

it("should change the favicon when the props change", () => {
const props = getProps()
const wrapper = mount(<Favicon {...props} />)
wrapper.setProps(getProps({ url: "🍕" }))

expect(getFaviconHref()).toBe(PIZZA_EMOJI_SVG)
it("should update the favicon when it changes", () => {
handleFavicon("/media/1234567890.png")
handleFavicon(":pizza:")
expect(getFaviconHref()).toBe(PIZZA_TWEMOJI_URL)
})
})
Loading