Welcome to the next generation of the TeddyCloud Administration Frontend!
If you are using this repository for the first time, please refer to the General React Information section first.
You'll need to allow CORS for your teddyCloud instance used for development. The easisiest variant is to set CORS Allow-Originⓘ to *.
Please place an enviroment file '.env.development.local' in the teddycloud_web directory.
VITE_APP_TEDDYCLOUD_API_URL=http://<teddycloud-ip>
VITE_APP_TEDDYCLOUD_WEB_BASE=/web
VITE_APP_TEDDYCLOUD_PORT_HTTPS=3443
VITE_APP_TEDDYCLOUD_PORT_HTTP=3000
SSL_CRT_FILE=./localhost.pem
SSL_KEY_FILE=./localhost-key.pem
VITE_APP_TEDDYCLOUD_PORT_HTTPS and VITE_APP_TEDDYCLOUD_PORT_HTTP should match the ones entered in the package.json. If you don't change them, these are the ones from the example above.
needed for ESP32 Box Flashing section
You need to provide certificates for https. Use for example mkcert. The generated certificates must be stored in projects root path (or adapt the env.development.local file accordingly).
mkcert -install
mkcert localhostYou must also allow unsecure content in chrome (HowTo) to be able to connect to teddycloud server in https context.
If you don't need the ESP32 Box flashing section working, you can adapt the package.json and change the following:
"scripts": {
"start-http": "cross-env PORT=3000 vite",
"start-https": "cross-env HTTPS=true PORT=3443 vite",
"start": "concurrently \"npm run start-http\" \"npm run start-https\"",
"build": "tsc && vite build",
"preview": "vite preview"
},to
"scripts": {
"start": "npm run start",
"build": "tsc && vite build",
"preview": "vite preview"
},Use ./start_dev.sh to start the NPM server in development mode. Be patient, it may take a while.
Be sure your teddyCloud instance is also running.
If you just need the http variant, simply call dotenv -e .env.development.local npm start-http
The TeddyCloud frontend follows a topic-based architecture.
Pages and components are organized by feature domains (e.g. tonies, tonieboxes,settings, community).
Each feature contains its own components, hooks, and modals.
This keeps all relevant code physically close, reduces duplication, and maintains clarity.
This architecture represents the intended structure of the frontend; however, due to legacy code and ongoing migration efforts, not all parts of the project fully adhere to it yet.
If you encounter areas that are not yet aligned with this architecture or appear messy, please feel free to clean them up as part of ongoing improvements.
Location:
src/pages/<topic>/...
Purpose:
- Represent application routes.
- Provide layout and structure (
StyledLayout,StyledSider, breadcrumbs). - Compose topic-specific components.
- Contain minimal logic.
Guidelines:
- Pages should stay thin.
- Do not embed business logic in a Page.
- Let the page assemble layout + feature components + navigation.
Location:
src/components/<topic>/...
Feature areas (e.g. tonies, settings) contain sub-folders for specific features:
src/components/tonies/encoder/...
src/components/settings/notificationlist/...
src/components/tonieboxes/tonieboxeslist/...
Purpose:
- Implement UI behavior for a domain-specific feature.
- Organize related components, hooks, and modals within the same feature folder.
- Keep JSX + view logic here, push non-view logic into hooks.
When to split into a hook?
- When a component grows beyond UI concerns.
- When API logic, state machines, or repeated side effects appear.
Hooks follow the same topic-based structure.
Location examples:
src/components/tonies/encoder/hooks/useEncoder.ts
src/components/settings/notificationlist/hooks/useNotificationsList.ts
Rules:
- Hooks that belong to one feature stay inside that feature’s folder.
- They encapsulate its behavior: API calls, state transitions, validation, etc.
- They are not shared across unrelated domains.
This avoids a global “hooks graveyard”.
Only domain-agnostic, multi-topic hooks belong here:
src/hooks/useDebounce.ts
src/hooks/useMediaQuery.ts
If it is not 100% generic → keep it in the feature folder.
Modals follow the feature they belong to.
Example:
src/components/tonies/filebrowser/modals/CreateDirectoryModal.tsx
Guidelines:
- State (open/close, selected path, etc.) is controlled in the parent component/hook.
- Modal components receive all required data via props.
- Modals should not contain business logic (fetch, validation) unless tightly coupled to the feature.
Generic helpers live in:
src/utils/
Allowed:
- Validators
- Formatter functions
- Encoding helpers
- URL builders
- Type utilities
Not allowed:
- React logic
- State management
- Component-specific utilities
There are no complete guidelines defined currently, only some fragments which you shall read and follow.
The following rules complement the project structure described above.
All changes must be added to the central CHANGELOG.md file.
Whenever you implement a change, add a new entry under the correct version.
If the next version does not yet exist in the changelog, create a new version block and append your changes there.
Reference related GitHub issues or pull requests whenever possible.
We are using the AntD framework. If you add anything new, try to use AntD components. AntD also provides a wide range of icons.
More details can be found here:
When building components, prefer AntD components and patterns over custom HTML whenever possible, to keep the UI consistent.
As we support dark and light themes, do not use hard-coded colors like #000000.
Instead, always use the AntD theme tokens.
If not already added, extend your file like this:
import { theme } from "antd";
...
const { useToken } = theme;
...
export const TonieCard: React.FC<{
overlay: string;
}> = ({ overlay }) => {
const { token } = useToken();
...
}Then you can use:
token.*
// e.g. token.colorTextDisabledThis ensures that your component respects both light and dark themes.
Always use t("...") instead of hard-coded text.
- Add new strings to the English, German, French and Spanish translation JSON files.
- Use meaningful, structured keys (e.g.
settings.notifications.title,tonies.encoder.uploadHint). - Avoid inline strings in JSX, especially in pages and reusable components.
If you need to add a new API request to the TeddyCloud API, please use one of the existing helper methods in src/api/apis/TeddyCloudApi.ts:
apiPostTeddyCloudRawapiPostTeddyCloudFormDataRawapiGetTeddyCloudApiRaw- or any other already existing method in
TeddyCloudApi.ts
If none of the existing methods meet your needs, add the new request to src/api/apis/TeddyCloudApi.ts.
We prefer to have all API requests centralized in this file.
One reason is the upcoming authentication for accessing the API and the possibility to reintroduce generated clients later.
If you need to link to another source, element, or URL, please check if it is already defined in src/constants/urls.ts.
- If it is, use the existing variable instead of hardcoding the URL.
- If it isn’t, consider adding it as a variable in
src/constants/urls.ts.
You may need the same URL more than once; defining it in one place ensures that updates are centralized.
Some URLs already defined (partial list):
tonieboxDefaultImageUrl = "https://cdn.tonies.de/thumbnails/03-0009-i.png"telegramGroupUrl = "https://t.me/toniebox_reverse_engineering"forumUrl = "https://forum.revvox.de/"gitHubUrl = "https://github.com/toniebox-reverse-engineering"wikiUrl = "https://tonies-wiki.revvox.de/docs/tools/teddycloud/"
- Pages: routing and layout per topic, minimal logic.
- Components: topic-specific UI and behavior; move heavy logic into hooks.
- Feature hooks: live next to the components they serve (
src/components/<topic>/<feature>/hooks/). - Shared hooks: only for generic, cross-feature helpers in
src/hooks/. - Modals: in the topic’s component tree, with parent-controlled state.
- Utils: pure helpers without React or domain-specific dependencies.
- Changelog, translations, and design tokens: keep them consistent and up to date.
This combined structure and guideline set should be followed for all new code and refactorings.
As the img_unknown.png is part of the teddycloud server, normally it's not shown in the running dev environment. To solve that you can do the following:
-
Just add
img_unknown.pngto the/publicfolder. -
Restart the dev environment.
After these steps, the img_unknown.png should be shown. The file is already part of the file .gitignore so you do not have to care about accidentially committing this file.
Sometimes it happens, that the dev environment unexpected crashes. Even after a new start it can crash immediatly. To solve that problem, you can delete the node_modules folder and call npm install again. Then the node_modules will be reloaded and you should be able to restart the dev environment.
Ideally, the TeddyCloudApi.ts should be generated using OpenApiTools with the swagger.yaml. However, it was actually changed manually and new API functions were added directly. This should be revised in the future. Until then, you should NOT generate the API with the OpenApiTools, as this will break the frontend.
Due to security reasons we removed "@openapitools/openapi-generator-cli" from the devDependencies completely. If you want to refactor the manually changed api functions and bring back support for OpenApiTools, add it and the following in the package.json:
"scripts": {
...
"api:generate": "rm -rf ./src/api && openapi-generator-cli generate -i ./api/swagger.yaml -g typescript-fetch -o ./src/api --additional-properties=typescriptThreePlus=true"
...
}This project was bootstrapped with Vite.
You have node.js and python installed.
sudo apt install python3-dotenv-cli
pip install python-dotenv
followed by
pip install "python-dotenv[cli]"
You need to install cross-env:
npm install --save-dev cross-env
In the project directory, you can run:
Runs the app in the development mode.
Open http://localhost:3000 to view the http variant in the browser.
Open https://localhost:3443 to view the https variant in the browser.
The page will reload if you make edits.
You will also see any lint errors in the console.
If you changed the default ports, adapt the links above accordingly.
Builds the app for production to the build folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.
Your app is ready to be deployed!
See the section about deployment for more information.
After building the app, you can test the optimized (minified) production build using this command. Unlike React’s development mode, which enables features such as hot reloading, detailed error overlays, and repeated API calls for strict mode checks, the preview mode runs the app exactly as it will behave in production.
This means:
- API calls are executed only once (no double-invocation from React Strict Mode)
- Performance reflects the real-world production setup
- You can verify that your build works correctly before deployment
You can learn more in the Vite documentation.
To learn React, check out the React documentation.
The Open Toniebox Guide ([teddycloud]/tonieboxes/boxsetup/openboxguide / src\pages\tonieboxes\boxsetup\OpenBoxGuidePage.tsx) is based on the following two excellent guides from iFixIt.com:
- [iFixIt[1]] Toniebox Opening Procedure
- [iFixIt[2]] Toniebox Teardown
Both guides were originally written and illustrated by Tobias Isakeit, who also created all the images used here.
Special thanks to Tobias for providing such clear and detailed instructions!
The icons used are from here:
Thanks for the original authors for these great icons.
The country flags are derived from here:
Thanks to Nikolay Kuchumov for creating this flag collection!