refactor: consolidate browser feature detection into typed hook. Update connect dialog messaging to describe requirement for https when conneecting
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { useBrowserFeatureDetection } from "@app/core/hooks/useBrowserFeatureDetection";
|
||||||
import { BLE } from "@components/PageComponents/Connect/BLE.tsx";
|
import { BLE } from "@components/PageComponents/Connect/BLE.tsx";
|
||||||
import { HTTP } from "@components/PageComponents/Connect/HTTP.tsx";
|
import { HTTP } from "@components/PageComponents/Connect/HTTP.tsx";
|
||||||
import { Serial } from "@components/PageComponents/Connect/Serial.tsx";
|
import { Serial } from "@components/PageComponents/Connect/Serial.tsx";
|
||||||
@@ -28,6 +29,20 @@ export interface TabManifest {
|
|||||||
disabledLink?: string;
|
disabledLink?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export interface NewDeviceProps {
|
||||||
|
open: boolean;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NewDeviceDialog = ({
|
||||||
|
open,
|
||||||
|
onOpenChange,
|
||||||
|
}: NewDeviceProps): JSX.Element => {
|
||||||
|
const { hasRequiredFeatures, isSecureContext, missingFeatures } = useBrowserFeatureDetection();
|
||||||
|
console.log(missingFeatures);
|
||||||
|
|
||||||
const tabs: TabManifest[] = [
|
const tabs: TabManifest[] = [
|
||||||
{
|
{
|
||||||
label: "HTTP",
|
label: "HTTP",
|
||||||
@@ -38,29 +53,23 @@ const tabs: TabManifest[] = [
|
|||||||
{
|
{
|
||||||
label: "Bluetooth",
|
label: "Bluetooth",
|
||||||
element: BLE,
|
element: BLE,
|
||||||
disabled: !navigator.bluetooth,
|
disabled: missingFeatures.includes("Web Bluetooth"),
|
||||||
disabledMessage:
|
disabledMessage:
|
||||||
"Web Bluetooth is currently only supported by Chromium-based browsers",
|
"Web Bluetooth is currently only supported by Chromium-based browsers",
|
||||||
disabledLink:
|
disabledLink:
|
||||||
"https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API#browser_compatibility",
|
"https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API#browser_compatibility"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Serial",
|
label: "Serial",
|
||||||
element: Serial,
|
element: Serial,
|
||||||
disabled: !navigator.serial,
|
disabled: missingFeatures.includes("Web Serial"),
|
||||||
disabledMessage:
|
disabledMessage:
|
||||||
"WebSerial is currently only supported by Chromium based browsers: https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API#browser_compatibility",
|
"Web Serial is currently only supported by Chromium based browsers",
|
||||||
|
disabledLink: "https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API#browser_compatibility",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
export interface NewDeviceProps {
|
|
||||||
open: boolean;
|
|
||||||
onOpenChange: (open: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const NewDeviceDialog = ({
|
|
||||||
open,
|
|
||||||
onOpenChange,
|
|
||||||
}: NewDeviceProps): JSX.Element => {
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
@@ -92,7 +101,21 @@ export const NewDeviceDialog = ({
|
|||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
{(!navigator.bluetooth || !navigator.serial) && (
|
{!isSecureContext && (
|
||||||
|
<>
|
||||||
|
<Subtle>
|
||||||
|
Web Bluetooth and Web Serial require using a HTTPS connection or to localhost.
|
||||||
|
</Subtle>
|
||||||
|
<Subtle>
|
||||||
|
Read more:
|
||||||
|
<Link href="https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts">
|
||||||
|
Secure Contexts
|
||||||
|
</Link>
|
||||||
|
</Subtle>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!hasRequiredFeatures && (
|
||||||
<>
|
<>
|
||||||
<Subtle>
|
<Subtle>
|
||||||
Web Bluetooth and Web Serial are currently only supported by
|
Web Bluetooth and Web Serial are currently only supported by
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
type Feature = 'Web Bluetooth' | 'Web Serial';
|
||||||
|
type FeatureKey = 'bluetooth' | 'serial';
|
||||||
|
|
||||||
|
interface BrowserFeatureDetection {
|
||||||
|
hasRequiredFeatures: boolean;
|
||||||
|
missingFeatures: Feature[];
|
||||||
|
isSecureContext: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const featureLabels: Record<FeatureKey, Feature> = {
|
||||||
|
bluetooth: 'Web Bluetooth',
|
||||||
|
serial: 'Web Serial'
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useBrowserFeatureDetection(): BrowserFeatureDetection {
|
||||||
|
const { bluetooth, serial } = navigator;
|
||||||
|
const isSecureContext = window.location.protocol === 'https:' ||
|
||||||
|
window.location.hostname === 'localhost';
|
||||||
|
|
||||||
|
const features = {
|
||||||
|
bluetooth,
|
||||||
|
serial
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
hasRequiredFeatures: Object.values(features).every(Boolean),
|
||||||
|
missingFeatures: Object.entries(features)
|
||||||
|
.filter(([_, supported]) => !supported)
|
||||||
|
.map(([feature]) => featureLabels[feature as FeatureKey]),
|
||||||
|
isSecureContext
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user