diff --git a/package-lock.json b/package-lock.json index 2f5e80e6d3e7f99a79d99ea1475af7cd887dc4ec..fc4c9a0c78e183b697c7676f99338c1815c4b1f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,7 @@ "requires": true, "packages": { "": { - "version": "0.3.11", + "version": "0.4.0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -13,6 +13,7 @@ "@emotion/styled": "^11.11.0", "@monaco-editor/react": "^4.6.0", "@mui/joy": "^5.0.0-beta.24", + "@mux/mux-player-react": "^2.9.0", "@rjsf/core": "^5.15.1", "@rjsf/utils": "^5.15.1", "@rjsf/validator-ajv8": "^5.15.1", @@ -3656,6 +3657,59 @@ } } }, + "node_modules/@mux/mux-player": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@mux/mux-player/-/mux-player-2.9.0.tgz", + "integrity": "sha512-4oRurMYhVsCxXrbkR+N9rnJAcpvVDbvE2aFM5BJ00PpcXDTvhZ2wVWpmrGGaHm1hFunfAfDUfPawt5SXk1C/nQ==", + "dependencies": { + "@mux/mux-video": "0.20.1", + "@mux/playback-core": "0.25.1", + "media-chrome": "~3.2.5" + } + }, + "node_modules/@mux/mux-player-react": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@mux/mux-player-react/-/mux-player-react-2.9.0.tgz", + "integrity": "sha512-QEpjhsJISpqL5wX9kN7qxueqASErw4ShTLtjb2ZoTQUbYglGq8/QdVyRyjPLCnHQ6Og3jxA9FvSwr29+HdSAYA==", + "dependencies": { + "@mux/mux-player": "2.9.0", + "@mux/playback-core": "0.25.1", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18 || ^19", + "react": "^17.0.2 || ^18 || ^19", + "react-dom": "^17.0.2 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mux/mux-video": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@mux/mux-video/-/mux-video-0.20.1.tgz", + "integrity": "sha512-q3tvu0L4iGpisp3AVNeef3FrR5dMiwsYb8WVuvkFjQvSDNyIaiMwnjLriG7VJR5Oc7sNXPl/RBsXFgi3V7SknA==", + "dependencies": { + "@mux/playback-core": "0.25.1", + "castable-video": "~1.0.9", + "custom-media-element": "~1.3.1", + "media-tracks": "~0.3.2" + } + }, + "node_modules/@mux/playback-core": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@mux/playback-core/-/playback-core-0.25.1.tgz", + "integrity": "sha512-BqGS11gn1CeKcR+aQ7LfawXLOjzf7bGkD1rBli/hfJYYqX6Br4fCpzpiBCOHOyWA2hc5H4LCTCLLjt2sARkTpw==", + "dependencies": { + "hls.js": "~1.5.11", + "mux-embed": "~5.2.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -7133,6 +7187,14 @@ } ] }, + "node_modules/castable-video": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/castable-video/-/castable-video-1.0.10.tgz", + "integrity": "sha512-tJgUv+8/zE191y8EKojvB0eKIyKA9obIttd6Wpdm6x2qBmuwZ7wDgzVCSmf5cN2v9jBiuu0s7O5poz8a8cFX/w==", + "dependencies": { + "custom-media-element": "~1.3.2" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -8315,6 +8377,11 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "node_modules/custom-media-element": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/custom-media-element/-/custom-media-element-1.3.2.tgz", + "integrity": "sha512-nDyMobZgoAVqz7mA8rsn7i1/6bjH6N9ab2Ge7LyyNxrvxAq7zQJPg8i3u2VH7wEB+Y1T1+C3/h1G774/D+ZLag==" + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -11895,6 +11962,11 @@ "node": "*" } }, + "node_modules/hls.js": { + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.5.13.tgz", + "integrity": "sha512-xRgKo84nsC7clEvSfIdgn/Tc0NOT+d7vdiL/wvkLO+0k0juc26NRBPPG1SfB8pd5bHXIjMW/F5VM8VYYkOYYdw==" + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -14999,6 +15071,16 @@ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "dev": true }, + "node_modules/media-chrome": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/media-chrome/-/media-chrome-3.2.5.tgz", + "integrity": "sha512-tTsgS7x77Bn4p/wca/Si/7A+Q3z9DzKq0SOkroQvrNMXBVyQasMayDcsKg5Ur5NGsymZfttnJi7tXvVr/tPj8g==" + }, + "node_modules/media-tracks": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/media-tracks/-/media-tracks-0.3.3.tgz", + "integrity": "sha512-9P2FuUHnZZ3iji+2RQk7Zkh5AmZTnOG5fODACnjhCVveX1McY3jmCRHofIEI+yTBqplz7LXy48c7fQ3Uigp88w==" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -16061,6 +16143,11 @@ "multicast-dns": "cli.js" } }, + "node_modules/mux-embed": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/mux-embed/-/mux-embed-5.2.1.tgz", + "integrity": "sha512-NukHw91xeEVDBeXVDBpi2BvXNix7gSuvdtyvOph5yR/ROn1hHbTlcYWoKQyCyJX9frsF00UROEul+S8wPzU3aQ==" + }, "node_modules/namespace-emitter": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz", @@ -22008,4 +22095,4 @@ } } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index da584c21631911227e149043b142ffe8153ed1b6..8760a2d215f758e86ae5c2ee415fe5e7a24c3e44 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "@emotion/styled": "^11.11.0", "@monaco-editor/react": "^4.6.0", "@mui/joy": "^5.0.0-beta.24", + "@mux/mux-player-react": "^2.9.0", "@rjsf/core": "^5.15.1", "@rjsf/utils": "^5.15.1", "@rjsf/validator-ajv8": "^5.15.1", @@ -290,4 +291,4 @@ ], "logLevel": "quiet" } -} \ No newline at end of file +} diff --git a/src/renderer/components/Connect/LocalConnection.tsx b/src/renderer/components/Connect/LocalConnection.tsx index 0cab211a1d1dd19aa0638cc2b3771e9d0a627480..44d07c1464e090a999fc89c6f74c6d58ca349c82 100644 --- a/src/renderer/components/Connect/LocalConnection.tsx +++ b/src/renderer/components/Connect/LocalConnection.tsx @@ -18,6 +18,7 @@ import { useCheckLocalConnection } from 'renderer/lib/transformerlab-api-sdk'; import { FaApple } from 'react-icons/fa6'; import LargeTooltip from './LargeTooltip'; +import OneTimePopup from '../Shared/OneTimePopup'; // Runs a callback every delay milliseconds, up to repetitions times. // If the callback returns true, the interval is cleared. diff --git a/src/renderer/components/Connect/LoginModal.tsx b/src/renderer/components/Connect/LoginModal.tsx index 26d33ee4da612be9cbe2006966f03e92df9a85cb..147f0eca193eb353e109e0c6b457a3f564b3669b 100644 --- a/src/renderer/components/Connect/LoginModal.tsx +++ b/src/renderer/components/Connect/LoginModal.tsx @@ -12,13 +12,9 @@ import { Alert, Checkbox, CircularProgress, - DialogContent, - DialogTitle, Divider, FormHelperText, Link, - ModalClose, - Sheet, Tab, TabList, TabPanel, @@ -27,9 +23,10 @@ import { import { apiHealthz } from '../../lib/transformerlab-api-sdk'; import { useState } from 'react'; -import { connect } from 'http2'; import LocalConnection from './LocalConnection'; -import { InfoIcon } from 'lucide-react'; +import OneTimePopup from '../Shared/OneTimePopup'; + +import MuxPlayer from '@mux/mux-player-react'; export default function LoginModal({ setServer, @@ -107,6 +104,30 @@ export default function LoginModal({ height: '90vh', }} > + <OneTimePopup title="Welcome To Transformer Lab"> + <> + <p> + To start using Transformer Lab, you can either install the + Transformer Lab engine on your local machine or connect to a + remote computer where the engine is already running. + </p> + <MuxPlayer + streamType="on-demand" + playbackId="2EK002M4GdFF32RCeOVIqEhas02GfUmu01UCSjuxqwRmcI" + metadataVideoTitle="Placeholder (optional)" + metadataViewerUserId="Placeholder (optional)" + primaryColor="#FFFFFF" + secondaryColor="#000000" + style={{ maxWidth: '300px', alignSelf: 'center' }} + autoPlay + /> + <p> + Installing the engine takes time but by the end of the process, + you will have all the components of a poweful LLM workstation at + your disposal. + </p> + </> + </OneTimePopup> <Tabs aria-label="Basic tabs" defaultValue={0} diff --git a/src/renderer/components/Shared/OneTimePopup.tsx b/src/renderer/components/Shared/OneTimePopup.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3c9caa2d7e67ca63012adf606bf8bac05c1f849e --- /dev/null +++ b/src/renderer/components/Shared/OneTimePopup.tsx @@ -0,0 +1,53 @@ +import { + Button, + DialogContent, + DialogTitle, + Modal, + ModalClose, + ModalDialog, +} from '@mui/joy'; +import React, { useState, useEffect } from 'react'; + +export default function OneTimePopup({ title, children }) { + const [open, setOpen] = useState(true); + + const localStorageKey = 'oneTimePopup' + '#' + title; + + // Check Local Storage if this popup has been shown before: + useEffect(() => { + const hasShownBefore = localStorage.getItem(localStorageKey); + if (hasShownBefore) { + setOpen(false); + } + }, []); + + function handleClose() { + localStorage.setItem(localStorageKey, 'shown'); + setOpen(false); + } + + return ( + <> + <Modal open={open} onClose={() => handleClose()}> + <ModalDialog + variant="soft" + sx={{ width: '50vw', maxHeight: '100%', overflowY: 'hidden' }} + > + <ModalClose /> + <DialogTitle>{title}</DialogTitle> + <DialogContent sx={{ pt: 2, overflowY: 'auto', overflowX: 'hidden' }}> + {children} + </DialogContent>{' '} + <Button + sx={{ width: 'fit-content', alignSelf: 'flex-end', mt: 1 }} + onClick={() => { + handleClose(); + }} + > + Got it + </Button> + </ModalDialog> + </Modal> + </> + ); +} diff --git a/src/renderer/components/TransformerLabSettings.tsx b/src/renderer/components/TransformerLabSettings.tsx index 6cd58f1e8ac4c0a1a064c9e0d1a49ad0ff633471..65960e4054adfcfba40fbb7d8acfe36699949b26 100644 --- a/src/renderer/components/TransformerLabSettings.tsx +++ b/src/renderer/components/TransformerLabSettings.tsx @@ -5,6 +5,7 @@ import Sheet from '@mui/joy/Sheet'; import { Button, CircularProgress, + Divider, FormControl, FormHelperText, FormLabel, @@ -84,8 +85,8 @@ export default function TransformerLabSettings({}) { Save </Button> <FormHelperText> - A Huggingface access token is required in order to access certain models - and datasets (those marked as "Gated"). + A Huggingface access token is required in order to access certain + models and datasets (those marked as "Gated"). </FormHelperText> <FormHelperText> Documentation here: @@ -97,6 +98,23 @@ export default function TransformerLabSettings({}) { </a> </FormHelperText> </FormControl> + <Divider sx={{ mt: 2, mb: 2 }} />{' '} + <Typography level="title-lg" marginBottom={2}> + Application: + </Typography> + <Button + variant="soft" + onClick={() => { + // find and delete all items in local storage that begin with oneTimePopup: + for (var key in localStorage) { + if (key.startsWith('oneTimePopup')) { + localStorage.removeItem(key); + } + } + }} + > + Reset all Tutorial Popup Screens + </Button> </Sheet> </> );