Skip to content
Open
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# AmpliPi Software Releases

# Future Release
* Web App
* Add warning for older versions of the webapp running on newer backends


# 0.4.11
Expand All @@ -9,7 +11,6 @@
* Web App
* Changed caching rules to ensure that users don't get stuck with old versions of the webapp post update


## 0.4.10

* Web App
Expand Down
3 changes: 2 additions & 1 deletion NEW_RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ This project follows [Semantic Versioning](https://semver.org/). Here are some e
- [ ] Update the API by running `scripts/create_spec` script.
- [ ] Create & merge a branch/PR off `main` to bump the version in the CHANGELOG and also using `poetry version ${VERSION}`
- [ ] Checkout main & create a detached HEAD: `git checkout main; git pull; git checkout --detach`
- [ ] Build the webapp in `web` with `npm run build` and force add the changes with `git add -f web/dist; git commit -m "Build web app for release"`
- [ ] CD into `web`, Run `echo "VITE_BACKEND_VERSION=$(poetry version -s)" > .env`
- [ ] Still in `web`, build the webapp with `npm run build` and force add the changes with `git add -f web/dist; git commit -m "Build web app for release"`
- [ ] Tag the changes so we can make a release on GitHub: `git tag -as ${VERSION} -m '' && git push origin ${VERSION}`
- [ ] Make a release using the GitHub interface
- [ ] Use the AmpliPi updater to update to the release
Expand Down
1 change: 1 addition & 0 deletions scripts/deploy
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ poetry version ${git_info}
echo "Building web app"
pushd ../web # Change to web directory
npm install # Install nodejs dependencies
echo "VITE_BACKEND_VERSION=$(poetry version -s)" > .env # Collect the version number and bake it into the frontend
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've learned that Vite can bake environment variables into the compiled webapp if you use a dotenv and prefix the vars with VITE_ so I dynamically grab the poetry version and put it in a .env at build time

npm run build # Build the web app
popd

Expand Down
24 changes: 18 additions & 6 deletions web/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import DisconnectedIcon from "./components/DisconnectedIcon/DisconnectedIcon";
import Browse from "@/pages/Browse/Browse";

import PropTypes from "prop-types";
import AlertBar from "./components/StatusBars/AlertBar";

// holds onto the selectedSource state so that it persists between refreshes
export const usePersistentStore = create(
Expand Down Expand Up @@ -40,6 +41,7 @@ export const useStatusStore = create((set, get) => ({
skipUpdate: false,
loaded: false, // using this instead of (status === null) because it fixes the re-rendering issue
disconnected: true,
alert: {"open": false, "text": "", "onClose": () => {}},
skipNextUpdate: () => {
set({ skipUpdate: true });
},
Expand Down Expand Up @@ -122,6 +124,9 @@ export const useStatusStore = create((set, get) => ({
}
});
},
setAlert: (text, onClose) => {
set({alert: {"open": true, "text": text, "onClose": onClose()}});
},

getSystemState: () => {
fetch("/api")
Expand All @@ -133,6 +138,9 @@ export const useStatusStore = create((set, get) => ({
set({ skipUpdate: false });
} else {
set({ status: s, loaded: true, disconnected: false });
if(s.info.version != import.meta.env.VITE_BACKEND_VERSION){
set({alert: {"open": true, "text": "Your webapp is out of date, closing this message will refresh the page. If this message persists post-refresh, clear your browser cache and try again.", "onClose": () => {window.location.reload();}}});
}
}
});
} else if (res.status == 401) {
Expand Down Expand Up @@ -225,15 +233,19 @@ Page.propTypes = {
};

const App = ({ selectedPage }) => {
const alert = useStatusStore((s) => s.alert);
return (
<div className="app">
<div className="app">
<DisconnectedIcon />
<div className="background-gradient"></div> {/* Used to make sure the background doesn't stretch or stop prematurely on scrollable pages */}
<div className="app-body">
<Page selectedPage={selectedPage} />
</div>
<MenuBar pageNumber={selectedPage} />
<div className="background-gradient">{/* Used to make sure the background doesn't stretch or stop prematurely on scrollable pages */}</div>
<div className="alert">
<AlertBar open={alert["open"]} text={alert["text"]} onClose={() => {alert["open"] == false; alert["onClose"]();}}/>
</div>
<div className="app-body">
<Page selectedPage={selectedPage} />
</div>
<MenuBar pageNumber={selectedPage} />
</div>
);
};
App.propTypes = {
Expand Down
18 changes: 17 additions & 1 deletion web/src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
}

// unused

.app-container {
display: flex;
width: 100%;
Expand All @@ -31,10 +32,25 @@
padding-bottom: general.$navbar-height;
}


.alert{
position: fixed;
top: 10px;
left: 10px;
right: 10px;
z-index: 2;
}

@media (general.$is-landscape){
// Themed scrollbar is overridden by 90% of mobile apps and browsers, but only partially overridden by one (andorid app)
// Themed scrollbar is overridden by 90% of mobile apps and browsers, but only partially overridden by one (android app)
// This still looks better on desktop, so gate it to only being on desktop without running the risk for the weird android app situation

.alert{
left: 25vw;
right: 25vw;
top: 10px;
}

.pill-scrollbar {
max-height: inherit;
overflow-y: auto;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@ const StreamModal = ({ stream, onClose, apply, del }) => {
renderAnimationState={renderAlertAnimation}
open={hasError}
onClose={() => {setHasError(false);}}
status={false}
text={errorMessage}
/>
}
Expand Down
23 changes: 13 additions & 10 deletions web/src/components/StatusBars/AlertBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Alert from "@mui/material/Alert";
export default function AlertBar(props) {
const {
open,
status,
success,
text,
onClose,
renderAnimationState,
Expand All @@ -19,34 +19,37 @@ export default function AlertBar(props) {
if(alertRef.current != null){
const alertComp = alertRef.current;
alertComp.classList.remove("error");
if(status == false){
if(!success){
alertComp.offsetWidth;
alertComp.classList.add("error");
}
}
}, [status, renderAnimationState]);
}, [success, renderAnimationState]);

if(open){
const [closedText, setClosedText] = React.useState(""); // If a user has closed a given message, don't show it again until another message tries to appear

if(open && text != closedText){
return(
<Alert
ref={alertRef}
onClose={onClose}
severity={status ? "success" : "error"}
onClose={() => {onClose(); setClosedText(text);}}
severity={success ? "success" : "error"}
variant="filled"
style={{width: "100%",}}
>
{text}
</Alert>
)
);
}
};
}
AlertBar.propTypes = {
open: PropTypes.bool.isRequired,
status: PropTypes.bool.isRequired,
success: PropTypes.bool,
text: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
renderAnimationState: PropTypes.number,
};
AlertBar.defaultProps = {
success: false,
renderAnimationState: 1,
}
};
2 changes: 1 addition & 1 deletion web/src/components/StatusBars/ResponseBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function ResponseBar(props) {
return(
<StatusBar
open={open}
status={success}
success={success}
text={text.current}
onClose={() => {setOpen(false);}}
/>
Expand Down
34 changes: 23 additions & 11 deletions web/src/components/StatusBars/StatusBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,50 @@ import PropTypes from "prop-types";
import "./StatusBars.scss";
import Snackbar from "@mui/material/Snackbar";

import Alert from "@mui/material/Alert"
import Alert from "@mui/material/Alert";

export default function StatusBar(props) {
const {
open,
status,
success,
text,
onClose,
anchorOrigin,
autoHideDuration,
} = props;

const [closedText, setClosedText] = React.useState(""); // If a user has closed a given message, don't show it again until another message tries to appear

return(
<Snackbar
className="snackbar"
autoHideDuration={3000}
anchorOrigin={{vertical: "bottom", horizontal: "left"}}
open={open}
onClose={onClose}
autoHideDuration={autoHideDuration != 0 ? autoHideDuration : 999999999999999}
anchorOrigin={anchorOrigin}
open={open && closedText != text}
onClose={() => {onClose(); setClosedText(text);}}
>
<Alert // Cannot be AlertBar due to React rendering throwing errors despite it being the same thing
onClose={onClose}
severity={status ? "success" : "error"}
onClose={() => {onClose(); setClosedText(text);}}
severity={success ? "success" : "error"}
variant="filled"
style={{width: "100%"}}
>
{text}
</Alert>
</Snackbar>
)
};
);
}
StatusBar.propTypes = {
open: PropTypes.bool.isRequired,
status: PropTypes.bool.isRequired,
success: PropTypes.bool,
text: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
autoHideDuration: PropTypes.number,
anchorOrigin: PropTypes.object,
};
StatusBar.defaultProps = {
success: false,
autoHideDuration: 3000,
anchorOrigin: {vertical: "bottom", horizontal: "left"},
};

1 change: 0 additions & 1 deletion web/src/pages/Browse/Browse.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ const Browse = () => {
</List>
<StatusBar
open={errorOpen}
status={false}
text={errorText.current}
onClose={()=>{setErrorOpen(false);}}
/>
Expand Down
6 changes: 3 additions & 3 deletions web/src/pages/Home/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const Home = () => {

const [showStatus, setShowStatus] = React.useState(false);
const statusText = React.useRef("");
const status = React.useRef(true);
const success = React.useRef(true);

let nextAvailableSource = null;
let cards = [];
Expand Down Expand Up @@ -145,10 +145,10 @@ const Home = () => {
)}
{presetsModalOpen && (
<PresetsModal
onApply={(state, text) => {status.current = state; statusText.current = text; setShowStatus(true);}}
onApply={(state, text) => {success.current = state; statusText.current = text; setShowStatus(true);}}
onClose={() => setPresetsModalOpen(false)} />
)}
<StatusBar open={showStatus} status={status.current} text={statusText.current} onClose={() => {setShowStatus(false);}} />
<StatusBar open={showStatus} success={success.current} text={statusText.current} onClose={() => {setShowStatus(false);}} />
</div>
);
};
Expand Down
Loading