diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index f994bab..54dfbed 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -161,5 +161,14 @@ "useDefaultLocationExplainer": { "message": "This is always the same location as selected in your Mozilla VPN desktop app.", "description": "Explanation of what 'Use default Mozilla VPN Location' means." + }, + "headerUnsupportedOSMessage": { + "message": "Unsupported platform" + }, + "bodyUnsupportedOSMessage": { + "message": "Currently, the Mozilla VPN extension is only available on Windows devices." + }, + "footnoteUnsupportedOSMessage": { + "message": "We’re working to bring support to macOS and Linux soon!" } } diff --git a/src/assets/img/message-os.svg b/src/assets/img/message-os.svg new file mode 100644 index 0000000..43124ce --- /dev/null +++ b/src/assets/img/message-os.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/background/vpncontroller/vpncontroller.js b/src/background/vpncontroller/vpncontroller.js index a584a91..7613bb9 100644 --- a/src/background/vpncontroller/vpncontroller.js +++ b/src/background/vpncontroller/vpncontroller.js @@ -43,6 +43,7 @@ export class VPNController extends Component { state: PropertyType.Bindable, postToApp: PropertyType.Function, isolationKey: PropertyType.Bindable, + featureList: PropertyType.Bindable, }; get state() { @@ -54,6 +55,10 @@ export class VPNController extends Component { get isExcluded() { return this.#isExcluded; } + /** @type {IBindable} */ + get featureList() { + return this.#mFeaturelist; + } async initNativeMessaging() { log("initNativeMessaging"); @@ -150,6 +155,11 @@ export class VPNController extends Component { this.#increaseIsolationKey(); } break; + case "featurelist": + this.#mFeaturelist.set({ + ...new FeatureFlags(), + ...response.featurelist, + }); default: throw Error("Unexpeted Message type: " + response.t); } @@ -171,6 +181,7 @@ export class VPNController extends Component { this.postToApp("status"); this.postToApp("servers"); this.postToApp("disabled_apps"); + this.postToApp("featurelist"); }); return; } @@ -203,6 +214,8 @@ export class VPNController extends Component { // @ts-ignore #mServers = property([]); + #mFeaturelist = property(new FeatureFlags()); + #isExcluded = property(false); } @@ -323,3 +336,8 @@ export function fromVPNStatusResponse( } return; } + +export class FeatureFlags { + localProxy = true; + webExtension = true; +} diff --git a/src/components/prefab-screens.js b/src/components/prefab-screens.js index 7a9380b..d3d87e8 100644 --- a/src/components/prefab-screens.js +++ b/src/components/prefab-screens.js @@ -11,6 +11,8 @@ const open = (url) => { url, }); }; +const sumoLink = + "https://support.mozilla.org/products/firefox-private-network-vpn"; const defineMessageScreen = ( tag, @@ -20,8 +22,7 @@ const defineMessageScreen = ( primaryAction, onPrimaryAction, secondarAction = tr("getHelp"), - onSecondaryAction = () => - open("https://support.mozilla.org/products/firefox-private-network-vpn") + onSecondaryAction = () => open(sumoLink) ) => { const body = typeof bodyText === "string" ? html`

${bodyText}

` : bodyText; @@ -85,3 +86,15 @@ defineMessageScreen( open("https://www.mozilla.org/products/vpn/download/"); } ); + +defineMessageScreen( + "unsupported-os-message-screen", + "message-os.svg", + tr("headerUnsupportedOSMessage"), + html` +

${tr("bodyUnsupportedOSMessage")}

+

${tr("footnoteUnsupportedOSMessage")}

+ `, + null, + null +); diff --git a/src/ui/browserAction/backend.js b/src/ui/browserAction/backend.js index 2c7a1d0..b077e9c 100644 --- a/src/ui/browserAction/backend.js +++ b/src/ui/browserAction/backend.js @@ -14,6 +14,7 @@ import { getExposedObject } from "../../shared/ipc.js"; * Manually define the types for convinence, please update if making changes :) * * @typedef {Object} vpnController + * @property {IBindable} featureList - A bindable property that contains the list or configuration of VPN servers. * @property {IBindable} servers - A bindable property that contains the list or configuration of VPN servers. * @property {IBindable} isExcluded - A bindable property that indicates whether the VPN is excluded from certain operations. * @property {IBindable} state - A bindable property representing the current state of the VPN controller (e.g., connected, disconnected). diff --git a/src/ui/browserAction/popup.html b/src/ui/browserAction/popup.html index 1652830..80e7305 100644 --- a/src/ui/browserAction/popup.html +++ b/src/ui/browserAction/popup.html @@ -23,6 +23,9 @@ + diff --git a/src/ui/browserAction/popupConditional.js b/src/ui/browserAction/popupConditional.js index c7905a3..ec371ff 100644 --- a/src/ui/browserAction/popupConditional.js +++ b/src/ui/browserAction/popupConditional.js @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { ConditionalView } from "../../components/conditional-view.js"; +import { propertySum } from "../../shared/property.js"; import { vpnController } from "./backend.js"; export class PopUpConditionalView extends ConditionalView { @@ -12,9 +13,14 @@ export class PopUpConditionalView extends ConditionalView { connectedCallback() { super.connectedCallback(); - vpnController.state.subscribe((s) => { - this.slotName = PopUpConditionalView.toSlotname(s); - }); + propertySum( + vpnController.state, + vpnController.featureList, + (state, features) => { + this.slotName = PopUpConditionalView.toSlotname(state, features); + } + ); + // Messages may dispatch an event requesting to send a Command to the VPN this.addEventListener("requestMessage", (e) => { console.log(`Message requested ${e}`); @@ -29,17 +35,22 @@ export class PopUpConditionalView extends ConditionalView { } /** + * @typedef {import("../../background/vpncontroller/vpncontroller.js").FeatureFlags} FeatureFlags * @typedef {import("../../background/vpncontroller/states.js").VPNState} State * @param {State} state + * @param {FeatureFlags} features * @returns {String} */ - static toSlotname(state) { + static toSlotname(state, features) { if (!state.installed) { return "MessageInstallVPN"; } if (!state.alive) { return "MessageStartVPN"; } + if (!features.webExtension) { + return "MessageOSNotSupported"; + } if (!state.authenticated) { return "MessageSignIn"; }