Compare commits

...

1079 Commits

Author SHA1 Message Date
Pujit Mehrotra
e861e44973 fix: build-web workflow 2025-01-21 14:23:11 -05:00
Pujit Mehrotra
81c953b68c add tw plugins to web 2025-01-21 14:13:28 -05:00
Pujit Mehrotra
de916d2338 hack(ui): force preservation of tailwind plugins 2025-01-21 12:42:11 -05:00
Pujit Mehrotra
f81b59a83a chore: mv tw plugins to dependencies 2025-01-17 13:35:22 -05:00
Pujit Mehrotra
83a4f61961 chore(ui): add typescript tailwind config to build artifact 2025-01-17 12:34:26 -05:00
Pujit Mehrotra
99c3cc633b chore(ui): expose & use typescript tailwind config in web 2025-01-17 12:02:12 -05:00
Pujit Mehrotra
44640bae8c fix(ui): tailwind config compatibility & types 2025-01-17 10:57:29 -05:00
Pujit Mehrotra
ebb67210c3 chore: update vulnerable dependencies 2025-01-17 10:56:50 -05:00
Pujit Mehrotra
5b2cbd670a chore(ui): add justfile to simplify setup 2025-01-17 10:54:42 -05:00
Pujit Mehrotra
c163998175 fix(api): retry mothership connection up to 3x before logout (#1069)
* fix(api): retry mothership connection up to 3x before logout

* refactor: add variable for max # of retry attempts
2025-01-16 16:15:58 -05:00
renovate[bot]
4fbbbd7f6a chore(deps): update dependency tailwindcss to v3.4.17 2025-01-16 10:44:52 -05:00
renovate[bot]
203c2b88ac chore(deps): update dependency prettier-plugin-tailwindcss to v0.6.10 2025-01-16 10:44:34 -05:00
renovate[bot]
746d1a8aaa chore(deps): update dependency typescript to v5.7.3 2025-01-16 10:44:14 -05:00
renovate[bot]
c0d3cf5782 fix(deps): update dependency @apollo/client to v3.12.6 2025-01-16 10:44:05 -05:00
renovate[bot]
64d3765a9a fix(deps): update dependency @floating-ui/dom to v1.6.13 2025-01-16 10:43:53 -05:00
Pujit Mehrotra
5dd36d1836 feat(api): graphql sandbox on unraid servers (#1047)
Enables a sandbox at /graphql for developers wanting to interact with the unraid api.

* chore(api): enable introspection by default in deploy-dev script

* refactor(api): load emhttp state during init

so emhttp settings are always available, even at module load time.

* feat(api): add csrf token to graphql playground

* Revert "refactor(api): load emhttp state during init"

* feat(api): use custom apollo plugin to render sandbox
2025-01-16 10:17:09 -05:00
renovate[bot]
4264557789 chore(deps): update dependency @ianvs/prettier-plugin-sort-imports to v4.4.1 2025-01-15 12:49:39 -05:00
renovate[bot]
344b023503 fix(deps): update graphql-tools monorepo 2025-01-15 12:49:23 -05:00
renovate[bot]
0331e24a74 fix(deps): update dependency uuid to v11.0.5 2025-01-15 11:45:04 -05:00
renovate[bot]
2b597f9f02 fix(deps): update nest monorepo to v10.4.15 2025-01-15 11:44:43 -05:00
renovate[bot]
bd31e09bcf fix(deps): update nest-graphql monorepo to v12.2.2 2025-01-15 11:44:34 -05:00
renovate[bot]
6c73cbf4ad chore(deps): update dependency @nuxt/devtools to v1.7.0 2025-01-15 11:44:17 -05:00
renovate[bot]
4b4aadb5f1 chore(deps): update dependency @nuxtjs/tailwindcss to v6.13.1 2025-01-15 11:43:49 -05:00
renovate[bot]
5ddecce21c chore(deps): update dependency @vue/tsconfig to ^0.7.0 2025-01-15 11:43:37 -05:00
Michael Datelle
6669a963af refactor: unraid ui cleanup and migration (#998)
Co-authored-by: Eli Bosley <ekbosley@gmail.com>
Co-authored-by: Pujit Mehrotra <pujit@lime-technology.com>
Co-authored-by: mdatelle <mike@datelle.net>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zack Spear <zackspear@users.noreply.github.com>
2025-01-15 11:15:52 -05:00
Eli Bosley
8d386043ae chore: comment to detail archived count 2025-01-14 18:14:42 -05:00
Eli Bosley
16f00a0d8c feat: update based on review feedback 2025-01-14 18:14:42 -05:00
Eli Bosley
a4e2a77410 feat: sidebar notification count 2025-01-14 18:14:42 -05:00
renovate[bot]
91a9949a5c fix(deps): update dependency @apollo/client to v3.12.6 2025-01-14 16:46:15 -05:00
renovate[bot]
235746c0ba chore(deps): update dependency @types/node to v20.17.13 2025-01-14 16:46:07 -05:00
renovate[bot]
e366cad0a4 fix(deps): update dependency pm2 to v5.4.3 2025-01-14 16:45:59 -05:00
renovate[bot]
83344e05c1 fix(deps): update dependency radix-vue to v1.9.12 2025-01-14 16:45:50 -05:00
renovate[bot]
61ec04cb87 fix(deps): update dependency node-window-polyfill to v1.0.4 2025-01-14 15:20:05 -05:00
renovate[bot]
a947ff14fa fix(deps): update dependency express to v4.21.2 2025-01-14 15:19:55 -05:00
renovate[bot]
5dfd6d5ded fix(deps): update dependency focus-trap to v7.6.4 2025-01-14 15:19:45 -05:00
renovate[bot]
71e2b70678 fix(deps): update dependency got to v14.4.5 2025-01-14 15:19:30 -05:00
renovate[bot]
4daa54cfb5 fix(deps): update dependency graphql-ws to v5.16.2 2025-01-14 15:19:19 -05:00
renovate[bot]
7ef3729769 fix(deps): update dependency openid-client to v6.1.7 2025-01-14 15:18:57 -05:00
renovate[bot]
46a368e1b5 fix(deps): update dependency p-retry to v6.2.1 2025-01-14 15:18:45 -05:00
Pujit Mehrotra
b53bb3f197 fix(api): pm2 start script & limit auto restarts (#1040)
* fix(api): limit auto restarts to 10

so persistent errors (e.g. during server boot) don't cause an infinite
loop that's difficult for users to see

* fix(api): invoke js directly from pm2 instead of npm script

npm script wraps it in a child process, so we lose ipc.

* fix(api): update api key service test for ensureDir change

* chore: increase max_restart threshold to 10s per cycle
2025-01-14 14:27:00 -05:00
renovate[bot]
1935ba1a7f chore(config): migrate config renovate.json 2025-01-14 13:15:34 -05:00
Eli Bosley
14abc13cc8 fix: mock ensureDirSync 2025-01-14 11:07:46 -05:00
renovate[bot]
c3548d5122 chore(deps): update dependency @types/node to v22.10.6 2025-01-13 16:17:24 -05:00
renovate[bot]
6c54fa14b1 fix(deps): update dependency execa to v9.5.2 2025-01-13 16:17:12 -05:00
Eli Bosley
8b93bcea08 feat: always ensureDirectory for keys exists 2025-01-13 15:58:43 -05:00
Eli Bosley
a6cd74dc5c fix: ensure directory exists before making connect key 2025-01-13 15:56:17 -05:00
Eli Bosley
aa1ef1bd4c feat: disable casbin logging 2025-01-13 15:41:09 -05:00
renovate[bot]
2cdc02f64a chore(deps): update dependency @ianvs/prettier-plugin-sort-imports to v4.4.1 2025-01-13 13:20:48 -05:00
Pujit Mehrotra
d0819b8d02 fix(web): flash of disconnected api state on page load
Changes initial unraidApiStatus to connecting instead of offline. This
prevents a flash of the offline state on page loads and navigation.
2025-01-13 13:20:32 -05:00
renovate[bot]
74b3e29c74 fix(deps): update dependency chokidar to v4.0.3 2025-01-13 13:20:18 -05:00
renovate[bot]
b32f84b105 fix(deps): update dependency dotenv to v16.4.7 2025-01-13 13:20:09 -05:00
renovate[bot]
806bd633ac fix(deps): update dependency @nestjs/schedule to v4.1.2 2025-01-13 13:05:26 -05:00
renovate[bot]
e5e1c43bb3 fix(deps): update dependency @floating-ui/vue to v1.1.6 2025-01-13 11:56:11 -05:00
Pujit Mehrotra
3b2d61efc2 fix(api): sanitize incoming user session id's 2025-01-13 11:50:24 -05:00
Pujit Mehrotra
fe98295496 fix(api): validate cookie session data 2025-01-13 11:50:24 -05:00
Pujit Mehrotra
b9947108a4 doc(api): document ready signal during nest server boot 2025-01-13 10:55:26 -05:00
Pujit Mehrotra
3c27b51ab8 fix(api): delay pm2 start until server has booted
prior to this, pm2 would mark unraid-api as started as soon as the
node process started. The Nest server wouldn't finish booting until
later. This meant unraid-api could "start", but the webgui wouldn't be
fully functional because it couldn't connect to the api yet. This was a
sucky user & dev experience.
2025-01-13 10:55:26 -05:00
Pujit Mehrotra
2327b00d30 fix(api): update deploy-dev script to dist instead of src 2025-01-13 10:55:26 -05:00
renovate[bot]
bf3b00fbaf chore(deps): update dependency @types/node to v20.17.12 2025-01-13 10:52:54 -05:00
renovate[bot]
4f04f93033 chore(deps): update dependency nodemon to v3.1.9 2025-01-13 10:52:44 -05:00
renovate[bot]
5dc13755df fix(deps): update dependency @floating-ui/dom to v1.6.13 2025-01-13 10:52:31 -05:00
renovate[bot]
69a34aca14 chore(deps): update dependency vite-tsconfig-paths to v5.1.4 2025-01-13 10:52:20 -05:00
renovate[bot]
bbc1e02782 chore(deps): update dependency vite to v5.4.11 2025-01-13 10:52:11 -05:00
renovate[bot]
e77db18870 chore(deps): update dependency tailwindcss to v3.4.17 2025-01-13 10:52:03 -05:00
renovate[bot]
b6805d439e chore(deps): update dependency typescript to v5.7.3 2025-01-13 10:51:52 -05:00
Pujit Mehrotra
f37dda16c2 fix(api): slow init of unraid-api cli (#1022)
* lazy load debug stuff

* refactor(api): lazy load cli help command
2025-01-13 10:26:38 -05:00
renovate[bot]
88be62317f chore(deps): update dependency @swc/core to v1.10.7 2025-01-10 10:18:51 -05:00
renovate[bot]
6b5e012950 chore(deps): update dependency @nuxt/eslint to v0.7.5 2025-01-10 10:18:42 -05:00
renovate[bot]
e05a05926d chore(deps): update dependency @types/bytes to v3.1.5 2025-01-10 09:23:57 -05:00
renovate[bot]
c817cc4b7e fix(deps): update dependency ini to v4.1.3 2025-01-10 09:23:46 -05:00
renovate[bot]
491b5fe8bc chore(deps): update dependency @rollup/plugin-node-resolve to v15.3.1 2025-01-10 09:23:37 -05:00
renovate[bot]
8675653e4e fix(deps): update graphqlcodegenerator monorepo 2025-01-10 09:23:17 -05:00
renovate[bot]
1f9e282880 fix(deps): update apollo graphql packages 2025-01-10 09:23:05 -05:00
renovate[bot]
90cf2c8a16 chore(deps): update dependency @types/dockerode to v3.3.34 2025-01-10 09:22:53 -05:00
renovate[bot]
729ed42329 chore(deps): update dependency @types/node to v22.10.5 2025-01-10 09:22:39 -05:00
Zack Spear
309d221542 feat / OEM whitelabel support (#973)
* feat: begin fixing dark mode in the webcomponents

* feat: lots of progress on colors

* feat: begin nuking alpha beta gamma

* feat: set background color on webcomponents

* fix: more color work

* feat: eliminate all alpha beta gamma variable usage

* feat: move variable declarations to theme.ts

* feat: begin fixing dark mode in the webcomponents

* feat: lots of progress on colors

* feat: begin nuking alpha beta gamma

* feat: set background color on webcomponents

* fix: more color work

* feat: eliminate all alpha beta gamma variable usage

* feat: download nodejs and install on legacy OS versions

* feat: do not move upgradepkg

* feat: array iteration for restoring files

* feat: separate install process

* feat: extract node to usr/local/

* feat: move variable declarations to theme.ts

* feat: remove nghttp3 and only bundle nodejs

* feat: validate entries correctly

* fix: upgradepkg

* feat: copy only needed files for nodejs

* fix: install syntax error

* fix: strip components from tar line

* feat: error when nodejs download fails

* feat(php): add OEM data extraction functionality

* feat(web): WIP add OEM activation modal and integrate OEM data handling

* refactor: replace oem etamology with activation

* feat(web): enhance activation modal with header and main title options

* refactor(web): update activation modal title to handle partner name conditionally

* feat: make partnerName optional in activation code data

* refactor: remove activationCodeStore from UserProfile component

* feat: integrate activation code data into server store

* feat: enhance activation code store to include callback actions and improve modal visibility logic

* refactor: remove unused theme reference from ColorSwitcher component

* fix: update partnerName in activationCodeData for clarity

* refactor: adjust gap spacing in Modal component for improved layout

* feat: enhance Activation Modal component with dynamic title and description, and add documentation buttons

* feat: implement localization for Activation Modal component titles and button texts

* feat: add new translations for activation prompts and welcome messages in the WebComponentTranslations class

* feat: implement key sequence to close Activation Modal and persist visibility state

* feat: update activation logic to conditionally activate or redeem based on activation code presence

* feat(plg): plg install / remove partner banner

* feat(plg): on install update config to enable display settings banner and on remove banner setting if no custom banner used

* fix(plg): plg remove, display banner no if no custom image

* feat(plg): implement partner banner handling and system model identification from activation JSON

* feat(web): add loading and error states to notification sidebar

* refactor(web): add container for loading & error states

* feat(web): add count labels to notification tabs

* refactor(web): lift notifications overview query to Sidebar from Indicator

* fix(web): refetch notifications for sidebar when new notifications arrive

* feat(web): move notification indicator icons to top-right of bell icon

previously, icons were placed next to bell icon because the status indicators
were not accessible to color-blind users. this commit replaces circular
status indicators with the icons.

* feat(web): remove notification indicator pulse

the pulse was initially added to provide visual feedback when:

1. a new notification arrived
2. an alert notification was unread

because we began using the legacy notify script, we now get a toast
on new notifications. re:2, feedback on the pulse was mixed, so i'm
removing it.

* refactor(plg): improve conditional for activation & partner setup

* feat(plg): add case model icon handling based on activation JSON

* feat(plg): enhance partner setup process with detailed logging and system identification updates and setup flag

* feat(plg): add setup flag file creation and logging for activation changes

* feat(plg): update activation setup flag checks for banner, case model icon, and system identity

* fix(plg): add error handling for invalid activation JSON and improve conditional checks for setup flags

* fix(plg): improve partner banner and case model icon setup logic with enhanced checks and comments

* fix(plg): update case model icon configuration to prevent newline issues in parsing

* fix(plg): remove unnecessary echo debug statements and improve setup flag handling for partner details

* fix(plg): remove unnecessary registration page check from activation code modal logic

* fix(plg): add overlay opacity prop to modal components for customizable background transparency

* fix(plg): enhance modal component with vertical centering option and adjust max-width

* fix(plg): enhance configuration handling by dynamically updating multiple header parameters in the config file

* fix(plg): improve comments and enhance setup flag handling for custom icons in activation logic

* fix(translations): correct capitalization and punctuation in user prompts for consistency

* fix(store): enhance activation code data structure with additional properties and correct partner URL reference

* fix(modal): enhance activation modal with dynamic partner logo and improved title handling

* fix(store): update activation code data structure with additional properties and correct partner details

* fix(index): refactor badge and button color handling with typed constants for improved maintainability

* fix(dependencies): add vue-tsc for improved TypeScript support in Vue projects

* refactor(plugin): remove unnecessary comments and clean up code structure

* refactor(plugin): remove todo comment for custom header logo

* fix(Modal): add partnerUrl handling for logo link and improve code structure

* fix(serverState): update partnerLogoPath to use a placeholder image for development

* feat(plugin): add rsync activation script for testing activation modal & installs

* refactor(activationCode): remove debug log for modal visibility check

* feat(plugin): enhance activation process by adding logo and case model handling

* refactor(activationCode): rename partnerLogoPath to partnerLogo and update handling for logo file type

* refactor(activationCode): remove debug log for partnerLogo watcher

* chore(nuxt.config): add ignore rule for webGui images directory

* refactor(plugin): rename params array to DISPLAY_PARAMS and update handling for configuration updates

* fix(web): partner logo handling for themes

* fix(plg): activation oem, custom case icon cfg handling

* fix(plugin): replace sed with awk for config file updates in DISPLAY_PARAMS handling

* fix(web): add target and rel attributes to partner logo link for security

* feat(plugin): add theme parameter to DISPLAY_PARAMS and activation code interface

* fix(plugin): replace sed with parameter expansion and awk for config file updates

* fix(plugin): reboot logic for plg install to prevent settings overwrite

* feat(plugin): streamline activation and partner setup by abstracting scripts for better maintainability

* fix(plugin): update script source paths for activation and partner setup

* fix(plugin): update script source paths for activation and partner setup to use relative paths

* fix(plugin): update script source paths for activation and partner setup to use absolute paths

* fix(plugin): add debug mode support to activation scripts and update setup flag handling

* fix(plugin): enhance activation scripts with debug mode and conditional execution for safety

* refactor(plugin): reposition execution of activation_code setup / remove scripts

* fix(plugin): add checks for activation_code_setup script existence and improve deletion logging

* fix(plugin): add option to remove setup flag after script execution

* fix(plugin): streamline activation script execution by removing unnecessary checks

* fix(plugin): remove duplicate activation_code_setup script sourcing

* feat(modal): add overlay color prop and enhance class binding for modal background

* feat(activation): update modal overlay color and opacity

* feat(plg): add WebComponentsExtractor class for managing JS file retrieval

* feat(plugin): myservers1.phpintegrate WebComponentsExtractor for dynamic script tag generation

* feat(activation): enhance getData method to support JSON output and add getDataForHtmlAttr for HTML-safe JSON

* refactor(activation): simplify getData method by removing parameters

* feat(plugin): add welcome-modal.php for displaying server state and web components

* refactor(web): activation code store rename modal visibility variables for clarity

* feat(web): add WelcomeModal component for user onboarding and server setup

* feat(plugin): activation_code setup and remove script support welcome modal

* refactor(plugin): streamline activation code setup script by removing some comments

* fix(plugin): update activation code setup script to prepend items to auth request allow list array

* feat: enhance ActivationCodeExtractor with partner logo handling and metadata extraction

- Added constants for document root and web GUI images directory.
- Introduced properties for partner name, URL, logo path, and logo file type.
- Implemented methods to retrieve partner logo path, render logo string, partner name, and URL.
- Enhanced data extraction logic to include partner-related information from JSON data.
- Added debug method for outputting internal state for troubleshooting.

* refactor: update activation-data.php to include debug output for ActivationCodeExtractor

- Removed JSON response and replaced it with a debug output wrapped in <pre> tags.
- This change allows for easier troubleshooting by displaying internal state information directly on the page.

* feat: inject partner logo into DefaultPageLayout and update JS file paths

- Modified the activation code setup script to change the path of JavaScript files to be relative to the web GUI's webroot.
- Added functionality to inject a partner logo into the DefaultPageLayout by replacing the existing logo string.
- Implemented a conditional backup mechanism for the DefaultPageLayout file before making changes.
- Included debug output to confirm successful injection or report errors during the process.

* feat: add partner logo display functionality and style adjustments

- Introduced a new file for displaying the partner logo, which retrieves the logo and URL based on the activation code.
- Added CSS styles to adjust the display properties of the partner logo in the header, ensuring proper sizing and alignment.
- Enhanced the integration of the partner logo into the existing plugin structure.

* refactor: simplify partner logo injection debug output in activation code setup script

- Removed syntax check for the DefaultPageLayout file after injecting the partner logo.
- Streamlined debug output to confirm successful injection without additional checks, enhancing clarity and reducing complexity.

* style: adjust partner logo height in myservers1.php

* style: update partner logo width in PartnerLogoImg.vue

- Changed the CSS class for the partner logo image from a max height constraint to a fixed width of 72 units, ensuring better responsiveness and alignment in the layout.

* fix: update modal title attribute for conditional close behavior

- Modified the title attribute of the modal overlay to conditionally display the close instruction based on the showCloseX property. This change improves accessibility by ensuring the title is only set when the close button is visible.

* refactor: update partner logo handling in activation code scripts and extractor

- Changed the partner logo file name to 'partner-logo.svg' in ActivationCodeExtractor.
- Simplified logo path handling by removing unnecessary file type checks and directly using the SVG file.
- Updated CSS in myservers1.php to target only the SVG logo.
- Modified activation code setup and removal scripts to consistently reference the SVG logo, improving clarity and maintainability.

* feat: enhance activation code setup script to include server name handling

- Added logic to retrieve and set the server name from the activation JSON if the current system model or comment is not set, or if the current name is "Tower".
- Improved debug output to include the partner server name, enhancing visibility during the activation process.
- Sanitized the partner server name to remove quotes and backslashes for better handling.

* feat: validate activation JSON before proceeding with setup

- Added validation for the activation JSON file to ensure it is correctly formatted before executing the setup process.
- Enhanced debug output to indicate whether the JSON is valid or not, improving troubleshooting capabilities.
- The setup will now only proceed if the activation JSON is confirmed to be valid, preventing potential errors during execution.

* fix(plg): improve warning message for invalid activation JSON in setup script

* feat: enhance activation code handling with partner logo integration

- Added a new optional property 'partnerLogo' to the ActivationCodeExtractor class and updated related interfaces to support boolean values for logo display.
- Removed the PNG logo reference from the activation code setup script, streamlining the logo handling process.
- Updated the server state to utilize the new 'partnerLogo' property, ensuring consistent logo display logic across the application.
- Adjusted computed properties in the activation code store to reflect the changes in logo handling, improving clarity and maintainability.

* fix: correct activation JSON validation in setup script

- Updated the activation code setup script to use 'jq empty' for validating the activation JSON file, ensuring proper error handling and validation.
- This change improves the robustness of the setup process by accurately checking the JSON format before proceeding.

* fix: correct comment formatting in dynamix.unraid.net.plg

- Fixed a formatting issue in the comment regarding the use of myservers.cfg values to prevent conflicts during installation. This change improves code readability and clarity.

* chore: update rsync activation script comments for clarity

- Revised comments in the rsync-activation-dir.sh script to better describe its purpose and usage.
- Enhanced documentation with an example usage to improve user understanding of the script's functionality.

* refactor: clean up activation data and extractor files

- Removed outdated copyright comments from activation-data.php and activation-code-extractor.php for improved readability.
- Simplified the debug output in activation-data.php by using short PHP tags.
- Updated the comment in the ActivationCodeExtractor class to be more concise, enhancing clarity for future developers.

* fix: remove unnecessary CSS properties in myservers1.php

- Eliminated redundant display and margin properties from the CSS in myservers1.php to streamline the styling and improve code clarity.

* refactor: streamline WebComponentsExtractor class and update method names

- Removed outdated copyright comments from web-components-extractor.php for improved readability.
- Renamed method getJsFileUrl() to getJSFileRelativePath() to enhance clarity and consistency in naming conventions.
- Adjusted indentation for better code formatting and readability.

* refactor: simplify partner logo handling in activation code script

- Removed unnecessary variable initialization and included only essential requires for improved clarity.
- Streamlined the code in partner-logo.php to focus on the core functionality of displaying the partner logo.
- Enhanced maintainability by reducing complexity in the script.

* refactor: clean up activation and server state files

- Removed outdated copyright comments and unnecessary variable initializations from activation-data.php and server-state.php for improved readability.
- Streamlined the code by eliminating redundant require statements, focusing on essential functionality.
- Enhanced maintainability and clarity by simplifying the structure of both files.

* feat: add password creation prompts to translations

- Introduced new translation strings for password creation in both PHP and JSON files.
- Enhanced user guidance by providing detailed messages about the importance of the password for system access and management.
- Improved overall user experience by ensuring clarity in the password setup process.

* refactor: update activation code setup script comments

* refactor: enhance activation code removal script functionality

- Updated the activation code removal script to delete additional related files, including PHP and setup scripts, for a more thorough cleanup.
- Improved comments for clarity on script usage and options, particularly regarding the self-delete functionality.
- Streamlined the deletion process by using an array to manage files to be removed, enhancing maintainability and readability.

* fix: update WelcomeModal to disable close button

* refactor: reorganize activation code setup and improve script clarity

- Moved the activation and partner setup section to follow the web component timestamp check to ensure correct targeting during setup.
- Updated comments for better clarity regarding the activation code setup process.
- Retained the warning message about not closing the window yet for user guidance.

* refactor: enhance activation code setup script with improved comments and logic

- Updated comments to clarify the purpose of server name, model, and description checks.
- Modified conditional logic to include additional checks for server identification.
- Added a TODO note regarding the necessity of updating the ident.cfg file, ensuring future review for potential optimizations.

* refactor: update activation code scripts to use .done flag

* refactor: introduce constant for activation modal storage key

- Added a new constant for the activation code modal hidden storage key to improve code maintainability and clarity.
- Updated the activation code store to utilize the new constant, replacing hardcoded string references.

* feat: enhance user onboarding and modal components

- Added new translation strings for activating Unraid licenses and creating Unraid.net accounts to improve user onboarding experience.
- Updated the WelcomeModal and Activation Modal components to reflect new messaging and improved styling options, including the ability to disable shadows.
- Implemented a workaround in the WelcomeModal to address font-size inconsistencies between login and authenticated pages.
- Refactored the index page to correctly pass server data to the WelcomeModal component.

* chore: comment out WelcomeModalCe component for testing

* feat: add disableOverlayClose prop to Modal and WelcomeModal components

- Introduced a new prop `disableOverlayClose` to the Modal component, allowing users to prevent closing the modal by clicking on the overlay.
- Updated the WelcomeModal component to utilize the new `disableOverlayClose` prop, enhancing modal behavior customization.

* refactor: update activation code removal script to delete by default

- Changed the activation code removal script to use a dry-run flag instead of a self-delete flag, enhancing safety during execution.
- Updated the plugin file to reflect the removal of the --delete option, ensuring consistency with the new script behavior.

---------

Co-authored-by: Eli Bosley <ekbosley@gmail.com>
Co-authored-by: Pujit Mehrotra <pujit@lime-technology.com>
2025-01-09 16:06:10 -05:00
renovate[bot]
859440386e chore(deps): update dependency @types/lodash to v4.17.14 2025-01-08 15:38:03 -05:00
Eli Bosley
ceac6269b3 fix: remove usage of Role.UPC 2025-01-08 14:47:47 -05:00
Eli Bosley
286ffc54e5 fix: excess spacing in api-key.service 2025-01-08 14:47:47 -05:00
Eli Bosley
84f4f67ce1 fix: extra spacing in config.ts 2025-01-08 14:47:47 -05:00
Eli Bosley
8827483699 feat: rename api key resource back to api_key 2025-01-08 14:47:47 -05:00
Eli Bosley
f8393eeebe fix: clearer error messaging 2025-01-08 14:47:47 -05:00
Eli Bosley
5d72b5a970 fix: use placeholder in test API key 2025-01-08 14:47:47 -05:00
Eli Bosley
1f5c6424c7 feat: faster failure logic 2025-01-08 14:47:47 -05:00
Eli Bosley
39612cd978 fix: swap to placeholder key 2025-01-08 14:47:47 -05:00
Eli Bosley
b1b93e2783 fix: only instantiate service one time 2025-01-08 14:47:47 -05:00
Eli Bosley
eff6c32ccd fix: connect key role 2025-01-08 14:47:47 -05:00
Eli Bosley
b1ac0f9c83 fix: update tests 2025-01-08 14:47:47 -05:00
Eli Bosley
d88b1e9660 fix: create connect key 2025-01-08 14:47:47 -05:00
Eli Bosley
124fb610b1 fix: find by key, not ID 2025-01-08 14:47:47 -05:00
Eli Bosley
143515560c feat: generate key one time 2025-01-08 14:47:47 -05:00
Pujit Mehrotra
f0f5a3057a feat: add csrf support to api & web components (#999) 2025-01-08 14:22:06 -05:00
Pujit Mehrotra
4404208deb chore(web): mock user session cookie during development (#997)
* chore(web): mock user session cookie during development

* refactor(scripts): change default mock session name to mock-user-session

* tmp: log cookies in production

* refactor(api): add dev fixture for a mock user session

* fix(web): only mock session cookie during development

* fix(web): type coercion of MOCK_USER_SESSION env flag
2025-01-08 14:15:46 -05:00
Pujit Mehrotra
f45719fa6b feat(api): rm 2fa & t2fa from myservers config type (#996)
* feat(api): rm 2fa & t2fa from myservers config type

* feat(api): rm 2fa & T2fa from config normalizer

* doc(plugin): rm obsolete documentation on 2fa/t2fa feature
2025-01-08 14:15:15 -05:00
Pujit Mehrotra
acba0b0365 feat(plugin): rm Date & Time format settings from Notification Settings 2025-01-08 14:14:41 -05:00
renovate[bot]
8760a66907 chore(deps): update dependency @tailwindcss/typography to v0.5.16 2025-01-08 13:13:29 -05:00
renovate[bot]
5f81c4bd27 chore(deps): update dependency @swc/core to v1.10.6 2025-01-08 13:04:57 -05:00
renovate[bot]
2310d53684 chore(deps): update dependency @nuxt/eslint to v0.7.4 2025-01-08 13:02:39 -05:00
renovate[bot]
5b3ec8304c chore(deps): update dependency jiti to v2.4.2 2025-01-08 12:58:13 -05:00
Eli Bosley
7a009b6be7 fix: logrotate error 2025-01-08 11:04:10 -05:00
Pujit Mehrotra
be7135efdd feat(web): clear notifications indicator after opening sidebar 2025-01-08 10:48:06 -05:00
Pujit Mehrotra
939383e4ef feat(web): rm api-key validation from connect sign in (#986)
* feat(api): rm api-key validation from connect sign in

This will now happen at the mothership layer.

* chore(api): rm redundant validate-api-key helper

* chore(api): rm obsolete api-key-check-job tests

* chore(api): suppress noisy notification loading logs

* feat(api): rm client-side mothership api key validation

refactor(api): encapsulate mothership jobs lifecycle

* fix(api): mothership gql client lifecycle & error handling

the api would crash when an invalid mothership api key was detected/invalidated *after* the inital server start/connection.

* refactor(api): rm mothership API_KEY_STATUS enum
2025-01-08 10:25:28 -05:00
Eli Bosley
0042f14ab3 fix: formatting issue 2025-01-08 10:16:34 -05:00
Eli Bosley
3e8c101edd fix: delete unused line 2025-01-08 10:16:34 -05:00
Eli Bosley
477c113ce1 fix: add another missing symlink 2025-01-08 10:16:34 -05:00
Eli Bosley
caf797cf4a feat: fix pm2 setup and add link command 2025-01-08 10:16:34 -05:00
Eli Bosley
73a12496d5 feat: attempt to start unraid-api with background task 2025-01-08 10:16:34 -05:00
Eli Bosley
cea11daf15 feat: manually install libvirt in build process to ensure it is included in the final build 2025-01-08 10:16:34 -05:00
Eli Bosley
bb6baf9bf4 feat: always start the API and run npm link from script path 2025-01-08 10:16:34 -05:00
Eli Bosley
5f1a61d4aa feat: fix missing flash line 2025-01-08 10:16:34 -05:00
Eli Bosley
bbf28075c6 feat: use plugin file for install and uninstall 2025-01-08 10:16:34 -05:00
Pujit Mehrotra
7dcf947527 feat(web): open official release notes via header os version 2025-01-07 09:59:36 -08:00
Pujit Mehrotra
4ee42a6cf6 fix(web): escaping html-encoded symbols like apostrophes in translations (#1002)
e.g. end user would see `&apos;` from translations
2025-01-06 14:59:36 -05:00
Michael Datelle
91de6e6c1e feat: unraid ui component library (#976) 2024-12-20 14:08:34 -05:00
Eli Bosley
e2a1f27b22 fix: check width before changing viewport 2024-12-18 14:22:28 -05:00
Eli Bosley
4e9ab645e6 fix: edit settings padding issue 2024-12-18 14:22:28 -05:00
Eli Bosley
7828ef2648 feat: use text-secondary-foreground instead of gray 2024-12-18 14:22:28 -05:00
Eli Bosley
dfa27e2c0d fix: improve typing and format lookup 2024-12-18 14:22:28 -05:00
Eli Bosley
9d2405bd21 feat: viewport watch refactor 2024-12-18 14:22:28 -05:00
Eli Bosley
e1515a118a fix: recreate package-lock to fix issues 2024-12-18 14:22:28 -05:00
Eli Bosley
961c343f5d Update web/components/Notifications/Sidebar.vue
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-12-18 14:22:28 -05:00
Eli Bosley
6cbb9c07e4 fix: 12 hour timestamp logic corrected 2024-12-18 14:22:28 -05:00
Eli Bosley
833a99fe18 fix: render function fixed 2024-12-18 14:22:28 -05:00
Eli Bosley
943c907d03 fix: downgrade marked to fix changelog preview issue 2024-12-18 14:22:28 -05:00
Eli Bosley
d28fb24d68 fix: marked single input 2024-12-18 14:22:28 -05:00
Eli Bosley
0c1b89ff41 fix: remove unused date-fns 2024-12-18 14:22:28 -05:00
Eli Bosley
cead97560c feat: responsive notifications 2024-12-18 14:22:28 -05:00
Michael Datelle
5f0446fa79 fix: authorization type error (#987)
Co-authored-by: Eli Bosley <ekbosley@gmail.com>
2024-12-18 12:03:28 -05:00
Eli Bosley
000692ca50 fix: remove extra space 2024-12-17 11:48:45 -05:00
Eli Bosley
d8f9f03146 fix: remove console log 2024-12-17 11:48:45 -05:00
Eli Bosley
29035429bd feat: nuxt config simplification and formatting 2024-12-17 11:48:45 -05:00
Eli Bosley
5f8602b864 fix: switch to useToggle 2024-12-17 11:48:45 -05:00
Eli Bosley
77558a5cd9 fix: dark theme as array 2024-12-17 11:48:45 -05:00
Eli Bosley
116efe6f72 fix: theme store now uses singular variables object 2024-12-17 11:48:45 -05:00
Eli Bosley
8e0962adba Update web/components/ColorSwitcher.ce.vue
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-12-17 11:48:45 -05:00
Eli Bosley
d23a38960b fix: upc header text color 2024-12-17 11:48:45 -05:00
Eli Bosley
d5f5921534 fix: use foreground text color for UPC 2024-12-17 11:48:45 -05:00
Eli Bosley
a52cc7861c Update web/components/ColorSwitcher.ce.vue
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-12-17 11:48:45 -05:00
Eli Bosley
0d6a0035aa feat: delete unused imports 2024-12-17 11:48:45 -05:00
Eli Bosley
0fa41f5690 fix: re-add type-check 2024-12-17 11:48:45 -05:00
Eli Bosley
45327ce01d fix: type error on element render 2024-12-17 11:48:45 -05:00
Eli Bosley
11ce9e2644 fix: revert changes to indicator.vue 2024-12-17 11:48:45 -05:00
Eli Bosley
00b8ffe87d feat: move variable declarations to theme.ts 2024-12-17 11:48:45 -05:00
Eli Bosley
4eda0991d6 feat: eliminate all alpha beta gamma variable usage 2024-12-17 11:48:45 -05:00
Eli Bosley
9a869a49e3 fix: more color work 2024-12-17 11:48:45 -05:00
Eli Bosley
7ef3286191 feat: set background color on webcomponents 2024-12-17 11:48:45 -05:00
Eli Bosley
cb91fbb054 feat: begin nuking alpha beta gamma 2024-12-17 11:48:45 -05:00
Eli Bosley
c6547a51fc feat: lots of progress on colors 2024-12-17 11:48:45 -05:00
Eli Bosley
24435613f8 feat: begin fixing dark mode in the webcomponents 2024-12-17 11:48:45 -05:00
Pujit Mehrotra
4a29fc9dda fix(web): display error message in sidebar when api is offline (#984)
* fix(web): display error message in sidebar when api is offline

* refactor(web): move offline error derivation to UnraidApiStore

* feat(web): display error in upc when api is offline
2024-12-17 10:25:05 -05:00
Michael Datelle
2ef9fbb20e refactor: permissions system rewrite (#942)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Eli Bosley <ekbosley@gmail.com>
2024-12-16 15:25:01 -05:00
Pujit Mehrotra
a09f7c935d refactor(api): delete only archived notifications in deleteAll (#983)
* refactor(api): delete only archived notifications in deleteAll

* refactor: rename deleteAllNotifications mutation to deleteArchivedNotifications

* fix: update mutation name for deleting archived notifications

* chore(web): update codegen dependencies to fix codegen issues

* chore(web): update vue-tsc to fix build typechecking
2024-12-13 14:50:33 -05:00
Pujit Mehrotra
29d9371cc3 fix(web): update unread total immediately upon archiving (#982) 2024-12-13 12:28:56 -05:00
Eli Bosley
ef82ec5af5 fix: cleanup commands 2024-12-13 12:14:23 -05:00
Eli Bosley
cf72c8b359 feat: name package with PR number 2024-12-13 12:14:23 -05:00
Zack Spear
0705764385 refactor(web): remove unused connectPluginInstalled from dropdown trigger 2024-12-13 11:40:01 -05:00
Eli Bosley
ea6ae83919 feat: hide sign in from the dropdown text 2024-12-13 11:40:01 -05:00
Pujit Mehrotra
478254e134 feat(web): rm old notification bell upon plugin installation (#979)
* feat(web): rm old notification bell upon plugin installation

* refactor: use grep flag to unescape regex operator

* fix: preserve DefaultPageLayout.php
2024-12-13 11:16:09 -05:00
Eli Bosley
8f5814589e fix: restore upgradepkg before install 2024-12-12 10:40:14 -05:00
Pujit Mehrotra
dab6985297 refactor(web): evict notification list on archival instead of manually modifying cache 2024-12-11 16:32:05 -05:00
Pujit Mehrotra
e40a9ebecd fix(web): edge case where archived notifications don't appear
if the archive has already been fetched/loaded.
2024-12-11 16:32:05 -05:00
Pujit Mehrotra
bc4708f405 feat(web): remove notification indicator pulse
the pulse was initially added to provide visual feedback when:

1. a new notification arrived
2. an alert notification was unread

because we began using the legacy notify script, we now get a toast
on new notifications. re:2, feedback on the pulse was mixed, so i'm
removing it.
2024-12-10 14:24:52 -05:00
Pujit Mehrotra
99704a9dbb feat(web): move notification indicator icons to top-right of bell icon
previously, icons were placed next to bell icon because the status indicators
were not accessible to color-blind users. this commit replaces circular
status indicators with the icons.
2024-12-10 14:24:52 -05:00
Pujit Mehrotra
23b1f1ac73 fix(web): refetch notifications for sidebar when new notifications arrive 2024-12-10 13:01:35 -05:00
Pujit Mehrotra
a5cf63fe28 refactor(web): lift notifications overview query to Sidebar from Indicator 2024-12-10 13:01:35 -05:00
Pujit Mehrotra
78ec4663cc feat(web): add count labels to notification tabs 2024-12-10 13:01:35 -05:00
Pujit Mehrotra
a3b171f58d refactor(web): add container for loading & error states 2024-12-06 12:56:58 -05:00
Pujit Mehrotra
060fb91546 feat(web): add loading and error states to notification sidebar 2024-12-06 12:56:58 -05:00
Eli Bosley
af1994cb62 feat: error when nodejs download fails 2024-12-05 16:04:16 -05:00
Eli Bosley
bad7f71fea fix: strip components from tar line 2024-12-05 16:04:16 -05:00
Eli Bosley
a355a64136 fix: install syntax error 2024-12-05 16:04:16 -05:00
Eli Bosley
cf08627725 feat: copy only needed files for nodejs 2024-12-05 16:04:16 -05:00
Eli Bosley
6962cdd214 fix: upgradepkg 2024-12-05 16:04:16 -05:00
Eli Bosley
a39da15be4 feat: validate entries correctly 2024-12-05 16:04:16 -05:00
Eli Bosley
bb555f8296 feat: remove nghttp3 and only bundle nodejs 2024-12-05 16:04:16 -05:00
Eli Bosley
9a0d63d4ee feat: extract node to usr/local/ 2024-12-05 16:04:16 -05:00
Eli Bosley
9bbab0f86c feat: separate install process 2024-12-05 16:04:16 -05:00
Eli Bosley
349145ba53 feat: array iteration for restoring files 2024-12-05 16:04:16 -05:00
Eli Bosley
c12d8dae4e feat: do not move upgradepkg 2024-12-05 16:04:16 -05:00
Eli Bosley
b1a2ba78cc feat: download nodejs and install on legacy OS versions 2024-12-05 16:04:16 -05:00
Pujit Mehrotra
2409ef2dd6 chore(api): auto-restart dev server on source file changes (#971) 2024-12-04 15:00:16 -05:00
Pujit Mehrotra
0055637602 chore: improve dx for scripting & setup (#969)
* chore: rm vs code visual customizations

* chore(api): fix vscode eslint extension

* chore(web): update env.example for local development

* chore: add justfiles to simplify workflows

* chore: stub monorepo readme

* chore: add nvmrc to monorepo root

* refactor: improve error handling in `just ignore`

* doc(web): explain TAILWIND_BASE_FONT_SIZE in .env.example

* chore: add logo to readme
2024-12-02 10:07:56 -05:00
Pujit Mehrotra
547b75a55e fix(web): notification styles & alignment (#968)
* fix(web): notification icon & indicator colors

* fix(web): notification item text size & weights

* fix(web): notification button styles

* fix(web): notification filter styles

* fix(web): Tab List styles

* fix(web): link button styles

* fix(web): vertical spacing in notifications sidebar

* fix(web): notification sidebar link styles

* refactor(web): change default button border radius to rounded instead of rounded-md

* fix(web): Notification Item alignment with other elements

* refactor(web): add tw color palettes for unraid-green & unraid-red
2024-11-25 12:12:26 -05:00
Pujit Mehrotra
c36082e82b feat(api): omit tz from sys time date format by default 2024-11-22 12:23:03 -05:00
Pujit Mehrotra
0f3bebf859 chore(api): update dynamix config types 2024-11-22 12:23:03 -05:00
Pujit Mehrotra
96f3902b57 refactor(api): pull date-time formatting into utils 2024-11-22 12:23:03 -05:00
Pujit Mehrotra
b9cd8c426d fix(api): append time to formatted date when a custom date format is selected 2024-11-22 12:23:03 -05:00
Pujit Mehrotra
7c8e8a0e53 feat(web): pull date format from display/date and time settings 2024-11-22 12:23:03 -05:00
Pujit Mehrotra
801abac06b chore(api): improve Notify config types
Pulled from `/boot/config/plugins/dynamix/dynamix.cfg` by changing
the relevant notification settings (display, date, time).
2024-11-22 12:23:03 -05:00
Pujit Mehrotra
3fe13d5235 fix(web): reset infinite scroll when notification filters change 2024-11-21 08:55:37 -05:00
Pujit Mehrotra
eeb3289ae8 fix(web): infinite scroll loop when there's only 1 page of notifications 2024-11-19 14:22:08 -05:00
Pujit Mehrotra
939d7a304d feat(web): add an 'all' option to notification filter
allows users to "reset" after selecting a filter. ideally, we'd be able to
clear the filter if it was clicked again, but I couldn't find a way to listen
to a second/repeat click on a SelectItem, so I added a new filter item instead.
2024-11-19 14:22:08 -05:00
Pujit Mehrotra
acccb3694c chore(web): add testing step to github actions 2024-11-19 13:21:41 -05:00
Pujit Mehrotra
2724485989 test(web): Markdown sanitization & extensibility
fix(web): replaces dompurify with isomorphic-dompurify to enable server-side usage with same syntax
2024-11-19 13:21:41 -05:00
Pujit Mehrotra
2f4ff21986 feat(web): use Markdown helper class to interact with markdown 2024-11-19 13:21:41 -05:00
Pujit Mehrotra
83e00c640a fix(web): sanitize changelog markup after parsing 2024-11-19 13:21:41 -05:00
Pujit Mehrotra
abcaa5aedb feat(web): support markdown in notification messages 2024-11-19 13:21:41 -05:00
Pujit Mehrotra
4c663dc69c feat(web): add confirmation before archiving or deleting all notifications 2024-11-18 14:44:20 -05:00
Pujit Mehrotra
89eb841b20 feat(web): add delete all notifications button to archive view in notifications sidebar 2024-11-18 14:44:20 -05:00
Pujit Mehrotra
7296195495 feat(web): add link to settings in notification sidebar 2024-11-18 14:44:20 -05:00
Pujit Mehrotra
696b55de6c refactor(web): use optional chaining for graphql errors
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-11-14 15:24:20 -05:00
Pujit Mehrotra
aa5fad39f3 refactor(web): improve incoming notifications var name in infinite scroll loader 2024-11-14 15:24:20 -05:00
Pujit Mehrotra
9c38fa6a9c fix(api): exclude duplicates from legacy script in archive retrieval 2024-11-14 15:24:20 -05:00
Pujit Mehrotra
da5d1132d1 chore(web): remove noisy console log in apollo disable link 2024-11-14 15:24:20 -05:00
Pujit Mehrotra
001be86181 fix(web): infinite trigger at bottom of infinite scroll 2024-11-14 15:24:20 -05:00
Pujit Mehrotra
ecfc797e7d fix(web): stop opening notification sidebar to archive tab 2024-11-14 15:24:20 -05:00
Pujit Mehrotra
dffbfc2dab fix(web): env var typo 2024-11-14 15:24:20 -05:00
Pujit Mehrotra
e5f029830b chore: add import organizer to prettier config (#959)
* chore(web): add import organizer plugin to prettier config

* chore(api): add import organizer plugin to prettier config

* chore(api): sort imports in notifications resolver & service

as a demonstration

* chore(web): sort imports in notifications indicator

as a demonstration
2024-11-12 09:46:29 -05:00
Pujit Mehrotra
1a33e6343a chore(web): add prettier config & tailwind class sorting (#955) 2024-11-08 13:17:10 -05:00
Eli Bosley
69441d890e feat: myservers_fb keepalive location 2024-11-08 10:17:45 -05:00
Eli Bosley
46c82ecae3 feat: upgrade dependencies 2024-11-08 10:17:45 -05:00
Pujit Mehrotra
0b469f5b3f feat(web): enhance notifications indicator in UPC (#950)
* feat(web): scaffold ui for notifications indicator

* refactor(web): poll for notification overview instead of subscription

* test: rm failing notifications.resolver test stub

* feat(web): pulse indicator when new notifications are received
2024-11-07 14:36:30 -05:00
Eli Bosley
3fc41480a2 fix: cwd on ecosystem.config.json 2024-11-06 15:29:11 -05:00
Eli Bosley
e27776df3d fix: use cwd when running application 2024-11-06 15:27:02 -05:00
Eli Bosley
abd8e09908 fix: forced restarting on commands 2024-11-06 15:21:08 -05:00
Eli Bosley
504283f227 fix: attempt to restore upgradepkg if install failed 2024-11-06 15:11:51 -05:00
Eli Bosley
ff7e09e15c Revert "fix: delete upgradepkg"
This reverts commit dc1c4fb6ec.
2024-11-06 15:03:21 -05:00
Eli Bosley
deb42f6a81 fix: delete upgradepkg 2024-11-06 15:03:21 -05:00
Eli Bosley
95d018ea05 Update plugin/source/dynamix.unraid.net/pkg_build.sh
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-11-06 15:03:21 -05:00
Eli Bosley
106b2e42c0 feat: nodejs issues with version 2 2024-11-06 15:03:21 -05:00
Eli Bosley
1c5ff58d2d Update plugin/plugins/dynamix.unraid.net.plg
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-11-06 15:03:21 -05:00
Eli Bosley
d7bab9f443 fix: used TGZ instead of TXZ for nghttp3 2024-11-06 15:03:21 -05:00
Eli Bosley
902c76c759 fix: capitalize name 2024-11-06 15:03:21 -05:00
Eli Bosley
5e50f24d70 fix: node_txz naming 2024-11-06 15:03:21 -05:00
Eli Bosley
4f0210d16a feat: nghttp3 sha256 missing 2024-11-06 15:03:21 -05:00
Eli Bosley
ddb8772692 feat: add validation step to ensure that variables are set 2024-11-06 15:03:21 -05:00
Eli Bosley
787f8b9bf5 fix: proper file replacements 2024-11-06 15:03:21 -05:00
Eli Bosley
61ba324ca0 fix: variables passed properly 2024-11-06 15:03:21 -05:00
Eli Bosley
a230a33df5 fix: pull node version directly from nvmrc 2024-11-06 15:03:21 -05:00
Eli Bosley
84b234c9cf feat: upload files directly to cloudflare 2024-11-06 15:03:21 -05:00
Eli Bosley
9bfc04c2a5 fix: dnserr on new line 2024-11-06 15:03:21 -05:00
Eli Bosley
e84430471d fix: add error check to nodejs 2024-11-06 15:03:21 -05:00
Eli Bosley
2d60045784 fix: pkg_build 2024-11-06 15:03:21 -05:00
Eli Bosley
e9137f2553 Update plugin/source/dynamix.unraid.net/pkg_build.sh
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-11-06 15:03:21 -05:00
Eli Bosley
dbe0dd5dfb Update plugin/source/dynamix.unraid.net/pkg_build.sh
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-11-06 15:03:21 -05:00
Eli Bosley
9d2796f2c9 feat: track node version in slackware 2024-11-06 15:03:21 -05:00
Eli Bosley
972a19be04 fix: better logging when error 2024-11-05 16:11:21 -05:00
Eli Bosley
c8da8fe314 fix: remove uneeded env variable 2024-11-05 16:11:21 -05:00
Eli Bosley
353132b67a feat: code review changes 2024-11-05 16:11:21 -05:00
Eli Bosley
88b7cbfe95 feat: actually exit on stop and start 2024-11-05 16:11:21 -05:00
Eli Bosley
3ed1d10c98 fix: properly restart the API when installed 2024-11-05 16:11:21 -05:00
Eli Bosley
62693cfcc0 feat: cleanup unused variables 2024-11-05 16:11:21 -05:00
Eli Bosley
810708f775 fix: use unraid binary path to call unraid commands 2024-11-05 16:11:21 -05:00
Eli Bosley
08f6d6df65 fix: no vite-node in non-dev mode 2024-11-05 16:11:21 -05:00
Eli Bosley
da673c3f2b feat: exit after running status 2024-11-05 16:11:21 -05:00
Eli Bosley
cb463bfdd0 feat: add ecosystem.config.json to files 2024-11-05 16:11:21 -05:00
Eli Bosley
7177171b75 feat: vite dev mode 2024-11-05 16:11:21 -05:00
Eli Bosley
9f0ab7fa38 feat: start command path 2024-11-05 16:11:21 -05:00
Eli Bosley
a32374a3ac feat: attempt to fix pm2 2024-11-05 16:11:21 -05:00
Eli Bosley
cb6534d9d9 feat: pm2 fixes 2024-11-05 16:11:21 -05:00
Eli Bosley
2eaf175515 fix: load PM2 from node_modules 2024-11-05 16:11:21 -05:00
Eli Bosley
50376a0d66 fix: make cli.js executable 2024-11-05 16:11:21 -05:00
Eli Bosley
4b2007b689 fix: plugin download route and add env node to cli script 2024-11-05 16:11:21 -05:00
Eli Bosley
72fcaca4f3 feat: process env fixed and copy gql files 2024-11-05 16:11:21 -05:00
Eli Bosley
2f48ddf942 feat: fix more imports 2024-11-05 16:11:21 -05:00
Eli Bosley
62dfa6c83a fix: invalid type 2024-11-05 16:11:21 -05:00
Eli Bosley
27bb375460 feat: vite 2024-11-05 16:11:21 -05:00
Eli Bosley
cc4d5bdefb feat: substantial docs updates 2024-11-05 16:11:21 -05:00
Eli Bosley
f55302c130 feat: add web gitignore 2024-11-05 16:11:21 -05:00
Eli Bosley
b8dbe3f9d9 fix: execa upgrade snapshots fixed 2024-11-05 16:11:21 -05:00
Eli Bosley
20771f61a8 feat: fix header strategy 2024-11-05 16:11:21 -05:00
Eli Bosley
b9b8bbe871 fix: unit test failure 2024-11-05 16:11:21 -05:00
Eli Bosley
b8e61007e3 fix: changelog parser 2024-11-05 16:11:21 -05:00
Eli Bosley
49536032df fix: handle special chars better 2024-11-05 16:11:21 -05:00
Eli Bosley
9229cf3df6 fix: version and EOF key 2024-11-05 16:11:21 -05:00
Eli Bosley
58665a4e98 fix: trigger loading correctly 2024-11-05 16:11:21 -05:00
Eli Bosley
885d1537b6 feat: fix issues with permissions and invalid modules 2024-11-05 16:11:21 -05:00
Eli Bosley
198cfe5015 fix: unraid-api in usr/bin 2024-11-05 16:11:21 -05:00
Eli Bosley
42189dd451 fix: detection script path bin instead of sbin 2024-11-05 16:11:21 -05:00
Eli Bosley
6122b3c001 feat: comment URL for plugin on PR 2024-11-05 16:11:21 -05:00
Eli Bosley
cda7368d3d fix: connect plugin location 2024-11-05 16:11:21 -05:00
Eli Bosley
447cecd19d feat: fix missing import in ESM 2024-11-05 16:11:21 -05:00
Eli Bosley
7321bd0088 fix: add ecosystem config 2024-11-05 16:11:21 -05:00
Eli Bosley
67e898efe1 fix: missing ip-regex module 2024-11-05 16:11:21 -05:00
Eli Bosley
41e5de83a2 feat: remove many unneded simple libraries 2024-11-05 16:11:21 -05:00
Eli Bosley
5c020a62d6 feat: package scripts 2024-11-05 16:11:21 -05:00
Eli Bosley
1393e967fa fix: production env for web build 2024-11-05 16:11:21 -05:00
Eli Bosley
f07c14354f feat: pack everything in API 2024-11-05 16:11:21 -05:00
Eli Bosley
d42a426244 fix: actually install dependencies 2024-11-05 16:11:21 -05:00
Eli Bosley
125bc29166 feat: also copy in other files 2024-11-05 16:11:21 -05:00
Eli Bosley
a6333bf5a2 fix: more filename fixes and PR var passing 2024-11-05 16:11:21 -05:00
Eli Bosley
e8e985ad6a feat: properly set outputs 2024-11-05 16:11:21 -05:00
Eli Bosley
1a598885cc feat: copy 2024-11-05 16:11:21 -05:00
Eli Bosley
d73f267245 feat: copy node modules 2024-11-05 16:11:21 -05:00
Eli Bosley
7c1873249e feat: more process improvements 2024-11-05 16:11:21 -05:00
Eli Bosley
09f33a0127 fix: don't LS in the release folder 2024-11-05 16:11:21 -05:00
Eli Bosley
db00d7442d feat: diff 2024-11-05 16:11:21 -05:00
Eli Bosley
724159314c fix: PR build missing files 2024-11-05 16:11:21 -05:00
Eli Bosley
180f115b71 feat: plg builder improvements to be more explicit 2024-11-05 16:11:21 -05:00
Eli Bosley
eb38eb219e feat: PR builds 2024-11-05 16:11:21 -05:00
Eli Bosley
3da701a53b fix: local variable assignment 2024-11-05 16:11:21 -05:00
Eli Bosley
6e5b2f1f67 fix: unused import 2024-11-05 16:11:21 -05:00
Eli Bosley
812053d7a4 feat: simplify getting version 2024-11-05 16:11:21 -05:00
Eli Bosley
a929c7e3b3 fix: pass env through to docker 2024-11-05 16:11:21 -05:00
Eli Bosley
c0179c8351 fix: env correct 2024-11-05 16:11:21 -05:00
Eli Bosley
d5c7be54b0 fix: only test when API is changed 2024-11-05 16:11:21 -05:00
Eli Bosley
32478f34c2 fix: variable naming 2024-11-05 16:11:21 -05:00
Eli Bosley
4daa09b340 fix: only test if API was changed 2024-11-05 16:11:21 -05:00
Eli Bosley
346ce91f73 fix: EOF 2024-11-05 16:11:21 -05:00
Eli Bosley
cee3a6d0ef fix: env input 2024-11-05 16:11:21 -05:00
Eli Bosley
e90f606f43 feat: pass env into builder 2024-11-05 16:11:21 -05:00
Eli Bosley
05fa344454 feat: mount git folder to builder 2024-11-05 16:11:21 -05:00
Eli Bosley
406c400bd2 fix: proper directory in rc.unraid-api 2024-11-05 16:11:21 -05:00
Eli Bosley
1ae466899e fix: rm rf to fix build issues 2024-11-05 16:11:21 -05:00
Eli Bosley
5178e131ce fix: docker formatting and build mkdir issues 2024-11-05 16:11:21 -05:00
Eli Bosley
0bd11bce5a feat: don't remove directory, only files 2024-11-05 16:11:21 -05:00
Eli Bosley
fddde33977 fix: remove unused job dependency 2024-11-05 16:11:21 -05:00
Eli Bosley
1f5df845eb feat: build and pack in docker 2024-11-05 16:11:21 -05:00
Eli Bosley
ef54af655e fix: build issues based on removed code 2024-11-05 16:11:21 -05:00
Eli Bosley
bb44862b7b fix: builder cache 2024-11-05 16:11:21 -05:00
Eli Bosley
9709dc82ea feat: swap to action 2024-11-05 16:11:21 -05:00
Eli Bosley
38f0699e19 feat: linting continues on error 2024-11-05 16:11:21 -05:00
Eli Bosley
6ca9f421eb fix: apollo client lint issues 2024-11-05 16:11:21 -05:00
Eli Bosley
935825571b fix: load builder image to cache 2024-11-05 16:11:21 -05:00
Eli Bosley
9beaa78820 feat: move to singular build and test step 2024-11-05 16:11:21 -05:00
Eli Bosley
420c2c1afd feat: buildx build caching 2024-11-05 16:11:21 -05:00
Eli Bosley
7c0cb07b83 feat: only run mainline build 2024-11-05 16:11:21 -05:00
Eli Bosley
c6a7137f19 feat: right workin directory 2024-11-05 16:11:21 -05:00
Eli Bosley
44f9ba0e7f fix: subdependenies 2024-11-05 16:11:21 -05:00
Eli Bosley
1c61e64169 feat: workflow changes 2024-11-05 16:11:21 -05:00
Eli Bosley
cf0eeebd31 feat: remove more unused calls 2024-11-05 16:11:21 -05:00
Eli Bosley
f118597e47 feat: massive rc.unraid-api updates to facilitate installing and linking 2024-11-05 16:11:21 -05:00
Eli Bosley
6f2fcffd3e fix: remove unused imports 2024-11-05 16:11:21 -05:00
Eli Bosley
8f7748404c chore: dependency updates 2024-11-05 16:11:21 -05:00
Eli Bosley
88c2605d4f fix: delete boot script and update nvmrc 2024-11-05 16:11:21 -05:00
Eli Bosley
c2d645612a feat: add exclude to vite.config 2024-11-05 16:11:21 -05:00
Eli Bosley
b20f69c208 feat: pm2 fully working 2024-11-05 16:11:21 -05:00
Eli Bosley
b9cedb70ff fix: logging location 2024-11-05 16:11:21 -05:00
Eli Bosley
a11978aa33 fix: app running 2024-11-05 16:11:21 -05:00
Eli Bosley
b0efcc0d51 feat: pm2 initial setup 2024-11-05 16:11:21 -05:00
Eli Bosley
92b5f2226e fix: eslint config 2024-11-05 16:11:21 -05:00
Eli Bosley
98f2603525 feat: more cleanup 2024-11-05 16:11:21 -05:00
Eli Bosley
cfb1d50c8e feat: remove wtfnode 2024-11-05 16:11:21 -05:00
Eli Bosley
545ccf1938 feat: working 2024-11-05 16:11:21 -05:00
Eli Bosley
0c79995107 feat: almost working 2024-11-05 16:11:21 -05:00
Pujit Mehrotra
9d3397a687 refactor(web): reduce magic in identifying apollo cache item 2024-11-05 09:27:43 -05:00
Pujit Mehrotra
11c160835a feat(web): display error when a notification mutation fails 2024-11-05 09:27:43 -05:00
Pujit Mehrotra
e388b37aa6 refactor(web): simplify naming of notification mutations 2024-11-05 09:27:43 -05:00
Pujit Mehrotra
1da882b807 refactor(web): extract notification object cache prefix to a constant 2024-11-05 09:27:43 -05:00
Pujit Mehrotra
d9d5a24b70 feat(web): delete notifications from archive view 2024-11-05 09:27:43 -05:00
Pujit Mehrotra
24e3cad882 feat(web): make empty notification message clearer 2024-11-01 12:18:20 -04:00
Pujit Mehrotra
323a4a17cf feat(web): add empty state to notifications list 2024-11-01 12:18:20 -04:00
Pujit Mehrotra
9968e0f7df feat(web): implement notification filtering 2024-11-01 12:18:20 -04:00
Pujit Mehrotra
2ccc53630b doc(web): using codegen scripts & graphql fragments 2024-11-01 09:53:46 -04:00
Pujit Mehrotra
d7bb3defc3 doc(web): intro to using graphql 2024-11-01 09:53:46 -04:00
Pujit Mehrotra
ddb8bf8a5c refactor(web): improve signature & readability of mergeAndDedup cache function 2024-10-28 10:00:23 -04:00
Pujit Mehrotra
6234d61ae5 fix(web): dedupe incoming notifications during cache merge 2024-10-28 10:00:23 -04:00
Pujit Mehrotra
a665ee3ec6 fix(web): remove unused infinite-scroll emit from SheetContent 2024-10-28 10:00:23 -04:00
Pujit Mehrotra
7ca3efe8b8 doc(web): possibly ambiguous css & confusing cache policies/types 2024-10-28 10:00:23 -04:00
Pujit Mehrotra
28f4952599 fix(web): replace manual height hack in notifications infinite scroll 2024-10-28 10:00:23 -04:00
Pujit Mehrotra
7e4022518d feat(web): reconcile pagination with notifications apollo cache 2024-10-28 10:00:23 -04:00
Pujit Mehrotra
4d1656eaa8 feat(web): make notifications list scrollable inside the sheet & tabs 2024-10-28 10:00:23 -04:00
Michael Datelle
5b2421cb0c feat: add date formatting helper (#938) 2024-10-25 10:43:38 -04:00
Pujit Mehrotra
0578b066f1 refactor(web): extract notifications list for cleaner state management 2024-10-23 16:19:33 -04:00
Pujit Mehrotra
57fdcf3e60 refactor(api): parameterize max iterations of updateObject util 2024-10-23 16:19:33 -04:00
Pujit Mehrotra
eb7bdb6a85 feat(api): sort notifications file listing by date (latest first) 2024-10-23 16:19:33 -04:00
Pujit Mehrotra
ebd671e7b6 refactor(web): move archiveAll cache invalidation into apollo client config 2024-10-23 16:19:33 -04:00
Pujit Mehrotra
15a1a3ac15 feat(web): update cache & view when archiving notifications 2024-10-23 16:19:33 -04:00
Pujit Mehrotra
9a0c7fe9c8 refactor(Notifications): return modified notification when mutated
updated archiveNotification & unreadNotification mutations to return the
modified notification instead of an overview to improve default caching mechanics
when updating/moving notifications.
2024-10-23 16:19:33 -04:00
Pujit Mehrotra
91bcbc3d6f fix(api): strip server id prefixes from graphql request variables 2024-10-23 16:19:33 -04:00
Eli Bosley
b3d046f4ea feat: actual install url 2024-10-23 09:57:46 -04:00
Eli Bosley
0f13e34562 feat: install nghttp3 2024-10-23 09:37:12 -04:00
Eli Bosley
e18cd87180 fix: add max var 2024-10-22 16:15:23 -04:00
Eli Bosley
421949a9f8 fix: node install process improvements 2024-10-22 16:15:23 -04:00
Eli Bosley
8c7c580f3f fix: no more node_dl_server 2024-10-22 16:15:23 -04:00
Eli Bosley
c616641044 fix: no nodehost 2024-10-22 16:15:23 -04:00
Eli Bosley
fd16243287 fix: unused node dl line 2024-10-22 16:15:23 -04:00
Eli Bosley
7352bbe77a feat: install node 2024-10-22 16:15:23 -04:00
Eli Bosley
4d33908e01 fix: always mangle 2024-10-22 11:16:03 -04:00
Pujit Mehrotra
adabe92f72 refactor(web): move cn utility inside shadcn for modularization 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
958f9e57e1 refactor(api): use a type wrapper around fastify request in cookie.strategy 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
ac5032df83 feat(api): add default dynamix config to dev docker container 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
5f4cc07473 fix(api): load dynamix config in the same way as the webgui
merge defaults + custom config

see original php implementation in the webgui:
[link](95c6913c62/emhttp/plugins/dynamix/include/Wrappers.php (L42))
2024-10-18 11:42:38 -04:00
Pujit Mehrotra
38524bce88 fix(web): add default values to optional vue component props 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
64db2f19a7 fix(web): replace incorrect custom types with codegen from gql & update values to match expected shapes 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
8fe1e80bbd feat(web): add gql archival mutations to notifications sidebar & item 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
1c4506cf50 refactor(web): shadcn styles for consistency 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
84fe7f6df6 refactor(web): rm shadcn border radius overrides for consistency & simplicity 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
5c7e650b3b fix(web): inline shadcn variables into tailwind config to simplify build 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
6cac078e15 refactor(web): instantiate apollo client statically instead of dynamically 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
4e555021a7 fix: type & build errors 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
b1e2f043b1 chore(web): fix lint errors about imports 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
bc69852333 chore(web): omit notifications sidebar from UPC in staging & prod 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
2c79ccc883 fix(NotificationItem): icon & text alignment in header 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
c240fab58a refactor(NotificationItem): use button to view link instead of making the whole notification a clickable target 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
3c50022ac3 fix(NotificationsSidebar): occupy full viewport on small screens 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
9201136cb1 refactor(NotificationsItem): component design & layout 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
ff52f75abf refactor(NotificationsSidebar): de-emphasize archive-all & filter 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
eed40f7875 test(api): update permissions snapshots 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
754d4560ea feat: integrate cross-domain authentication to api 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
f6d09f4ba2 refactor(web): use tabs instead of buttons in NotificationsSidebar header 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
a1f0dac42d chore(web): display NotificationsSidebar in UserProfile component 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
fff935cf02 chore(api): add script to create mock user session in api container 2024-10-18 11:42:38 -04:00
Pujit Mehrotra
0849468fc2 chore(web): restore lockfile to correct state 2024-10-18 11:42:38 -04:00
Zack Spear
6a57924fbf feat: WIP sidebar filter select 2024-10-18 11:42:38 -04:00
mdatelle
57802c2ea0 feat(web): wip query api for notifications 2024-10-18 11:42:38 -04:00
mdatelle
924df0dc9e refactor(api): local dev permissions for notifications 2024-10-18 11:42:38 -04:00
Zack Spear
d04001e052 feat: WIP create teleport composable 2024-10-18 11:42:38 -04:00
Zack Spear
92ec931aff refactor: Update connectPluginInstalled value in serverState.ts 2024-10-18 11:42:38 -04:00
Eli Bosley
30f92374d0 fix: floating-ui fixes 2024-10-18 11:42:38 -04:00
Zack Spear
6bfd221cd1 test: sidebar tabs 2024-10-18 11:42:38 -04:00
Zack Spear
ceb537ae91 refactor: Update NotificationItemProps interface
- Add 'event' and 'date' properties to the NotificationItemProps interface
- Add 'view' property to the NotificationItemProps interface
- Remove trailing newline at the end of the file
2024-10-18 11:42:38 -04:00
Zack Spear
81b197a9aa refactor: Remove duplicate declaration of 'combinations' in terserReservations function 2024-10-18 11:42:38 -04:00
Zack Spear
54b4ad0df8 refactor: Remove extra whitespace in Notifications Sidebar and optimize Terser options in nuxt.config.ts 2024-10-18 11:42:38 -04:00
Zack Spear
e84c3ebe14 feat: WIP notifications w/ shadcn
Currently the build doesn't work in webgui
2024-10-18 11:42:38 -04:00
Zack Spear
81acf1d947 feat: wip Notification UI starter 2024-10-18 11:42:38 -04:00
renovate[bot]
80bfc231e0 chore(deps): update dependency @swc/core to v1.7.36 2024-10-18 10:06:20 -04:00
Zack Spear
b1409684db refactor: conditionally skip removeConsole plugin based on VITE_ALLOW_CONSOLE_LOGS env 2024-10-11 10:58:36 -04:00
Zack Spear
14d9448e4c refactor: build removeConsole conditionally skip via VITE_ALLOW_CONSOLE_LOGS env 2024-10-11 10:58:36 -04:00
Eli Bosley
924fa699eb fix: linter error 2024-10-10 09:42:38 -04:00
Eli Bosley
999a8e39eb fix: remove console logs with vue plugin 2024-10-10 09:41:12 -04:00
Eli Bosley
5a1c85d739 fix: remove unused disableProductionConsoleLogs call 2024-10-09 13:49:57 -04:00
Eli Bosley
ba77ff4a4c feat: remove console log disabler 2024-10-09 13:49:57 -04:00
Pujit Mehrotra
05765495c4 test(NotificationsService): add snapshot test to legacy script execution error 2024-10-09 13:12:15 -04:00
Pujit Mehrotra
f7cccc8c37 test(NotificationsService): add special characters to legacy script test 2024-10-09 13:12:15 -04:00
Pujit Mehrotra
85e0f7993e feat(NotificationsService): use existing notifier script to create notifications when possible 2024-10-09 13:12:15 -04:00
Pujit Mehrotra
d5a424ebe1 refactor(api): directly accept importance level in UnraidLocalNotifier 2024-10-09 13:12:15 -04:00
Pujit Mehrotra
01441961c3 doc(cors): update name of bypass flag 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
836f64d28f test(api): add auth-sessions to paths test snapshot 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
79bb4e585b refactor(CookieService): use paths store to get default sessions directory instead of a literal 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
409e88b727 refactor(cors): use BYPASS_CORS_CHECKS flag to ignore cors failures instead of BYPASS_PERMISSION_CHECKS 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
5034a8981a chore(CookieService): remove unused CookieGuard 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
e61d9f195d fix(CookieService): potential race condition in unit tests 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
b3e213ba04 refactor(CookieService): rename SESSION_COOKIE_OPTIONS to SESSION_COOKIE_CONFIG for clearer semantics 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
a7ea678683 fix(cors): excessive instantiation of CookieService to improve memory overhead 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
791e16ce52 test(CookieService): reading valid & invalid session cookies 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
173da0e65b refactor(CookieService): make cookie prefix & session directory injectable via Nest.js 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
287aabfda7 feat(auth): make cors aware of authenticated sessions 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
d8656cc6b3 fix: replace express cookie parser with fastify's 2024-10-08 15:52:43 -04:00
Pujit Mehrotra
a3500c9bc9 feat(Auth): add cookie guard to check for valid sessions 2024-10-08 15:52:43 -04:00
Zack Spear
b513cbe614 refactor(web): update README.md with instructions for dev testing and builds 2024-10-03 13:47:12 -07:00
Zack Spear
b5c525a9c2 refactor(web): tailwind config use .env VITE_TAILWIND_BASE_FONT_SIZE 2024-10-03 13:47:12 -07:00
Zack Spear
648b560148 refactor(package.json): update build scripts for dev and webgui
- Update the prebuild and postbuild scripts in package.json to handle environment variables and file paths correctly for the dev and webgui builds.
2024-10-03 13:47:12 -07:00
Zack Spear
6eb34c3501 refactor(prebuild-webgui-set-env.sh): update default file paths and handle requested env file
This commit updates the default file paths in the prebuild-webgui-set-env.sh script to use the requested env file instead of always using .env.production. If a specific env file is provided as an argument, its contents will be copied to .env. If the requested env file is not found, an error message will be displayed.
2024-10-03 13:47:12 -07:00
Zack Spear
21544bd2dc refactor(UserProfile): update text classes in banner section 2024-10-03 13:47:12 -07:00
Eli Bosley
3e115f84d7 fix: text classes 2024-10-02 16:02:01 -04:00
Eli Bosley
ba586fc438 feat: rem converter 2024-10-02 16:02:01 -04:00
Pujit Mehrotra
e6cbed14a9 fix(NotificationsService): edge-case in deleteAllNotifications by adding fs-extra package 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
f531e68b87 doc(NotificationService): rm obsolete note about race conditions 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
53f718e240 test: fix test definition for safely encoding top-level fields into INI strings 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
de36bfab99 chore: fix lint issues 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
1e2f57a4cd feat(NotificationService): endpoint to manually recalculate notification overview 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
46aa3a3e24 refactor(NotificationService): batchProcess util, gql Notifications->list instead of ->data to get notifications 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
0c627d1ade refactor(NotificationService): replace removeFromOverview
with `decrement` & `publishOverview`
2024-10-02 12:30:12 -04:00
Pujit Mehrotra
f20349fb2a chore: update vitest major version 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
dc72d63481 fix(NotificationService): file watcher initialization 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
e9efed8067 test(NotificationService): compatibility of outputs & combine archival filter tests 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
71ce064008 fix: rm getServerIdentifier wrapping Notifications id 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
b67b0ea633 test: filtering notifications 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
bf3d46d190 test,fix: crud'ing notifications, timestamp format consistency 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
a1fa3462eb feat,refactor: update notifications by filter & by id's 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
c84175e763 feat: implement mutations for updating many notifications at once 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
0f9fe18379 refactor: unraid timestamp into src/utils 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
76c0d35783 feat: make notification id logic 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
3ece0d1acc chore: update uuid@10.0.0 for v7 uuids
v7 uuids are basically v4 uuids that are sortable (by creation time)
2024-10-02 12:30:12 -04:00
Pujit Mehrotra
0473c9b676 fix: use correct ini encoder in notification service 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
1956227f63 fix: mv paths() to top of NotificationsService to make it more intuitive 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
c515d08d5c fix: race condition when updating notification types 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
0bd9820c00 feat: expose mutations for notifications over graphql 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
0c2299cfcd feat: add deletion & update methods to NotificationService
also stubs create method
2024-10-02 12:30:12 -04:00
Pujit Mehrotra
12fdfac467 chore: update prettier line width limit to 105ch
to prevent over-aggressive line breaks & wraps.
2024-10-02 12:30:12 -04:00
Pujit Mehrotra
3fc20ec593 fix: disable permissions bypass to avoid incorrect role assignment to api keys 2024-10-02 12:30:12 -04:00
Pujit Mehrotra
69a6163e29 feat: wrap Notifications in a GraphQL Node & implement notification overviews 2024-10-02 12:30:12 -04:00
mdatelle
00294699f0 fix: add return to resolver and update jsdoc for getNotifications 2024-10-02 12:30:12 -04:00
mdatelle
90ff980a00 refactor: update notifications.resolver to handle filtering
- Updates the getNotifications function to use the refactored getNotificationsFromPaths function
- Adds filtering logic to the updated  getNotificationsFromPaths function
- Update JSdocs
2024-10-02 12:30:12 -04:00
Pujit Mehrotra
17e7d2a2de fix: load notifications from file system instead of redux state
- Adds a Nest.js service for notifications
- Helps improve our memory footprint!
2024-10-02 12:30:12 -04:00
Eli Bosley
d2a88df5bf fix: lint issues 2024-09-27 13:57:47 -04:00
Eli Bosley
9471f5c918 fix: swap to flexible IDs in tests 2024-09-27 13:57:47 -04:00
Eli Bosley
492d45f363 feat: server identifier changes 2024-09-27 13:57:47 -04:00
Eli Bosley
2951d68f9d feat: ID prefixer improvement 2024-09-27 13:57:47 -04:00
Eli Bosley
4857bc0478 fix: convert updateId function to iterative instead of recursive 2024-09-27 13:57:47 -04:00
Eli Bosley
c794a1d1a1 feat: add ID prefix plugin to prefix IDs with server identifier 2024-09-27 13:57:47 -04:00
Zack Spear
d2a34acfb9 refactor: always show footer in CheckUpdateResponseModal 2024-09-12 20:14:10 -07:00
Zack Spear
3dc60b6106 feat: add deviceCount to serverAccountPayload for callbacks 2024-09-12 20:14:10 -07:00
Eli Bosley
57587b9175 chore(release): 3.11.0 2024-09-11 13:25:19 -04:00
ljm42
5ee7cb2647 feat: reduce how often rc.flashbackup checks for changes
Instead of checking once per minute, check once every 30 minutes
2024-09-10 12:48:40 -04:00
ljm42
911a3f8f1a feat: send api_version to flash/activate endpoint
also use _var() function in a few more places for consistency
2024-09-10 09:30:17 -07:00
ljm42
d426001372 feat: update ProvisionCert.php to clean hosts file when it runs 2024-09-09 12:49:15 -07:00
ljm42
2d0c65aaf4 fix: remove local flash backup ratelimit file on uninstall/update 2024-09-06 16:38:10 -07:00
ljm42
fd4605b956 chore: prevent corner case issue and fix php warning
* Update remoteerror in flashback.ini if it gets out of sync with gitratelimit (can happen during testing if you delete flashbackup.ini)
* Fix php warning for retry_after
2024-09-06 11:27:17 -07:00
Eli Bosley
3f84b6bbfd chore(release): 3.10.1 2024-09-03 14:43:08 -04:00
github-actions[bot]
5ad10af303 chore: release main 2024-09-03 14:36:05 -04:00
Eli Bosley
9aa11faaaa fix: don't release to github 2024-09-03 14:32:04 -04:00
Eli Bosley
bfa98574f1 fix: single tag for both components 2024-09-03 14:30:03 -04:00
github-actions[bot]
dd2dc40ff1 chore: release main 2024-09-03 14:24:36 -04:00
ljm42
8a3265d7b1 Feat: flash backup supports keyserver rate limits 2024-09-03 11:14:56 -07:00
ljm42
a240a031a8 feat: set OS minver to 6.12.0 2024-08-30 12:50:44 -07:00
ljm42
979e41fe41 fix: remove hard-coded entry for keyserver from hosts file 2024-08-30 10:52:50 -04:00
ljm42
03dc404aa7 Use "go links" when linking to Docs 2024-08-29 16:35:02 -07:00
Eli Bosley
364320ffc9 fix: unify pull requests for release-please 2024-08-28 16:51:26 -04:00
Eli Bosley
2492f4cec9 feat: web version set 2024-08-28 16:37:15 -04:00
Eli Bosley
1a643b3eef feat: set API version 2024-08-28 16:36:34 -04:00
Eli Bosley
58ee3b958b feat: remove plugin as part of release please 2024-08-28 16:15:00 -04:00
Eli Bosley
2928cf5821 fix: add manifest 2024-08-28 15:58:02 -04:00
Eli Bosley
b21b276151 fix: infer release type 2024-08-28 15:55:58 -04:00
Eli Bosley
d80f25dc96 feat: begin release-please setup 2024-08-28 15:53:24 -04:00
Eli Bosley
f5f5a081e6 fix: unused import 2024-08-28 15:44:03 -04:00
Eli Bosley
f60474b4d7 fix: lint 2024-08-28 15:44:03 -04:00
Eli Bosley
364373df0c fix: revert myservers.cfg to fix test 2024-08-28 15:44:03 -04:00
Eli Bosley
bb38533bb2 fix: update snapshots 2024-08-28 15:44:03 -04:00
Eli Bosley
836801c524 feat: dynamic remote access using remote queries 2024-08-28 15:44:03 -04:00
Eli Bosley
b54cf5ede9 feat: move dynamic remote access to be fully api controlled 2024-08-28 15:44:03 -04:00
Eli Bosley
1a20c66c02 fix: permission for dashboard payload 2024-08-28 15:44:03 -04:00
Eli Bosley
587bbb3b4d feat: create stable hash based on apikey rather than hostname 2024-08-28 15:44:03 -04:00
Eli Bosley
e95f7a1a03 feat: remove dashboard types 2024-08-28 15:44:03 -04:00
Eli Bosley
9c75f6e2ca feat: update tests and snapshots 2024-08-28 15:44:03 -04:00
Eli Bosley
822042ab9c feat: remove dashboard resolver completely in favor of direct field resolvers 2024-08-28 15:44:03 -04:00
Eli Bosley
3a843b6e16 feat: disable all legacy dashboard and network logic 2024-08-28 15:44:03 -04:00
renovate[bot]
6072387c37 chore(deps): update dependency @types/node to v18.19.46 (#795)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-27 14:27:11 -04:00
renovate[bot]
313162dbf2 fix(deps): update dependency wtfnode to v0.9.3 (#901)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-27 14:26:50 -04:00
Eli Bosley
495515abac feat: move FQDN urls to a generic parser (#899)
* feat: move FQDN urls to a generic parser

* feat: update myservers.cfg

* feat: update parser to begin changing ID fields

* fix: ID parser issues resolved

* fix: remove console log

* fix: update snapshots
2024-08-21 10:38:16 -04:00
Zack Spear
09087040e9 fix: flash backup activated detection in account payload (#898)
fix: flash backup activated detection in account payload to warn users to download back before unregistering with connect
2024-08-16 10:08:42 -04:00
Eli Bosley
4423829911 feat: add global agent (#897)
* feat: add global agent

* feat: add proxy setup to rc.unraid-api

* feat: update myservers.cfg to latest version
2024-08-14 14:52:36 -04:00
Eli Bosley
c8f469c4fb chore(release): 3.8.1 2024-08-13 14:11:02 -04:00
Zack Spear
bc61b45f9f refactor: registration component remove contact support 2024-08-13 14:04:54 -04:00
Eli Bosley
f530d9ea82 chore(release): 3.8.0 2024-08-13 13:50:07 -04:00
ljm42
2046fa5310 refactor: change flag that skips delete on uninstall (#892) 2024-08-13 13:40:18 -04:00
Zack Spear
9ea2327fa0 refactor: registration transfer check ineligible copy 2024-08-13 10:31:50 -07:00
Zack Spear
ff67b54a1b refactor: doc urls use /go links 2024-08-13 10:31:31 -07:00
ljm42
e6bd7a54be feat: always force push 2024-08-13 10:30:49 -07:00
Eli Bosley
5827b5ffa3 feat: swap to docker compose from docker-compose 2024-08-07 11:04:54 -04:00
ljm42
572a1310e0 Use "go links" when linking to Docs (#891) 2024-08-07 10:41:57 -04:00
ljm42
c1403d3826 feat: don't allow flash backup repos larger than 500MB (#890)
* feat: don't allow flash backup repos larger than 500MB

* fix: don't backup dynamix.file.integrity/logs

* feat: max file size for backup limited to 10mb

* feat: limit max repo size to 100MB

* feat: delete large repo again after 90 days
2024-08-07 10:41:36 -04:00
Eli Bosley
29afe9b9e8 feat: settings through the API (#867)
* feat: api settings fully working
* refactor: nuxt config ConnectSettings

---------

Co-authored-by: Zack Spear <hi@zackspear.com>
2024-07-03 13:38:09 -04:00
Zack Spear
e9ff33d263 feat: downgradeOs callback for non stable osCurrentBranch 2024-05-28 11:57:05 -07:00
Zack Spear
a62f60a436 fix: update status button alignment 2024-05-28 11:57:05 -07:00
Eli Bosley
838964c6ef chore: update package.json with new dependencies (#886)
* chore: update package.json with new dependencies

* feat: run codegen

* fix: got and reflect metadata revert version

* fix: pino version mismatch

* feat: update package-lock.json
2024-05-17 11:21:55 -04:00
Zack Spear
800fc12c15 refactor: server state refresh and response mutations 2024-05-16 14:13:01 -07:00
Zack Spear
80175241e3 fix: lint error for web components 2024-05-16 14:13:01 -07:00
Zack Spear
5d801f22f5 chore: ts-expect-error description for webgui troubleshoot form 2024-05-16 14:13:01 -07:00
Zack Spear
ba772add54 refactor: instantiation of web components 2024-05-16 14:13:01 -07:00
Zack Spear
ff24f12cae refactor: optional chaining for click props 2024-05-16 14:13:01 -07:00
Eli Bosley
487f5c1865 fix: tailwind config types 2024-05-16 14:13:01 -07:00
Eli Bosley
e0c90037fb fix: swap undefined to null 2024-05-16 14:13:01 -07:00
Eli Bosley
aa5f603cba fix: apolloClient types 2024-05-16 14:13:01 -07:00
Eli Bosley
409db43973 fix: ts-expect-error unneeded 2024-05-16 14:13:01 -07:00
Zack Spear
cef1b29355 fix: type check 2024-05-16 14:13:01 -07:00
Zack Spear
045750c87e fix: lint issues 2024-05-16 14:13:01 -07:00
Zack Spear
85802e7af7 fix: formattedRegTm type 2024-05-16 14:13:01 -07:00
Zack Spear
4bfdb66d46 fix: i18n t prop type 2024-05-16 14:13:01 -07:00
Zack Spear
81a6a52d9f fix: type errors round 1 2024-05-16 14:13:01 -07:00
Zack Spear
7759fe1dc3 chore(web): update deps + eslint (#887)
* chore: update deps + eslint

* fix: lint + type errors
2024-05-16 09:26:39 -04:00
renovate[bot]
3b2acb29b5 chore(deps): update dependency @vueuse/nuxt to v10.9.0 (#797)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 15:23:11 -04:00
renovate[bot]
5f2b949ecf chore(deps): update dependency @nuxtjs/tailwindcss to v6.12.0 (#794)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 15:22:43 -04:00
renovate[bot]
1b956d563e fix(deps): update dependency @vue/apollo-composable to v4.0.2 (#787)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 15:22:30 -04:00
Eli Bosley
c6a97f5082 chore(release): 3.7.1 2024-05-15 14:33:43 -04:00
Zack Spear
7f512e47e9 fix: reboot required and available edge case (#885)
* fix: reboot required and available edge case

* chore: add missing web component translations

* chore: translations sort unique ascending, case insensitive

* fix: translation json
2024-05-15 12:24:06 -04:00
Eli Bosley
5d725b0e76 chore(release): 3.7.0 2024-05-14 15:18:07 -04:00
renovate[bot]
fe63607260 chore(deps): update dependency @types/dockerode to v3.3.29 (#768)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-13 16:03:35 -04:00
Zack Spear
0a1d4daf6e refactor: update os status updateAvailable 2024-05-13 10:52:30 -07:00
Zack Spear
9e9e385bef chore: UnraidUpdateCancel reorganize 2024-05-13 10:52:30 -07:00
Zack Spear
6fed39e05b chore: update cancel comment 2024-05-13 10:52:30 -07:00
Zack Spear
3dec53d13d chore: UpdateOS Status unused import 2024-05-13 10:52:30 -07:00
Zack Spear
f0ded9f5be fix: update os cancel refresh on update page 2024-05-13 10:52:30 -07:00
Zack Spear
7d55a1c2cd chore: UpdateOS Status unused import 2024-05-13 10:52:30 -07:00
Zack Spear
f3dc9663b8 feat: UI Update OS Cancel 2024-05-13 10:52:30 -07:00
Zack Spear
05c7c481a9 chore: update cancel script 2024-05-13 10:52:30 -07:00
Zack Spear
adcc1543f0 feat: UnraidUpdateCancel script 2024-05-13 10:52:30 -07:00
Zack Spear
95f873c752 refactor: UnraidCheck use current unRAIDServer.plg 2024-05-13 10:52:30 -07:00
Zack Spear
ec90f8b295 fix: plugin file deployment script 2024-05-13 10:52:30 -07:00
Zack Spear
f84195a98d fix(web): lint unused rebootVersion 2024-05-13 10:52:30 -07:00
Zack Spear
5e98a68e2e feat: ui to allow second update without reboot 2024-05-13 10:52:30 -07:00
Zack Spear
b91dbca144 refactor: btnStyle prop for CallbackButton component 2024-05-13 10:52:30 -07:00
Zack Spear
79a01da18d refactor: ButtonStyle type 2024-05-13 10:52:30 -07:00
Zack Spear
14951d3004 refactor: reboot details added to server payload to account 2024-05-13 10:52:30 -07:00
Zack Spear
64c2061bea chore: dev deployment script improvements 2024-05-13 10:52:30 -07:00
Zack Spear
e3adc9a29a chore: dev deployment script improvements 2024-05-13 10:52:30 -07:00
ljm42
6b689ffcce Chore: sync http_get_contents() with webgui (#883) 2024-05-10 12:57:57 -07:00
ljm42
c995a4c5c8 Fix: rc.flashbackup needs to check both signed in and connected (#882)
because /var/local/emhttp/myservers.cfg does not clear the connected status when the user signs out
2024-05-10 10:44:21 -07:00
Zack Spear
8d1e0f67d1 refactor: simplify version_compare in reboot-details 2024-05-08 12:47:29 -07:00
Zack Spear
7877a5dca2 refactor: reboot type detection for downgrade via callback 2024-05-08 12:47:29 -07:00
Zack Spear
16db278ffd feat: downgradeOs callback 2024-05-08 12:47:29 -07:00
ljm42
521b4381f2 Fix bug in flash backup rate limiter (#880)
Don't try to read from an empty file
2024-05-07 17:11:36 -07:00
ljm42
9ae9d40f94 fix: keep minor enhancements from #872 (#878) 2024-05-07 08:39:46 -07:00
Zack Spear
1d562d404c fix(web): registration component remove unused ref 2024-05-06 10:44:16 -07:00
Zack Spear
7ac1b268d9 refactor(web): registration linked learn more callback to my keys 2024-05-06 10:44:16 -07:00
Zack Spear
4833e9dccf chore: translations 2024-05-06 10:44:16 -07:00
Zack Spear
f28b7510fa feat(web): Registration key linked to account status 2024-05-06 10:44:16 -07:00
Zack Spear
37b717b142 refactor(web): button component no style option 2024-05-06 10:44:16 -07:00
Zack Spear
fd8b40d9aa feat(web): callback types myKeys & linkKey 2024-05-06 10:44:16 -07:00
Eli Bosley
1d944781cf feat: add a timestamp to flash backup (#877)
* feat: add a timestamp to flash backup

* feat: update gitignore

* feat: random interval is now 30 minutes
2024-05-06 13:40:42 -04:00
Zack Spear
1f4c64d022 feat(plg): install prevent downgrade of shared page & php files (#873)
* feat(plg): install prevent downgrade of shared page & php files

* chore(plg): remove debug echo

* fix(plg): remove extra char
2024-05-02 14:08:38 -07:00
Zack Spear
f69b5130a3 refactor(web): copy Ineligible for feature updates (#875)
* refactor(web): copy Ineligible for feature updates

* refactor(web): Eligible for free feature updates
2024-05-02 14:04:16 -07:00
Zack Spear
f8b143904b fix: prevent corrupt case model in state.php (#874)
fix: prevent corruprt case model in state.php
2024-05-02 14:00:29 -07:00
Zack Spear
31a5413643 feat(web): registration page array status messaging 2024-05-01 12:21:24 -07:00
Zack Spear
a95fc5ed07 chore: lint fix 2024-05-01 12:21:24 -07:00
Zack Spear
fcd7bb790e refactor(web): ineligible release messaging 2024-05-01 12:21:24 -07:00
Zack Spear
008e10948e fix: prevent local dev from throwing ssl error 2024-05-01 12:21:24 -07:00
Zack Spear
c97a4f1268 feat: registration page server error heading + subheading 2024-05-01 12:21:24 -07:00
Zack Spear
3eba95b8cc feat: array state on registration page 2024-05-01 12:21:24 -07:00
Zack Spear
2bf8f0b937 fix(api): readme discord url 2024-04-30 17:34:46 -07:00
Zack Spear
9ae45d1258 fix(web): discord url 2024-04-30 17:34:46 -07:00
Zack Spear
1835a4cf3f chore(plg): comment explain web component downgrade prevention 2024-04-30 17:12:33 -07:00
Zack Spear
2ab44b894d feat(plg): plg install prevent web component downgrade 2024-04-30 17:12:33 -07:00
Zack Spear
1108f49b07 feat: postbuild script to add timestamp to web component manifest 2024-04-30 17:12:33 -07:00
ljm42
cc69213beb Feat: Flash Backup requires connection to mothership (#868)
* fix: branding

* feat: flash backup requires connection to mothership

* feat: flash backup requires connection to mothership
2024-04-26 12:01:42 -04:00
ljm42
460e557dd8 Flash Backup: exclude large files from repo (#866) 2024-04-23 21:21:01 -04:00
Zack Spear
05e29468d2 refactor: trial messaging replace pro with unleashed (#865)
* refactor: trial messaging replace pro with unleashed

* fix: trial messaging grammar

* refactor: web component translations trial messaging
2024-04-03 13:46:25 -04:00
ljm42
4d3a311fb4 Feat: add support for outgoing proxies (#863) 2024-03-27 15:14:18 -07:00
Zack Spear
bc62d210ec refactor: config error messages (#862) 2024-03-26 12:30:34 -04:00
Eli Bosley
43d3ea6553 chore(release): 3.6.0 2024-03-26 10:19:31 -04:00
Zack Spear
882e3e1ef4 feat: server config enum message w/ ineligible support (#861)
* test: serverState local components data tweaks

* feat: server config enum message w/ ineligible support

* refactor: config error messages

* chore: lint
2024-03-26 09:57:04 -04:00
Eli Bosley
b33c86c99c chore(release): 3.5.3 2024-03-25 09:22:14 -04:00
Zack Spear
cd0248e4c9 refactor: upgrade action button for unleashed to lifetime (#859) 2024-03-20 10:27:33 -04:00
Zack Spear
ecb3ed5003 fix: regDevs usage to allow more flexibility for STARTER (#860)
* fix: regDevs usage to allow more flexibility for STARTER

* fix: lint and type-check
2024-03-20 08:50:02 -04:00
Zack Spear
0569339a41 refactor(upc): remove UpdateDNS requests 2024-03-12 16:36:04 -07:00
ljm42
3e9faead43 Replace UpdateDNS.php with a stub (#857)
* This new stub file makes no network calls and always returns success
* It is meant to be backwards compatible with older releases of Unraid that expect the script to exist
2024-03-12 15:57:17 -04:00
Eli Bosley
6e700b2385 chore(release): 3.5.2 2024-03-06 10:20:09 -05:00
renovate[bot]
464fc4993c fix(deps): update dependency vue-i18n to v9.10.1 (#813)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 15:08:22 -05:00
renovate[bot]
4316c72809 chore(deps): update dependency terser to v5.28.1 (#802)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 15:08:05 -05:00
renovate[bot]
ce0cebe09c chore(deps): update dependency node to v18.19.1 (#801)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 15:07:51 -05:00
renovate[bot]
23b90a0d56 fix(deps): update dependency wretch to v2.8.0 (#814)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 15:07:38 -05:00
Zack Spear
3f8b3536b5 refactor: ENOKEYFILE messaging + button order (#856) 2024-03-05 15:07:20 -05:00
Zack Spear
0dcf785b45 fix: update os check modal button conditionals 2024-02-29 14:49:20 -08:00
Zack Spear
8cf4aff622 fix: update os check modal ineligible date format 2024-02-29 14:16:09 -08:00
Eli Bosley
cefda7c42b chore(release): 3.5.1 2024-02-29 12:43:48 -05:00
Eli Bosley
0393b2382c fix: build docker command updated to use dc.sh script 2024-02-29 12:43:41 -05:00
renovate[bot]
23e900f7fd chore(deps): update docker/setup-buildx-action action to v3 (#827)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-29 09:36:32 -05:00
renovate[bot]
2d6aafc257 chore(deps): update dependency eslint to v8.57.0 (#798)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-29 09:29:55 -05:00
renovate[bot]
b191efece1 chore(deps): update vitest monorepo to v1.3.1 (#784)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-29 09:29:40 -05:00
renovate[bot]
2a7f0043f5 fix(deps): update dependency @heroicons/vue to v2.1.1 (#804)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-29 09:29:17 -05:00
renovate[bot]
607c7e3704 fix(deps): update dependency @apollo/client to v3.9.5 (#785)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-29 09:29:01 -05:00
renovate[bot]
c246a443c5 fix(deps): update dependency graphql-ws to v5.15.0 (#790)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-29 09:25:35 -05:00
renovate[bot]
fd495e1f5c fix(deps): update dependency focus-trap to v7.5.4 (#788)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-29 09:24:58 -05:00
Zack Spear
621a06cafa fix: unraid-api.php $param1 fallback 2024-02-28 21:11:21 -08:00
Zack Spear
f890b05151 fix: unraid-api missing start command + var defaults 2024-02-28 21:11:21 -08:00
Zack Spear
567d8fdd6d fix: state php special chars for html attributes (#853)
* fix: state php special chars for html attributes

* refactor: upc description as v-html to latest state php change
2024-02-28 13:42:11 -05:00
ljm42
7d996906ad fix: date format in UnraidCheck.php (#852) 2024-02-27 13:43:01 -05:00
Zack Spear
b5ec076279 fix: os updates rc to stable 2024-02-23 13:47:35 -08:00
Zack Spear
de8dfe3dba fix: state php breaking with double quotes in server description 2024-02-23 13:46:09 -08:00
Zack Spear
7249956d40 fix: state connect values without connect installed 2024-02-23 13:46:09 -08:00
Zack Spear
e6eb56466e fix: display dropdown for pro key no connect installed (#848) 2024-02-14 11:10:28 -05:00
Zack Spear
8954700bcb fix: dropdown reboot link text (#849)
fix: dropdown reboot link
2024-02-14 10:50:03 -05:00
Eli Bosley
eb595cea9e chore(release): 3.5.0 2024-02-07 12:51:01 -05:00
Eli Bosley
9a1a0a54e6 feat: ship production to different bucket (#846) 2024-02-07 12:47:35 -05:00
Zack Spear
134396b602 refactor: state class webgui global fallback 2024-02-05 12:58:15 -08:00
Zack Spear
2aa65fdb68 fix: state php usage from cli 2024-02-05 12:58:15 -08:00
Zack Spear
a9c4d7d5dd chore: comment to handle error on sha256 fetch 2024-02-05 12:58:15 -08:00
Zack Spear
2cbbd5ee40 refactor: remove client side auto renewal 2024-02-05 12:58:15 -08:00
Zack Spear
c84c55761c fix: State Class usage in other files 2024-02-05 12:58:15 -08:00
Zack Spear
77eed36990 refactor: replaceRenewCheck only fire on Tools > Registration 2024-02-05 12:58:15 -08:00
Eli Bosley
5c2d84d8b4 feat: ship preview to different bucket (#845) 2024-02-02 12:01:18 -05:00
Eli Bosley
9883f0f82f feat: also ship to cloudflare (#844) 2024-02-02 10:53:24 -05:00
Zack Spear
e62b05b6f6 fix: extraLinks when no updates available 2024-02-01 12:38:10 -08:00
Zack Spear
8e6ee8b770 refactor: copy Extend Key to Extend License 2024-02-01 12:11:38 -08:00
Zack Spear
666b51a28a refactor: update os response modal button ordering 2024-02-01 11:48:14 -08:00
Zack Spear
1962097a66 refactor: callback modal button icons 2024-01-31 18:45:42 -08:00
Zack Spear
7f010854b5 refactor: availableWithRenewal determined by updateOsResponse isEligible
refactor: updateOsResponse changelogPretty key renamed
2024-01-31 14:52:04 -08:00
Zack Spear
17288a4c02 refactor: removing ignored release uncheck ignoreThisRelease 2024-01-31 14:52:04 -08:00
ljm42
ea48def9fc fix: backport _var() PHP function to older versions of Unraid 2024-01-31 14:06:15 -08:00
Zack Spear
a1d5c29ffb fix: state data humanReadable switch fallthrus 2024-01-31 13:33:34 -08:00
Zack Spear
bf99eb25c8 feat: update os notifications enabled usage + link to enable & more options to account app 2024-01-31 12:39:14 -08:00
Zack Spear
b35a440792 refactor: callback modal spacing 2024-01-31 11:02:37 -08:00
Zack Spear
58f9eec8b1 refactor: targeting keyType strings for Starter / Unleashed 2024-01-31 11:02:37 -08:00
Zack Spear
26841aa10d refactor: Registration component onBeforeMount 2024-01-31 11:02:37 -08:00
Zack Spear
e18a8d670e refactor: UnraidCheck writeJsonFile JSON_UNESCAPED_SLASHES 2024-01-31 11:02:37 -08:00
Zack Spear
49d077db97 refactor: UnraidCheck removeAllIgnored fail silently 2024-01-31 11:02:37 -08:00
Zack Spear
9dafe165b0 chore: UnraidCheck.checkForUpdate todo comment 2024-01-31 11:02:37 -08:00
Zack Spear
cce1953cb8 fix: ServerUpdateOsResponse type 2024-01-31 11:02:37 -08:00
Zack Spear
7e33b25593 refactor: header os version update status only when no state error 2024-01-31 11:02:37 -08:00
Zack Spear
78fb49a6fc refactor: only display UPC update links when no stateDataError 2024-01-31 11:02:37 -08:00
Zack Spear
f1e0d93bc5 refactor: header os version reboot type status simplify 2024-01-31 11:02:37 -08:00
Zack Spear
195a178d15 refactor: unraidcheck to use UnraidCheck class 2024-01-31 11:02:37 -08:00
Zack Spear
b9257fce28 refactor: state php to use UnraidCheck class 2024-01-31 11:02:37 -08:00
Zack Spear
41eaf4ef1b fix: lint 2024-01-31 11:02:37 -08:00
Zack Spear
93d0c08955 fix: check update response modal expired key button styles 2024-01-31 11:02:37 -08:00
Zack Spear
c5bc3454ff refactor: UnraidCheck clean up 2024-01-31 11:02:37 -08:00
Zack Spear
c33b4ef709 refactor: consolidate UpdateOS php files into a single class 2024-01-31 11:02:37 -08:00
Zack Spear
ce3ba7d070 refactor: update os check conditional altUrl param 2024-01-31 11:02:37 -08:00
Zack Spear
639eb08291 refactor: modal close button spacing 2024-01-31 11:02:37 -08:00
Zack Spear
6d109b4c4c refactor: upc dropdown conditional update os buttons 2024-01-31 11:02:37 -08:00
Zack Spear
6f3971dc47 refactor: check update response modal copy + alignment 2024-01-31 11:02:37 -08:00
Zack Spear
2ccb503dc8 refactor: lint clean up 2024-01-31 11:02:37 -08:00
Zack Spear
3cb9fdf102 refactor: modal spacing 2024-01-31 11:02:37 -08:00
Zack Spear
40d81a4081 refactor: translations 2024-01-31 11:02:37 -08:00
Zack Spear
5a85f55be8 refactor: header os version update os status pills 2024-01-31 11:02:37 -08:00
Zack Spear
5455e211bc chore: @todo for changelog_pretty 2024-01-31 11:02:37 -08:00
Zack Spear
cb4cc989c7 fix: missing translations 2024-01-31 11:02:37 -08:00
Zack Spear
037aa479bf refactor: improve responsive modal 2024-01-31 11:02:37 -08:00
Zack Spear
08567f287a fix: marked-base-url install 2024-01-31 11:02:37 -08:00
Zack Spear
a57f1d890d fix: changlog relative links and external links 2024-01-31 11:02:37 -08:00
Zack Spear
3ab406e012 refactor: modal styles & content scrollable 2024-01-31 11:02:37 -08:00
Zack Spear
f36f4702a2 fix: lint unused value 2024-01-31 11:02:37 -08:00
Zack Spear
62697f7972 feat: updateOs check response determines if update auth is required 2024-01-31 11:02:37 -08:00
Zack Spear
ec8d2bc0e8 feat: getOsReleaseBySha256 cached endpoint with keyfile header 2024-01-31 11:02:37 -08:00
Zack Spear
d83664b6a3 refactor: update os change modal continue button 2024-01-31 11:02:37 -08:00
Zack Spear
6910a020d2 chore: clean up console log 2024-01-31 11:02:37 -08:00
Zack Spear
60e5c6e3e8 fix: regTm format when already set 2024-01-31 11:02:37 -08:00
Zack Spear
90b1432875 fix: regTm format after key install without page refresh 2024-01-31 11:02:37 -08:00
Zack Spear
f1059aa381 refactor: header os update available badge open update modal 2024-01-31 11:02:37 -08:00
Zack Spear
01b4937f35 refactor: update os ignore release text 2024-01-31 11:02:37 -08:00
Zack Spear
3e051815c5 feat: update os ignore release 2024-01-31 11:02:37 -08:00
Zack Spear
e976daf8b0 refactor: ignore release switch colors 2024-01-31 11:02:37 -08:00
Zack Spear
422046dc03 refactor: registration item label text-right 2024-01-31 11:02:37 -08:00
Zack Spear
9a270971d1 refactor: center registration item without label 2024-01-31 11:02:37 -08:00
Zack Spear
0742382ae1 refactor: registration page conditionals 2024-01-31 11:02:37 -08:00
Zack Spear
763c38430e feat: add manage account link to all versions of upc dropdown 2024-01-31 11:02:37 -08:00
Zack Spear
4d926bba8e refactor: remove update os callback link from upc dropdown 2024-01-31 11:02:37 -08:00
Zack Spear
4acc4ea9a9 fix: ignore release localStorage 2024-01-31 11:02:37 -08:00
Zack Spear
565bf47818 fix: translations 2024-01-31 11:02:37 -08:00
Zack Spear
176a0f30be refactor: check update modal styles 2024-01-31 11:02:37 -08:00
Zack Spear
6f4d983d89 chore: uninstall pinia-plugin-persistedstate 2024-01-31 11:02:37 -08:00
Zack Spear
6a0e258cf2 test: component viewer 2024-01-31 11:02:37 -08:00
Zack Spear
8d82064888 refactor: translations 2024-01-31 11:02:37 -08:00
Zack Spear
4300179b67 refactor: check update response modal styling 2024-01-31 11:02:37 -08:00
Zack Spear
7e31ae2ebf refactor: changelog modal improvements 2024-01-31 11:02:37 -08:00
Zack Spear
7a27560b0d fix: type issue with changlelog modal visibility 2024-01-31 11:02:37 -08:00
Zack Spear
93655fef62 refactor: tailwind prose styles 2024-01-31 11:02:37 -08:00
Zack Spear
a581a95cb4 chore: formatting 2024-01-31 11:02:37 -08:00
Zack Spear
261fdda47c test: update data 2024-01-31 11:02:37 -08:00
Zack Spear
7a2a243a21 refactor: translations for new check update modals 2024-01-31 11:02:37 -08:00
Zack Spear
bead4256af feat: new check update buttons in dropdown 2024-01-31 11:02:37 -08:00
Zack Spear
e8dfd7e3b3 feat: update modals 2024-01-31 11:02:37 -08:00
Zack Spear
e456b7fcac feat: changelog modal 2024-01-31 11:02:37 -08:00
Zack Spear
fbe5e417ef feat: check update response modal 2024-01-31 11:02:37 -08:00
Zack Spear
5f80053a33 refactor: test page 2024-01-31 11:02:37 -08:00
Zack Spear
fa520a2d3e feat: button add underline-hover-red style option 2024-01-31 11:02:37 -08:00
Zack Spear
cf54f01945 chore: install marked 2024-01-31 11:02:37 -08:00
Zack Spear
44d2d58f12 refactor: modal spacing 2024-01-31 11:02:37 -08:00
Zack Spear
daba2a352f feat: updateOs store call local server-side endpoint & add modal support 2024-01-31 11:02:37 -08:00
Zack Spear
d1ff2b1fad refactor: button props type usage 2024-01-31 11:02:37 -08:00
Zack Spear
b1bd71f2e2 refactor: updateOs callback button action 2024-01-31 11:02:37 -08:00
Zack Spear
7f49816275 refactor: use account store updateOs callback 2024-01-31 11:02:37 -08:00
Zack Spear
d73d460e88 feat: create WebguiCheckForUpdate endpoint 2024-01-31 11:02:37 -08:00
Zack Spear
ab1e852b6c refactor: abstract button compnoent props type 2024-01-31 11:02:37 -08:00
Zack Spear
117b7430db chore: organize npm scripts & install pinia-plugin-persistedstate 2024-01-31 11:02:37 -08:00
Zack Spear
2e73f9e37a refactor: account updateOs callback 2024-01-31 11:02:37 -08:00
Zack Spear
d3158983b4 refactor: ServerUpdateOsResponse type 2024-01-31 11:02:37 -08:00
Zack Spear
dae7baa6ad refactor: server state parsedRegExp & set updateOsResponse 2024-01-31 11:02:37 -08:00
Zack Spear
e29f5e1adf feat: WebguiCheckForUpdate using server-side check 2024-01-31 11:02:37 -08:00
Zack Spear
e8d15c7dbb refactor: nuxt auto import components 2024-01-31 11:02:37 -08:00
Zack Spear
58be009da4 feat: unraidcheck callable from webgui with altUrl & json output 2024-01-31 11:02:37 -08:00
Eli Bosley
d4eb0ce3f2 feat: add new staging url for connect website (#841)
* feat: add new staging url for connect website

* feat: add url to plg
2024-01-12 13:42:15 -05:00
Eli Bosley
d73324a141 feat: upgrade a ton of dependencies (#842)
* feat: upgrade a ton of dependencies
2024-01-12 13:05:51 -05:00
renovate[bot]
7061be60f4 chore(deps): update docker/build-push-action action to v5 (#826)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-12 11:03:19 -05:00
renovate[bot]
2a65f64ac1 fix(deps): update dependency ws to v8.16.0 (#815)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-12 11:03:02 -05:00
Eli Bosley
120ba3e447 chore(release): 3.4.0 2024-01-11 17:28:39 -05:00
Eli Bosley
a527c7183a fix: run hourly 2024-01-11 17:25:57 -05:00
Eli Bosley
a0dfbb4e15 feat: add logrotate to cron in nestjs (#839)
* feat: add logrotate to cron in nestjs

* fix: set max size to 5m and remove old logs

* fix: logrotate command invalid
2024-01-11 17:17:23 -05:00
Eli Bosley
764f65ff61 fix: allow failure for log deletion 2024-01-11 16:44:25 -05:00
Eli Bosley
1615e8623c fix: excessive logging 2024-01-11 16:34:10 -05:00
Eli Bosley
d7bb9ff073 fix: allowed origins check not working without spaces (#838)
* fix: allowed origins check not working without spaces

* fix: broken test
2024-01-11 10:52:42 -05:00
Eli Bosley
d896581e12 chore(release): 3.3.0 2024-01-09 17:07:42 -05:00
ljm42
f833fa1fab fix: patch ShowChanges.php in 6.10 2024-01-09 13:51:00 -08:00
Zack Spear
2823517b26 fix: 6.10 view release notes js 2024-01-09 13:51:00 -08:00
Zack Spear
3e0a8d0070 fix: unraid-api server state refresh after key extension use regExp 2024-01-09 12:41:59 -08:00
Eli Bosley
b3768d65aa fix: codegen on web run 2024-01-09 12:15:38 -08:00
Eli Bosley
d2e17c0051 fix: local container startup commands cleaned up 2024-01-09 11:29:23 -08:00
Eli Bosley
d0354c2ef2 feat: local start command 2024-01-09 11:29:23 -08:00
Eli Bosley
17fc1181c2 feat: add support for expiration in var.ini (#833)
* feat: add support for expiration in var.ini

* tests: update snapshots
2024-01-09 12:19:59 -05:00
renovate[bot]
dbe7c5fb93 chore(deps): update actions/checkout action to v4 (#817)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-09 09:59:26 -05:00
renovate[bot]
54b421d01f chore(deps): update actions/download-artifact action to v4 (#818)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-09 09:59:14 -05:00
renovate[bot]
0e9611f802 chore(deps): update actions/upload-artifact action to v4 (#820)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-09 09:59:02 -05:00
renovate[bot]
4743a2439d chore(deps): update actions/setup-node action to v4 (#819)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-09 09:58:34 -05:00
Zack Spear
242c167f82 fix: refreshServerState check regExp 2024-01-08 13:12:33 -06:00
Zack Spear
e071b994cf refactor: installKey.install failure handling 2024-01-08 13:12:14 -06:00
Zack Spear
60bb8aa0fa chore: translations 2024-01-08 13:11:47 -06:00
Zack Spear
9f56f34ea4 fix: renew callback messaging in modal 2024-01-08 13:11:23 -06:00
Zack Spear
d66b33e600 fix: replaceRenew response cache use & purge 2024-01-08 12:31:20 -06:00
Zack Spear
63b7c0361e feat: npm scripts to prevent webgui builds with wrong urls 2024-01-08 11:13:22 -06:00
renovate[bot]
dea66ff49d fix(deps): update nest monorepo (#816)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-05 13:41:48 -05:00
renovate[bot]
c29621741e chore(deps): update dependency @swc/core to v1.3.102 (#700)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-05 09:52:22 -05:00
renovate[bot]
6d7d013f7a fix(deps): update graphql-tools monorepo (major) (#693)
fix(deps): update graphql-tools monorepo

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-05 09:51:46 -05:00
Eli Bosley
ed8e2420a5 fix: logrotate not working due to invalid ownership of unraid-api folder 2024-01-05 09:47:27 -05:00
Zack Spear
92ad66dd59 refactor: removed new key type translations 2024-01-04 12:04:00 -08:00
Zack Spear
5699e34ae9 refactor: sort translations alpha order case insensitive 2024-01-04 12:04:00 -08:00
Zack Spear
5f9dc26173 refactor: Registration page link order (#760) 2024-01-04 11:19:36 -07:00
Zack Spear
6d29ec2b90 fix: azure and gray theme custom colors 2024-01-03 13:50:36 -08:00
Eli Bosley
f91ae5c7a0 fix: rearrange exit hook to try to fix closing 2024-01-03 15:12:17 -05:00
Eli Bosley
33c69bf76f feat: fix exit hook and cleanup docker scripts (#758)
* feat: cleanup docker scripts

* feat: make logging directory if non-existent to fix stop behavior
2024-01-03 12:12:37 -05:00
ljm42
3e95bb259f fix: plugin install should suppress output from unraid-api stop (#757) 2024-01-03 10:10:37 -07:00
Eli Bosley
64b6bee559 fix: exit with process.exit not process.exitcode 2024-01-03 11:23:38 -05:00
Eli Bosley
61cb029780 feat: stretch downgrade component buttons 2024-01-03 08:13:56 -08:00
Eli Bosley
c02d823618 feat: fix logging format on start and stop 2024-01-03 10:43:00 -05:00
ljm42
fec36919c2 feat: change sort order of Update/Downgrade (#754) 2024-01-03 10:39:36 -05:00
Zack Spear
072242704d chore: translations note 2023-12-29 12:22:26 -05:00
ljm42
9199ffdeee feat: improve check for OS updates via PHP
* use http_build_query, and include query parms in result.json
* capture warnings and errors from file_get_contents in result.json
* track json decoding errors in result.json
2023-12-21 10:21:49 -08:00
ljm42
b92307eef5 feat: check for OS updates via PHP (#752) 2023-12-19 21:49:04 -07:00
Zack Spear
6445d1647a refactor: HeaderOsVersion update available badge 2023-12-19 16:25:26 -08:00
Zack Spear
3046fb9eed test: temp comment out serverState imports 2023-12-19 16:25:26 -08:00
Zack Spear
ad2c8b451a test: temp comment out mimicWebguiUnraidCheck in static serverStatic 2023-12-19 16:25:26 -08:00
Zack Spear
b39c5203fd chore: lint fix 2023-12-19 16:25:26 -08:00
Zack Spear
6e11ca209b refactor: clean up URLs 2023-12-19 16:25:26 -08:00
Zack Spear
eeb3598255 chore: lint 2023-12-19 16:25:26 -08:00
Zack Spear
c2063c28af refactor: components with refactored updateOsStore 2023-12-19 16:25:26 -08:00
Zack Spear
23b63de91f chore: remove unused component 2023-12-19 16:25:26 -08:00
Zack Spear
05a9340fc3 refactor: updateOsActions store with new updateOs store 2023-12-19 16:25:26 -08:00
Zack Spear
16f0ac5771 refactor: simplified updateOs store to use updateOsResponse from server store 2023-12-19 16:25:26 -08:00
Zack Spear
ebebf76933 refactor: clean up URLs 2023-12-19 16:25:26 -08:00
Zack Spear
8c956d45c7 fix: add missing translation keys 2023-12-19 16:25:26 -08:00
Zack Spear
4040933fad test: local dev serverState updateOsResponse 2023-12-19 16:25:26 -08:00
Zack Spear
63899f94fc refactor: state updateOs key to updateOsResponse 2023-12-19 16:25:26 -08:00
Zack Spear
7630ae87d4 refactor: state get updateOs details from /tmp/unraidcheck/response.json 2023-12-19 16:25:26 -08:00
Eli Bosley
127e2c3be6 feat: log config recreation reason 2023-12-13 12:47:40 -05:00
Eli Bosley
2aacbc1f1a feat: close log on exit 2023-12-13 12:27:47 -05:00
Eli Bosley
6f0673f428 feat: nestjs initial query implementation (#748)
* feat: nestjs initial query implementation
* feat: more permissions and resolver cleanup
* fix: back to ubuntu to remain compatible with pkg docker building
* feat: listen on socket as well as ports
* feat: swap to bookworm instead of ubuntu
2023-12-12 13:59:59 -05:00
Zack Spear
1315dc6099 chore: dateTime comment 2023-12-12 13:55:22 -05:00
Zack Spear
48bc19543e fix: dateTime system settings 2023-12-12 13:54:48 -05:00
Eli Bosley
08f7f95ea0 feat: always show DRA even if disabled 2023-12-12 13:02:22 -05:00
Zack Spear
6b72f188ef refactor: host in known origin check 2023-12-12 08:22:47 -08:00
Zack Spear
79ff9bedb9 refactor: add title to BrandButton usage 2023-12-12 08:22:47 -08:00
Zack Spear
d1c0f46325 refactor: Connect page web component button sizes 2023-12-12 08:22:47 -08:00
Zack Spear
909c2c6798 feat: disable account & key actions when unraid-api CORS error 2023-12-12 08:22:47 -08:00
Zack Spear
56dcd85aa1 fix: graphQL CORS error detection 2023-12-12 08:22:47 -08:00
Zack Spear
7918f5754f refactor: Connect extra origins add current host button 2023-12-12 08:22:47 -08:00
Zack Spear
519c24983a fix: combinedKnownOrigins in state.php for UPC 2023-12-12 08:22:47 -08:00
Zack Spear
735db3d5f5 refactor: connect page and state php data sharing 2023-12-12 08:22:47 -08:00
Zack Spear
53627f20c7 refactor: upc sign in text dropdown button 2023-12-12 08:22:47 -08:00
Zack Spear
181026567e refactor: include extraOrigins in list of allowedOrigins when checking for warning 2023-12-12 08:22:47 -08:00
Zack Spear
db6ca23533 feat: add button to add current origin to extra origins setting 2023-12-12 08:22:47 -08:00
Zack Spear
e0560afb6d chore: vscode settings 2023-12-12 08:22:47 -08:00
Eli Bosley
7e081e6661 fix: optional check on api.version to allow fallback to save value 2023-12-08 10:47:14 -05:00
Zack Spear
213caea5b6 fix: missing translation 2023-12-07 11:51:18 -05:00
Zack Spear
abd439f131 test: serverState osVersionBranch 2023-12-07 11:51:07 -05:00
Zack Spear
c681848d60 fix(web): azure & gray theme header font colors 2023-11-27 17:36:49 -05:00
Zack Spear
46a0567881 fix: lint unused param var prefixed 2023-11-21 10:59:48 -08:00
Zack Spear
0c80ef88b5 refactor(plg): state read case model from flash 2023-11-21 10:42:30 -08:00
Zack Spear
71252ddbea fix: state php version checking 2023-11-20 19:24:29 -08:00
Zack Spear
1ef2522089 refactor: updateOs lint 2023-11-20 19:24:14 -08:00
Zack Spear
f9652d7c06 refactor: updateOs store to match auth repo 2023-11-20 18:15:35 -08:00
Zack Spear
1de59150bc chore: rename web component deploy script 2023-11-20 17:43:19 -08:00
Zack Spear
2dd8cbb779 feat(web): caseModel 2023-11-20 17:42:40 -08:00
Zack Spear
f2b9cb0478 fix(plg): third party reboot detection 2023-11-15 16:02:38 -08:00
Zack Spear
e79ac7122a refactor(web): change callback url replace /Tools/Update to /Tolls 2023-11-15 15:21:02 -08:00
Zack Spear
c1c4baf476 test: remove standard-version 2023-11-15 13:55:10 -08:00
Zack Spear
e023ba6a19 chore(release): 1.0.8 2023-11-15 13:54:05 -08:00
Zack Spear
2ffeabe2a6 chore(release): 1.0.6 2023-11-15 13:49:25 -08:00
Zack Spear
36c5bbc3fd chore(release): 1.0.4 2023-11-15 13:49:07 -08:00
Zack Spear
da1ee3d631 test: package.json 2023-11-15 13:43:42 -08:00
Zack Spear
86b54dbe9a chore(release): 1.0.2 2023-11-15 13:42:59 -08:00
Zack Spear
296906758d chore(web): setup .versionrc to update version.txt on release 2023-11-15 13:42:43 -08:00
Zack Spear
cc2ea1244d chore(release): 1.0.1 2023-11-15 13:41:16 -08:00
Zack Spear
4aaf223007 chore(release): 1.0.0 2023-11-15 13:41:06 -08:00
Zack Spear
d283f1f321 refactor(web): remove unused onBeforeMount with console out 2023-11-15 13:35:31 -08:00
Zack Spear
f1731d732b refactor(web): remove console output 2023-11-15 13:32:09 -08:00
Zack Spear
33e4ba261c chore(web): add release script 2023-11-15 13:20:23 -08:00
Zack Spear
00f73bd3b8 chore(release): 1.0.0 2023-11-15 13:18:14 -08:00
Zack Spear
5ebce0ebfc refactor(plg): include Translations wrapper in translation class 2023-11-15 13:01:44 -08:00
Zack Spear
81f7f41b3b fix(web): use dateTime format from server 2023-11-15 13:01:13 -08:00
Zack Spear
00182ebb3c chore: deps updated 2023-11-14 17:22:48 -08:00
Zack Spear
58b2b2f130 fix: plg remove reboot-details path 2023-11-14 16:02:05 -08:00
Zack Spear
d132ad481b fix: header version thirdPartyDriversDownloading pill 2023-11-14 15:39:00 -08:00
Zack Spear
dd1ec82a52 fix: ThirdPartyDriver messaging on Update page 2023-11-14 14:04:24 -08:00
Zack Spear
2edc062569 fix: remove var_dump Connect settings 2023-11-14 13:52:40 -08:00
Zack Spear
a9c4e69e01 fix: Connect settings myservers config parse 2023-11-14 13:52:06 -08:00
Zack Spear
5f987458ef fix: uninstall reboot-details include 2023-11-14 13:10:48 -08:00
Eli Bosley
376a19bac6 fix: set sha in test step as well. 2023-11-14 14:19:23 -05:00
Eli Bosley
a1c07370ca fix: try to set environment in docker build 2023-11-14 14:16:10 -05:00
Zack Spear
1efd6b7e18 chore: copyright comments 2023-11-13 14:56:12 -08:00
Eli Bosley
1a31b2c929 feat: run codegen and update build script 2023-11-13 12:49:53 -05:00
Eli Bosley
9623f238b3 feat: add environment to docker-compose 2023-11-13 12:49:53 -05:00
Eli Bosley
fa5658fd81 feat: swap to fragement usage on webcomponent 2023-11-13 12:49:53 -05:00
Eli Bosley
0fa76f5d09 feat: extraOrigins public, remove origin listener 2023-11-13 12:49:53 -05:00
Eli Bosley
b4f0a084f1 feat: fix codegen 2023-11-13 12:49:53 -05:00
Eli Bosley
7d49bb2f10 feat: regTy swapped 2023-11-13 12:49:53 -05:00
Eli Bosley
8dd99b7f32 fix: add serverName / description to dashboard payload 2023-11-13 12:49:53 -05:00
Eli Bosley
eaddb696d4 feat: new key types in API 2023-11-13 12:49:53 -05:00
renovate[bot]
898c4e5656 chore(deps): update dependency eslint to v8.53.0 2023-11-13 10:41:03 -05:00
Zack Spear
62900565fb refactor: translations class usage 2023-11-09 16:49:47 -08:00
Zack Spear
e409ab805d chore: file formatting 2023-11-09 16:32:10 -08:00
Zack Spear
463ff4a38a refactor: state class usage with getServerStateJson 2023-11-09 16:31:48 -08:00
Zack Spear
205552eda5 fix: web component translations class 2023-11-09 16:09:43 -08:00
Zack Spear
ca3ffdc603 refactor: downgrade reboot details class usage 2023-11-09 15:45:30 -08:00
Zack Spear
be9e1e34f4 refactor: update os component prop reboot version 2023-11-09 10:05:15 -08:00
Zack Spear
00f1c63c46 refactor: web components translation php to class 2023-11-09 09:53:39 -08:00
Zack Spear
1c8437733c refactor: translations.php 2023-11-08 17:22:18 -08:00
Zack Spear
a658206cd4 refactor(plg): state include ServerState class 2023-11-08 16:17:06 -08:00
Zack Spear
95554e9832 chore(web): lint & type check to build:dev & build:webgui 2023-11-08 16:15:54 -08:00
Zack Spear
fb31fb584b refactor(web): registration feedback 2023-11-08 16:15:26 -08:00
Zack Spear
051faa06ac fix(web): reboot required disable update check link 2023-11-08 15:07:25 -08:00
Zack Spear
0e0a652dff refactor(web): improved header reboot pill link 2023-11-08 15:06:31 -08:00
Zack Spear
1403a76b80 fix: downgrade remove erroneous file_get_contents 2023-11-08 14:50:15 -08:00
Zack Spear
c4c51e83c2 refactor: php $docroot null coalescing assignment 2023-11-07 16:36:40 -08:00
Zack Spear
c91fef9c5f refactor(web): updateOs store release response group filtering 2023-11-07 15:40:36 -08:00
Zack Spear
9c33ef8248 refactor: state.php with RebootDetails class for type and version 2023-11-07 14:49:41 -08:00
Zack Spear
05ce165b83 refactor(web): improved downgrade ux 2023-11-07 13:07:02 -08:00
Zack Spear
485fc2a3b6 refactor: plg file upload to unraid server script 2023-11-07 13:07:02 -08:00
Zack Spear
f45f5f7a9a fix(web): update CallbackButton import 2023-11-07 13:07:02 -08:00
Zack Spear
9b9a6998b7 refactor(web): update page redirect 2023-11-07 13:07:02 -08:00
Zack Spear
82d9dc644b fix(web): downgrade-not-available when downgrade initiated 2023-11-07 13:07:02 -08:00
ljm42
81678d4de5 plg: update showchanges script 2023-11-07 09:28:00 -08:00
ljm42
032fd9853e plg: disable header message in DefaultPageLayout.php 2023-11-06 16:08:26 -08:00
Zack Spear
bf60f1e5ac refactor(web): downgrade view release notes 2023-11-06 16:06:05 -08:00
Zack Spear
bda8f4e1b3 fix(web): downgrade status pill for no downgrade available 2023-11-06 16:05:47 -08:00
Zack Spear
8c7160de2e refactor(web): registration item less padding 2023-11-06 15:21:27 -08:00
Zack Spear
2bd460effb fix(web): preview and test releases usage 2023-11-06 14:48:38 -08:00
Zack Spear
fdadfe699c fix(web): upc dropdown updates external icon 2023-11-06 14:14:03 -08:00
Zack Spear
84c96371f5 chore: lint and type check fixes 2023-11-06 13:53:29 -08:00
Zack Spear
799b77f09b refactor: downgrade and update improvements with store refactors 2023-11-06 13:20:06 -08:00
Zack Spear
1d67fa4c56 refactor(web): callback send redirect types 2023-11-06 13:18:28 -08:00
Zack Spear
8534fec4b2 refactor(web): webgui will not use preview & test release urls 2023-11-06 13:16:22 -08:00
Zack Spear
5483861055 fix(web): Update OS auto redirect loop with account 2023-11-06 13:15:57 -08:00
Zack Spear
bb60cbbc18 refactor(web): state consolidation 2023-11-06 13:13:53 -08:00
Zack Spear
fe906c025e refactor(web): update page downgrade in progress messaging 2023-11-03 17:11:37 -07:00
Zack Spear
79e2e89a80 refactor(web): downgrade status 2023-11-03 16:51:48 -07:00
Zack Spear
c30b926134 fix: plg installer header version replacement 2023-11-03 08:55:21 -07:00
Zack Spear
a87d83de04 refactor(web): dropdown post connect install 2023-11-03 08:40:21 -07:00
Zack Spear
7b3bd08c15 fix(web): updateOs lint 2023-11-03 08:40:21 -07:00
Zack Spear
00375a4590 fix: updateOs auth group usage 2023-11-03 08:40:21 -07:00
Zack Spear
6619138b54 refactor(web): updateOs store release error handling 2023-11-03 08:40:21 -07:00
ljm42
e9a7fcf95b feat: patch DefaultPageLayout for web component 2023-11-03 08:40:21 -07:00
Zack Spear
be1f419d92 refactor(web): updateOs release groups 2023-11-03 08:40:21 -07:00
Zack Spear
3a6b511de3 refactor: Tools page downgrade icon rotation 2023-11-03 08:40:21 -07:00
Zack Spear
82f15afbd2 refactor(web): sessionStorage name change 2023-11-03 08:40:21 -07:00
Zack Spear
524867b4e2 refactor(web): sessionStorage account & purchase url overrides 2023-11-03 08:40:21 -07:00
Zack Spear
d289e06c0b fix(plg): Downgrade & Update page file locations 2023-11-03 08:40:21 -07:00
renovate[bot]
13f366472b chore(deps): update graphqlcodegenerator monorepo 2023-11-02 12:37:59 -04:00
renovate[bot]
830718cd2c fix(deps): update dependency graphql to v16.8.1 2023-11-02 07:37:44 -04:00
renovate[bot]
8fffc7725c chore(deps): update dependency @types/semver to v7.5.4 2023-11-02 07:37:23 -04:00
Zack Spear
6fa6beb270 chore(web): shared callback store parity 2023-11-01 13:36:17 -07:00
Zack Spear
36846d2377 chore(web): state todo 2023-11-01 13:36:17 -07:00
Zack Spear
ef962f5f5d fix(web): lint fixes 2023-11-01 13:36:17 -07:00
Zack Spear
5cbccb06ad fix(web): type errors 2023-11-01 13:36:17 -07:00
Zack Spear
220a64ebdc chore(web): type fixes 2023-11-01 13:36:17 -07:00
Zack Spear
3145e30cf1 chore: remove test osReleases static json 2023-11-01 13:36:17 -07:00
Zack Spear
ef198494b0 chore: add nuxt type-check to package scripts 2023-11-01 13:36:17 -07:00
Zack Spear
9f1e3c5fda refactor: shared callback store with ServerState 2023-11-01 13:36:17 -07:00
Zack Spear
ddf8dc7ebf fix(web): regTy on account payload 2023-11-01 13:36:17 -07:00
Zack Spear
8bdffdc7b0 fix: updateOs type check 2023-11-01 13:36:17 -07:00
ljm42
915cdc3e06 remove legacy unraid.net settings migration from plugin (#741) 2023-11-01 13:36:17 -07:00
ljm42
4601388f3f Fix Remote Access Apply button 2023-11-01 13:36:17 -07:00
ljm42
66913bd221 Pass wanip to checkdns 2023-11-01 13:36:17 -07:00
Zack Spear
f554c3d3e2 chore: package updates 2023-11-01 13:36:17 -07:00
Zack Spear
2104eebe02 chore: lint manual fixes 2023-11-01 13:36:17 -07:00
Zack Spear
caab570be6 chore: lint auto fixes 2023-11-01 13:36:17 -07:00
ljm42
ca93ac7143 Add VS Code settings from the webgui
* add recommended extensions
* associate .page files with PHP
* add sftp-template.json
2023-11-01 13:36:17 -07:00
Zack Spear
9e895aed58 refactor(web): state.php use apikey $registered 2023-11-01 13:36:17 -07:00
Zack Spear
af4f53ed04 refactor: use env vars for os releases urls 2023-11-01 13:36:17 -07:00
Zack Spear
e021c48daa refactor(web): refactor copy-to-webgui-repo script 2023-11-01 13:36:17 -07:00
Zack Spear
ed4aa3d62c refactor(web): improved updateOs store extensibility 2023-11-01 13:36:17 -07:00
Zack Spear
2aa491e6f2 refactor(web): use osVersionBranch to determine releases endpoint 2023-11-01 13:36:17 -07:00
Zack Spear
1098e0f0e9 fix(web): reg component conditional keyActions 2023-11-01 13:36:17 -07:00
Zack Spear
8903371409 refactor: update os translations & auto callback for Tools > Update to account 2023-11-01 13:36:17 -07:00
Zack Spear
749eab85bd refactor: prevent callback send to /Tools/Update 2023-11-01 13:36:17 -07:00
Zack Spear
86d4defa3e refactor: remove emphasis from upc dropdown check for update link 2023-11-01 13:36:17 -07:00
Zack Spear
41fd15e7e3 test: dev page 2023-11-01 13:36:17 -07:00
Zack Spear
c1cff9e95f refactor: renew to extend front-end facing copy 2023-11-01 13:36:17 -07:00
Zack Spear
30a0e7d082 refactor(web): updateOs callback prevent duplicate install 2023-11-01 13:36:17 -07:00
Zack Spear
c387a28dbd refactor(web): upc check for updates callback link 2023-11-01 13:36:17 -07:00
Zack Spear
207ae12522 refactor: updateOs shared store better branch handling 2023-11-01 13:36:17 -07:00
Zack Spear
22ebb06980 refactor(web): update os use sha256 key server lookup + callback handle multiple actions with update os 2023-11-01 13:36:17 -07:00
Zack Spear
c0319d56b0 fix(web): translation 2023-11-01 13:36:17 -07:00
Zack Spear
3aaac2c244 fix(web): installPlugin composable for os updates 2023-11-01 13:36:17 -07:00
Zack Spear
d8a66e7b22 refactor(web): shared callback store extensibility 2023-11-01 13:36:17 -07:00
Zack Spear
00838e5cb8 test(web): dev callback builder helper 2023-11-01 13:36:17 -07:00
Zack Spear
6deaf9c342 refactor(web): button disabled styles 2023-11-01 13:36:17 -07:00
Zack Spear
5d6d91cfbd refactor(web): header os version styling 2023-11-01 13:36:17 -07:00
Zack Spear
f35e0ab627 test(web): serverState seed data 2023-11-01 13:36:17 -07:00
Zack Spear
c5da9ea002 test: dev removev unused props 2023-11-01 13:36:17 -07:00
Zack Spear
9334322f11 refactor: updateOs 2023-11-01 13:36:17 -07:00
Zack Spear
57a039b7d8 refactor(web): translations 2023-11-01 13:36:17 -07:00
Zack Spear
2621137e31 refactor(web): check os update button 2023-11-01 13:36:17 -07:00
Zack Spear
7276e9ddc9 refactor(web): prevent os update check with callback data present 2023-11-01 13:36:17 -07:00
Zack Spear
4e60c0ac1e fix(web): connect graph error handling 2023-11-01 13:36:17 -07:00
Zack Spear
13df4923a1 refactor(plg): downgrade page 2023-11-01 13:36:17 -07:00
Zack Spear
0eb0bdc918 refactor(plg): clean up Update page 2023-11-01 13:36:17 -07:00
Zack Spear
aaaa93f79e chore(web): formatting 2023-11-01 13:36:17 -07:00
Zack Spear
280dbfa53a refactor(web): os status 2023-11-01 13:36:17 -07:00
Zack Spear
3a5f976ff6 refactor: updateOs store parity with web components 2023-11-01 13:36:17 -07:00
Zack Spear
ea417435ac refactor: add os releases urls 2023-11-01 13:36:17 -07:00
Zack Spear
ecb69ba059 refactor(web): button component 2023-11-01 13:36:17 -07:00
Zack Spear
35f6a6cd3c refactor(plg): registration page web component 2023-11-01 13:36:17 -07:00
Zack Spear
64dc4c922d chore(web): clean up 2023-11-01 13:36:17 -07:00
Zack Spear
33a1e20338 chore(web): dateTime param comment 2023-11-01 13:36:17 -07:00
Zack Spear
9e1320b272 refactor(web): rename time composable to dateTime 2023-11-01 13:36:17 -07:00
Zack Spear
93649d0557 refactor(web): update ineligible text + DateTime helper exports 2023-11-01 13:36:17 -07:00
Zack Spear
46181dfa08 fix(web): regUpdatesExpired use .isAfter 2023-11-01 13:36:17 -07:00
Zack Spear
44066b292e test: seed data 2023-11-01 13:36:17 -07:00
Zack Spear
2f84fae344 refactor(web): downgrade 2023-11-01 13:36:17 -07:00
Zack Spear
d75548e219 feat(web): downgrade os web component 2023-11-01 13:36:17 -07:00
Zack Spear
ad416413fe refactor(web): ineligible available update ui/ux 2023-11-01 13:36:17 -07:00
Zack Spear
f99ea0bf16 chore(web): clean up unsued props 2023-11-01 13:36:17 -07:00
Zack Spear
d97be1e7aa refactor(web): add helper url 2023-11-01 13:36:17 -07:00
Zack Spear
01019ad546 refactor(web): ineligible copy 2023-11-01 13:36:17 -07:00
Zack Spear
3d99061a07 chore(web): clean up unsued props 2023-11-01 13:36:17 -07:00
Zack Spear
4c6ed1b530 refactor(web): button ui / ux 2023-11-01 13:36:17 -07:00
Zack Spear
50f0d03735 test(web): real expiration time 2023-11-01 13:36:17 -07:00
Zack Spear
9461a3e889 refactor(web): tailwind prose black 2023-11-01 13:36:17 -07:00
Zack Spear
65a69b2009 fix(web): state $_SESSION usage 2023-11-01 13:36:17 -07:00
Zack Spear
c07e4f45fb refactor(web): remove consoles 2023-11-01 13:36:17 -07:00
Zack Spear
2fc8169d00 refactor(web): updates expiration no minutes and seconds 2023-11-01 13:36:17 -07:00
Zack Spear
a152943047 chore(web): remove @todo 2023-11-01 13:36:17 -07:00
Zack Spear
4444af6938 refactor(web): improved replaceRenew caching 2023-11-01 13:36:17 -07:00
Zack Spear
ed0b41a425 feat(web): guidValidation if new keyfile auto install 2023-11-01 13:36:17 -07:00
Zack Spear
41879fa27c fix(web): state php warnings 2023-11-01 13:36:17 -07:00
Zack Spear
110108daf6 refactor(web): WIP renewed key file check 2023-11-01 13:36:17 -07:00
Zack Spear
27deaf91cc refactor(web): update os styles for regExp expiration 2023-11-01 13:36:17 -07:00
Zack Spear
37d548db8c refactor(web): key server valid guid response type 2023-11-01 13:36:17 -07:00
Zack Spear
67c2e1f3cf refactor(web): updateOsActions usage 2023-11-01 13:36:17 -07:00
Zack Spear
efc55e77ef fix(web): default time format include am/pm 2023-11-01 13:36:17 -07:00
Zack Spear
a1a10777a5 refactor(web): card wrapper warning styles 2023-11-01 13:36:17 -07:00
Zack Spear
7282bde765 refactor(web): badge yellow text color black 2023-11-01 13:36:17 -07:00
Zack Spear
1a384e53ec refactor(web): button component tweaks 2023-11-01 13:36:17 -07:00
Zack Spear
00c07290ad feat(web): refactor generic updateOS with date comparison 2023-11-01 13:36:17 -07:00
Zack Spear
817f92d398 refactor: Registration component regExp usage & styles 2023-11-01 13:36:17 -07:00
Zack Spear
d943b67270 refactor: Registration component regExp usage & styles 2023-11-01 13:36:17 -07:00
Zack Spear
c171524dc6 test: dev seed data 2023-11-01 13:36:17 -07:00
Zack Spear
0dcff37419 test: updated static releases json 2023-11-01 13:36:17 -07:00
Zack Spear
65ebfc95d0 fix(web): card wrapper error border styles 2023-11-01 13:36:17 -07:00
Zack Spear
e8609526b0 refactor(web): improved ux for update os flash backup 2023-11-01 13:36:17 -07:00
Zack Spear
4bc0015b48 refactor(web): new key type callback payloads 2023-11-01 13:36:17 -07:00
Zack Spear
bfa667c1ab feat(web): update os create flash backup button 2023-11-01 13:36:17 -07:00
Zack Spear
cadbd65cf6 chore(web): button component comment 2023-11-01 13:36:17 -07:00
Zack Spear
eae6d75bca refactor(web): update os check includeNext defaults 2023-11-01 13:36:17 -07:00
Zack Spear
f4ab363901 refactor(web): improved regExp handling 2023-11-01 13:36:17 -07:00
Zack Spear
7c806fee8a fix(web): missing translations 2023-11-01 13:36:17 -07:00
Zack Spear
9f3fab6de4 refactor(web): header os version logic 2023-11-01 13:36:17 -07:00
Zack Spear
2c3c9c441e refactor(web): header os version spacing 2023-11-01 13:36:17 -07:00
Zack Spear
a7644ee487 refactor(web): button styles 2023-11-01 13:36:17 -07:00
Zack Spear
396b98da01 test(web): serverState 2023-11-01 13:36:17 -07:00
Zack Spear
d0da1f4e39 fix(web): missing translation 2023-11-01 13:36:17 -07:00
Zack Spear
a24e73da7e refactor(web): replaceCheck sessionStorage key 2023-11-01 13:36:17 -07:00
Zack Spear
3aa082fec1 refactor(web): update ui improvement 2023-11-01 13:36:17 -07:00
Zack Spear
70fd31afb6 fix(web): Registration key actions 2023-11-01 13:36:17 -07:00
Zack Spear
c299a794b2 refactor(web): KeyActions extensibility 2023-11-01 13:36:17 -07:00
Zack Spear
d3429f31a6 refactor(web): button hover display right icon 2023-11-01 13:36:17 -07:00
Zack Spear
7b951f3e3b refactor(web): Os Update component conditional error styles 2023-11-01 13:36:17 -07:00
Zack Spear
b0bd1b9635 fix(web): replace check request error handling 2023-11-01 13:36:17 -07:00
Zack Spear
10ab864a43 refactor(web): ReplaceCheck status feedback 2023-11-01 13:36:17 -07:00
Zack Spear
6a6f0e9c53 refactor(web): CardWrapper error styles prop 2023-11-01 13:36:17 -07:00
Zack Spear
8cd19bbc26 fix(web): missing translations 2023-11-01 13:36:17 -07:00
Zack Spear
7404c4ce6b refactor(web): docs url 2023-11-01 13:36:17 -07:00
Zack Spear
6d336fda23 refactor(web): upgrade expiration button white 2023-11-01 13:36:17 -07:00
Zack Spear
b9c45d96c1 chore(web): clean up replace check component 2023-11-01 13:36:17 -07:00
Zack Spear
b0e1d5dafb refactor(web): button component additional colors & size prop 2023-11-01 13:36:17 -07:00
Zack Spear
05369a49a4 refactor(web): registration ux/ui button placement 2023-11-01 13:36:17 -07:00
Zack Spear
04916756c6 fix(web): replaceCheck type 2023-11-01 13:36:17 -07:00
Zack Spear
2581254a02 refactor(web): key actions component filter props 2023-11-01 13:36:17 -07:00
Zack Spear
c1b509220e fix(web): replaceCheck type 2023-11-01 13:36:17 -07:00
Zack Spear
676ea0629b chore(web): concise param 2023-11-01 13:36:17 -07:00
Zack Spear
41d6ebe536 refactor(web): progress on regExp & dateTimeFormat from server 2023-11-01 13:36:17 -07:00
Zack Spear
422b93495a refactor(web): formatDate helper format to LLLL 2023-11-01 13:36:17 -07:00
Zack Spear
7246ee34bd feat(web): WIP key expiration 2023-11-01 13:36:17 -07:00
Zack Spear
4d3e8bee84 refactor(web): replace key eligibility using store 2023-11-01 13:36:17 -07:00
Zack Spear
7dffa1a701 refactor(web): HeaderOsVersion text size 2023-11-01 13:36:17 -07:00
Zack Spear
ba16411bf1 feat(web): start prep for new key type support 2023-11-01 13:36:17 -07:00
Zack Spear
de1da57286 fix(web): missing translation for update 2023-11-01 13:36:17 -07:00
Zack Spear
6687a1eba0 refactor(web): RegistrationItem props 2023-11-01 13:36:17 -07:00
Zack Spear
f0998271ba refactor(web): lan ip copy 2023-11-01 13:36:17 -07:00
Zack Spear
a84b972121 feat(web): registration too many devices messaging 2023-11-01 13:36:17 -07:00
Zack Spear
e5b51564fd fix(web): localStorage craftUrl for dev 2023-11-01 13:36:17 -07:00
Zack Spear
6ddcdf2812 chore(web): dev seed data 2023-11-01 13:36:17 -07:00
Zack Spear
bc177ad740 refactor(web): state regTo htmlspecialchars to match original registration.page 2023-11-01 13:36:17 -07:00
Zack Spear
7b471588ab feat(web): localStorage craftUrl for dev 2023-11-01 13:36:17 -07:00
Zack Spear
d7a4e4fde6 refactor(web): tailwind prose styles 2023-11-01 13:36:17 -07:00
Zack Spear
4986b69c62 refactor(web): registration item rounded 2023-11-01 13:36:17 -07:00
Zack Spear
7a22f4ac88 refactor(web): replace eligibility notes + passing keyfile 2023-11-01 13:36:17 -07:00
Zack Spear
f059b6fd0d refactor(web): keyServer validate types 2023-11-01 13:36:17 -07:00
Zack Spear
65fb41c562 refactor(web): replace check use UiBadge for status 2023-11-01 13:36:17 -07:00
Zack Spear
c3d8002a76 feat(web): registration replace eligibility docs btn 2023-11-01 13:36:17 -07:00
Zack Spear
6c98369719 feat(web): registration component ui / ux 2023-11-01 13:36:17 -07:00
Zack Spear
f5b0ca63e8 chore(web): remove console 2023-11-01 13:36:17 -07:00
Zack Spear
90303689db refactor: WIP registration update expiration 2023-11-01 13:36:17 -07:00
Zack Spear
17a5767108 refactor(web): registration page UI UX 2023-11-01 13:36:17 -07:00
Zack Spear
e04b619071 feat(web): WIP registration page UI UX 2023-11-01 13:36:17 -07:00
Zack Spear
858a93ccd2 feat(web): WIP registration page web component 2023-11-01 13:36:17 -07:00
Zack Spear
e22d1f0a6c refactor(web): update handle third-party drivers 2023-11-01 13:36:17 -07:00
Zack Spear
9994dd49f7 refactor(web): theme gamma opaque color for border 2023-11-01 13:36:17 -07:00
Zack Spear
5cf1740977 refactor: reboot detection passed to upc 2023-11-01 13:36:17 -07:00
Zack Spear
297bce3a89 refactor: downgrades working + reboot notice 2023-11-01 13:36:17 -07:00
Zack Spear
d8faef0146 refactor: WIP on downgrade and UI / UX 2023-11-01 13:36:17 -07:00
Zack Spear
57efcef072 feat: WIP first pass at UpdateOs page replacement component 2023-11-01 13:36:17 -07:00
Zack Spear
5c58a86d86 feat: WIP UpdateOs page component 2023-11-01 13:36:17 -07:00
Zack Spear
ab06ed75c3 refactor: update os callback action confirm 2023-11-01 13:36:17 -07:00
Zack Spear
6f812dad90 refactor: updateOs init callback includeNext true 2023-11-01 13:36:17 -07:00
Zack Spear
aa50d88575 refactor: generic updateOs store 2023-11-01 13:36:17 -07:00
Zack Spear
971e879744 refactor: genericized updateOs store to be shared with other repos 2023-11-01 13:36:17 -07:00
Zack Spear
dc2191f228 refactor: WIP updateOs store – response caching and update version checking 2023-11-01 13:36:17 -07:00
Zack Spear
a270b926b3 chore: dev static osReleases json 2023-11-01 13:36:17 -07:00
Zack Spear
051bcf1dc2 chore: dev server state seed data 2023-11-01 13:36:17 -07:00
Zack Spear
578e5ea6b7 chore: @todo callbackfeedback 2023-11-01 13:36:17 -07:00
Zack Spear
56525f8008 refactor: callback payload for updateOS use md5 2023-11-01 13:36:17 -07:00
Zack Spear
32559bab5d feat: server store isOsVersionStable 2023-11-01 13:36:17 -07:00
Zack Spear
cb1f3411ce refactor: callback payload for updateOS use md5 2023-11-01 13:36:17 -07:00
Zack Spear
6fb916eccd feat(web): WIP updateOs callback 2023-11-01 13:36:17 -07:00
Zack Spear
313736e3c6 refactor(web): callbackAction updateOs 2023-11-01 13:36:17 -07:00
Zack Spear
f8eccde99b refactor(web): callback OsRelease type 2023-11-01 13:36:17 -07:00
Zack Spear
c5cc372d7f refactor(web): install plugin composable extensibility 2023-11-01 13:36:17 -07:00
Zack Spear
8b5ba1aa97 wip: update os via upc 2023-11-01 13:36:17 -07:00
712 changed files with 92014 additions and 47716 deletions

1
.github/unraid.svg vendored Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 1000 1000"><defs><linearGradient id="a" x1="-900" x2="-100" y1="-100" y2="-900" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#e32929"/><stop offset="1" stop-color="#ff8d30"/></linearGradient></defs><path fill="url(#a)" d="M1000 500.1v376.4c0 57.5-43.4 110.1-100 120.9-8.4 1.6-17.1 2.5-25.6 2.5-250.1.1-500.2.1-750.3.1-61.3 0-114.8-47-122.8-108q-.3-2.1-.6-4.1-.2-2-.3-4.1-.2-2-.3-4v-4.1C0 624.9 0 374.2 0 123.5 0 66 43.4 13.3 100 2.6 108.4 1 117.1.1 125.6.1 375.9 0 626.2 0 876.5 0 934 0 986.7 43.4 997.4 100c1.5 8.4 2.5 17.1 2.5 25.6.1 124.8.1 249.7.1 374.5z"/><path fill="#fff" d="M481.6 392.1h36.5v216.2h-36.5zm-356 0h36.5v216.2h-36.5zm178 242h36.5v82.5h-36.5zm-89.3-92.7h36.5v133.7h-36.5zm178 0h36.5V675h-36.5zm445.8-149.3h36.5v216.1h-36.5zm-178-107.8h36.5v82.6h-36.5zm89.3 41.5h36.5v133.1h-36.5zm-178.6 0h36.5v133h-36.5z"/></svg>

After

Width:  |  Height:  |  Size: 915 B

View File

@@ -1,74 +0,0 @@
name: Lint, Test, and Build Web Components
on:
workflow_dispatch:
jobs:
lint-web:
defaults:
run:
working-directory: web
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Create env file
run: |
touch .env
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
cat .env
- name: Install node
uses: actions/setup-node@v3
with:
cache: "npm"
cache-dependency-path: "web/package-lock.json"
node-version-file: "web/.nvmrc"
- name: Installing node deps
run: npm install
- name: Lint files
run: npm run lint
build-web:
defaults:
run:
working-directory: web
runs-on: ubuntu-latest
needs: [lint-web]
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Create env file
run: |
touch .env
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
cat .env
- name: Install node
uses: actions/setup-node@v3
with:
cache: "npm"
cache-dependency-path: "web/package-lock.json"
node-version-file: "web/.nvmrc"
- name: Installing node deps
run: npm install
- name: Build
run: npm run build
- name: Upload build to Github artifacts
uses: actions/upload-artifact@v3
with:
name: unraid-web
path: web/.nuxt/nuxt-custom-elements/dist/unraid-components

View File

@@ -1,6 +1,7 @@
name: CI - Main (API)
on:
pull_request:
push:
branches:
- main
@@ -12,6 +13,18 @@ concurrency:
cancel-in-progress: true
jobs:
release-please:
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- id: release
uses: googleapis/release-please-action@v4
outputs:
releases_created: ${{ steps.release.outputs.releases_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
start:
# This prevents a tag running twice as it'll have a "tag" and a "commit" event
# We only want the tag to run the action as it'll be able to create the release notes
@@ -21,202 +34,167 @@ jobs:
- name: Validate branch and tag
run: exit 0
lint-api:
continue-on-error: true
build-test-api:
name: Build and Test API
runs-on: ubuntu-latest
defaults:
run:
working-directory: api
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
persist-credentials: false
- name: Reconfigure git to use HTTP authenti:cation
run: >
git config --global url."https://github.com/".insteadOf
ssh://git@github.com/
- name: Install node
uses: actions/setup-node@v3
with:
node-version-file: "api/.nvmrc"
# - name: Get npm cache directory
# id: npm-cache
# run: echo "::set-output name=dir::$(npm config get cache)"
# - name: Load npm cache
# uses: actions/cache@v3
# with:
# path: ${{ steps.npm-cache.outputs.dir }}
# key: ${{ runner.os }}-npm-cache-${{ hashFiles('**/package-lock.json') }}
- name: Install libvirt-dev
run: sudo apt-get update && sudo apt-get install libvirt-dev
- name: Installing node deps
run: npm install
- name: Lint files
run: npm run lint
test-api:
defaults:
run:
working-directory: api
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
persist-credentials: false
- name: Reconfigure git to use HTTP authentication
run: >
git config --global url."https://github.com/".insteadOf
ssh://git@github.com/
- name: Build Docker Compose
run: |
docker network create mothership_default
docker-compose build builder
- name: Run Docker Compose
run: docker-compose run builder npm run coverage
lint-web:
defaults:
run:
working-directory: web
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Create env file
run: |
touch .env
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
cat .env
- name: Install node
uses: actions/setup-node@v3
with:
cache: "npm"
cache-dependency-path: "web/package-lock.json"
node-version-file: "web/.nvmrc"
- name: Installing node deps
run: npm install
- name: Lint files
run: npm run lint
build-api:
defaults:
run:
working-directory: api
runs-on: ubuntu-latest
outputs:
API_VERSION: ${{ steps.build-pack-binary.outputs.API_VERSION }}
API_VERSION: ${{ steps.vars.outputs.API_VERSION }}
API_MD5: ${{ steps.set-hashes.outputs.API_MD5 }}
API_SHA256: ${{ steps.set-hashes.outputs.API_SHA256 }}
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Add SSH deploy key
uses: shimataro/ssh-key-action@v2
uses: actions/checkout@v4
- name: Build with Buildx
uses: docker/setup-buildx-action@v3
with:
key: ${{ secrets.UNRAID_BOT_SSH_KEY }}
known_hosts: ${{ secrets.KNOWN_HOSTS }}
- name: Install node
uses: actions/setup-node@v3
install: true
platforms: linux/amd64
- name: Build Builder
uses: docker/build-push-action@v6
with:
node-version-file: "api/.nvmrc"
context: ./api
push: false
tags: builder:latest
cache-from: type=gha,ref=builder:latest
cache-to: type=gha,mode=max,ref=builder:latest
load: true
- name: Lint inside of the docker container
continue-on-error: true
run: |
docker run --rm builder npm run lint
- name: Install libvirt-dev
run: sudo apt-get update && sudo apt-get install libvirt-dev
- name: Installing node deps
run: npm install
- name: Install pkg and node-prune
run: npm i -g pkg && curl -sf https://gobinaries.com/tj/node-prune | sh
# See https://github.com/apollographql/subscriptions-transport-ws/issues/433
- name: Patch subscriptions-transport-ws
run: npm run patch:subscriptions-transport-ws
- name: Build and Pack
- name: Test inside of the docker container
run: |
git fetch --depth=2 origin main
if git diff --name-only --relative=api origin/main HEAD | grep -q '.'; then
docker run --rm builder npm run coverage
else
echo "No changes in /api folder, skipping coverage."
fi
- name: Get Git Short Sha and API version
id: vars
run: |
GIT_SHA=$(git rev-parse --short HEAD)
IS_TAGGED=$(git describe --tags --abbrev=0 --exact-match || echo '')
PACKAGE_LOCK_VERSION=$(jq -r '.version' package-lock.json)
echo "GIT_SHA=$GIT_SHA" >> $GITHUB_OUTPUT
echo "IS_TAGGED=$IS_TAGGED" >> $GITHUB_OUTPUT
echo "PACKAGE_LOCK_VERSION=$PACKAGE_LOCK_VERSION" >> $GITHUB_OUTPUT
echo "API_VERSION=$([[ -n "$IS_TAGGED" ]] && echo "$PACKAGE_LOCK_VERSION" || echo "${PACKAGE_LOCK_VERSION}+${GIT_SHA}")" >> $GITHUB_OUTPUT
- name: Build inside of the docker container
id: build-pack-binary
run: WORKDIR=${{ github.workspace }} && npm run build-pkg
run: |
docker run --rm -v ${{ github.workspace }}/api/deploy/release:/app/deploy/release -e API_VERSION=${{ steps.vars.outputs.API_VERSION }} builder npm run build-and-pack
- name: Set Hashes
id: set-hashes
run: |
API_MD5=$(md5sum ${{ github.workspace }}/api/deploy/release/*.tgz | awk '{ print $1 }')
API_SHA256=$(sha256sum ${{ github.workspace }}/api/deploy/release/*.tgz | awk '{ print $1 }')
echo "::set-output name=API_MD5::${API_MD5}"
echo "::set-output name=API_SHA256::${API_SHA256}"
echo "API_MD5=$(md5sum ${{ github.workspace }}/api/deploy/release/*.tgz | awk '{ print $1 }')" >> $GITHUB_OUTPUT
echo "API_SHA256=$(sha256sum ${{ github.workspace }}/api/deploy/release/*.tgz | awk '{ print $1 }')" >> $GITHUB_OUTPUT
- name: Upload tgz to Github artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: unraid-api
path: ${{ github.workspace }}/api/deploy/release/*.tgz
build-web:
build-unraid-ui:
name: Build Unraid UI Library
defaults:
run:
working-directory: web
working-directory: unraid-ui
runs-on: ubuntu-latest
environment:
name: production
needs: [lint-web]
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Create env file
run: |
touch .env
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
cat .env
uses: actions/checkout@v4
- name: Install node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
cache: "npm"
cache-dependency-path: "web/package-lock.json"
node-version-file: "web/.nvmrc"
cache-dependency-path: |
unraid-ui/package-lock.json
node-version-file: ".nvmrc"
- name: Installing node deps
- name: Install dependencies
run: npm install
- name: Build
run: npm run build
- name: Make Built Node Artifact
run: |
mkdir unraid-ui-dist
mv dist/ unraid-ui-dist/dist/
mv src unraid-ui-dist/src
ln -s unraid-ui-dist/dist/node_modules unraid-ui-dist/node_modules
mv tailwind.config.ts unraid-ui-dist/tailwind.config.ts
mv package.json unraid-ui-dist/package.json
ls unraid-ui-dist
- name: Upload Artifact to Github
uses: actions/upload-artifact@v4
with:
name: unraid-ui
path: unraid-ui/unraid-ui-dist
build-web:
needs: [build-unraid-ui]
name: Build Web App
environment:
name: production
defaults:
run:
working-directory: web
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Create env file
run: |
touch .env
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
cat .env
- name: Install node
uses: actions/setup-node@v4
with:
cache: "npm"
cache-dependency-path: |
web/package-lock.json
node-version-file: "web/.nvmrc"
- name: Setup Just
uses: extractions/setup-just@v2
- name: Installing deps
run: just setup
- name: Lint files
continue-on-error: true
run: npm run lint
- name: Test
run: npm run test:ci
- name: Build
run: npm run build
- name: Upload build to Github artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: unraid-web
path: web/.nuxt/nuxt-custom-elements/dist/unraid-components
build-plugin:
needs: [lint-api, lint-web, test-api, build-api, build-web]
needs: [build-test-api, build-web]
defaults:
run:
working-directory: plugin
@@ -227,22 +205,29 @@ jobs:
with:
timezoneLinux: "America/Los_Angeles"
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Download unraid web components
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: unraid-web
path: ./plugin/source/dynamix.unraid.net/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components
- name: Build Plugin
run: |
cd source/dynamix.unraid.net
export API_VERSION=${{needs.build-api.outputs.API_VERSION}}
export API_MD5=${{needs.build-api.outputs.API_MD5}}
export API_SHA256=${{needs.build-api.outputs.API_SHA256}}
bash ./pkg_build.sh s
export API_VERSION=${{needs.build-test-api.outputs.API_VERSION}}
export API_MD5=${{needs.build-test-api.outputs.API_MD5}}
export API_SHA256=${{needs.build-test-api.outputs.API_SHA256}}
if [ -z "${API_VERSION}" ] ||
[ -z "${API_MD5}" ] ||
[ -z "${API_SHA256}" ]; then
echo "Error: One or more required variables are not set."
exit 1
fi
bash ./pkg_build.sh s ${{github.event.pull_request.number}}
bash ./pkg_build.sh p
- name: Upload binary txz and plg to Github artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: connect-files
path: |
@@ -251,7 +236,69 @@ jobs:
retention-days: 5
if-no-files-found: error
release-pull-request:
if: |
github.event_name == 'pull_request' &&
github.event.pull_request.base.ref == 'main'
runs-on: ubuntu-latest
needs: [build-plugin]
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Make PR Release Folder
run: mkdir pr-release/
- name: Download unraid-api binary tgz
uses: actions/download-artifact@v4
with:
name: unraid-api
path: pr-release
- name: Download plugin binary tgz
uses: actions/download-artifact@v4
with:
name: connect-files
- name: Write Changelog to Plugin XML
run: |
# Capture the pull request number and latest commit message
pr_number="${{ github.event.pull_request.number }}"
commit_message=$(git log -1 --pretty=%B)
# Clean up newlines, escape special characters, and handle line breaks
notes=$(echo -e "Pull Request Build: ${pr_number}\n${commit_message}" | \
sed ':a;N;$!ba;s/\n/\\n/g' | \
sed -e 's/[&\\/]/\\&/g')
# Replace <CHANGES> tag content in the file
sed -i -z -E "s/<CHANGES>(.*)<\/CHANGES>/<CHANGES>\n${notes}\n<\/CHANGES>/g" "plugins/dynamix.unraid.net.staging.plg"
- name: Copy other release files to pr-release
run: |
cp archive/*.txz pr-release/
cp plugins/dynamix.unraid.net.staging.plg pr-release/
- name: Upload to Cloudflare
uses: jakejarvis/s3-sync-action@v0.5.1
env:
AWS_S3_ENDPOINT: ${{ secrets.CF_ENDPOINT }}
AWS_S3_BUCKET: ${{ secrets.CF_BUCKET_PREVIEW }}
AWS_ACCESS_KEY_ID: ${{ secrets.CF_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}
AWS_REGION: "auto"
SOURCE_DIR: pr-release
DEST_DIR: unraid-api/pr/${{ github.event.pull_request.number }}
- name: Comment URL
uses: thollander/actions-comment-pull-request@v3
with:
message: |
This plugin has been deployed to Cloudflare R2 and is available for testing.
Download it at this URL: [https://preview.dl.unraid.net/unraid-api/pr/${{ github.event.pull_request.number }}/dynamix.unraid.net.staging.plg](https://preview.dl.unraid.net/unraid-api/pr/${{ github.event.pull_request.number }}/dynamix.unraid.net.staging.plg)
release-staging:
environment:
name: staging
# Only release if this is a push to the main branch
if: startsWith(github.ref, 'refs/heads/main')
runs-on: ubuntu-latest
@@ -259,19 +306,19 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Make Staging Release Folder
run: mkdir staging-release/
- name: Download unraid-api binary tgz
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: unraid-api
path: staging-release
- name: Download plugin binary tgz
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: connect-files
@@ -282,9 +329,9 @@ jobs:
removeMarkdown: false
filePath: "./api/CHANGELOG.md"
- name: Run LS in unraid-api folder
- name: Copy Files for Staging Release
run: |
cp archive/dynamix.unraid.net.staging-*.txz staging-release/
cp archive/*.txz staging-release/
cp plugins/dynamix.unraid.net.staging.plg staging-release/
ls -al staging-release
@@ -298,6 +345,17 @@ jobs:
source: staging-release
out_dir: unraid-api
- name: Upload Staging Plugin to Cloudflare Bucket
uses: jakejarvis/s3-sync-action@v0.5.1
env:
AWS_S3_ENDPOINT: ${{ secrets.CF_ENDPOINT }}
AWS_S3_BUCKET: ${{ secrets.CF_BUCKET_PREVIEW }}
AWS_ACCESS_KEY_ID: ${{ secrets.CF_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}
AWS_REGION: "auto"
SOURCE_DIR: staging-release
DEST_DIR: unraid-api
create-draft-release:
# Only create new draft if this is a version tag
if: |
@@ -307,15 +365,15 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Download unraid-api binary tgz
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: unraid-api
- name: Download plugin binary tgz
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: connect-files
@@ -327,6 +385,6 @@ jobs:
files: |
unraid-api-*.tgz
plugins/dynamix.unraid.net*
archive/dynamix.unraid.net*
archive/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,82 +0,0 @@
name: Pull Request Web
on:
pull_request:
paths:
- 'web/**'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-web
cancel-in-progress: true
jobs:
lint-web:
defaults:
run:
working-directory: web
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Create env file
run: |
touch .env
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
cat .env
- name: Install node
uses: actions/setup-node@v3
with:
cache: "npm"
cache-dependency-path: "web/package-lock.json"
node-version-file: "web/.nvmrc"
- name: Installing node deps
run: npm install
- name: Lint files
run: npm run lint
build-web:
defaults:
run:
working-directory: web
runs-on: ubuntu-latest
environment:
name: production
needs: [lint-web]
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Create env file
run: |
touch .env
echo VITE_ACCOUNT=${{ vars.VITE_ACCOUNT }} >> .env
echo VITE_CONNECT=${{ vars.VITE_CONNECT }} >> .env
echo VITE_UNRAID_NET=${{ vars.VITE_UNRAID_NET }} >> .env
echo VITE_CALLBACK_KEY=${{ vars.VITE_CALLBACK_KEY }} >> .env
cat .env
- name: Install node
uses: actions/setup-node@v3
with:
cache: "npm"
cache-dependency-path: "web/package-lock.json"
node-version-file: "web/.nvmrc"
- name: Installing node deps
run: npm install
- name: Build
run: npm run build
- name: Upload build to Github artifacts
uses: actions/upload-artifact@v3
with:
name: unraid-web
path: web/.nuxt/nuxt-custom-elements/dist/unraid-components

View File

@@ -1,183 +0,0 @@
name: Pull Request
on:
pull_request:
paths:
- api/**
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
lint-api:
services:
registry: # Using a local registry is ~3x faster than exporting the image to docker agent
image: registry:2
ports:
- 5000:5000
continue-on-error: true
defaults:
run:
working-directory: api
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
persist-credentials: true
- uses: docker/setup-buildx-action@v2
with:
# network=host driver-opt needed to push to local registry
driver-opts: network=host
- name: Build and push
uses: docker/build-push-action@v4
with:
context: api
target: builder
push: true
tags: localhost:5000/unraid-api:builder
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Lint
run: |
docker run localhost:5000/unraid-api:builder npm run lint
test-api:
services:
registry: # Using a local registry is ~3x faster than exporting the image to docker agent
image: registry:2
ports:
- 5000:5000
defaults:
run:
working-directory: api
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
persist-credentials: true
- uses: docker/setup-buildx-action@v2
with:
# network=host driver-opt needed to push to local registry
driver-opts: network=host
- name: Build and push
uses: docker/build-push-action@v4
with:
context: api
target: builder
push: true
tags: localhost:5000/unraid-api:builder
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Test
run: |
docker run localhost:5000/unraid-api:builder npm run coverage
build-api:
services:
registry: # Using a local registry is ~3x faster than exporting the image to docker agent
image: registry:2
ports:
- 5000:5000
defaults:
run:
working-directory: api
runs-on: ubuntu-latest
outputs:
API_VERSION: ${{ steps.build-pack-binary.outputs.API_VERSION }}
API_MD5: ${{ steps.set-hashes.outputs.API_MD5 }}
API_SHA256: ${{ steps.set-hashes.outputs.API_SHA256 }}
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
persist-credentials: true
- uses: docker/setup-buildx-action@v2
with:
# network=host driver-opt needed to push to local registry
driver-opts: network=host
- name: Build and push
uses: docker/build-push-action@v4
with:
context: api
target: builder
push: true
tags: localhost:5000/unraid-api:builder
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run Build
run: docker run -e GIT_SHA=$(git rev-parse --short HEAD) -e IS_TAGGED=$(git describe --tags --abbrev=0 --exact-match) -v $(pwd)/deploy:/app/deploy/ localhost:5000/unraid-api:builder npm run build-pkg
- name: Set Hashes
id: set-hashes
run: |
API_MD5=$(md5sum ${{ github.workspace }}/api/deploy/release/*.tgz | awk '{ print $1 }')
API_SHA256=$(sha256sum ${{ github.workspace }}/api/deploy/release/*.tgz | awk '{ print $1 }')
echo "::set-output name=API_MD5::${API_MD5}"
echo "::set-output name=API_SHA256::${API_SHA256}"
- name: Upload tgz to Github artifacts
uses: actions/upload-artifact@v3
with:
name: unraid-api
path: ${{ github.workspace }}/api/deploy/release/*.tgz
- name: Parse Changelog
id: changelog
uses: ocavue/changelog-parser-action@v1
with:
removeMarkdown: false
filePath: "./api/CHANGELOG.md"
- name: View release notes
run: |
escapedNotes=$(sed -e 's/[&\\/]/\\&/g; s/$/\\/' -e '$s/\\$//' <<<"${{steps.changelog.outputs.latestBody}}")
echo "${escapedNotes}"
build-plugin:
defaults:
run:
working-directory: plugin
runs-on: ubuntu-latest
needs: [lint-api, test-api, build-api]
steps:
- name: Set Timezone
uses: szenius/set-timezone@v1.2
with:
timezoneLinux: "America/Los_Angeles"
- name: Checkout repo
uses: actions/checkout@v3
- name: Build Plugin
run: |
cd source/dynamix.unraid.net
export API_VERSION=${{needs.build-api.outputs.API_VERSION}}
export API_MD5=${{needs.build-api.outputs.API_MD5}}
export API_SHA256=${{needs.build-api.outputs.API_SHA256}}
bash ./pkg_build.sh s
bash ./pkg_build.sh p
- name: Create release notes
run: |
LAST_RELEASE=$(git tag --list --sort=v:refname | tail -1)
echo ${LAST_RELEASE}
RELEASE_NOTES=$(git log "$LAST_RELEASE...HEAD" --pretty=format:"- %s [\`%h\`](http://github.com/$GITHUB_REPOSITORY/commit/%H)" --reverse)
echo "${RELEASE_NOTES}"
# escapedNotes=$(sed -e 's/[&\\/]/\\&/g; s/$/\\/' -e '$s/\\$//' <<<"${RELEASE_NOTES}")
# sed -i -z -E "s/<CHANGES>(.*)<\/CHANGES>/<CHANGES>\n${escapedNotes}\n<\/CHANGES>/g" "plugins/dynamix.unraid.net.staging.plg"
- name: Upload binary txz and plg to Github artifacts
uses: actions/upload-artifact@v3
with:
name: connect-files
path: |
${{ github.workspace }}/plugin/archive/*.txz
${{ github.workspace }}/plugin/plugins/*.plg
retention-days: 5
if-no-files-found: error

View File

@@ -0,0 +1,57 @@
name: Publish Release to Digital Ocean
on:
release:
types: [published]
jobs:
publish-to-digital-ocean:
runs-on: ubuntu-latest
steps:
- name: Download Release Artifacts (Plugins)
uses: dsaltares/fetch-gh-release-asset@master
with:
file: ".*"
regex: true
token: ${{ secrets.GITHUB_TOKEN }}
target: "./"
version: "latest"
- uses: cardinalby/git-get-release-action@v1
id: release-info
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
latest: true
prerelease: false
- name: Get Release Changelog
run: |
notes=$(cat << EOF
${{ steps.release-info.outputs.body }}
EOF
)
escapedNotes=$(sed -e 's/[&\\/]/\\&/g; s/$/\\/' -e '$s/\\$//' <<<"$notes")
sed -i -z -E "s/<CHANGES>(.*)<\/CHANGES>/<CHANGES>\n${escapedNotes}\n<\/CHANGES>/g" "dynamix.unraid.net.plg"
sed -i -z -E "s/<CHANGES>(.*)<\/CHANGES>/<CHANGES>\n${escapedNotes}\n<\/CHANGES>/g" "dynamix.unraid.net.staging.plg"
- name: Upload All Release Files to DO Spaces
uses: BetaHuhn/do-spaces-action@v2
with:
access_key: ${{ secrets.DO_ACCESS_KEY }}
secret_key: ${{ secrets.DO_SECRET_KEY }}
space_name: ${{ secrets.DO_SPACE_NAME }}
space_region: ${{ secrets.DO_SPACE_REGION }}
source: "."
out_dir: unraid-api
- name: Upload Staging Plugin to Cloudflare Bucket
uses: jakejarvis/s3-sync-action@v0.5.1
env:
AWS_S3_ENDPOINT: ${{ secrets.CF_ENDPOINT }}
AWS_S3_BUCKET: ${{ secrets.CF_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.CF_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_SECRET_ACCESS_KEY }}
AWS_REGION: 'auto'
SOURCE_DIR: "."
DEST_DIR: unraid-api

15
.gitignore vendored
View File

@@ -24,6 +24,7 @@ build/Release
# Dependency directories
node_modules/
jspm_packages/
unraid-ui/node_modules/
# TypeScript v1 declaration files
typings/
@@ -50,17 +51,21 @@ typings/
.next
# Visual Studio Code workspace
.vscode/*
!.vscode/extensions.json
.vscode/sftp.json
.history/
# OSX
.DS_Store
# Jetbrains Settings Files
.idea
# Temp dir for tests
test/__temp__/*
# Built files
dist
unraid-ui/storybook-static
# Typescript
typescript
@@ -71,7 +76,7 @@ typescript
# Github actions
RELEASE_NOTES.md
# Docker Deploy Folder
# Docker Deploy Folder
deploy/*
!deploy/.gitkeep
@@ -84,4 +89,6 @@ deploy/*
.cache
.output
.env*
!.env.example
!.env.example
fb_keepalive

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
20

View File

@@ -0,0 +1 @@
{"api":"3.10.0","web":"3.10.0"}

10
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
"recommendations": [
"natizyskunk.sftp",
"davidanson.vscode-markdownlint",
"bmewburn.vscode-intelephense-client",
"foxundermoon.shell-format",
"timonwong.shellcheck",
"esbenp.prettier-vscode"
]
}

43
.vscode/settings.json vendored
View File

@@ -1,30 +1,15 @@
{
"editor.codeActionsOnSave": {
"source.fixAll": false,
"source.fixAll.eslint": true
},
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#78797d",
"activityBar.background": "#78797d",
"activityBar.foreground": "#e7e7e7",
"activityBar.inactiveForeground": "#e7e7e799",
"activityBarBadge.background": "#df9fac",
"activityBarBadge.foreground": "#15202b",
"commandCenter.border": "#e7e7e799",
"sash.hoverBorder": "#78797d",
"statusBar.background": "#5f6063",
"statusBar.foreground": "#e7e7e7",
"statusBarItem.hoverBackground": "#78797d",
"statusBarItem.remoteBackground": "#5f6063",
"statusBarItem.remoteForeground": "#e7e7e7",
"titleBar.activeBackground": "#5f6063",
"titleBar.activeForeground": "#e7e7e7",
"titleBar.inactiveBackground": "#5f606399",
"titleBar.inactiveForeground": "#e7e7e799"
},
"peacock.color": "#5f6063",
"i18n-ally.localesPaths": [
"locales"
],
"i18n-ally.keystyle": "flat"
}
"files.associations": {
"*.page": "php"
},
"editor.codeActionsOnSave": {
"source.fixAll": "never",
"source.fixAll.eslint": "explicit"
},
"i18n-ally.localesPaths": [
"locales"
],
"i18n-ally.keystyle": "flat",
"eslint.experimental.useFlatConfig": true
}

22
.vscode/sftp-template.json vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"_comment": "rename this file to .vscode/sftp.json and replace name/host/privateKeyPath for your system",
"name": "Tower",
"host": "Tower.local",
"protocol": "sftp",
"port": 22,
"username": "root",
"privateKeyPath": "C:/Users/username/.ssh/tower",
"remotePath": "/",
"context": "plugin/source/dynamix.unraid.net/",
"uploadOnSave": true,
"useTempFile": false,
"openSsh": false,
"ignore": [
"// comment: ignore dot files/dirs in root of repo",
".github",
".vscode",
".git",
".DS_Store"
]
}

1
api/.dockerignore Normal file
View File

@@ -0,0 +1 @@
node_modules/

View File

@@ -1,11 +1,14 @@
PATHS_UNRAID_DATA=./dev/data # Where we store plugin data (e.g. permissions.json)
PATHS_STATES=./dev/states # Where .ini files live (e.g. vars.ini)
PATHS_AUTH_SESSIONS=./dev/sessions # Where user sessions live
PATHS_AUTH_KEY=./dev/keys # Auth key directory
PATHS_DYNAMIX_BASE=./dev/dynamix # Dynamix's data directory
PATHS_DYNAMIX_CONFIG_DEFAULT=./dev/dynamix/default.cfg # Dynamix's default config file, which ships with unraid
PATHS_DYNAMIX_CONFIG=./dev/dynamix/dynamix.cfg # Dynamix's config file
PATHS_MY_SERVERS_CONFIG=./dev/Unraid.net/myservers.cfg # My servers config file
PATHS_MY_SERVERS_FB=./dev/Unraid.net/fb_keepalive # My servers flashbackup timekeeper file
PATHS_KEYFILE_BASE=./dev/Unraid.net # Keyfile location
PATHS_MACHINE_ID=./dev/data/machine-id
ENVIRONMENT="development"
NODE_ENV="development"
PORT="3001"
@@ -13,6 +16,8 @@ PLAYGROUND=true
INTROSPECTION=true
MOTHERSHIP_GRAPHQL_LINK="http://authenticator:3000/graphql"
NODE_TLS_REJECT_UNAUTHORIZED=0
BYPASS_PERMISSION_CHECKS=true
BYPASS_CORS_CHECKS=false
BYPASS_PERMISSION_CHECKS=false
BYPASS_CORS_CHECKS=true
CHOKIDAR_USEPOLLING=true
LOG_TRANSPORT=console
LOG_LEVEL=trace

11
api/.env.test Normal file
View File

@@ -0,0 +1,11 @@
VERSION="THIS_WILL_BE_REPLACED_WHEN_BUILT"
PATHS_UNRAID_DATA=./dev/data # Where we store plugin data (e.g. permissions.json)
PATHS_STATES=./dev/states # Where .ini files live (e.g. vars.ini)
PATHS_DYNAMIX_BASE=./dev/dynamix # Dynamix's data directory
PATHS_DYNAMIX_CONFIG=./dev/dynamix/dynamix.cfg # Dynamix's config file
PATHS_MY_SERVERS_CONFIG=./dev/Unraid.net/myservers.cfg # My servers config file
PATHS_MY_SERVERS_FB=./dev/Unraid.net/fb_keepalive # My servers flashbackup timekeeper file
PATHS_KEYFILE_BASE=./dev/Unraid.net # Keyfile location
PORT=5000
NODE_ENV=test

View File

@@ -1,47 +0,0 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
root: true,
plugins: [
'@typescript-eslint/eslint-plugin',
'unused-imports',
'eslint-plugin-unicorn',
],
ignorePatterns: ['src/graphql/generated/**/*.ts', '*.test.ts', 'tsup.config.ts', 'vite.config.ts'],
parser: '@typescript-eslint/parser',
rules: {
'@typescript-eslint/no-redundant-type-constituents': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/consistent-type-imports': [
'warn',
{ fixStyle: 'inline-type-imports' },
],
'unicorn/numeric-separators-style': [
'error',
{ number: { minimumDigits: 0, groupLength: 3 } },
],
'import/no-cycle': 'off', // Change this to "error" to find circular imports
'@typescript-eslint/no-use-before-define': ['error'],
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 1 }],
},
overrides: [
{
files: ['*.ts'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
],
parserOptions: {
project: true,
tsconfigRootDir: __dirname,
},
rules: {
'@typescript-eslint/no-explicit-any': 'off',
},
},
],
};

21
api/.eslintrc.ts Normal file
View File

@@ -0,0 +1,21 @@
import type { Linter } from 'eslint';
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, {
rules: {
'@typescript-eslint/no-redundant-type-constituents': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
'no-use-before-define': ['off'],
'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 1 }],
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
},
});

82
api/.gitignore vendored Normal file
View File

@@ -0,0 +1,82 @@
# Logs
./logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
coverage-ts
# nyc test coverage
.nyc_output
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
# Visual Studio Code workspace
.vscode/*
!.vscode/extensions.json
# OSX
.DS_Store
# Temp dir for tests
test/__temp__/*
# Built files
dist
# Typescript
typescript
# Ultra runner
.ultra.cache.json
# Github actions
RELEASE_NOTES.md
# Docker Deploy Folder
deploy/*
!deploy/.gitkeep
# pkg cache
.pkg-cache
# IDE Settings Files
.idea

View File

@@ -1 +1 @@
18.17.1
v20

38
api/.prettierrc.cjs Normal file
View File

@@ -0,0 +1,38 @@
/**
* @see https://prettier.io/docs/en/configuration.html
* @type {import("prettier").Config}
*/
module.exports = {
trailingComma: 'es5',
tabWidth: 4,
semi: true,
singleQuote: true,
printWidth: 105,
plugins: ['@ianvs/prettier-plugin-sort-imports'],
// decorators-legacy lets the import sorter transform files with decorators
importOrderParserPlugins: ['typescript', 'decorators-legacy'],
importOrder: [
/**----------------------
* Nest.js & node.js imports
*------------------------**/
'<TYPES>^@nestjs(/.*)?$',
'^@nestjs(/.*)?$', // matches imports starting with @nestjs
'<TYPES>^(node:)',
'<BUILTIN_MODULES>', // Node.js built-in modules
'',
/**----------------------
* Third party packages
*------------------------**/
'<TYPES>',
'<THIRD_PARTY_MODULES>', // Imports not matched by other special words or groups.
'',
/**----------------------
* Application Code
*------------------------**/
'<TYPES>^@app(/.*)?$', // matches type imports starting with @app
'^@app(/.*)?$',
'',
'<TYPES>^[.]',
'^[.]', // relative imports
],
};

7
api/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"eslint.lintTask.options": "--flag unstable_ts_config",
"eslint.options": {
"flags": ["unstable_ts_config"],
"overrideConfigFile": ".eslintrc.ts"
}
}

View File

@@ -2,6 +2,459 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [3.11.0](https://github.com/unraid/api/compare/v3.10.1...v3.11.0) (2024-09-11)
### Features
* reduce how often rc.flashbackup checks for changes ([793d368](https://github.com/unraid/api/commit/793d3681404018e0ae933df0ad111809220ad138))
* send api_version to flash/activate endpoint ([d8ec20e](https://github.com/unraid/api/commit/d8ec20ea6aa35aa241abd8424c4d884bcbb8f590))
* update ProvisionCert.php to clean hosts file when it runs ([fbe20c9](https://github.com/unraid/api/commit/fbe20c97b327849c15a4b34f5f53476edaefbeb6))
### Bug Fixes
* remove local flash backup ratelimit file on uninstall/update ([abf207b](https://github.com/unraid/api/commit/abf207b077861798c53739b1965207f87d5633b3))
### [3.10.1](https://github.com/unraid/api/compare/v3.10.0...v3.10.1) (2024-09-03)
## [3.10.0](https://github.com/unraid/api/compare/v3.9.0...v3.10.0) (2024-09-03)
### Features
* add a timestamp to flash backup ([#877](https://github.com/unraid/api/issues/877)) ([b868fd4](https://github.com/unraid/api/commit/b868fd46c3886b2182245a61f20be6df65e46abe))
* add environment to docker-compose ([2ee4683](https://github.com/unraid/api/commit/2ee46839095e3b8ee287cfe10f29ae9a39dcff68))
* add global agent ([#897](https://github.com/unraid/api/issues/897)) ([8b0dc69](https://github.com/unraid/api/commit/8b0dc69f65bd3e280a21c50aab221334f7341b1c))
* add logrotate to cron in nestjs ([#839](https://github.com/unraid/api/issues/839)) ([5c91524](https://github.com/unraid/api/commit/5c91524d849147c0ac7925f3a2f1cce67ffe75de))
* add new staging url for connect website ([#841](https://github.com/unraid/api/issues/841)) ([4cfc07b](https://github.com/unraid/api/commit/4cfc07b6763dbb79b68cf01f7eaf7cf33370d4db))
* add support for expiration in var.ini ([#833](https://github.com/unraid/api/issues/833)) ([0474c2e](https://github.com/unraid/api/commit/0474c2e14fa462d2e1ec6d9a7f974660385d073e))
* always show DRA even if disabled ([ab708c0](https://github.com/unraid/api/commit/ab708c0df634e21bf81595412d7de0be3ff7c392))
* close log on exit ([d6ede86](https://github.com/unraid/api/commit/d6ede86eca6301342cdf35bf1f9365896b5e5009))
* create stable hash based on apikey rather than hostname ([ecf5554](https://github.com/unraid/api/commit/ecf5554e304cc7dee78cb1f206ef4e80222c3e64))
* disable all legacy dashboard and network logic ([6784f4b](https://github.com/unraid/api/commit/6784f4b6e1a12b2f30bfa9ab4fe6310994bd18ae))
* dynamic remote access using remote queries ([f7fc0c4](https://github.com/unraid/api/commit/f7fc0c431561978054d2ff37d1aa644865e846ec))
* extraOrigins public, remove origin listener ([91f96ba](https://github.com/unraid/api/commit/91f96ba818773d6e71dde1ff52a4c8ec21ba6b5d))
* fix codegen ([d0bf5bb](https://github.com/unraid/api/commit/d0bf5bb8197b11f7a250ca5392890184a1dbeff7))
* fix exit hook and cleanup docker scripts ([#758](https://github.com/unraid/api/issues/758)) ([a9ff73e](https://github.com/unraid/api/commit/a9ff73e0a04c67e9ec9d5551cf0b1f124be6f381))
* fix logging format on start and stop ([c6720c3](https://github.com/unraid/api/commit/c6720c331df055480d2d65b37290f4978fe429da))
* local start command ([99b6007](https://github.com/unraid/api/commit/99b6007ba30353084a8bea54cc0e782fcc1bfea4))
* log config recreation reason ([f36c72f](https://github.com/unraid/api/commit/f36c72f5ad44b7e41d1726fa181dc2b9f594c72c))
* move dynamic remote access to be fully api controlled ([206eb6b](https://github.com/unraid/api/commit/206eb6b74aa83047237e5f6c94c46b08c6507168))
* move FQDN urls to a generic parser ([#899](https://github.com/unraid/api/issues/899)) ([246595e](https://github.com/unraid/api/commit/246595ee7acd8370906a759cbe618def4f52c173))
* nestjs initial query implementation ([#748](https://github.com/unraid/api/issues/748)) ([075d7f2](https://github.com/unraid/api/commit/075d7f25785bf686779b7fee1d5ea39f09ff3ea8))
* new key types in API ([e42f9dc](https://github.com/unraid/api/commit/e42f9dc95be03e8389aac443f2147c07a316d48d))
* regTy swapped ([564b25c](https://github.com/unraid/api/commit/564b25cf5ce0a62d40f8d63d44c81e9c8560e0be))
* remove dashboard resolver completely in favor of direct field resolvers ([1cd1ee5](https://github.com/unraid/api/commit/1cd1ee534825ccf775208c438ae0bd777bbe4d39))
* remove dashboard types ([2f0167d](https://github.com/unraid/api/commit/2f0167dc89835bcf8aa946425c5c6683221fd763))
* run codegen and update build script ([07512ad](https://github.com/unraid/api/commit/07512adc13ee0d819db45ff6c5c5f58a0ba31141))
* settings through the API ([#867](https://github.com/unraid/api/issues/867)) ([e73624b](https://github.com/unraid/api/commit/e73624be6be8bc2c70d898b8601a88cc8d20a3e4))
* swap to docker compose from docker-compose ([ec16a6a](https://github.com/unraid/api/commit/ec16a6aab1a2d5c836387da438fbeade07d23425))
* swap to fragement usage on webcomponent ([42733ab](https://github.com/unraid/api/commit/42733abf6e443516ff715569333422ce80d3b1d2))
* update tests and snapshots ([c39aa17](https://github.com/unraid/api/commit/c39aa17e4302ed56b3097ab3244d840f11eb686b))
* upgrade a ton of dependencies ([#842](https://github.com/unraid/api/issues/842)) ([94c1746](https://github.com/unraid/api/commit/94c174620c2347a3cf3d100404635f99a5b47287))
### Bug Fixes
* add serverName / description to dashboard payload ([9677aff](https://github.com/unraid/api/commit/9677aff1cd0942f36a2845f3f105601c494efd9e))
* allow failure for log deletion ([eff3142](https://github.com/unraid/api/commit/eff31423927644be436a831126678719c2eb0621))
* allowed origins check not working without spaces ([#838](https://github.com/unraid/api/issues/838)) ([b998b38](https://github.com/unraid/api/commit/b998b38355fab77ecc2f62bc64896766218db3d4))
* **api:** readme discord url ([ffd5c6a](https://github.com/unraid/api/commit/ffd5c6afb64956e76df22c77104a21bc22798008))
* build docker command updated to use dc.sh script ([0b40886](https://github.com/unraid/api/commit/0b40886e84f27a94dbf67ef4ca0cd8539ef3913e))
* codegen on web run ([e2e67c2](https://github.com/unraid/api/commit/e2e67c21067a138d963f5f10760b84cf6a533542))
* **deps:** update dependency @apollo/client to v3.9.5 ([#785](https://github.com/unraid/api/issues/785)) ([75b98bc](https://github.com/unraid/api/commit/75b98bc1cbca5b66ae72f52a0b6f5f58230a2473))
* **deps:** update dependency graphql to v16.8.1 ([bff1b19](https://github.com/unraid/api/commit/bff1b19706bee1e3103e3a0a1d2fceb3154f9bba))
* **deps:** update dependency graphql-ws to v5.15.0 ([#790](https://github.com/unraid/api/issues/790)) ([4773b13](https://github.com/unraid/api/commit/4773b132167d740d4c996efe22e0f1b99576fb9b))
* **deps:** update dependency ws to v8.16.0 ([#815](https://github.com/unraid/api/issues/815)) ([212020e](https://github.com/unraid/api/commit/212020e78d4de0576137058a3374837b4a43e02d))
* **deps:** update dependency wtfnode to v0.9.3 ([#901](https://github.com/unraid/api/issues/901)) ([a88482b](https://github.com/unraid/api/commit/a88482bfcbf134f55330f8728bc5c7f67c521773))
* **deps:** update graphql-tools monorepo ([3447eb0](https://github.com/unraid/api/commit/3447eb047a1dcd575b88a96bbcef9946aca366a1))
* **deps:** update graphql-tools monorepo (major) ([#693](https://github.com/unraid/api/issues/693)) ([3447eb0](https://github.com/unraid/api/commit/3447eb047a1dcd575b88a96bbcef9946aca366a1))
* **deps:** update nest monorepo ([#816](https://github.com/unraid/api/issues/816)) ([4af3699](https://github.com/unraid/api/commit/4af36991b8b376f816ed51fd503a66e99675a3e7))
* excessive logging ([89cb254](https://github.com/unraid/api/commit/89cb2544ed0e0edd33b59f15d487487e22c0ae32))
* exit with process.exit not process.exitcode ([dcb6def](https://github.com/unraid/api/commit/dcb6def1cf3365dca819feed101160c8ad0125dc))
* lint ([919873d](https://github.com/unraid/api/commit/919873d9edee304d99036a4a810db3789c734fbf))
* local container startup commands cleaned up ([6c0ccb2](https://github.com/unraid/api/commit/6c0ccb2b24f98282be4db2e0b2e6362f4a187def))
* logrotate not working due to invalid ownership of unraid-api folder ([ec0581a](https://github.com/unraid/api/commit/ec0581abf58a217f698d52d5337f2b312e5a645b))
* optional check on api.version to allow fallback to save value ([0ac4455](https://github.com/unraid/api/commit/0ac4455f78407eca7aa1d6ee360830067a1c5c3e))
* permission for dashboard payload ([704a530](https://github.com/unraid/api/commit/704a530653dac415766bded5e96f6060f931e591))
* rearrange exit hook to try to fix closing ([843d3f4](https://github.com/unraid/api/commit/843d3f41162c5dbcfd7803912b1879d7a182231a))
* revert myservers.cfg to fix test ([a7705be](https://github.com/unraid/api/commit/a7705beb0a5b32660367ad8de9b46b06f7a3bec7))
* run hourly ([0425794](https://github.com/unraid/api/commit/0425794356a01262222e7dff2645d3629e00d0f6))
* unused import ([065fe57](https://github.com/unraid/api/commit/065fe575f578a74d593805c3121dd7fbdfc3e5ae))
* update snapshots ([c8a0a8e](https://github.com/unraid/api/commit/c8a0a8ec007abc0372464c7e2b44bd47b6babd94))
## [3.9.0](https://github.com/unraid/api/compare/api-v3.8.1...api-v3.9.0) (2024-09-03)
### Features
* add a timestamp to flash backup ([#877](https://github.com/unraid/api/issues/877)) ([b868fd4](https://github.com/unraid/api/commit/b868fd46c3886b2182245a61f20be6df65e46abe))
* add environment to docker-compose ([2ee4683](https://github.com/unraid/api/commit/2ee46839095e3b8ee287cfe10f29ae9a39dcff68))
* add global agent ([#897](https://github.com/unraid/api/issues/897)) ([8b0dc69](https://github.com/unraid/api/commit/8b0dc69f65bd3e280a21c50aab221334f7341b1c))
* add logrotate to cron in nestjs ([#839](https://github.com/unraid/api/issues/839)) ([5c91524](https://github.com/unraid/api/commit/5c91524d849147c0ac7925f3a2f1cce67ffe75de))
* add new staging url for connect website ([#841](https://github.com/unraid/api/issues/841)) ([4cfc07b](https://github.com/unraid/api/commit/4cfc07b6763dbb79b68cf01f7eaf7cf33370d4db))
* add support for expiration in var.ini ([#833](https://github.com/unraid/api/issues/833)) ([0474c2e](https://github.com/unraid/api/commit/0474c2e14fa462d2e1ec6d9a7f974660385d073e))
* always show DRA even if disabled ([ab708c0](https://github.com/unraid/api/commit/ab708c0df634e21bf81595412d7de0be3ff7c392))
* close log on exit ([d6ede86](https://github.com/unraid/api/commit/d6ede86eca6301342cdf35bf1f9365896b5e5009))
* create stable hash based on apikey rather than hostname ([ecf5554](https://github.com/unraid/api/commit/ecf5554e304cc7dee78cb1f206ef4e80222c3e64))
* disable all legacy dashboard and network logic ([6784f4b](https://github.com/unraid/api/commit/6784f4b6e1a12b2f30bfa9ab4fe6310994bd18ae))
* dynamic remote access using remote queries ([f7fc0c4](https://github.com/unraid/api/commit/f7fc0c431561978054d2ff37d1aa644865e846ec))
* extraOrigins public, remove origin listener ([91f96ba](https://github.com/unraid/api/commit/91f96ba818773d6e71dde1ff52a4c8ec21ba6b5d))
* fix codegen ([d0bf5bb](https://github.com/unraid/api/commit/d0bf5bb8197b11f7a250ca5392890184a1dbeff7))
* fix exit hook and cleanup docker scripts ([#758](https://github.com/unraid/api/issues/758)) ([a9ff73e](https://github.com/unraid/api/commit/a9ff73e0a04c67e9ec9d5551cf0b1f124be6f381))
* fix logging format on start and stop ([c6720c3](https://github.com/unraid/api/commit/c6720c331df055480d2d65b37290f4978fe429da))
* local start command ([99b6007](https://github.com/unraid/api/commit/99b6007ba30353084a8bea54cc0e782fcc1bfea4))
* log config recreation reason ([f36c72f](https://github.com/unraid/api/commit/f36c72f5ad44b7e41d1726fa181dc2b9f594c72c))
* move dynamic remote access to be fully api controlled ([206eb6b](https://github.com/unraid/api/commit/206eb6b74aa83047237e5f6c94c46b08c6507168))
* move FQDN urls to a generic parser ([#899](https://github.com/unraid/api/issues/899)) ([246595e](https://github.com/unraid/api/commit/246595ee7acd8370906a759cbe618def4f52c173))
* nestjs initial query implementation ([#748](https://github.com/unraid/api/issues/748)) ([075d7f2](https://github.com/unraid/api/commit/075d7f25785bf686779b7fee1d5ea39f09ff3ea8))
* new key types in API ([e42f9dc](https://github.com/unraid/api/commit/e42f9dc95be03e8389aac443f2147c07a316d48d))
* regTy swapped ([564b25c](https://github.com/unraid/api/commit/564b25cf5ce0a62d40f8d63d44c81e9c8560e0be))
* remove dashboard resolver completely in favor of direct field resolvers ([1cd1ee5](https://github.com/unraid/api/commit/1cd1ee534825ccf775208c438ae0bd777bbe4d39))
* remove dashboard types ([2f0167d](https://github.com/unraid/api/commit/2f0167dc89835bcf8aa946425c5c6683221fd763))
* run codegen and update build script ([07512ad](https://github.com/unraid/api/commit/07512adc13ee0d819db45ff6c5c5f58a0ba31141))
* settings through the API ([#867](https://github.com/unraid/api/issues/867)) ([e73624b](https://github.com/unraid/api/commit/e73624be6be8bc2c70d898b8601a88cc8d20a3e4))
* swap to docker compose from docker-compose ([ec16a6a](https://github.com/unraid/api/commit/ec16a6aab1a2d5c836387da438fbeade07d23425))
* swap to fragement usage on webcomponent ([42733ab](https://github.com/unraid/api/commit/42733abf6e443516ff715569333422ce80d3b1d2))
* update tests and snapshots ([c39aa17](https://github.com/unraid/api/commit/c39aa17e4302ed56b3097ab3244d840f11eb686b))
* upgrade a ton of dependencies ([#842](https://github.com/unraid/api/issues/842)) ([94c1746](https://github.com/unraid/api/commit/94c174620c2347a3cf3d100404635f99a5b47287))
### Bug Fixes
* add serverName / description to dashboard payload ([9677aff](https://github.com/unraid/api/commit/9677aff1cd0942f36a2845f3f105601c494efd9e))
* allow failure for log deletion ([eff3142](https://github.com/unraid/api/commit/eff31423927644be436a831126678719c2eb0621))
* allowed origins check not working without spaces ([#838](https://github.com/unraid/api/issues/838)) ([b998b38](https://github.com/unraid/api/commit/b998b38355fab77ecc2f62bc64896766218db3d4))
* **api:** readme discord url ([ffd5c6a](https://github.com/unraid/api/commit/ffd5c6afb64956e76df22c77104a21bc22798008))
* build docker command updated to use dc.sh script ([0b40886](https://github.com/unraid/api/commit/0b40886e84f27a94dbf67ef4ca0cd8539ef3913e))
* codegen on web run ([e2e67c2](https://github.com/unraid/api/commit/e2e67c21067a138d963f5f10760b84cf6a533542))
* **deps:** update dependency @apollo/client to v3.9.5 ([#785](https://github.com/unraid/api/issues/785)) ([75b98bc](https://github.com/unraid/api/commit/75b98bc1cbca5b66ae72f52a0b6f5f58230a2473))
* **deps:** update dependency graphql to v16.8.1 ([bff1b19](https://github.com/unraid/api/commit/bff1b19706bee1e3103e3a0a1d2fceb3154f9bba))
* **deps:** update dependency graphql-ws to v5.15.0 ([#790](https://github.com/unraid/api/issues/790)) ([4773b13](https://github.com/unraid/api/commit/4773b132167d740d4c996efe22e0f1b99576fb9b))
* **deps:** update dependency ws to v8.16.0 ([#815](https://github.com/unraid/api/issues/815)) ([212020e](https://github.com/unraid/api/commit/212020e78d4de0576137058a3374837b4a43e02d))
* **deps:** update dependency wtfnode to v0.9.3 ([#901](https://github.com/unraid/api/issues/901)) ([a88482b](https://github.com/unraid/api/commit/a88482bfcbf134f55330f8728bc5c7f67c521773))
* **deps:** update graphql-tools monorepo ([3447eb0](https://github.com/unraid/api/commit/3447eb047a1dcd575b88a96bbcef9946aca366a1))
* **deps:** update graphql-tools monorepo (major) ([#693](https://github.com/unraid/api/issues/693)) ([3447eb0](https://github.com/unraid/api/commit/3447eb047a1dcd575b88a96bbcef9946aca366a1))
* **deps:** update nest monorepo ([#816](https://github.com/unraid/api/issues/816)) ([4af3699](https://github.com/unraid/api/commit/4af36991b8b376f816ed51fd503a66e99675a3e7))
* excessive logging ([89cb254](https://github.com/unraid/api/commit/89cb2544ed0e0edd33b59f15d487487e22c0ae32))
* exit with process.exit not process.exitcode ([dcb6def](https://github.com/unraid/api/commit/dcb6def1cf3365dca819feed101160c8ad0125dc))
* lint ([919873d](https://github.com/unraid/api/commit/919873d9edee304d99036a4a810db3789c734fbf))
* local container startup commands cleaned up ([6c0ccb2](https://github.com/unraid/api/commit/6c0ccb2b24f98282be4db2e0b2e6362f4a187def))
* logrotate not working due to invalid ownership of unraid-api folder ([ec0581a](https://github.com/unraid/api/commit/ec0581abf58a217f698d52d5337f2b312e5a645b))
* optional check on api.version to allow fallback to save value ([0ac4455](https://github.com/unraid/api/commit/0ac4455f78407eca7aa1d6ee360830067a1c5c3e))
* permission for dashboard payload ([704a530](https://github.com/unraid/api/commit/704a530653dac415766bded5e96f6060f931e591))
* rearrange exit hook to try to fix closing ([843d3f4](https://github.com/unraid/api/commit/843d3f41162c5dbcfd7803912b1879d7a182231a))
* revert myservers.cfg to fix test ([a7705be](https://github.com/unraid/api/commit/a7705beb0a5b32660367ad8de9b46b06f7a3bec7))
* run hourly ([0425794](https://github.com/unraid/api/commit/0425794356a01262222e7dff2645d3629e00d0f6))
* unused import ([065fe57](https://github.com/unraid/api/commit/065fe575f578a74d593805c3121dd7fbdfc3e5ae))
* update snapshots ([c8a0a8e](https://github.com/unraid/api/commit/c8a0a8ec007abc0372464c7e2b44bd47b6babd94))
### [3.8.1](https://github.com/unraid/api/compare/v3.8.0...v3.8.1) (2024-08-13)
## [3.8.0](https://github.com/unraid/api/compare/v3.7.1...v3.8.0) (2024-08-13)
### Features
* always force push ([662f3ce](https://github.com/unraid/api/commit/662f3ce440593e609c64364726f7da16dda0972b))
* don't allow flash backup repos larger than 500MB ([#890](https://github.com/unraid/api/issues/890)) ([30a32f5](https://github.com/unraid/api/commit/30a32f5fe684bb32c084c4125aade5e63ffd788b))
* downgradeOs callback for non stable osCurrentBranch ([17c4489](https://github.com/unraid/api/commit/17c4489e97bda504ca45e360591655ded166c355))
* settings through the API ([#867](https://github.com/unraid/api/issues/867)) ([e73624b](https://github.com/unraid/api/commit/e73624be6be8bc2c70d898b8601a88cc8d20a3e4))
* swap to docker compose from docker-compose ([ec16a6a](https://github.com/unraid/api/commit/ec16a6aab1a2d5c836387da438fbeade07d23425))
### Bug Fixes
* apolloClient types ([f14c767](https://github.com/unraid/api/commit/f14c7673735b92aa167e9e8dcb14a045bcfea994))
* **deps:** update dependency @vue/apollo-composable to v4.0.2 ([#787](https://github.com/unraid/api/issues/787)) ([edfc846](https://github.com/unraid/api/commit/edfc8464b0e0c2f38003ae8420e81532fd18351f))
* formattedRegTm type ([748906e](https://github.com/unraid/api/commit/748906e15d30c6162e2f08f28724c9104c81d123))
* i18n t prop type ([96d519f](https://github.com/unraid/api/commit/96d519f3e6b96ea7c4dc60616522216de20ee140))
* lint error for web components ([bc27b20](https://github.com/unraid/api/commit/bc27b20524934cf896efb84a131cd270431c508c))
* lint issues ([853dc19](https://github.com/unraid/api/commit/853dc195b13fff29160afb44f9ff11d4dd6a3232))
* swap undefined to null ([ebba976](https://github.com/unraid/api/commit/ebba9769873a6536e3fce65978e6475d93280560))
* tailwind config types ([0f77e55](https://github.com/unraid/api/commit/0f77e5596db3356b5dc05129b3ce215a8809e1dc))
* ts-expect-error unneeded ([ee4d4e9](https://github.com/unraid/api/commit/ee4d4e9f12b4488ff39445bc72c1b83a9d93e993))
* type check ([606aad7](https://github.com/unraid/api/commit/606aad703d91b72a14e15da3100dfa355052ed58))
* type errors round 1 ([977d5da](https://github.com/unraid/api/commit/977d5daf04012f16e7b6602167338f0bc363735a))
* update status button alignment ([4f2deaf](https://github.com/unraid/api/commit/4f2deaf70e5caa9f29fc5b2974b278f80b7b3a8a))
### [3.7.1](https://github.com/unraid/api/compare/v3.7.0...v3.7.1) (2024-05-15)
### Bug Fixes
* reboot required and available edge case ([#885](https://github.com/unraid/api/issues/885)) ([76e9cdf](https://github.com/unraid/api/commit/76e9cdf81f06a19c2e4c9a40a4d8e062bad2a607))
## [3.7.0](https://github.com/unraid/api/compare/v3.6.0...v3.7.0) (2024-05-14)
### Features
* add a timestamp to flash backup ([#877](https://github.com/unraid/api/issues/877)) ([b868fd4](https://github.com/unraid/api/commit/b868fd46c3886b2182245a61f20be6df65e46abe))
* add support for outgoing proxies ([#863](https://github.com/unraid/api/issues/863)) ([223693e](https://github.com/unraid/api/commit/223693e0981d5f2884a1f8b8baf03d4dc58e8cb2))
* array state on registration page ([d36fef0](https://github.com/unraid/api/commit/d36fef0545ddb820e67e8bc6cb42ea3644021d66))
* downgradeOs callback ([154a976](https://github.com/unraid/api/commit/154a976109f0a32653a2851988420707631327ca))
* Flash Backup requires connection to mothership ([#868](https://github.com/unraid/api/issues/868)) ([d127208](https://github.com/unraid/api/commit/d127208b5e0f7f9991f515f95b0e266d38cf3287))
* **plg:** install prevent downgrade of shared page & php files ([#873](https://github.com/unraid/api/issues/873)) ([4ac72b1](https://github.com/unraid/api/commit/4ac72b16692c4246c9d2c0b53b23d8b2d95f5de6))
* **plg:** plg install prevent web component downgrade ([8703bd4](https://github.com/unraid/api/commit/8703bd498108f5c05562584a708bd2306e53f7a6))
* postbuild script to add timestamp to web component manifest ([47f08ea](https://github.com/unraid/api/commit/47f08ea3594a91098f67718c0123110c7b5f86f7))
* registration page server error heading + subheading ([6038ebd](https://github.com/unraid/api/commit/6038ebdf39bf47f2cb5c0b1de84764795374f018))
* remove cron to download JS daily ([#864](https://github.com/unraid/api/issues/864)) ([33f6d6b](https://github.com/unraid/api/commit/33f6d6b343de07dbe70de863926906736d42f371)), closes [#529](https://github.com/unraid/api/issues/529)
* ui to allow second update without reboot ([b0f2d10](https://github.com/unraid/api/commit/b0f2d102917f54ab33f0ad10863522b8ff8e3ce5))
* UI Update OS Cancel ([7c02308](https://github.com/unraid/api/commit/7c02308964d5e21990427a2c626c9db2d9e1fed0))
* UnraidUpdateCancel script ([b73bdc0](https://github.com/unraid/api/commit/b73bdc021764762ed12dca494e1345412a45c677))
* **web:** callback types myKeys & linkKey ([c88ee01](https://github.com/unraid/api/commit/c88ee01827396c3fa8a30bb88c4be712c80b1f4f))
* **web:** Registration key linked to account status ([8f6182d](https://github.com/unraid/api/commit/8f6182d426453b73aa19c5f0f59469fa07571694))
* **web:** registration page array status messaging ([23ef5a9](https://github.com/unraid/api/commit/23ef5a975e0d5ff0c246c2df5e6c2cb38979d12a))
### Bug Fixes
* **api:** readme discord url ([ffd5c6a](https://github.com/unraid/api/commit/ffd5c6afb64956e76df22c77104a21bc22798008))
* keep minor enhancements from [#872](https://github.com/unraid/api/issues/872) ([#878](https://github.com/unraid/api/issues/878)) ([94a5aa8](https://github.com/unraid/api/commit/94a5aa87b9979fe0f02f884ac61298473bb3271a))
* plugin file deployment script ([780d87d](https://github.com/unraid/api/commit/780d87d6589a5469f47ac3fdfd50610ecfc394c8))
* prevent corrupt case model in state.php ([#874](https://github.com/unraid/api/issues/874)) ([4ad31df](https://github.com/unraid/api/commit/4ad31dfea9192146dbd2c90bc64a913c696ab0b7))
* prevent local dev from throwing ssl error ([051f647](https://github.com/unraid/api/commit/051f6474becf3b25b242cdc6ceee67247b79f8ba))
* rc.flashbackup needs to check both signed in and connected ([#882](https://github.com/unraid/api/issues/882)) ([ac8068c](https://github.com/unraid/api/commit/ac8068c9b084622d46fe2c9cb320b793c9ea8c52))
* update os cancel refresh on update page ([213c16b](https://github.com/unraid/api/commit/213c16ba3d5a84ebf4965f9d2f4024c66605a613))
* **web:** discord url ([1a6f4c6](https://github.com/unraid/api/commit/1a6f4c6db4ef0e5eefac467ec6583b14cb3546c4))
* **web:** lint unused rebootVersion ([e198ec9](https://github.com/unraid/api/commit/e198ec9d458e262c412c2dcb5a9d279238de1730))
* **web:** registration component remove unused ref ([76f556b](https://github.com/unraid/api/commit/76f556bd64b95ba96af795c9edfa045ebdff4444))
## [3.6.0](https://github.com/unraid/api/compare/v3.5.3...v3.6.0) (2024-03-26)
### Features
* server config enum message w/ ineligible support ([#861](https://github.com/unraid/api/issues/861)) ([4d3a351](https://github.com/unraid/api/commit/4d3a3510777090788573f4cee83694a0dc6f8df5))
### [3.5.3](https://github.com/unraid/api/compare/v3.5.2...v3.5.3) (2024-03-25)
### Bug Fixes
* regDevs usage to allow more flexibility for STARTER ([#860](https://github.com/unraid/api/issues/860)) ([92a9600](https://github.com/unraid/api/commit/92a9600f3a242c5f263f1672eab81054b9cf4fae))
### [3.5.2](https://github.com/unraid/api/compare/v3.5.1...v3.5.2) (2024-03-06)
### Bug Fixes
* **deps:** update dependency vue-i18n to v9.10.1 ([#813](https://github.com/unraid/api/issues/813)) ([69b599c](https://github.com/unraid/api/commit/69b599c5ed8d44864201a32b4d952427d454dc74))
* **deps:** update dependency wretch to v2.8.0 ([#814](https://github.com/unraid/api/issues/814)) ([66900b4](https://github.com/unraid/api/commit/66900b495b82b923264897d38b1529a22b10aa1c))
* update os check modal button conditionals ([282a836](https://github.com/unraid/api/commit/282a83625f417ccefe090b65cc6b73a084727a87))
* update os check modal ineligible date format ([83083de](https://github.com/unraid/api/commit/83083de1e698f73a35635ae6047dcf49fd4b8114))
### [3.5.1](https://github.com/unraid/api/compare/v3.5.0...v3.5.1) (2024-02-29)
### Bug Fixes
* build docker command updated to use dc.sh script ([0b40886](https://github.com/unraid/api/commit/0b40886e84f27a94dbf67ef4ca0cd8539ef3913e))
* date format in UnraidCheck.php ([#852](https://github.com/unraid/api/issues/852)) ([6465f2d](https://github.com/unraid/api/commit/6465f2d7b2394090f35e29cdd680d98ce37f3728))
* **deps:** update dependency @apollo/client to v3.9.5 ([#785](https://github.com/unraid/api/issues/785)) ([75b98bc](https://github.com/unraid/api/commit/75b98bc1cbca5b66ae72f52a0b6f5f58230a2473))
* **deps:** update dependency @heroicons/vue to v2.1.1 ([#804](https://github.com/unraid/api/issues/804)) ([a0eb7ee](https://github.com/unraid/api/commit/a0eb7ee3ec459dbe1992a7f85bf194da30395a74))
* **deps:** update dependency focus-trap to v7.5.4 ([#788](https://github.com/unraid/api/issues/788)) ([fe000e8](https://github.com/unraid/api/commit/fe000e83825e82cac558d3277664a440e59c0e4a))
* **deps:** update dependency graphql-ws to v5.15.0 ([#790](https://github.com/unraid/api/issues/790)) ([4773b13](https://github.com/unraid/api/commit/4773b132167d740d4c996efe22e0f1b99576fb9b))
* display dropdown for pro key no connect installed ([#848](https://github.com/unraid/api/issues/848)) ([b559604](https://github.com/unraid/api/commit/b55960429895b46627f1cd3ed1683ee527e62944))
* dropdown reboot link text ([#849](https://github.com/unraid/api/issues/849)) ([a8ed5e5](https://github.com/unraid/api/commit/a8ed5e5628bc71fb783a03c3db92d21805243738))
* os updates rc to stable ([bf1bd88](https://github.com/unraid/api/commit/bf1bd887d60ac085bf4aeae90f11be3b45ee1182))
* state connect values without connect installed ([e47de6c](https://github.com/unraid/api/commit/e47de6c2c5db7a2a1a9b24099feb02023b3a7bbf))
* state php breaking with double quotes in server description ([c6e92aa](https://github.com/unraid/api/commit/c6e92aa3157c9fe9e7b83580881ebcc1cbd03658))
* state php special chars for html attributes ([#853](https://github.com/unraid/api/issues/853)) ([dd4139c](https://github.com/unraid/api/commit/dd4139cf1a7ae5c6f9b00111c33ae124bb17e630))
* unraid-api missing start command + var defaults ([ceb4c58](https://github.com/unraid/api/commit/ceb4c587d20c7527f2b36a3278c310b0e657bfba))
* unraid-api.php $param1 fallback ([909c79c](https://github.com/unraid/api/commit/909c79c8c82500aea1a0d4d00766f788103c5fe3))
## [3.5.0](https://github.com/unraid/api/compare/v3.4.0...v3.5.0) (2024-02-07)
### Features
* add manage account link to all versions of upc dropdown ([678e620](https://github.com/unraid/api/commit/678e620c1902a376b1866265711d5722b4119d8e))
* add new staging url for connect website ([#841](https://github.com/unraid/api/issues/841)) ([4cfc07b](https://github.com/unraid/api/commit/4cfc07b6763dbb79b68cf01f7eaf7cf33370d4db))
* also ship to cloudflare ([#844](https://github.com/unraid/api/issues/844)) ([41c4210](https://github.com/unraid/api/commit/41c42103685209592b272f81a877702da04d0915))
* button add underline-hover-red style option ([f2fa5fa](https://github.com/unraid/api/commit/f2fa5fa49675ef461330be7b7eb3e3e4106983b0))
* changelog modal ([2ddbacd](https://github.com/unraid/api/commit/2ddbacd137cc5748244c3d25ac91f82e64d77f99))
* check update response modal ([39678f0](https://github.com/unraid/api/commit/39678f0bb0ddc5f87ea7f5ed80a0472100ea8b5d))
* create WebguiCheckForUpdate endpoint ([41d546e](https://github.com/unraid/api/commit/41d546eea5fcf6593d7b5047274c074bb89c1802))
* getOsReleaseBySha256 cached endpoint with keyfile header ([cd2413a](https://github.com/unraid/api/commit/cd2413abe8c5baab40e4e5974e08a5d18dce8e0d))
* new check update buttons in dropdown ([ef5fcb9](https://github.com/unraid/api/commit/ef5fcb96a324143da864df803acaa0da1cd00eb7))
* ship preview to different bucket ([#845](https://github.com/unraid/api/issues/845)) ([8e5d247](https://github.com/unraid/api/commit/8e5d247bca83d9e50977c9b16b212841ac9f70ad))
* ship production to different bucket ([#846](https://github.com/unraid/api/issues/846)) ([63c0875](https://github.com/unraid/api/commit/63c08758c76425e007b1779bb2f77b75bc45896e))
* unraidcheck callable from webgui with altUrl & json output ([ba8a67e](https://github.com/unraid/api/commit/ba8a67edfa043f442b11724227129f8d3f6cae0a))
* update modals ([8ad7d8b](https://github.com/unraid/api/commit/8ad7d8be9437e0caa0409da8f7322050919fbbaa))
* update os ignore release ([1955eb2](https://github.com/unraid/api/commit/1955eb23a3cdc30f0a67bc5950a047f83a860d99))
* update os notifications enabled usage + link to enable & more options to account app ([5c82aff](https://github.com/unraid/api/commit/5c82aff80dc7e6d8f4b23e52af29abc2b8576424))
* updateOs check response determines if update auth is required ([a9816d9](https://github.com/unraid/api/commit/a9816d9ad48ff80d87b5aeb236ff60c4979ad298))
* updateOs store call local server-side endpoint & add modal support ([be48447](https://github.com/unraid/api/commit/be48447f943828af281095c5a092ac686e729030))
* upgrade a ton of dependencies ([#842](https://github.com/unraid/api/issues/842)) ([94c1746](https://github.com/unraid/api/commit/94c174620c2347a3cf3d100404635f99a5b47287))
* WebguiCheckForUpdate using server-side check ([590deb1](https://github.com/unraid/api/commit/590deb130c301d4004fecdc211270583806b5593))
### Bug Fixes
* backport _var() PHP function to older versions of Unraid ([f53150e](https://github.com/unraid/api/commit/f53150e1fa33b3f45b66ad0dc5eaabc470564d45))
* changlog relative links and external links ([a789e20](https://github.com/unraid/api/commit/a789e204ce7b966e6c935923626538ac344aeefe))
* check update response modal expired key button styles ([92993e3](https://github.com/unraid/api/commit/92993e3e0b6240c83a6a64efedd8ddb3be3f9ef7))
* **deps:** update dependency ws to v8.16.0 ([#815](https://github.com/unraid/api/issues/815)) ([212020e](https://github.com/unraid/api/commit/212020e78d4de0576137058a3374837b4a43e02d))
* extraLinks when no updates available ([853a991](https://github.com/unraid/api/commit/853a9911e3fd7eec9bbc88468de78f87b448d477))
* ignore release localStorage ([62c45ec](https://github.com/unraid/api/commit/62c45ec9d7c68498bbcfe933a5b63e4759c7129c))
* lint ([83235f9](https://github.com/unraid/api/commit/83235f9db726f4582b9d353a66f2f5e8925b8e34))
* lint unused value ([2c7e53b](https://github.com/unraid/api/commit/2c7e53bf67d1f214201624b39786bfb7de6aa520))
* marked-base-url install ([416ba71](https://github.com/unraid/api/commit/416ba716aa750a094e8cd521a79f6deebcd37864))
* missing translations ([faf17e4](https://github.com/unraid/api/commit/faf17e41e81c11443bc062d8ce35a33d9ae9ebbc))
* regTm format after key install without page refresh ([f3ddb31](https://github.com/unraid/api/commit/f3ddb31f994de9192f7203698ecc5d7de673c6a3))
* regTm format when already set ([5ad911f](https://github.com/unraid/api/commit/5ad911f8133daa60de53da738d41c6a59e2f02cc))
* ServerUpdateOsResponse type ([78bdae8](https://github.com/unraid/api/commit/78bdae86c907142d3ee32d6715eaa8f5a974a1ed))
* State Class usage in other files ([4ad7f53](https://github.com/unraid/api/commit/4ad7f53ec145b2e6d2895619523e90c1daa3f68f))
* state data humanReadable switch fallthrus ([9144e39](https://github.com/unraid/api/commit/9144e39d39aa56af0ad897735d1a3545330920d0))
* state php usage from cli ([46fd321](https://github.com/unraid/api/commit/46fd321707c14cd1f265ee806f673500d87132dd))
* translations ([3fabd57](https://github.com/unraid/api/commit/3fabd5756674c06fa803729cf13d19c592d8d46a))
* type issue with changlelog modal visibility ([e3c3f6b](https://github.com/unraid/api/commit/e3c3f6bf0f1882788291db17bd74865fefc3abf6))
## [3.4.0](https://github.com/unraid/api/compare/v3.3.0...v3.4.0) (2024-01-11)
### Features
* add logrotate to cron in nestjs ([#839](https://github.com/unraid/api/issues/839)) ([5c91524](https://github.com/unraid/api/commit/5c91524d849147c0ac7925f3a2f1cce67ffe75de))
### Bug Fixes
* allow failure for log deletion ([eff3142](https://github.com/unraid/api/commit/eff31423927644be436a831126678719c2eb0621))
* allowed origins check not working without spaces ([#838](https://github.com/unraid/api/issues/838)) ([b998b38](https://github.com/unraid/api/commit/b998b38355fab77ecc2f62bc64896766218db3d4))
* excessive logging ([89cb254](https://github.com/unraid/api/commit/89cb2544ed0e0edd33b59f15d487487e22c0ae32))
* run hourly ([0425794](https://github.com/unraid/api/commit/0425794356a01262222e7dff2645d3629e00d0f6))
## [3.3.0](https://github.com/unraid/api/compare/v3.2.3...v3.3.0) (2024-01-09)
### Features
* add button to add current origin to extra origins setting ([8c15163](https://github.com/unraid/api/commit/8c15163b3b072122bff1f8f25de62594b1e67992))
* add environment to docker-compose ([2ee4683](https://github.com/unraid/api/commit/2ee46839095e3b8ee287cfe10f29ae9a39dcff68))
* add support for expiration in var.ini ([#833](https://github.com/unraid/api/issues/833)) ([0474c2e](https://github.com/unraid/api/commit/0474c2e14fa462d2e1ec6d9a7f974660385d073e))
* always show DRA even if disabled ([ab708c0](https://github.com/unraid/api/commit/ab708c0df634e21bf81595412d7de0be3ff7c392))
* change sort order of Update/Downgrade ([#754](https://github.com/unraid/api/issues/754)) ([be96b3a](https://github.com/unraid/api/commit/be96b3aac709682a6517fa6e84beb586b9d8bf5c))
* check for OS updates via PHP ([#752](https://github.com/unraid/api/issues/752)) ([4496615](https://github.com/unraid/api/commit/44966157b80a51dfe01d927c2af2d010c04becc5))
* close log on exit ([d6ede86](https://github.com/unraid/api/commit/d6ede86eca6301342cdf35bf1f9365896b5e5009))
* disable account & key actions when unraid-api CORS error ([1d15406](https://github.com/unraid/api/commit/1d1540646a264038ae96f4063c31a40cd048d2f9))
* extraOrigins public, remove origin listener ([91f96ba](https://github.com/unraid/api/commit/91f96ba818773d6e71dde1ff52a4c8ec21ba6b5d))
* fix codegen ([d0bf5bb](https://github.com/unraid/api/commit/d0bf5bb8197b11f7a250ca5392890184a1dbeff7))
* fix exit hook and cleanup docker scripts ([#758](https://github.com/unraid/api/issues/758)) ([a9ff73e](https://github.com/unraid/api/commit/a9ff73e0a04c67e9ec9d5551cf0b1f124be6f381))
* fix logging format on start and stop ([c6720c3](https://github.com/unraid/api/commit/c6720c331df055480d2d65b37290f4978fe429da))
* improve check for OS updates via PHP ([cde12b2](https://github.com/unraid/api/commit/cde12b247f9bba97644750cd95a2b0db320ca1d9))
* local start command ([99b6007](https://github.com/unraid/api/commit/99b6007ba30353084a8bea54cc0e782fcc1bfea4))
* log config recreation reason ([f36c72f](https://github.com/unraid/api/commit/f36c72f5ad44b7e41d1726fa181dc2b9f594c72c))
* nestjs initial query implementation ([#748](https://github.com/unraid/api/issues/748)) ([075d7f2](https://github.com/unraid/api/commit/075d7f25785bf686779b7fee1d5ea39f09ff3ea8))
* new key types in API ([e42f9dc](https://github.com/unraid/api/commit/e42f9dc95be03e8389aac443f2147c07a316d48d))
* npm scripts to prevent webgui builds with wrong urls ([279966a](https://github.com/unraid/api/commit/279966afa3c218fbe85bafe91ee40fff2eb59ef2))
* patch DefaultPageLayout for web component ([629fec6](https://github.com/unraid/api/commit/629fec64f911131e4ab3810c99028b484ce18b83))
* **plg:** WIP extra origins support ([85acaae](https://github.com/unraid/api/commit/85acaaee02dad98eeef8a8c4a09b463e84d593b4))
* regTy swapped ([564b25c](https://github.com/unraid/api/commit/564b25cf5ce0a62d40f8d63d44c81e9c8560e0be))
* run codegen and update build script ([07512ad](https://github.com/unraid/api/commit/07512adc13ee0d819db45ff6c5c5f58a0ba31141))
* server store isOsVersionStable ([b5ee4d4](https://github.com/unraid/api/commit/b5ee4d4ee632a7528e6f5df079cab0cb5ea656eb))
* stretch downgrade component buttons ([fa4f63e](https://github.com/unraid/api/commit/fa4f63e8bfca525ccfedb16f19d395bf11a68561))
* swap to fragement usage on webcomponent ([42733ab](https://github.com/unraid/api/commit/42733abf6e443516ff715569333422ce80d3b1d2))
* **web:** caseModel ([4174d0b](https://github.com/unraid/api/commit/4174d0bf2cac99af5db48e5642e0037d7425c952))
* **web:** create script to move build to webgui repo ([92df453](https://github.com/unraid/api/commit/92df453255fed45210d9a192c68bb27d3b0ee981))
* **web:** downgrade os web component ([45496ab](https://github.com/unraid/api/commit/45496ab7685d4bbfe591be46489260bac9b03474))
* **web:** finalize api cors error & settings field ([e1d9e16](https://github.com/unraid/api/commit/e1d9e16b8e80e0940a0078131ea629559e3238ec))
* **web:** guidValidation if new keyfile auto install ([0abb196](https://github.com/unraid/api/commit/0abb196d2c57ead4dca2adb2981ab79cdd1647c4))
* **web:** localStorage craftUrl for dev ([e646187](https://github.com/unraid/api/commit/e646187b04548c010cf26c7ae38a82ced6270394))
* **web:** refactor generic updateOS with date comparison ([91a753c](https://github.com/unraid/api/commit/91a753cd7018b89d53e9cd2d7c429ce53e291336))
* **web:** registration component ui / ux ([717d873](https://github.com/unraid/api/commit/717d8733bd4b8c87b6ae6f1cd66717056c5df876))
* **web:** registration replace eligibility docs btn ([b69285f](https://github.com/unraid/api/commit/b69285ff8ca5b896082b5f0e1aeba70f9a2c5129))
* **web:** registration too many devices messaging ([1c0b5a3](https://github.com/unraid/api/commit/1c0b5a317aadf6173405770878e6038d4d8b448f))
* **web:** start prep for new key type support ([5c5035a](https://github.com/unraid/api/commit/5c5035a5446516999729ddc56d1077ee512f14d3))
* **web:** update os create flash backup button ([50ba61c](https://github.com/unraid/api/commit/50ba61cf80b7df2d121962cf4ec4b10952e8eecb))
* **web:** WIP key expiration ([24618fe](https://github.com/unraid/api/commit/24618fe09db2109c2eb57ab1655ab0fb7d79fc90))
* **web:** WIP registration page UI UX ([559e5b8](https://github.com/unraid/api/commit/559e5b8698d5df80ca57f530a2bf2cb6f01e30c7))
* **web:** WIP registration page web component ([bd772a9](https://github.com/unraid/api/commit/bd772a9c97d49b57a0b5a0e6a367c9a4e3732086))
* **web:** WIP updateOs callback ([2ad55ed](https://github.com/unraid/api/commit/2ad55ed019155e46d8627ea5c1b82cd5e4351127))
* WIP first pass at UpdateOs page replacement component ([3a5d871](https://github.com/unraid/api/commit/3a5d871f1fd054720c3693705484072ff567ff28))
* WIP UpdateOs page component ([8e4c36d](https://github.com/unraid/api/commit/8e4c36d38ce4e70307f5d14c953d5103c8b7e8e4))
### Bug Fixes
* 6.10 view release notes js ([254d894](https://github.com/unraid/api/commit/254d894f39e512d1b4a0472180cb27090de256a0))
* add missing translation keys ([03b506c](https://github.com/unraid/api/commit/03b506cd4e68f23a85bbfd54205322a6a4f93e5b))
* add serverName / description to dashboard payload ([9677aff](https://github.com/unraid/api/commit/9677aff1cd0942f36a2845f3f105601c494efd9e))
* allow null for the local entry in the myservers cfg ([01157c8](https://github.com/unraid/api/commit/01157c86ea3838ca675d65528a882cf25d0019a6))
* azure and gray theme custom colors ([92e552c](https://github.com/unraid/api/commit/92e552c9c7f7804902f18eb2d71f8483671fe048))
* codegen on web run ([e2e67c2](https://github.com/unraid/api/commit/e2e67c21067a138d963f5f10760b84cf6a533542))
* combinedKnownOrigins in state.php for UPC ([b550eea](https://github.com/unraid/api/commit/b550eeae7077cbdbd6d004506bdc96d04c04bc4c))
* Connect settings myservers config parse ([1c1483a](https://github.com/unraid/api/commit/1c1483a5cc506deab9d858dabbb8388c8b1d1ec1))
* dateTime system settings ([56ccbff](https://github.com/unraid/api/commit/56ccbff61fb61ab67277100c525b80adf95e9b72))
* **deps:** update dependency graphql to v16.8.1 ([bff1b19](https://github.com/unraid/api/commit/bff1b19706bee1e3103e3a0a1d2fceb3154f9bba))
* **deps:** update graphql-tools monorepo (major) ([#693](https://github.com/unraid/api/issues/693)) ([3447eb0](https://github.com/unraid/api/commit/3447eb047a1dcd575b88a96bbcef9946aca366a1))
* **deps:** update nest monorepo ([#816](https://github.com/unraid/api/issues/816)) ([4af3699](https://github.com/unraid/api/commit/4af36991b8b376f816ed51fd503a66e99675a3e7))
* downgrade remove erroneous file_get_contents ([df9c918](https://github.com/unraid/api/commit/df9c91867cf3f7cf6b424a386d7e68bd510ec20f))
* exit with process.exit not process.exitcode ([dcb6def](https://github.com/unraid/api/commit/dcb6def1cf3365dca819feed101160c8ad0125dc))
* graphQL CORS error detection ([e5ea67f](https://github.com/unraid/api/commit/e5ea67fe5224fd5aaf06e1e63e7efc01974a10ac))
* header version thirdPartyDriversDownloading pill ([c2ff31c](https://github.com/unraid/api/commit/c2ff31c672bc30683062c6cefbd5e744a7a2a676))
* lint unused param var prefixed ([8d103a9](https://github.com/unraid/api/commit/8d103a9ca89139d7b4f513318a67bcc64c0daa0c))
* local container startup commands cleaned up ([6c0ccb2](https://github.com/unraid/api/commit/6c0ccb2b24f98282be4db2e0b2e6362f4a187def))
* logrotate not working due to invalid ownership of unraid-api folder ([ec0581a](https://github.com/unraid/api/commit/ec0581abf58a217f698d52d5337f2b312e5a645b))
* missing translation ([81a9380](https://github.com/unraid/api/commit/81a93802993e7d95fb587cbfe3b598136a89348b))
* optional check on api.version to allow fallback to save value ([0ac4455](https://github.com/unraid/api/commit/0ac4455f78407eca7aa1d6ee360830067a1c5c3e))
* patch ShowChanges.php in 6.10 ([92d09c2](https://github.com/unraid/api/commit/92d09c2846c1bf64276e140c4cf4635e8bbfa94b))
* plg installer header version replacement ([7d0de2c](https://github.com/unraid/api/commit/7d0de2c8b3dc3c2d3c204e7846cf65d6df07545f))
* plg remove reboot-details path ([d54d90e](https://github.com/unraid/api/commit/d54d90ec04c67ee532cbcb77c4c5890545899e5a))
* **plg:** Downgrade & Update page file locations ([3fbb6b7](https://github.com/unraid/api/commit/3fbb6b70c1152d0691f3d74298908338e19cda53))
* **plg:** third party reboot detection ([f0ee640](https://github.com/unraid/api/commit/f0ee640767e446a829fd2e60033560786e5f63b0))
* plugin install should suppress output from `unraid-api stop` ([#757](https://github.com/unraid/api/issues/757)) ([3da5d95](https://github.com/unraid/api/commit/3da5d9573b499c84c25e33b26a2014e79bef40f7))
* rearrange exit hook to try to fix closing ([843d3f4](https://github.com/unraid/api/commit/843d3f41162c5dbcfd7803912b1879d7a182231a))
* refreshServerState check regExp ([7fca971](https://github.com/unraid/api/commit/7fca971cab40b6e5493e7e21baf85e3d6ba66b90))
* remove var_dump Connect settings ([9425f8b](https://github.com/unraid/api/commit/9425f8b133d44ac759d09158eadd13c81e7796fb))
* renew callback messaging in modal ([e98d065](https://github.com/unraid/api/commit/e98d0654237b111cf912eb5014dbcc5da0e92ca3))
* replaceRenew response cache use & purge ([ca85199](https://github.com/unraid/api/commit/ca851991ecb09720d70135d302aa93ad10a96d3a))
* set sha in test step as well. ([8af3367](https://github.com/unraid/api/commit/8af3367226f9a3bc51db65ffe5dd53d6c5aa0017))
* state php version checking ([494f5e9](https://github.com/unraid/api/commit/494f5e9935bc207b81098e84a0fe3e259939cf39))
* stop using username to determine reg status ([c5a6cd7](https://github.com/unraid/api/commit/c5a6cd7bf930d8bc94ccae45f5363c12fd1fccfc))
* ThirdPartyDriver messaging on Update page ([f23ad76](https://github.com/unraid/api/commit/f23ad762c04c3da918429a376146fe096a5030d5))
* try to set environment in docker build ([caece63](https://github.com/unraid/api/commit/caece63e7f180f94a7ee6b962c905296c6b987bb))
* uninstall reboot-details include ([3849462](https://github.com/unraid/api/commit/3849462f572659a43157a49511075f2d8cd5dd4c))
* unraid-api server state refresh after key extension use regExp ([490595f](https://github.com/unraid/api/commit/490595f9b420054e6c2fe40d868b902b262718af))
* updateOs auth group usage ([52b1ad9](https://github.com/unraid/api/commit/52b1ad9a7d3c9cdc989dd729d7828b0678349c27))
* updateOs type check ([ba230e2](https://github.com/unraid/api/commit/ba230e2643399fbfa1612059f235ccdf61f7f486))
* web component translations class ([6c81f6f](https://github.com/unraid/api/commit/6c81f6f70dcbe4f055a0041863fe275d6e01d6b9))
* **web:** azure & gray theme header font colors ([8a5c7c9](https://github.com/unraid/api/commit/8a5c7c9304a063b26d7ff2df5c174aa9f1c0f53c))
* **web:** card wrapper error border styles ([c71f420](https://github.com/unraid/api/commit/c71f420a4c9f7325127e3f38157dbc6255b3e139))
* **web:** connect graph error handling ([c239937](https://github.com/unraid/api/commit/c239937c407cfea0defde1994809a5c0a196cca2))
* **web:** default time format include am/pm ([31694cd](https://github.com/unraid/api/commit/31694cd7141e2ec0b0c3b4e4480d34d19c80adae))
* **web:** downgrade status pill for no downgrade available ([9d9ebb1](https://github.com/unraid/api/commit/9d9ebb1c6efd486a90dcd78ba63766e24be26d55))
* **web:** downgrade-not-available when downgrade initiated ([d060359](https://github.com/unraid/api/commit/d0603592596a3173889e9d06d57cfaa602eb80bb))
* **web:** installPlugin composable for os updates ([9fb024a](https://github.com/unraid/api/commit/9fb024a68d65905e5351cfa71ca64cdffa0fa74c))
* **web:** lint fixes ([224d637](https://github.com/unraid/api/commit/224d63773d505b8d65c9455fb94260ae617d9fe5))
* **web:** localStorage craftUrl for dev ([2e108da](https://github.com/unraid/api/commit/2e108da0db7de01d03ee3b0657a614355a61b208))
* **web:** missing translation ([74a8f27](https://github.com/unraid/api/commit/74a8f27643d7ba9c9d5dcd6a43b189a936dae648))
* **web:** missing translation for update ([cb46a94](https://github.com/unraid/api/commit/cb46a94c7238bf381fbfc48109b1dd648d2e4949))
* **web:** missing translations ([8ea733b](https://github.com/unraid/api/commit/8ea733b295a5f3bd922e867f544e5538873a5088))
* **web:** missing translations ([d2eed92](https://github.com/unraid/api/commit/d2eed9291de9297aa0d556f06b9b8f5f09734250))
* **web:** no plugin, don't show restart api button ([e628a8b](https://github.com/unraid/api/commit/e628a8b64fab4d1a5ce84af62abde3cd4c53ba96))
* **web:** preview and test releases usage ([4b8cfb4](https://github.com/unraid/api/commit/4b8cfb464e8296ce20d6ff3870949d739a86ca1b))
* **web:** reboot required disable update check link ([f029652](https://github.com/unraid/api/commit/f0296528bae52227ecbe281786ddf4d3a0cc940f))
* **web:** reg component conditional keyActions ([730dff2](https://github.com/unraid/api/commit/730dff2e6344f7ee076e1c67d82ef0783a5931b2))
* **web:** Registration key actions ([f7b1016](https://github.com/unraid/api/commit/f7b1016980c3f576b007a1d01184bf35f0eef311))
* **web:** regTy on account payload ([64b0b5e](https://github.com/unraid/api/commit/64b0b5eb5767d41012f6bcb9536030ec39e45af9))
* **web:** regUpdatesExpired use .isAfter ([5d67adf](https://github.com/unraid/api/commit/5d67adf4625a108e3374eb72714cdc1747b2a9c5))
* **web:** replace check request error handling ([c1491fe](https://github.com/unraid/api/commit/c1491fecdc327d78f8de7c0f04fda481fb47cb56))
* **web:** replaceCheck type ([1bd9729](https://github.com/unraid/api/commit/1bd9729b0197b49ca460912bbc56cd3b206d00dc))
* **web:** replaceCheck type ([8cc6020](https://github.com/unraid/api/commit/8cc602019a2c8a718b59590d166644a1cb4d16cc))
* **web:** state $_SESSION usage ([412392d](https://github.com/unraid/api/commit/412392dc1c5e612199e76ee7e1cae03705957e3d))
* **web:** state php warnings ([1460cab](https://github.com/unraid/api/commit/1460cabe6b041f9f9fb89ca474a7d7e872d31c39))
* **web:** translation ([cc85a49](https://github.com/unraid/api/commit/cc85a4903178999dbb80da50aa3b02ff38012172))
* **web:** type errors ([e6c57eb](https://github.com/unraid/api/commit/e6c57eb910a1c1f948a3104c4e7fc04ac8b2d327))
* **web:** upc dropdown updates external icon ([13936bb](https://github.com/unraid/api/commit/13936bb157f9097a19c7498fce252f3f86526ccb))
* **web:** update CallbackButton import ([eabfeca](https://github.com/unraid/api/commit/eabfeca618d3bf682a331c6d9e1f17b5facdcdca))
* **web:** Update OS auto redirect loop with account ([9b56fc3](https://github.com/unraid/api/commit/9b56fc3883f51942de9b1c8d1d1f30595fee7fa5))
* **web:** updateOs lint ([bd9e9d5](https://github.com/unraid/api/commit/bd9e9d55cc7bba432f65d78feee83526dbfff059))
* **web:** use dateTime format from server ([7090f38](https://github.com/unraid/api/commit/7090f38a9ab8b2d1dfce4095f4e2669d4d78a3e1))
### [3.2.3](https://github.com/unraid/api/compare/v3.2.2...v3.2.3) (2023-09-08)
@@ -3168,4 +3621,4 @@ All notable changes to this project will be documented in this file. See [standa
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

View File

@@ -1,39 +1,31 @@
###########################################################
# Development/Build Image
###########################################################
FROM node:18.17.1-alpine As development
FROM node:20-bookworm-slim AS development
# Install build tools and dependencies
RUN apk add --no-cache \
RUN apt-get update -y && apt-get install -y \
bash \
# Real PS Command (needed for some dependencies)
procps \
alpine-sdk \
python3 \
libvirt-dev \
jq \
zstd
RUN mkdir /var/log/unraid-api/
zstd \
git \
build-essential
WORKDIR /app
# Set app env
ENV NODE_ENV=development
# Setup cache for pkg
ENV PKG_CACHE_PATH /app/.pkg-cache
RUN mkdir -p ${PKG_CACHE_PATH}
COPY tsconfig.json tsup.config.ts .eslintrc.cjs .npmrc .env.production .env.staging ./
COPY tsconfig.json .eslintrc.ts .npmrc .env.production .env.staging ./
COPY package.json package-lock.json ./
# Install pkg
RUN npm i -g pkg zx
# Install deps
RUN npm ci
RUN npm i
EXPOSE 4000
@@ -43,6 +35,8 @@ EXPOSE 4000
FROM development AS builder
ENV NODE_ENV=production
COPY . .
CMD ["npm", "run", "build-pkg"]
CMD ["npm", "run", "build-and-pack"]

62
api/README.md Normal file
View File

@@ -0,0 +1,62 @@
# @unraid/api
## Installation
Install the production plugin via the apps tab (search for "Unraid Connect")
Manual install can be done with the following routes:
[production](https://stable.dl.unraid.net/unraid-api/dynamix.unraid.net.plg)
[staging](https://preview.dl.unraid.net/unraid-api/dynamix.unraid.net.staging.plg)
## CLI
If you're on a unraid v6.9.2 or later machine this should be available by running `unraid-api` in any directory.
```bash
root@Devon:~# unraid-api
Unraid API
Thanks for using the official Unraid API
Usage:
$ unraid-api command <options>
Commands:
start/stop/restart/version/status/report/switch-env
Options:
-h, --help Prints this usage guide.
-d, --debug Enabled debug mode.
-p, --port string Set the graphql port.
--environment production/staging/development Set the working environment.
--log-level ALL/TRACE/DEBUG/INFO/WARN/ERROR/FATAL/MARK/OFF Set the log level.
Copyright © 2024 Lime Technology, Inc.
```
## Report
To view the current status of the unraid-api and its connection to mothership, run:
```
unraid-api report
```
To view verbose data (anonymized), run:
```
unraid-api report -v
```
To view non-anonymized verbose data, run:
```
unraid-api report -vv
```
## Secrets
If you found this file you're likely a developer. If you'd like to know more about the API and when it's available please join [our discord](https://discord.unraid.net/).
## License
Copyright Lime Technology Inc. All rights reserved.

105
api/codegen.ts Normal file
View File

@@ -0,0 +1,105 @@
import type { CodegenConfig } from '@graphql-codegen/cli';
const config: CodegenConfig = {
overwrite: true,
emitLegacyCommonJSImports: false,
verbose: true,
config: {
namingConvention: {
typeNames: './fix-array-type.cjs',
enumValues: 'change-case#upperCase',
useTypeImports: true,
},
scalars: {
DateTime: 'string',
Long: 'number',
JSON: '{ [key: string]: any }',
URL: 'URL',
Port: 'number',
UUID: 'string',
},
},
generates: {
'src/graphql/generated/client/': {
documents: './src/graphql/mothership/*.ts',
schema: {
[process.env.MOTHERSHIP_GRAPHQL_LINK as string]: {
headers: {
origin: 'https://forums.unraid.net',
},
},
},
preset: 'client',
presetConfig: {
gqlTagName: 'graphql',
},
config: {
useTypeImports: true,
withObjectType: true,
},
plugins: [
{ add: { content: '/* eslint-disable */' } },
],
},
// Generate Types for the API Server
'src/graphql/generated/api/types.ts': {
schema: [
'./src/graphql/types.ts',
'./src/graphql/schema/types/**/*.graphql',
],
plugins: [
'typescript',
'typescript-resolvers',
{ add: { content: '/* eslint-disable */' } },
],
config: {
contextType: '@app/graphql/schema/utils#Context',
useIndexSignature: true,
},
},
// Generate Operations for any built-in API Server Operations (e.g., report.ts)
'src/graphql/generated/api/operations.ts': {
documents: './src/graphql/client/api/*.ts',
schema: [
'./src/graphql/types.ts',
'./src/graphql/schema/types/**/*.graphql',
],
preset: 'import-types',
presetConfig: {
typesPath: '@app/graphql/generated/api/types',
},
plugins: [
'typescript-validation-schema',
'typescript-operations',
'typed-document-node',
{ add: { content: '/* eslint-disable */' } },
],
config: {
importFrom: '@app/graphql/generated/api/types',
strictScalars: false,
schema: 'zod',
withObjectType: true,
},
},
'src/graphql/generated/client/validators.ts': {
schema: {
[process.env.MOTHERSHIP_GRAPHQL_LINK as string]: {
headers: {
origin: 'https://forums.unraid.net',
},
},
},
plugins: [
'typescript-validation-schema',
{ add: { content: '/* eslint-disable */' } },
],
config: {
importFrom: '@app/graphql/generated/client/graphql',
strictScalars: false,
schema: 'zod',
},
},
},
};
export default config;

View File

@@ -1,77 +0,0 @@
overwrite: true
emitLegacyCommonJSImports: false
verbose: true
require:
- ts-node/register
config:
namingConvention:
typeNames: './fix-array-type.cjs'
enumValues: 'change-case#upperCase'
useTypeImports: true
scalars:
DateTime: string
Long: number
JSON: "{ [key: string]: any }"
URL: URL
Port: number
UUID: string
generates:
src/graphql/generated/client/:
documents: './src/graphql/mothership/*.ts'
schema:
'${MOTHERSHIP_GRAPHQL_LINK}':
headers:
origin: 'https://forums.unraid.net'
preset: client
presetConfig:
gqlTagName: graphql
config:
useTypeImports: true
withObjectType: true
plugins:
- add: { content: '/* eslint-disable */' }
# Generate Types for the API Server
src/graphql/generated/api/types.ts:
schema:
- './src/graphql/types.ts'
- './src/graphql/schema/types/**/*.graphql'
plugins:
- typescript
- typescript-resolvers
- add: { content: '/* eslint-disable */' }
config:
contextType: '@app/graphql/schema/utils#Context'
useIndexSignature: true
# Generate Operations for any built in API Server Operations (ie report.ts)
src/graphql/generated/api/operations.ts:
documents: './src/graphql/client/api/*.ts'
schema:
- './src/graphql/types.ts'
- './src/graphql/schema/types/**/*.graphql'
preset: import-types
presetConfig:
typesPath: '@app/graphql/generated/api/types'
plugins:
- typescript-validation-schema
- typescript-operations
- typed-document-node
- add: { content: '/* eslint-disable */' }
config:
importFrom: '@app/graphql/generated/api/types'
strictScalars: false
schema: 'zod'
withObjectType: true
src/graphql/generated/client/validators.ts:
schema:
'${MOTHERSHIP_GRAPHQL_LINK}':
headers:
origin: 'https://forums.unraid.net'
plugins:
- typescript-validation-schema
- add: { content: '/* eslint-disable */'}
config:
importFrom: '@app/graphql/generated/client/graphql'
strictScalars: false
schema: 'zod'

View File

@@ -1,5 +1,6 @@
[api]
version="3.1.1+8efc0992"
version="3.11.0"
extraOrigins="https://google.com,https://test.com"
[local]
[notifier]
apikey="unnotify_30994bfaccf839c65bae75f7fa12dd5ee16e69389f754c3b98ed7d5"
@@ -8,6 +9,7 @@ wanaccess="yes"
wanport="8443"
upnpEnabled="no"
apikey="_______________________BIG_API_KEY_HERE_________________________"
localApiKey="_______________________LOCAL_API_KEY_HERE_________________________"
email="test@example.com"
username="zspearmint"
avatar="https://via.placeholder.com/200"
@@ -15,5 +17,6 @@ regWizTime="1611175408732_0951-1653-3509-FBA155FA23C0"
idtoken=""
accesstoken=""
refreshtoken=""
dynamicRemoteAccessType="DISABLED"
[upc]
apikey="unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810"

View File

@@ -0,0 +1,80 @@
[confirm]
down="1"
stop="1"
[display]
width=""
font=""
tty="15"
date="%c"
time="%R"
number=".,"
unit="C"
scale="-1"
resize="0"
wwn="0"
total="1"
banner=""
header=""
background=""
tabs="1"
users="Tasks:3"
usage="0"
text="1"
warning="70"
critical="90"
hot="45"
max="55"
hotssd="60"
maxssd="70"
power=""
theme="white"
locale=""
raw=""
rtl=""
headermetacolor=""
headerdescription="yes"
showBannerGradient="yes"
[parity]
mode="0"
hour="0 0"
dotm="1"
month="1"
day="0"
cron=""
write="NOCORRECT"
[notify]
display="0"
life="5"
date="d-m-Y"
time="H:i"
position="top-right"
path="/tmp/notifications"
system="*/1 * * * *"
entity="1"
normal="1"
warning="1"
alert="1"
unraid="1"
plugin="1"
docker_notify="1"
language_notify="1"
report="1"
unraidos=""
version=""
docker_update=""
language_update=""
status=""
[ssmtp]
root=""
RcptTo=""
SetEmailPriority="True"
Subject="Unraid Status: "
server="smtp.gmail.com"
port="465"
UseTLS="YES"
UseSTARTTLS="NO"
UseTLSCert="NO"
TLSCert=""
AuthMethod="login"
AuthUser=""
AuthPass=""

View File

@@ -1,5 +1,6 @@
[display]
date="%c"
time="%I:%M %p"
number=".,"
scale="-1"
tabs="1"

View File

@@ -0,0 +1,8 @@
{
"id": "10f356da-1e9e-43b8-9028-a26a645539a6",
"key": "73717ca0-8c15-40b9-bcca-8d85656d1438",
"name": "Test API Key",
"description": "Testing API key creation",
"roles": ["guest", "connect"],
"createdAt": "2024-10-29T19:59:12.569Z"
}

View File

@@ -0,0 +1,10 @@
{
"createdAt": "2024-12-20T15:05:55.336Z",
"description": "API key for Connect user",
"id": "d166bf8b-3615-444a-8932-c460b2132ba3",
"key": "_______________________LOCAL_API_KEY_HERE_________________________",
"name": "Connect",
"roles": [
"connect"
]
}

View File

@@ -3,3 +3,4 @@ event=Unraid Parity check
subject=Notice [UNRAID] - Parity check finished (0 errors)
description=Canceled
importance=warning
link=/

View File

@@ -0,0 +1 @@
unraid_login|i:1736523078;unraid_user|s:4:"root";locale|s:0:"";buildDate|s:8:"20241202";

View File

@@ -1,5 +1,6 @@
[api]
version="3.1.1+8efc0992"
version="3.11.0"
extraOrigins="https://google.com,https://test.com"
[local]
[notifier]
apikey="unnotify_30994bfaccf839c65bae75f7fa12dd5ee16e69389f754c3b98ed7d5"
@@ -8,6 +9,7 @@ wanaccess="yes"
wanport="8443"
upnpEnabled="no"
apikey="_______________________BIG_API_KEY_HERE_________________________"
localApiKey="_______________________LOCAL_API_KEY_HERE_________________________"
email="test@example.com"
username="zspearmint"
avatar="https://via.placeholder.com/200"
@@ -15,7 +17,8 @@ regWizTime="1611175408732_0951-1653-3509-FBA155FA23C0"
idtoken=""
accesstoken=""
refreshtoken=""
allowedOrigins="/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, http://localhost:8080, https://localhost:4443, https://tower.local:4443, https://192.168.1.150:4443, https://tower:4443, https://192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net:4443, https://85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net:8443, https://10-252-0-1.hash.myunraid.net:4443, https://10-252-1-1.hash.myunraid.net:4443, https://10-253-3-1.hash.myunraid.net:4443, https://10-253-4-1.hash.myunraid.net:4443, https://10-253-5-1.hash.myunraid.net:4443, https://connect.myunraid.net, https://staging.connect.myunraid.net, https://dev-my.myunraid.net:4000, https://studio.apollographql.com"
allowedOrigins="/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, http://localhost:8080, https://localhost:4443, https://tower.local:4443, https://192.168.1.150:4443, https://tower:4443, https://192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net:4443, https://85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net:8443, https://10-252-0-1.hash.myunraid.net:4443, https://10-252-1-1.hash.myunraid.net:4443, https://10-253-3-1.hash.myunraid.net:4443, https://10-253-4-1.hash.myunraid.net:4443, https://10-253-5-1.hash.myunraid.net:4443, https://10-100-0-1.hash.myunraid.net:4443, https://10-100-0-2.hash.myunraid.net:4443, https://10-123-1-2.hash.myunraid.net:4443, https://221-123-121-112.hash.myunraid.net:4443, https://google.com, https://test.com, https://connect.myunraid.net, https://connect-staging.myunraid.net, https://dev-my.myunraid.net:4000, https://studio.apollographql.com"
dynamicRemoteAccessType="DISABLED"
[upc]
apikey="unupc_fab6ff6ffe51040595c6d9ffb63a353ba16cc2ad7d93f813a2e80a5810"
[connectionStatus]

26
api/dev/states/nginx.ini Normal file
View File

@@ -0,0 +1,26 @@
NGINX_LANIP="192.168.1.150"
NGINX_LANIP6=""
NGINX_LANNAME="Tower"
NGINX_LANMDNS="Tower.local"
NGINX_CERTPATH="/boot/config/ssl/certs/certificate_bundle.pem"
NGINX_USESSL="yes"
NGINX_PORT="8080"
NGINX_PORTSSL="4443"
NGINX_DEFAULTURL="https://Tower.local:4443"
NGINX_CERTNAME="*.thisisfourtyrandomcharacters012345678900.myunraid.net"
NGINX_LANFQDN="192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net"
NGINX_LANFQDN6=""
NGINX_WANACCESS=""
NGINX_WANIP=""
NGINX_WANIP6=""
NGINX_WANFQDN="85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net"
NGINX_WANFQDN6=""
NGINX_WG0FQDN="10-252-0-1.hash.myunraid.net"
NGINX_WG1FQDN="10-252-1-1.hash.myunraid.net"
NGINX_WG3FQDN="10-253-3-1.hash.myunraid.net"
NGINX_WG4FQDN="10-253-4-1.hash.myunraid.net"
NGINX_WG55FQDN="10-253-5-1.hash.myunraid.net"
NGINX_TAILSCALEFQDN="10-100-0-1.hash.myunraid.net"
NGINX_TAILSCALE0FQDN="10-100-0-2.hash.myunraid.net"
NGINX_CUSTOMFQDN="10-123-1-2.hash.myunraid.net"
NGINX_CUSTOMFQDN6="221-123-121-112.hash.myunraid.net"

143
api/dev/states/var.ini Normal file
View File

@@ -0,0 +1,143 @@
version="6.11.2"
MAX_ARRAYSZ="30"
MAX_CACHESZ="30"
NAME="Tower"
timeZone="Australia/Adelaide"
COMMENT="Dev Server"
SECURITY="user"
WORKGROUP="WORKGROUP"
DOMAIN=""
DOMAIN_SHORT=""
hideDotFiles="no"
localMaster="yes"
enableFruit="no"
USE_NETBIOS="yes"
USE_WSD="no"
WSD_OPT=""
USE_NTP="yes"
NTP_SERVER1="time1.google.com"
NTP_SERVER2="time2.google.com"
NTP_SERVER3="time3.google.com"
NTP_SERVER4="time4.google.com"
DOMAIN_LOGIN="Administrator"
SYS_MODEL="Dell R710"
SYS_ARRAY_SLOTS="24"
SYS_FLASH_SLOTS="1"
USE_SSL="auto"
PORT="80"
PORTSSL="443"
LOCAL_TLD="local"
BIND_MGT="no"
USE_TELNET="yes"
PORTTELNET="23"
USE_SSH="yes"
PORTSSH="22"
USE_UPNP="yes"
START_PAGE="Main"
startArray="no"
spindownDelay="0"
spinupGroups="no"
defaultFsType="xfs"
shutdownTimeout="90"
luksKeyfile="/tmp/unraid/keyfile"
poll_attributes="1800"
poll_attributes_default="1800"
poll_attributes_status="default"
queueDepth="auto"
nr_requests="Auto"
nr_requests_default="Auto"
nr_requests_status="default"
md_scheduler="auto"
md_scheduler_default="auto"
md_scheduler_status="default"
md_num_stripes="1280"
md_num_stripes_default="1280"
md_num_stripes_status="default"
md_queue_limit="80"
md_queue_limit_default="80"
md_queue_limit_status="default"
md_sync_limit="5"
md_sync_limit_default="5"
md_sync_limit_status="default"
md_write_method="auto"
md_write_method_default="auto"
md_write_method_status="default"
shareDisk="yes"
shareUser="e"
shareUserInclude=""
shareUserExclude=""
shareSMBEnabled="yes"
shareNFSEnabled="no"
shareInitialOwner="Administrator"
shareInitialGroup="Domain Users"
shareCacheEnabled="yes"
shareCacheFloor="2000000"
shareMoverSchedule="40 3 * * *"
shareMoverLogging="no"
fuse_remember="330"
fuse_remember_default="330"
fuse_remember_status="default"
fuse_directio="auto"
fuse_directio_default="auto"
fuse_directio_status="default"
fuse_useino="yes"
shareAvahiEnabled="yes"
shareAvahiSMBName="%h"
shareAvahiSMBModel="Xserve"
shfs_logging="1"
safeMode="no"
startMode="Normal"
configValid="yes"
joinStatus="Not joined"
deviceCount="4"
flashGUID="0000-0000-0000-000000000000"
flashProduct="DataTraveler_3.0"
flashVendor="KINGSTON"
regCheck=""
regFILE="/app/dev/Unraid.net/Pro.key"
regGUID="13FE-4200-C300-58C372A52B19"
regTy="Pro"
regTo="Eli Bosley"
regTm="1833409182"
regTm2="0"
regExp=""
regGen="0"
sbName="/boot/config/super.dat"
sbVersion="2.9.13"
sbUpdated="1596079143"
sbEvents="173"
sbState="1"
sbClean="yes"
sbSynced="1586819259"
sbSyncErrs="0"
sbSynced2="1586822456"
sbSyncExit="0"
sbNumDisks="5"
mdColor="green-blink"
mdNumDisks="4"
mdNumDisabled="1"
mdNumInvalid="1"
mdNumMissing="0"
mdNumNew="0"
mdNumErased="0"
mdResync="0"
mdResyncCorr="0"
mdResyncPos="0"
mdResyncDb="0"
mdResyncDt="0"
mdResyncAction="check P"
mdResyncSize="438960096"
mdState="STOPPED"
mdVersion="2.9.14"
fsState="Stopped"
fsProgress="Autostart disabled"
fsCopyPrcnt="0"
fsNumMounted="0"
fsNumUnmountable="0"
fsUnmountableMask=""
shareCount="0"
shareSMBCount="1"
shareNFSCount="0"
shareMoverActive="no"
reservedNames="parity,parity2,parity3,diskP,diskQ,diskR,disk,disks,flash,boot,user,user0,disk0,disk1,disk2,disk3,disk4,disk5,disk6,disk7,disk8,disk9,disk10,disk11,disk12,disk13,disk14,disk15,disk16,disk17,disk18,disk19,disk20,disk21,disk22,disk23,disk24,disk25,disk26,disk27,disk28,disk29,disk30,disk31"
csrf_token="0000000000000000"

View File

@@ -4,11 +4,9 @@ x-volumes: &volumes
volumes:
- ./dev:/app/dev
- ./src:/app/src
- ./patches:/app/patches
- ./package.json:/app/package.json
- ./package-lock.json:/app/package-lock.json
- ./tsconfig.json:/app/tsconfig.json
- ./tsup.config.ts:/app/tsup.config.ts
- ./vite.config.ts:/app/vite.config.ts
- ./dist/:/app/dist/
- ./deploy/:/app/deploy/
@@ -19,19 +17,15 @@ x-volumes: &volumes
- ./.env.staging:/app/.env.staging
- ./.env.test:/app/.env.test
- ./.env.development:/app/.env.development
- ./.pkg-cache:/app/.pkg-cache
- ./codegen.yml:/app/codegen.yml
- ./codegen.ts:/app/codegen.ts
- ./fix-array-type.cjs:/app/fix-array-type.cjs
- /var/run/docker.sock:/var/run/docker.sock
- ./unraid-api.js:/app/unraid-api.js
- ./ecosystem.config.json:/app/ecosystem.config.json
networks:
mothership_default:
services:
dev:
networks:
- mothership_default
image: unraid-api:development
ports:
- "3001:3001"
@@ -45,12 +39,33 @@ services:
entrypoint: /bin/bash
environment:
- IS_DOCKER=true
- GIT_SHA=${GIT_SHA:?err}
- IS_TAGGED=${IS_TAGGED}
profiles:
- builder
local:
image: unraid-api:development
ports:
- "3001:3001"
build:
context: .
target: development
dockerfile: Dockerfile
<<: *volumes
command: npm run start:dev
environment:
- IS_DOCKER=true
- GIT_SHA=${GIT_SHA:?err}
- IS_TAGGED=${IS_TAGGED}
profiles:
- builder
builder:
image: unraid-api:builder
environment:
- GIT_SHA=${GIT_SHA:?err}
- IS_TAGGED=${IS_TAGGED}
build:
context: .
target: builder

116
api/docs/development.md Normal file
View File

@@ -0,0 +1,116 @@
# Development
## Installation
Manual install can be done with the following routes:
[production](https://stable.dl.unraid.net/unraid-api/dynamix.unraid.net.plg)
[staging](https://preview.dl.unraid.net/unraid-api/dynamix.unraid.net.staging.plg)
## Connecting to the API
### HTTP
This can be accessed by default via `http://tower.local/graphql`.
See <https://graphql.org/learn/serving-over-http/#http-methods-headers-and-body>
## Building in Docker
To get a development environment for testing start by running this docker command:
`npm run build:docker`
`npm run start:ddev`
which will give you an interactive shell inside of the newly build linux container.
To automatically build the plugin run the command below:
`npm run build:docker`
The builder command will build the plugin into deploy/release, and the interactive plugin lets you build the plugin or install node modules how you like.
## Logs
Logging can be configured via environment variables.
Log levels can be set when the api starts via `LOG_LEVEL=all/trace/debug/info/warn/error/fatal/mark/off`.
Additional detail for the log entry can be added with `LOG_CONTEXT=true` (warning, generates a lot of data).
By default, logs will be sent to syslog. Or you can set `LOG_TRANSPORT=file` to have logs saved in `/var/log/unraid-api/stdout.log`. Or enable debug mode to view logs inline.
Examples:
- `unraid-api start`
- `LOG_LEVEL=debug unraid-api start --debug`
- `LOG_LEVEL=trace LOG_CONTEXT=true LOG_TRANSPORT=file unraid-api start`
## Viewing data sent to mothership
If the environment variable `LOG_MOTHERSHIP_MESSAGES=true` exists, any data the unraid-api sends to mothership will be saved in clear text here: `/var/log/unraid-api/relay-messages.log`
Examples:
- `LOG_MOTHERSHIP_MESSAGES=true unraid-api start`
- `LOG_MOTHERSHIP_MESSAGES=true LOG_LEVEL=debug unraid-api start --debug`
## Debug Logging
To view debug logs, change the log level when starting the API. Then type unraid-api logs to trail the logs.
Examples:
- `LOG_LEVEL=debug unraid-api start`
- `unraid-api logs`
## Switching between staging and production environments
1. Stop the api: `unraid-api stop`
2. Switch environments: `unraid-api switch-env`
3. Start the api: `unraid-api start`
4. Confirm the environment: `unraid-api report`
## Playground
The playground can be access via `http://tower.local/graphql` while in debug mode.
To get your API key open a terminal on your server and run `cat /boot/config/plugins/dynamix.my.servers/myservers.cfg | grep apikey=\"unraid | cut -d '"' -f2`. Add that API key in the "HTTP headers" panel of the playground.
```json
{
"x-api-key": "__REPLACE_ME_WITH_API_KEY__"
}
```
Next add the query you want to run and hit the play icon.
```gql
query welcome {
welcome {
message
}
}
```
You should get something like this back.
```json
{
"data": {
"welcome": {
"message": "Welcome root to this Unraid 6.10.0 server"
}
}
}
```
Click the "Schema" and "Docs" button on the right side of the playground to learn more.
## Create a new release
To create a new version run `npm run release` and then run **ONLY** the `git push` section of the commands it returns.
To create a new prerelease run `npm run release -- --prerelease alpha`.
Pushing to this repo will cause an automatic "rolling" release to be built which can be accessed via the page for the associated Github action run.
## Using a custom version (e.g. testing a new release)
Find the Pull Request you'd like to install, and a link will be present as a comment to install a PR-specific version.

21
api/ecosystem.config.json Normal file
View File

@@ -0,0 +1,21 @@
{
"apps": [
{
"name": "unraid-api",
"script": "./dist/main.js",
"cwd": "/usr/local/unraid-api",
"log": "/var/log/unraid-api/unraid-api.log",
"exec_mode": "fork",
"wait_ready": true,
"listen_timeout": 30000,
"max_restarts": 10,
"min_uptime": 10000,
"ignore_watch": [
"node_modules",
"src",
".env.*",
"myservers.cfg"
]
}
]
}

21
api/justfile Normal file
View File

@@ -0,0 +1,21 @@
set fallback
default:
@just --list --justfile {{justfile()}} --list-heading $'\nAPI project recipes:\n'
@just list-commands
setup:
npm install
npm run container:build
# builds js files that can run on an unraid server
@build:
npm run build
# deploys to an unraid server
@deploy:
./scripts/deploy-dev.sh
# build & deploy
bd: build deploy

52829
api/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,202 +1,193 @@
{
"name": "@unraid/api",
"version": "3.2.3",
"main": "dist/index.js",
"bin": "dist/unraid-api.cjs",
"type": "module",
"repository": "git@github.com:unraid/api.git",
"author": "Alexis Tyler <xo@wvvw.me> (https://wvvw.me/)",
"license": "UNLICENSED",
"engines": {
"node": ">=16.5.0"
},
"pkg": {
"assets": [
"dist/index.cjs",
"node_modules/@vmngr/libvirt/build/Release",
"node_modules/ts-invariant/",
"src/**/*.graphql"
"name": "@unraid/api",
"version": "3.11.0",
"main": "src/cli/index.ts",
"type": "module",
"repository": "git@github.com:unraid/api.git",
"author": "Lime Technology, Inc. <unraid.net>",
"license": "UNLICENSED",
"scripts": {
"start": "node dist/main.js",
"build:docker": "./scripts/dc.sh run --rm builder",
"build": "vite build --mode=production",
"postbuild": "chmod +x dist/main.js && chmod +x dist/cli.js",
"build-and-pack": "./scripts/build.mjs",
"codegen": "MOTHERSHIP_GRAPHQL_LINK='https://staging.mothership.unraid.net/ws' graphql-codegen --config codegen.ts -r dotenv/config './.env.staging'",
"codegen:watch": "DOTENV_CONFIG_PATH='./.env.staging' graphql-codegen --config codegen.ts --watch -r dotenv/config",
"codegen:local": "NODE_TLS_REJECT_UNAUTHORIZED=0 MOTHERSHIP_GRAPHQL_LINK='https://mothership.localhost/ws' graphql-codegen --config codegen.ts --watch",
"tsc": "tsc --noEmit",
"lint": "eslint --flag unstable_ts_config --config .eslintrc.ts src/",
"lint:fix": "eslint --flag unstable_ts_config --fix --config .eslintrc.ts src/",
"test:watch": "vitest --pool=forks",
"test": "vitest run --pool=forks",
"coverage": "vitest run --pool=forks --coverage",
"release": "standard-version",
"dev": "vite",
"container:build": "./scripts/dc.sh build dev",
"container:start": "./scripts/dc.sh run --rm --service-ports dev",
"container:test": "./scripts/dc.sh run --rm builder npm run test",
"container:enter": "./scripts/dc.sh exec dev /bin/bash"
},
"files": [
".env.staging",
".env.production",
"ecosystem.config.json",
"README.md",
"src",
"node_modules/"
],
"targets": [
"node18-linux-x64"
],
"outputPath": "dist"
},
"scripts": {
"compile": "tsup --config ./tsup.config.ts",
"bundle": "pkg . --public",
"build": "npm run compile && npm run bundle",
"build:docker": "docker-compose run --rm builder",
"build-pkg": "./scripts/build.mjs",
"codegen": "MOTHERSHIP_GRAPHQL_LINK='https://staging.mothership.unraid.net/ws' graphql-codegen --config codegen.yml -r dotenv/config './.env.staging'",
"codegen:watch": "DOTENV_CONFIG_PATH='./.env.staging' graphql-codegen-esm --config codegen.yml --watch -r dotenv/config",
"codegen:local": "MOTHERSHIP_GRAPHQL_LINK='http://localhost:3000/graphql' graphql-codegen-esm --config codegen.yml --watch",
"tsc": "tsc --noEmit",
"lint": "DEBUG=eslint:cli-engine eslint . --config .eslintrc.cjs",
"lint:fix": "DEBUG=eslint:cli-engine eslint . --fix --config .eslintrc.cjs",
"test:watch": "vitest --segfault-retry=3 --no-threads",
"test": "vitest run --segfault-retry=3 --no-threads",
"coverage": "vitest run --segfault-retry=3 --coverage",
"patch:subscriptions-transport-ws": "node ./.scripts/patches/subscriptions-transport-ws.cjs",
"release": "standard-version",
"typesync": "typesync",
"install:unraid": "./scripts/install-in-unraid.sh",
"start:plugin": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty LOG_LEVEL=trace unraid-api start --debug",
"start:plugin-verbose": "LOG_CONTEXT=true LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty LOG_LEVEL=trace unraid-api start --debug",
"start:dev": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty NODE_ENV=development LOG_LEVEL=trace NODE_ENV=development tsup --config ./tsup.config.ts --watch --onSuccess 'DOTENV_CONFIG_PATH=./.env.development node -r dotenv/config dist/unraid-api.cjs start --debug'",
"stop:dev": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty NODE_ENV=development LOG_LEVEL=trace NODE_ENV=development tsup --config ./tsup.config.ts --watch --onSuccess 'DOTENV_CONFIG_PATH=./.env.development node -r dotenv/config dist/unraid-api.cjs stop --debug'",
"start:report": "LOG_MOTHERSHIP_MESSAGES=true LOG_TYPE=pretty NODE_ENV=development LOG_LEVEL=trace NODE_ENV=development LOG_CONTEXT=true tsup --config ./tsup.config.ts --watch --onSuccess 'DOTENV_CONFIG_PATH=./.env.development node -r dotenv/config dist/unraid-api.cjs report --debug'",
"start:docker": "docker compose run --rm builder-interactive",
"docker:dev": "docker-compose run --rm --service-ports dev",
"docker:test": "docker-compose run --rm builder npm run test"
},
"files": [
".env.staging",
".env.production",
"dist",
"unraid-api"
],
"dependencies": {
"@apollo/client": "^3.7.12",
"@apollo/server": "^4.6.0",
"@graphql-codegen/client-preset": "^3.0.0",
"@graphql-tools/load-files": "^6.6.1",
"@graphql-tools/merge": "^8.4.0",
"@graphql-tools/schema": "^9.0.17",
"@graphql-tools/utils": "^9.2.1",
"@reduxjs/toolkit": "^1.9.5",
"@reflet/cron": "^1.3.1",
"@runonflux/nat-upnp": "^1.0.2",
"accesscontrol": "^2.2.1",
"am": "github:unraid/am",
"async-exit-hook": "^2.0.1",
"btoa": "^1.2.1",
"bycontract": "^2.0.11",
"bytes": "^3.1.2",
"cacheable-lookup": "^6.1.0",
"catch-exit": "^1.2.2",
"chalk": "^4.1.2",
"chokidar": "^3.5.3",
"cli-table": "^0.3.11",
"command-exists": "^1.2.9",
"convert": "^4.10.0",
"cors": "^2.8.5",
"cross-fetch": "^4.0.0",
"docker-event-emitter": "^0.3.0",
"dockerode": "^3.3.5",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"find-process": "^1.4.7",
"graphql": "^16.6.0",
"graphql-fields": "^2.0.3",
"graphql-scalars": "^1.21.3",
"graphql-subscriptions": "^2.0.0",
"graphql-tag": "^2.12.6",
"graphql-type-json": "^0.3.2",
"graphql-type-uuid": "^0.2.0",
"graphql-ws": "^5.12.1",
"htpasswd-js": "^1.0.2",
"ini": "^4.1.0",
"ip": "^1.1.8",
"jose": "^4.14.2",
"lodash": "^4.17.21",
"multi-ini": "^2.2.0",
"mustache": "^4.2.0",
"nanobus": "^4.5.0",
"node-cache": "^5.1.2",
"node-window-polyfill": "^1.0.2",
"openid-client": "^5.4.0",
"p-iteration": "^1.1.8",
"p-retry": "^4.6.2",
"pidusage": "^3.0.2",
"reflect-metadata": "^0.1.13",
"request": "^2.88.2",
"semver": "^7.4.0",
"stoppable": "^1.1.0",
"subscriptions-transport-ws": "^0.11.0",
"systeminformation": "^5.21.2",
"ts-command-line-args": "^2.5.0",
"uuid": "^9.0.0",
"ws": "^8.13.0",
"wtfnode": "^0.9.1",
"xhr2": "^0.2.1",
"zod": "^3.22.2"
},
"devDependencies": {
"@babel/runtime": "^7.21.0",
"@graphql-codegen/add": "^4.0.1",
"@graphql-codegen/cli": "^3.3.0",
"@graphql-codegen/fragment-matcher": "^4.0.1",
"@graphql-codegen/import-types-preset": "^2.2.6",
"@graphql-codegen/typed-document-node": "^4.0.0",
"@graphql-codegen/typescript": "^3.0.3",
"@graphql-codegen/typescript-operations": "^3.0.3",
"@graphql-codegen/typescript-resolvers": "3.2.1",
"@graphql-typed-document-node/core": "^3.2.0",
"@swc/core": "^1.3.81",
"@types/async-exit-hook": "^2.0.0",
"@types/btoa": "^1.2.3",
"@types/bytes": "^3.1.1",
"@types/cli-table": "^0.3.1",
"@types/command-exists": "^1.2.0",
"@types/dockerode": "^3.3.16",
"@types/express": "^4.17.17",
"@types/graphql-fields": "^1.3.5",
"@types/graphql-type-uuid": "^0.2.3",
"@types/ini": "^1.3.31",
"@types/lodash": "^4.14.192",
"@types/mustache": "^4.2.2",
"@types/node": "^18.17.12",
"@types/pidusage": "^2.0.2",
"@types/pify": "^5.0.1",
"@types/semver": "^7.3.13",
"@types/sendmail": "^1.4.4",
"@types/stoppable": "^1.1.1",
"@types/uuid": "^9.0.1",
"@types/ws": "^8.5.4",
"@types/wtfnode": "^0.7.0",
"@typescript-eslint/eslint-plugin": "^5.58.0",
"@typescript-eslint/parser": "^5.58.0",
"@unraid/eslint-config": "github:unraid/eslint-config",
"@vitest/coverage-v8": "^0.34.1",
"@vitest/ui": "^0.34.0",
"camelcase-keys": "^8.0.2",
"cz-conventional-changelog": "3.3.0",
"eslint": "^8.38.0",
"eslint-import-resolver-typescript": "^3.6.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-unicorn": "^48.0.1",
"eslint-plugin-unused-imports": "^2.0.0",
"execa": "^7.1.1",
"filter-obj": "^5.1.0",
"got": "^13.0.0",
"graphql-codegen-typescript-validation-schema": "^0.11.0",
"ip-regex": "^5.0.0",
"json-difference": "^1.9.1",
"log4js": "^6.9.1",
"map-obj": "^5.0.2",
"p-props": "^5.0.0",
"path-exists": "^5.0.0",
"path-type": "^5.0.0",
"pkg": "^5.8.1",
"pretty-bytes": "^6.1.0",
"pretty-ms": "^8.0.0",
"serialize-error": "^11.0.2",
"standard-version": "^9.5.0",
"tsup": "^7.0.0",
"typescript": "^4.9.4",
"typesync": "^0.11.0",
"vite-tsconfig-paths": "^4.2.0",
"vitest": "^0.34.0",
"zx": "^7.2.1"
},
"optionalDependencies": {
"@vmngr/libvirt": "github:unraid/libvirt"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
"bin": {
"unraid-api": "dist/cli.js"
},
"dependencies": {
"@apollo/client": "^3.11.8",
"@apollo/server": "^4.11.2",
"@as-integrations/fastify": "^2.1.1",
"@fastify/cookie": "^9.4.0",
"@graphql-codegen/client-preset": "^4.5.0",
"@graphql-tools/load-files": "^7.0.0",
"@graphql-tools/merge": "^9.0.8",
"@graphql-tools/schema": "^10.0.7",
"@graphql-tools/utils": "^10.5.5",
"@nestjs/apollo": "^12.2.1",
"@nestjs/core": "^10.4.7",
"@nestjs/graphql": "^12.2.1",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-fastify": "^10.4.7",
"@nestjs/schedule": "^4.1.1",
"@nestjs/throttler": "^6.2.1",
"@reduxjs/toolkit": "^2.3.0",
"@reflet/cron": "^1.3.1",
"@runonflux/nat-upnp": "^1.0.2",
"accesscontrol": "^2.2.1",
"btoa": "^1.2.1",
"bycontract": "^2.0.11",
"bytes": "^3.1.2",
"cacheable-lookup": "^7.0.0",
"camelcase-keys": "^9.1.3",
"casbin": "^5.32.0",
"catch-exit": "^1.2.2",
"chokidar": "^4.0.1",
"cli-table": "^0.3.11",
"command-exists": "^1.2.9",
"convert": "^5.5.1",
"cross-fetch": "^4.0.0",
"docker-event-emitter": "^0.3.0",
"dockerode": "^3.3.5",
"dotenv": "^16.4.5",
"execa": "^9.5.1",
"exit-hook": "^4.0.0",
"express": "^4.21.1",
"filenamify": "^6.0.0",
"fs-extra": "^11.2.0",
"global-agent": "^3.0.0",
"got": "^14.4.4",
"graphql": "^16.9.0",
"graphql-fields": "^2.0.3",
"graphql-scalars": "^1.23.0",
"graphql-subscriptions": "^2.0.0",
"graphql-tag": "^2.12.6",
"graphql-type-json": "^0.3.2",
"graphql-type-uuid": "^0.2.0",
"graphql-ws": "^5.16.0",
"ini": "^4.1.2",
"ip": "^2.0.1",
"ip-regex": "^5.0.0",
"jose": "^5.9.6",
"lodash-es": "^4.17.21",
"multi-ini": "^2.3.2",
"mustache": "^4.2.0",
"nest-access-control": "^3.1.0",
"nest-authz": "^2.11.0",
"nestjs-pino": "^4.1.0",
"node-cache": "^5.1.2",
"node-window-polyfill": "^1.0.2",
"openid-client": "^6.1.3",
"p-retry": "^6.2.0",
"passport-custom": "^1.1.1",
"passport-http-header-strategy": "^1.1.0",
"path-type": "^6.0.0",
"pidusage": "^3.0.2",
"pino": "^9.5.0",
"pino-http": "^10.3.0",
"pino-pretty": "^11.3.0",
"pm2": "^5.4.2",
"reflect-metadata": "^0.1.14",
"request": "^2.88.2",
"semver": "^7.6.3",
"stoppable": "^1.1.0",
"strftime": "^0.10.3",
"systeminformation": "^5.23.5",
"ts-command-line-args": "^2.5.1",
"uuid": "^11.0.2",
"ws": "^8.18.0",
"xhr2": "^0.2.1",
"zod": "^3.23.8"
},
"devDependencies": {
"@graphql-codegen/add": "^5.0.3",
"@graphql-codegen/cli": "^5.0.3",
"@graphql-codegen/fragment-matcher": "^5.0.2",
"@graphql-codegen/import-types-preset": "^3.0.0",
"@graphql-codegen/typed-document-node": "^5.0.11",
"@graphql-codegen/typescript": "^4.1.1",
"@graphql-codegen/typescript-operations": "^4.3.1",
"@graphql-codegen/typescript-resolvers": "4.4.1",
"@graphql-typed-document-node/core": "^3.2.0",
"@ianvs/prettier-plugin-sort-imports": "^4.4.0",
"@nestjs/testing": "^10.4.7",
"@originjs/vite-plugin-commonjs": "^1.0.3",
"@rollup/plugin-node-resolve": "^15.3.0",
"@swc/core": "^1.10.1",
"@types/async-exit-hook": "^2.0.2",
"@types/btoa": "^1.2.5",
"@types/bytes": "^3.1.4",
"@types/cli-table": "^0.3.4",
"@types/command-exists": "^1.2.3",
"@types/cors": "^2.8.17",
"@types/dockerode": "^3.3.31",
"@types/express": "^5.0.0",
"@types/graphql-fields": "^1.3.9",
"@types/graphql-type-uuid": "^0.2.6",
"@types/ini": "^4.1.1",
"@types/ip": "^1.1.3",
"@types/lodash": "^4.17.13",
"@types/mustache": "^4.2.5",
"@types/node": "^22.9.0",
"@types/pidusage": "^2.0.5",
"@types/pify": "^5.0.4",
"@types/semver": "^7.5.8",
"@types/sendmail": "^1.4.7",
"@types/stoppable": "^1.1.3",
"@types/strftime": "^0.9.8",
"@types/uuid": "^10.0.0",
"@types/ws": "^8.5.13",
"@types/wtfnode": "^0.7.3",
"@vitest/coverage-v8": "^2.1.8",
"@vitest/ui": "^2.1.4",
"cz-conventional-changelog": "3.3.0",
"eslint": "^9.14.0",
"graphql-codegen-typescript-validation-schema": "^0.16.0",
"jiti": "^2.4.0",
"nodemon": "^3.1.7",
"rollup-plugin-node-externals": "^7.1.3",
"standard-version": "^9.5.0",
"typescript": "^5.6.3",
"typescript-eslint": "^8.13.0",
"unplugin-swc": "^1.5.1",
"vite": "^5.4.10",
"vite-plugin-node": "^4.0.0",
"vite-plugin-static-copy": "^2.0.0",
"vite-tsconfig-paths": "^5.1.0",
"vitest": "^2.1.8",
"zx": "^8.2.0"
},
"optionalDependencies": {
"@vmngr/libvirt": "github:unraid/libvirt"
},
"overrides": {
"eslint": {
"jiti": "2"
}
}
}
}

View File

@@ -2,71 +2,85 @@
import { exit } from 'process';
import { cd, $ } from 'zx';
import getTags from './get-tags.mjs'
import { getDeploymentVersion } from './get-deployment-version.mjs';
try {
// Enable colours in output
process.env.FORCE_COLOR = '1';
// Enable colours in output
process.env.FORCE_COLOR = '1';
// Ensure we have the correct working directory
process.env.WORKDIR = process.env.WORKDIR ?? process.env.PWD;
cd(process.env.WORKDIR);
// Ensure we have the correct working directory
process.env.WORKDIR ??= process.env.PWD;
cd(process.env.WORKDIR);
// Clean up last deploy
await $`rm -rf ./deploy/release`;
await $`rm -rf ./deploy/pre-pack`;
await $`mkdir -p ./deploy/release/`;
await $`mkdir -p ./deploy/pre-pack/`;
// Create deployment directories - ignore if they already exist
await $`mkdir -p ./deploy/release`;
await $`mkdir -p ./deploy/pre-pack`;
// Ensure all deps are installed
await $`npm i`;
await $`rm -rf ./deploy/release/*`;
await $`rm -rf ./deploy/pre-pack/*`;
// Build Generated Types
await $`npm run codegen`;
// Build binary
await $`npm run build`;
// Build Generated Types
await $`npm run codegen`;
// Copy binary + extra files to deployment directory
await $`cp ./dist/api ./deploy/pre-pack/unraid-api`;
await $`cp ./.env.production ./deploy/pre-pack/.env.production`;
await $`cp ./.env.staging ./deploy/pre-pack/.env.staging`;
await $`npm run build`;
// Copy app files to plugin directory
await $`cp -r ./src/ ./deploy/pre-pack/src/`;
await $`cp -r ./dist/ ./deploy/pre-pack/dist/`;
// Get package details
const { name, version } = await import('../package.json', {
assert: { type: 'json' },
}).then(pkg => pkg.default);
// Copy environment to deployment directory
const files = [
'.env.production',
'.env.staging',
'tsconfig.json',
'codegen.ts',
'ecosystem.config.json',
'vite.config.ts',
]
const tags = getTags(process.env);
// Decide whether to use full version or just tag
const isTaggedRelease = tags.isTagged;
const gitShaShort = tags.shortSha;
const deploymentVersion = isTaggedRelease ? version : `${version}+${gitShaShort}`;
for (const file of files) {
await $`cp ./${file} ./deploy/pre-pack/${file}`;
}
// Create deployment package.json
await $`echo ${JSON.stringify({ name, version: deploymentVersion })} > ./deploy/pre-pack/package.json`;
// Get package details
const { name, version, ...rest } = await import('../package.json', {
assert: { type: 'json' },
}).then((pkg) => pkg.default);
// # Create final tgz
await $`cp ./README.md ./deploy/pre-pack/`;
cd('./deploy/pre-pack');
await $`npm pack`;
const deploymentVersion = getDeploymentVersion(process.env, version);
// Move unraid-api.tgz to release directory
await $`mv unraid-api-${deploymentVersion}.tgz ../release`;
// Create deployment package.json
await $`echo ${JSON.stringify({
...rest,
name,
version: deploymentVersion,
})} > ./deploy/pre-pack/package.json`;
// Set API_VERSION output based on this command
await $`echo "::set-output name=API_VERSION::${deploymentVersion}"`;
// # Create final tgz
await $`cp ./README.md ./deploy/pre-pack/`;
await $`cp -r ./node_modules ./deploy/pre-pack/node_modules`;
// Install production dependencies
cd('./deploy/pre-pack');
await $`npm prune --omit=dev`;
await $`npm install --omit=dev`;
await $`npm install github:unraid/libvirt`;
// Now we'll pack everything in the pre-pack directory
await $`tar -czf ../unraid-api-${deploymentVersion}.tgz .`;
// Move unraid-api.tgz to release directory
await $`mv ../unraid-api-${deploymentVersion}.tgz ../release`;
} catch (error) {
// Error with a command
if (Object.keys(error).includes('stderr')) {
console.log(`Failed building package. Exit code: ${error.exitCode}`);
console.log(`Error: ${error.stderr}`);
} else {
// Normal js error
console.log('Failed building package.');
console.log(`Error: ${error.message}`);
}
// Error with a command
if (Object.keys(error).includes('stderr')) {
console.log(`Failed building package. Exit code: ${error.exitCode}`);
console.log(`Error: ${error.stderr}`);
} else {
// Normal js error
console.log('Failed building package.');
console.log(`Error: ${error.message}`);
}
exit(error.exitCode);
exit(error.exitCode);
}

33
api/scripts/create-session.sh Executable file
View File

@@ -0,0 +1,33 @@
# This script creates a mock session on a server.
# During local dev/testing, you should run it in the api container,
# so the nest.js api can authenticate cookies against it.
#
# You should also set a cookie named 'unraid_...' whose value matches
# the name of the session you created (where name is sess_<name>).
# By default, this is my-session
sessions_dir=/var/lib/php
default_session_name=mock-user-session
if [ "$1" = "--help" ]; then
echo "This script creates a mock session on a server."
echo ""
echo "Usage: $0 [options]"
echo ""
echo "Options:"
echo " [name] Name of the session to create (default: mock-user-session)"
echo " --help Display this help message and exit"
echo ""
echo "Example: $0 a-session-name"
echo ""
echo "Current list of sessions:"
ls $sessions_dir
exit 0
fi
session_name="${1:-$default_session_name}"
mkdir -p $sessions_dir
touch "$sessions_dir/sess_$session_name"
ls $sessions_dir

4
api/scripts/dc.sh Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
# Pass all entered params after the docker compose call
COMPOSE_PROJECT_NAME="connect" GIT_SHA=$(git rev-parse --short HEAD) IS_TAGGED=$(git describe --tags --abbrev=0 --exact-match || echo '') docker compose -f docker-compose.yml "$@"

70
api/scripts/deploy-dev.sh Executable file
View File

@@ -0,0 +1,70 @@
#!/bin/bash
# Path to store the last used server name
state_file="$HOME/.deploy_state"
# Read the last used server name from the state file
if [[ -f "$state_file" ]]; then
last_server_name=$(cat "$state_file")
else
last_server_name=""
fi
# Read the server name from the command-line argument or use the last used server name as the default
server_name="${1:-$last_server_name}"
# Check if the server name is provided
if [[ -z "$server_name" ]]; then
echo "Please provide the SSH server name."
exit 1
fi
# Save the current server name to the state file
echo "$server_name" > "$state_file"
# Source directory path
source_directory="./dist"
if [ ! -d "$source_directory" ]; then
echo "The dist directory does not exist. Attempting build..."
npm run build
if [ $? -ne 0 ]; then
echo "Build failed!"
exit 1
fi
fi
# Replace the value inside the rsync command with the user's input
rsync_command="rsync -avz -e ssh $source_directory root@${server_name}:/usr/local/unraid-api"
echo "Executing the following command:"
echo "$rsync_command"
# Execute the rsync command and capture the exit code
eval "$rsync_command"
exit_code=$?
# Run unraid-api restart on remote host
dev=${DEV:-true}
if [ "$dev" = true ]; then
ssh root@"${server_name}" "INTROSPECTION=true unraid-api restart"
else
ssh root@"${server_name}" "unraid-api restart"
fi
# Play built-in sound based on the operating system
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
afplay /System/Library/Sounds/Glass.aiff
elif [[ "$OSTYPE" == "linux-gnu" ]]; then
# Linux
paplay /usr/share/sounds/freedesktop/stereo/complete.oga
elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
# Windows
powershell.exe -c "(New-Object Media.SoundPlayer 'C:\Windows\Media\Windows Default.wav').PlaySync()"
fi
# Exit with the rsync command's exit code
exit $exit_code

View File

@@ -0,0 +1,29 @@
import { execSync } from 'child_process';
const runCommand = (command) => {
try {
return execSync(command, { stdio: 'pipe' }).toString().trim();
} catch (error) {
console.log('Failed to get value from tag command: ', command, error.message);
return;
}
};
export const getDeploymentVersion = (env = process.env, packageVersion) => {
if (env.API_VERSION) {
console.log(`Using env var for version: ${env.API_VERSION}`);
return env.API_VERSION;
} else if (env.GIT_SHA && env.IS_TAGGED) {
console.log(`Using env vars for git tags: ${env.GIT_SHA} ${env.IS_TAGGED}`);
return env.IS_TAGGED ? packageVersion : `${packageVersion}+${env.GIT_SHA}`;
} else {
const gitShortSHA = runCommand('git rev-parse --short HEAD');
const isCommitTagged = runCommand('git describe --tags --abbrev=0 --exact-match') !== undefined;
console.log('gitShortSHA', gitShortSHA, 'isCommitTagged', isCommitTagged);
if (!gitShortSHA) {
console.error('Failed to get git short SHA');
process.exit(1);
}
return isCommitTagged ? packageVersion : `${packageVersion}+${gitShortSHA}`;
}
};

View File

@@ -1,33 +0,0 @@
import { execSync } from 'child_process';
const runCommand = (command) => {
try {
return execSync(command, { stdio: 'pipe' }).toString().trim();
} catch(error) {
console.log('Failed to get value from tag command: ', command, error.message);
return;
}
};
const getTags = (env = process.env) => {
if (env.GIT_SHA) {
return {
shortSha: env.GIT_SHA,
isTagged: Boolean(env.IS_TAGGED)
}
} else {
const gitShortSHA = runCommand('git rev-parse --short HEAD');
const isCommitTagged = runCommand('git describe --tags --abbrev=0 --exact-match') !== undefined;
console.log('gitShortSHA', gitShortSHA, 'isCommitTagged', isCommitTagged);
if (!gitShortSHA) {
throw new Error('Failing build due to missing SHA');
}
return {
shortSha: gitShortSHA,
isTagged: isCommitTagged
}
}
}
export default getTags;

View File

@@ -1,31 +0,0 @@
import { beforeEach, expect, test, vi } from 'vitest';
// Preloading imports for faster tests
import '@app/cli/commands/restart';
import '@app/cli/commands/start';
import '@app/cli/commands/stop';
beforeEach(() => {
vi.resetAllMocks();
});
test('calls stop and then start', async () => {
vi.mock('@app/cli/commands/start');
vi.mock('@app/cli/commands/stop');
// Call restart
const { restart } = await import('@app/cli/commands/restart');
const { start } = await import('@app/cli/commands/start');
const { stop } = await import('@app/cli/commands/stop');
await restart();
// Check stop was called
expect(vi.mocked(stop).mock.calls.length).toBe(1);
// Check start was called
expect(vi.mocked(start).mock.calls.length).toBe(1);
// Check stop was called first
expect(vi.mocked(stop).mock.invocationCallOrder[0]).toBeLessThan(
vi.mocked(start).mock.invocationCallOrder[0]
);
});

View File

@@ -0,0 +1,48 @@
import 'reflect-metadata';
import { expect, test } from 'vitest';
// Preloading imports for faster tests
import '@app/common/allowed-origins';
import '@app/store/modules/emhttp';
import '@app/store';
test('Returns allowed origins', async () => {
const { store } = await import('@app/store');
const { loadStateFiles } = await import('@app/store/modules/emhttp');
const { getAllowedOrigins } = await import('@app/common/allowed-origins');
const { loadConfigFile } = await import('@app/store/modules/config');
// Load state files into store
await store.dispatch(loadStateFiles());
await store.dispatch(loadConfigFile());
// Get allowed origins
expect(getAllowedOrigins()).toMatchInlineSnapshot(`
[
"/var/run/unraid-notifications.sock",
"/var/run/unraid-php.sock",
"/var/run/unraid-cli.sock",
"http://localhost:8080",
"https://localhost:4443",
"https://tower.local:4443",
"https://192.168.1.150:4443",
"https://tower:4443",
"https://192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net:4443",
"https://85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net:8443",
"https://10-252-0-1.hash.myunraid.net:4443",
"https://10-252-1-1.hash.myunraid.net:4443",
"https://10-253-3-1.hash.myunraid.net:4443",
"https://10-253-4-1.hash.myunraid.net:4443",
"https://10-253-5-1.hash.myunraid.net:4443",
"https://10-100-0-1.hash.myunraid.net:4443",
"https://10-100-0-2.hash.myunraid.net:4443",
"https://10-123-1-2.hash.myunraid.net:4443",
"https://221-123-121-112.hash.myunraid.net:4443",
"https://google.com",
"https://test.com",
"https://connect.myunraid.net",
"https://connect-staging.myunraid.net",
"https://dev-my.myunraid.net:4000",
]
`);
});

View File

@@ -1,120 +0,0 @@
import { expect, test, vi } from 'vitest';
import { store } from '@app/store';
import { loadStateFiles } from '@app/store/modules/emhttp';
vi.mock('@vmngr/libvirt', () => ({
ConnectListAllDomainsFlags: {
ACTIVE: 0,
INACTIVE: 1,
},
}));
vi.mock('@app/core/log', () => ({
logger: {
info: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
trace: vi.fn(),
addContext: vi.fn(),
removeContext: vi.fn(),
},
dashboardLogger: {
info: vi.fn(),
error: vi.fn((...input) => console.log(input)),
debug: vi.fn(),
trace: vi.fn(),
addContext: vi.fn(),
removeContext: vi.fn(),
},
emhttpLogger: {
info: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
trace: vi.fn(),
addContext: vi.fn(),
removeContext: vi.fn(),
},
}));
vi.mock('@app/common/two-factor', () => ({
checkTwoFactorEnabled: vi.fn(() => ({
isRemoteEnabled: false,
isLocalEnabled: false,
})),
}));
vi.mock('@app/common/dashboard/boot-timestamp', () => ({
bootTimestamp: new Date('2022-06-10T04:35:58.276Z'),
}));
test('Returns generated data', async () => {
await store.dispatch(loadStateFiles()).unwrap();
const { generateData } = await import('@app/common/dashboard/generate-data');
const result = await generateData();
expect(result).toMatchInlineSnapshot(`
{
"apps": {
"installed": 0,
"started": 0,
},
"array": {
"capacity": {
"bytes": {
"free": 19495825571000,
"total": 41994745901000,
"used": 22498920330000,
},
},
"state": "STOPPED",
},
"config": {
"valid": true,
},
"display": {
"case": {
"base64": "",
"error": "",
"icon": "case-model.png",
"url": "",
},
},
"os": {
"hostname": "Tower",
"uptime": "2022-06-10T04:35:58.276Z",
},
"services": [
{
"name": "unraid-api",
"online": true,
"uptime": {
"timestamp": "2022-06-10T04:35:58.276Z",
},
"version": "THIS_WILL_BE_REPLACED_WHEN_BUILT",
},
{
"name": "dynamic-remote-access",
"online": false,
"uptime": {
"timestamp": "2022-06-10T04:35:58.276Z",
},
"version": "DISABLED",
},
],
"vars": {
"flashGuid": "0000-0000-0000-000000000000",
"regState": "PRO",
"regTy": "PRO",
},
"versions": {
"unraid": "6.11.2",
},
"vms": {
"installed": 0,
"started": 0,
},
}
`);
}, 10_000);

View File

@@ -1,360 +0,0 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`Returns default permissions 1`] = `
{
"admin": {
"extends": "user",
"permissions": [
{
"action": "read:any",
"attributes": "*",
"resource": "apikey",
},
{
"action": "read:any",
"attributes": "*",
"resource": "array",
},
{
"action": "read:any",
"attributes": "*",
"resource": "cpu",
},
{
"action": "read:any",
"attributes": "*",
"resource": "crash-reporting-enabled",
},
{
"action": "read:any",
"attributes": "*",
"resource": "device",
},
{
"action": "read:any",
"attributes": "*",
"resource": "device/unassigned",
},
{
"action": "read:any",
"attributes": "*",
"resource": "disk",
},
{
"action": "read:any",
"attributes": "*",
"resource": "disk/settings",
},
{
"action": "read:any",
"attributes": "*",
"resource": "display",
},
{
"action": "read:any",
"attributes": "*",
"resource": "docker/container",
},
{
"action": "read:any",
"attributes": "*",
"resource": "docker/network",
},
{
"action": "read:any",
"attributes": "*",
"resource": "flash",
},
{
"action": "read:any",
"attributes": "*",
"resource": "info",
},
{
"action": "read:any",
"attributes": "*",
"resource": "license-key",
},
{
"action": "read:any",
"attributes": "*",
"resource": "machine-id",
},
{
"action": "read:any",
"attributes": "*",
"resource": "memory",
},
{
"action": "read:any",
"attributes": "*",
"resource": "notifications",
},
{
"action": "read:any",
"attributes": "*",
"resource": "online",
},
{
"action": "read:any",
"attributes": "*",
"resource": "os",
},
{
"action": "read:any",
"attributes": "*",
"resource": "owner",
},
{
"action": "read:any",
"attributes": "*",
"resource": "parity-history",
},
{
"action": "read:any",
"attributes": "*",
"resource": "permission",
},
{
"action": "read:any",
"attributes": "*",
"resource": "registration",
},
{
"action": "read:any",
"attributes": "*",
"resource": "servers",
},
{
"action": "read:any",
"attributes": "*",
"resource": "service",
},
{
"action": "read:any",
"attributes": "*",
"resource": "service/emhttpd",
},
{
"action": "read:any",
"attributes": "*",
"resource": "service/unraid-api",
},
{
"action": "read:any",
"attributes": "*",
"resource": "services",
},
{
"action": "read:any",
"attributes": "*",
"resource": "share",
},
{
"action": "read:any",
"attributes": "*",
"resource": "software-versions",
},
{
"action": "read:any",
"attributes": "*",
"resource": "unraid-version",
},
{
"action": "read:any",
"attributes": "*",
"resource": "uptime",
},
{
"action": "read:any",
"attributes": "*",
"resource": "user",
},
{
"action": "read:any",
"attributes": "*",
"resource": "vars",
},
{
"action": "read:any",
"attributes": "*",
"resource": "vms",
},
{
"action": "read:any",
"attributes": "*",
"resource": "vms/domain",
},
{
"action": "read:any",
"attributes": "*",
"resource": "vms/network",
},
],
},
"guest": {
"permissions": [
{
"action": "read:any",
"attributes": "*",
"resource": "me",
},
{
"action": "read:any",
"attributes": "*",
"resource": "welcome",
},
],
},
"my_servers": {
"extends": "guest",
"permissions": [
{
"action": "read:any",
"attributes": "*",
"resource": "dashboard",
},
{
"action": "read:own",
"attributes": "*",
"resource": "two-factor",
},
{
"action": "read:any",
"attributes": "*",
"resource": "array",
},
{
"action": "read:any",
"attributes": "*",
"resource": "docker/container",
},
{
"action": "read:any",
"attributes": "*",
"resource": "docker/network",
},
{
"action": "read:any",
"attributes": "*",
"resource": "notifications",
},
{
"action": "read:any",
"attributes": "*",
"resource": "vms/domain",
},
{
"action": "read:any",
"attributes": "*",
"resource": "unraid-version",
},
],
},
"notifier": {
"extends": "guest",
"permissions": [
{
"action": "create:own",
"attributes": "*",
"resource": "notifications",
},
],
},
"upc": {
"extends": "guest",
"permissions": [
{
"action": "read:own",
"attributes": "*",
"resource": "apikey",
},
{
"action": "read:own",
"attributes": "*",
"resource": "cloud",
},
{
"action": "read:any",
"attributes": "*",
"resource": "config",
},
{
"action": "read:any",
"attributes": "*",
"resource": "crash-reporting-enabled",
},
{
"action": "read:any",
"attributes": "*",
"resource": "disk",
},
{
"action": "read:any",
"attributes": "*",
"resource": "display",
},
{
"action": "read:any",
"attributes": "*",
"resource": "flash",
},
{
"action": "read:any",
"attributes": "*",
"resource": "os",
},
{
"action": "read:any",
"attributes": "*",
"resource": "owner",
},
{
"action": "read:any",
"attributes": "*",
"resource": "permission",
},
{
"action": "read:any",
"attributes": "*",
"resource": "registration",
},
{
"action": "read:any",
"attributes": "*",
"resource": "servers",
},
{
"action": "read:any",
"attributes": "*",
"resource": "vars",
},
{
"action": "read:own",
"attributes": "*",
"resource": "connect",
},
{
"action": "update:own",
"attributes": "*",
"resource": "connect",
},
],
},
"user": {
"extends": "guest",
"permissions": [
{
"action": "read:own",
"attributes": "*",
"resource": "apikey",
},
{
"action": "read:any",
"attributes": "*",
"resource": "permission",
},
],
},
}
`;

View File

@@ -0,0 +1,457 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`Returns default permissions 1`] = `
RolesBuilder {
"_grants": {
"admin": {
"$extend": [
"guest",
],
"apikey": {
"read:any": [
"*",
],
},
"array": {
"read:any": [
"*",
],
},
"cloud": {
"read:own": [
"*",
],
},
"config": {
"read:any": [
"*",
],
"update:own": [
"*",
],
},
"connect": {
"read:own": [
"*",
],
"update:own": [
"*",
],
},
"cpu": {
"read:any": [
"*",
],
},
"crash-reporting-enabled": {
"read:any": [
"*",
],
},
"customizations": {
"read:any": [
"*",
],
},
"device": {
"read:any": [
"*",
],
},
"device/unassigned": {
"read:any": [
"*",
],
},
"disk": {
"read:any": [
"*",
],
},
"disk/settings": {
"read:any": [
"*",
],
},
"display": {
"read:any": [
"*",
],
},
"docker/container": {
"read:any": [
"*",
],
},
"docker/network": {
"read:any": [
"*",
],
},
"flash": {
"read:any": [
"*",
],
},
"info": {
"read:any": [
"*",
],
},
"license-key": {
"read:any": [
"*",
],
},
"logs": {
"read:any": [
"*",
],
},
"machine-id": {
"read:any": [
"*",
],
},
"memory": {
"read:any": [
"*",
],
},
"notifications": {
"create:any": [
"*",
],
"read:any": [
"*",
],
},
"online": {
"read:any": [
"*",
],
},
"os": {
"read:any": [
"*",
],
},
"owner": {
"read:any": [
"*",
],
},
"parity-history": {
"read:any": [
"*",
],
},
"permission": {
"read:any": [
"*",
],
},
"registration": {
"read:any": [
"*",
],
},
"servers": {
"read:any": [
"*",
],
},
"service": {
"read:any": [
"*",
],
},
"service/emhttpd": {
"read:any": [
"*",
],
},
"service/unraid-api": {
"read:any": [
"*",
],
},
"services": {
"read:any": [
"*",
],
},
"share": {
"read:any": [
"*",
],
},
"software-versions": {
"read:any": [
"*",
],
},
"unraid-version": {
"read:any": [
"*",
],
},
"uptime": {
"read:any": [
"*",
],
},
"user": {
"read:any": [
"*",
],
},
"vars": {
"read:any": [
"*",
],
},
"vms": {
"read:any": [
"*",
],
},
"vms/domain": {
"read:any": [
"*",
],
},
"vms/network": {
"read:any": [
"*",
],
},
},
"guest": {
"me": {
"read:any": [
"*",
],
},
"welcome": {
"read:any": [
"*",
],
},
},
"my_servers": {
"$extend": [
"guest",
],
"array": {
"read:any": [
"*",
],
},
"config": {
"read:any": [
"*",
],
},
"connect": {
"read:any": [
"*",
],
},
"connect/dynamic-remote-access": {
"read:any": [
"*",
],
"update:own": [
"*",
],
},
"customizations": {
"read:any": [
"*",
],
},
"dashboard": {
"read:any": [
"*",
],
},
"display": {
"read:any": [
"*",
],
},
"docker": {
"read:any": [
"*",
],
},
"docker/container": {
"read:any": [
"*",
],
},
"info": {
"read:any": [
"*",
],
},
"logs": {
"read:any": [
"*",
],
},
"network": {
"read:any": [
"*",
],
},
"notifications": {
"read:any": [
"*",
],
},
"services": {
"read:any": [
"*",
],
},
"unraid-version": {
"read:any": [
"*",
],
},
"vars": {
"read:any": [
"*",
],
},
"vms": {
"read:any": [
"*",
],
},
"vms/domain": {
"read:any": [
"*",
],
},
},
"notifier": {
"$extend": [
"guest",
],
"notifications": {
"create:own": [
"*",
],
},
},
"upc": {
"$extend": [
"guest",
],
"apikey": {
"read:own": [
"*",
],
},
"cloud": {
"read:own": [
"*",
],
},
"config": {
"read:any": [
"*",
],
"update:own": [
"*",
],
},
"connect": {
"read:own": [
"*",
],
"update:own": [
"*",
],
},
"crash-reporting-enabled": {
"read:any": [
"*",
],
},
"customizations": {
"read:any": [
"*",
],
},
"disk": {
"read:any": [
"*",
],
},
"display": {
"read:any": [
"*",
],
},
"flash": {
"read:any": [
"*",
],
},
"info": {
"read:any": [
"*",
],
},
"logs": {
"read:any": [
"*",
],
},
"notifications": {
"read:any": [
"*",
],
"update:any": [
"*",
],
},
"os": {
"read:any": [
"*",
],
},
"owner": {
"read:any": [
"*",
],
},
"permission": {
"read:any": [
"*",
],
},
"registration": {
"read:any": [
"*",
],
},
"servers": {
"read:any": [
"*",
],
},
"vars": {
"read:any": [
"*",
],
},
},
},
"_isLocked": false,
}
`;

View File

@@ -10,12 +10,14 @@ test('Creates an array event', async () => {
);
const { store } = await import('@app/store');
const { loadStateFiles } = await import('@app/store/modules/emhttp');
const { loadConfigFile } = await import('@app/store/modules/config');
// Load state files into store
await store.dispatch(loadStateFiles());
await store.dispatch(loadConfigFile());
const arrayEvent = getArrayData(store.getState);
expect(arrayEvent).toMatchInlineSnapshot(`
expect(arrayEvent).toMatchObject(
{
"boot": {
"comment": "Unraid OS boot device",
@@ -177,6 +179,7 @@ test('Creates an array event', async () => {
"warning": null,
},
],
"id": expect.any(String),
"parities": [
{
"comment": null,
@@ -205,5 +208,5 @@ test('Creates an array event', async () => {
],
"state": "STOPPED",
}
`);
);
});

View File

@@ -0,0 +1,8 @@
import 'reflect-metadata';
import { expect, test } from 'vitest';
import { setupPermissions } from '@app/core/permissions';
test('Returns default permissions', () => {
expect(setupPermissions()).toMatchSnapshot();
});

View File

@@ -0,0 +1,169 @@
import 'reflect-metadata';
import { cloneDeep } from 'lodash-es';
import { expect, test } from 'vitest';
import { getWriteableConfig } from '@app/core/utils/files/config-file-normalizer';
import { initialState } from '@app/store/modules/config';
test('it creates a FLASH config with NO OPTIONAL values', () => {
const basicConfig = initialState;
const config = getWriteableConfig(basicConfig, 'flash');
expect(config).toMatchInlineSnapshot(`
{
"api": {
"extraOrigins": "",
"version": "",
},
"local": {},
"notifier": {
"apikey": "",
},
"remote": {
"accesstoken": "",
"apikey": "",
"avatar": "",
"dynamicRemoteAccessType": "DISABLED",
"email": "",
"idtoken": "",
"localApiKey": "",
"refreshtoken": "",
"regWizTime": "",
"username": "",
"wanaccess": "",
"wanport": "",
},
"upc": {
"apikey": "",
},
}
`);
});
test('it creates a MEMORY config with NO OPTIONAL values', () => {
const basicConfig = initialState;
const config = getWriteableConfig(basicConfig, 'memory');
expect(config).toMatchInlineSnapshot(`
{
"api": {
"extraOrigins": "",
"version": "",
},
"connectionStatus": {
"minigraph": "PRE_INIT",
},
"local": {},
"notifier": {
"apikey": "",
},
"remote": {
"accesstoken": "",
"allowedOrigins": "/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, https://connect.myunraid.net, https://connect-staging.myunraid.net, https://dev-my.myunraid.net:4000",
"apikey": "",
"avatar": "",
"dynamicRemoteAccessType": "DISABLED",
"email": "",
"idtoken": "",
"localApiKey": "",
"refreshtoken": "",
"regWizTime": "",
"username": "",
"wanaccess": "",
"wanport": "",
},
"upc": {
"apikey": "",
},
}
`);
});
test('it creates a FLASH config with OPTIONAL values', () => {
const basicConfig = cloneDeep(initialState);
// 2fa & t2fa should be ignored
basicConfig.remote['2Fa'] = 'yes';
basicConfig.local['2Fa'] = 'yes';
basicConfig.local.showT2Fa = 'yes';
basicConfig.api.extraOrigins = 'myextra.origins';
basicConfig.remote.upnpEnabled = 'yes';
basicConfig.connectionStatus.upnpStatus = 'Turned On';
const config = getWriteableConfig(basicConfig, 'flash');
expect(config).toMatchInlineSnapshot(`
{
"api": {
"extraOrigins": "myextra.origins",
"version": "",
},
"local": {},
"notifier": {
"apikey": "",
},
"remote": {
"accesstoken": "",
"apikey": "",
"avatar": "",
"dynamicRemoteAccessType": "DISABLED",
"email": "",
"idtoken": "",
"localApiKey": "",
"refreshtoken": "",
"regWizTime": "",
"upnpEnabled": "yes",
"username": "",
"wanaccess": "",
"wanport": "",
},
"upc": {
"apikey": "",
},
}
`);
});
test('it creates a MEMORY config with OPTIONAL values', () => {
const basicConfig = cloneDeep(initialState);
// 2fa & t2fa should be ignored
basicConfig.remote['2Fa'] = 'yes';
basicConfig.local['2Fa'] = 'yes';
basicConfig.local.showT2Fa = 'yes';
basicConfig.api.extraOrigins = 'myextra.origins';
basicConfig.remote.upnpEnabled = 'yes';
basicConfig.connectionStatus.upnpStatus = 'Turned On';
const config = getWriteableConfig(basicConfig, 'memory');
expect(config).toMatchInlineSnapshot(`
{
"api": {
"extraOrigins": "myextra.origins",
"version": "",
},
"connectionStatus": {
"minigraph": "PRE_INIT",
"upnpStatus": "Turned On",
},
"local": {},
"notifier": {
"apikey": "",
},
"remote": {
"accesstoken": "",
"allowedOrigins": "/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, https://connect.myunraid.net, https://connect-staging.myunraid.net, https://dev-my.myunraid.net:4000",
"apikey": "",
"avatar": "",
"dynamicRemoteAccessType": "DISABLED",
"email": "",
"idtoken": "",
"localApiKey": "",
"refreshtoken": "",
"regWizTime": "",
"upnpEnabled": "yes",
"username": "",
"wanaccess": "",
"wanport": "",
},
"upc": {
"apikey": "",
},
}
`);
});

View File

@@ -0,0 +1,69 @@
import { test, expect } from 'vitest';
import { parse } from 'ini';
import { safelySerializeObjectToIni } from '@app/core/utils/files/safe-ini-serializer';
import { Serializer } from 'multi-ini';
test('MultiIni breaks when serializing an object with a boolean inside', async () => {
const objectToSerialize = {
root: {
anonMode: false,
},
};
const serializer = new Serializer({ keep_quotes: false });
expect(serializer.serialize(objectToSerialize)).toMatchInlineSnapshot(`
"[root]
anonMode=false
"
`);
});
test('MultiIni can safely serialize an object with a boolean inside', async () => {
const objectToSerialize = {
root: {
anonMode: false,
},
};
expect(safelySerializeObjectToIni(objectToSerialize)).toMatchInlineSnapshot(`
"[root]
anonMode="false"
"
`);
const result = safelySerializeObjectToIni(objectToSerialize);
expect(parse(result)).toMatchInlineSnapshot(`
{
"root": {
"anonMode": false,
},
}
`);
});
test.skip('Can serialize top-level fields', async () => {
const objectToSerialize = {
id: 'an-id',
message: 'hello-world',
number: 1,
float: 1.1,
flag: true,
flag2: false,
item: undefined,
missing: null,
empty: {},
};
const expected = `
"id=an-id
message=hello-world
number=1
float=1.1
flag="true"
flag2="false"
[empty]
"
`
.split('\n')
.map((line) => line.trim())
.join('\n');
expect(safelySerializeObjectToIni(objectToSerialize)).toMatchInlineSnapshot(expected);
});

View File

@@ -0,0 +1,114 @@
import { test, expect } from 'vitest';
import { parseConfig } from '@app/core/utils/misc/parse-config';
import { Parser as MultiIniParser } from 'multi-ini';
import { readFile, writeFile } from 'fs/promises';
import { parse } from 'ini';
import { safelySerializeObjectToIni } from '@app/core/utils/files/safe-ini-serializer';
const iniTestData = `["root"]
idx="0"
name="root"
desc="Console and webGui login account"
passwd="yes"
["xo"]
idx="1"
name="xo"
desc=""
passwd="yes"
["test_user"]
idx="2"
name="test_user"
desc=""
passwd="no"`;
test('it loads a config from a passed in ini file successfully', () => {
const res = parseConfig<any>({
file: iniTestData,
type: 'ini',
});
expect(res).toMatchInlineSnapshot(`
{
"root": {
"desc": "Console and webGui login account",
"idx": "0",
"name": "root",
"passwd": "yes",
},
"testUser": {
"desc": "",
"idx": "2",
"name": "test_user",
"passwd": "no",
},
"xo": {
"desc": "",
"idx": "1",
"name": "xo",
"passwd": "yes",
},
}
`);
expect(res?.root.desc).toEqual('Console and webGui login account');
});
test('it loads a config from disk properly', () => {
const path = './dev/states/var.ini';
const res = parseConfig<any>({ filePath: path, type: 'ini' });
expect(res.DOMAIN_SHORT).toEqual(undefined);
expect(res.domainShort).toEqual('');
expect(res.shareCount).toEqual('0');
});
test('Confirm Multi-Ini Parser Still Broken', () => {
const parser = new MultiIniParser();
const res = parser.parse(iniTestData);
expect(res).toMatchInlineSnapshot('{}');
});
test('Combine Ini and Multi-Ini to read and then write a file with quotes', async () => {
const parsedFile = parse(iniTestData);
expect(parsedFile).toMatchInlineSnapshot(`
{
"root": {
"desc": "Console and webGui login account",
"idx": "0",
"name": "root",
"passwd": "yes",
},
"test_user": {
"desc": "",
"idx": "2",
"name": "test_user",
"passwd": "no",
},
"xo": {
"desc": "",
"idx": "1",
"name": "xo",
"passwd": "yes",
},
}
`);
const ini = safelySerializeObjectToIni(parsedFile);
await writeFile('/tmp/test.ini', ini);
const file = await readFile('/tmp/test.ini', 'utf-8');
expect(file).toMatchInlineSnapshot(`
"[root]
idx="0"
name="root"
desc="Console and webGui login account"
passwd="yes"
[xo]
idx="1"
name="xo"
desc=""
passwd="yes"
[test_user]
idx="2"
name="test_user"
desc=""
passwd="no"
"
`);
});

View File

@@ -0,0 +1,10 @@
import 'reflect-metadata';
import { checkMothershipAuthentication } from "@app/graphql/resolvers/query/cloud/check-mothership-authentication";
import { expect, test } from "vitest";
import packageJson from '@app/../package.json'
test('It fails to authenticate with mothership with no credentials', async () => {
await expect(checkMothershipAuthentication('BAD', 'BAD')).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Failed to connect to https://mothership.unraid.net/ws with a "426" HTTP error.]`);
expect(packageJson.version).not.toBeNull();
await expect(checkMothershipAuthentication(packageJson.version, 'BAD_API_KEY')).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Invalid credentials]`);
}, 15_000)

View File

@@ -0,0 +1,206 @@
import { expect, test } from 'vitest';
import { type Nginx } from '../../../../core/types/states/nginx';
import { getUrlForField, getUrlForServer, getServerIps, type NginxUrlFields } from '@app/graphql/resolvers/subscription/network';
import { store } from '@app/store';
import { loadStateFiles } from '@app/store/modules/emhttp';
import { loadConfigFile } from '@app/store/modules/config';
test.each([
[{ httpPort: 80, httpsPort: 443, url: 'my-default-url.com' }],
[{ httpPort: 123, httpsPort: 443, url: 'my-default-url.com' }],
[{ httpPort: 80, httpsPort: 12_345, url: 'my-default-url.com' }],
[{ httpPort: 212, httpsPort: 3_233, url: 'my-default-url.com' }],
[{ httpPort: 80, httpsPort: 443, url: 'https://BROKEN_URL' }],
])('getUrlForField', ({ httpPort, httpsPort, url }) => {
const responseInsecure = getUrlForField({
port: httpPort,
url,
});
const responseSecure = getUrlForField({
portSsl: httpsPort,
url,
});
if (httpPort === 80) {
expect(responseInsecure.port).toBe('');
} else {
expect(responseInsecure.port).toBe(httpPort.toString());
}
if (httpsPort === 443) {
expect(responseSecure.port).toBe('');
} else {
expect(responseSecure.port).toBe(httpsPort.toString());
}
});
test('getUrlForServer - field exists, ssl disabled', () => {
const result = getUrlForServer({ nginx: { lanIp: '192.168.1.1', sslEnabled: false, httpPort: 123, httpsPort: 445 } as const as Nginx,
field: 'lanIp',
});
expect(result).toMatchInlineSnapshot('"http://192.168.1.1:123/"');
});
test('getUrlForServer - field exists, ssl yes', () => {
const result = getUrlForServer({
nginx: { lanIp: '192.168.1.1', sslEnabled: true, sslMode: 'yes', httpPort: 123, httpsPort: 445 } as const as Nginx,
field: 'lanIp',
});
expect(result).toMatchInlineSnapshot('"https://192.168.1.1:445/"');
});
test('getUrlForServer - field exists, ssl yes, port empty', () => {
const result = getUrlForServer(
{ nginx: { lanIp: '192.168.1.1', sslEnabled: true, sslMode: 'yes', httpPort: 80, httpsPort: 443 } as const as Nginx,
field: 'lanIp',
});
expect(result).toMatchInlineSnapshot('"https://192.168.1.1/"');
});
test('getUrlForServer - field exists, ssl auto', async () => {
const getResult = async () => getUrlForServer({
nginx: { lanIp: '192.168.1.1', sslEnabled: true, sslMode: 'auto', httpPort: 123, httpsPort: 445 } as const as Nginx,
field: 'lanIp',
});
await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Cannot get IP Based URL for field: "lanIp" SSL mode auto]`);
});
test('getUrlForServer - field does not exist, ssl disabled', async () => {
const getResult = async () => getUrlForServer(
{
nginx: { lanIp: '192.168.1.1', sslEnabled: false, sslMode: 'no' } as const as Nginx,
ports: {
port: ':123', portSsl: ':445', defaultUrl: new URL('https://my-default-url.unraid.net'),
},
// @ts-expect-error Field doesn't exist
field: 'idontexist',
});
await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`);
});
test('getUrlForServer - FQDN - field exists, port non-empty', () => {
const result = getUrlForServer({
nginx: { lanFqdn: 'my-fqdn.unraid.net', httpsPort: 445 } as const as Nginx,
field: 'lanFqdn',
});
expect(result).toMatchInlineSnapshot('"https://my-fqdn.unraid.net:445/"');
});
test('getUrlForServer - FQDN - field exists, port empty', () => {
const result = getUrlForServer({ nginx: { lanFqdn: 'my-fqdn.unraid.net', httpPort: 80, httpsPort: 443 } as const as Nginx,
field: 'lanFqdn',
});
expect(result).toMatchInlineSnapshot('"https://my-fqdn.unraid.net/"');
});
test.each([
[{ nginx: { lanFqdn: 'my-fqdn.unraid.net', sslEnabled: false, sslMode: 'no', httpPort: 80, httpsPort: 443 } as const as Nginx, field: 'lanFqdn' as NginxUrlFields }],
[{ nginx: { wanFqdn: 'my-fqdn.unraid.net', sslEnabled: true, sslMode: 'yes', httpPort: 80, httpsPort: 443 } as const as Nginx, field: 'wanFqdn' as NginxUrlFields }],
[{ nginx: { wanFqdn6: 'my-fqdn.unraid.net', sslEnabled: true, sslMode: 'auto', httpPort: 80, httpsPort: 443 } as const as Nginx, field: 'wanFqdn6' as NginxUrlFields }],
])('getUrlForServer - FQDN', ({ nginx, field }) => {
const result = getUrlForServer({ nginx, field });
expect(result.toString()).toBe('https://my-fqdn.unraid.net/');
});
test('getUrlForServer - field does not exist, ssl disabled', async () => {
const getResult = async () => getUrlForServer({ nginx:
{ lanFqdn: 'my-fqdn.unraid.net' } as const as Nginx,
ports: { portSsl: '', port: '', defaultUrl: new URL('https://my-default-url.unraid.net') },
// @ts-expect-error Field doesn't exist
field: 'idontexist' });
await expect(getResult).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: IP URL Resolver: Could not resolve any access URL for field: "idontexist", is FQDN?: false]`);
});
test('integration test, loading nginx ini and generating all URLs', async () => {
await store.dispatch(loadStateFiles());
await store.dispatch(loadConfigFile());
const urls = getServerIps();
expect(urls.urls).toMatchInlineSnapshot(`
[
{
"ipv4": "https://tower.local:4443/",
"ipv6": "https://tower.local:4443/",
"name": "Default",
"type": "DEFAULT",
},
{
"ipv4": "https://192.168.1.150:4443/",
"name": "LAN IPv4",
"type": "LAN",
},
{
"ipv4": "https://tower:4443/",
"name": "LAN Name",
"type": "MDNS",
},
{
"ipv4": "https://tower.local:4443/",
"name": "LAN MDNS",
"type": "MDNS",
},
{
"ipv4": "https://192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net:4443/",
"name": "FQDN LAN",
"type": "LAN",
},
{
"ipv4": "https://85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net:8443/",
"name": "FQDN WAN",
"type": "WAN",
},
{
"ipv4": "https://10-252-0-1.hash.myunraid.net:4443/",
"name": "FQDN WG 0",
"type": "WIREGUARD",
},
{
"ipv4": "https://10-252-1-1.hash.myunraid.net:4443/",
"name": "FQDN WG 1",
"type": "WIREGUARD",
},
{
"ipv4": "https://10-253-3-1.hash.myunraid.net:4443/",
"name": "FQDN WG 2",
"type": "WIREGUARD",
},
{
"ipv4": "https://10-253-4-1.hash.myunraid.net:4443/",
"name": "FQDN WG 3",
"type": "WIREGUARD",
},
{
"ipv4": "https://10-253-5-1.hash.myunraid.net:4443/",
"name": "FQDN WG 4",
"type": "WIREGUARD",
},
{
"ipv4": "https://10-100-0-1.hash.myunraid.net:4443/",
"name": "FQDN TAILSCALE 0",
"type": "WIREGUARD",
},
{
"ipv4": "https://10-100-0-2.hash.myunraid.net:4443/",
"name": "FQDN TAILSCALE 1",
"type": "WIREGUARD",
},
{
"ipv4": "https://10-123-1-2.hash.myunraid.net:4443/",
"name": "FQDN CUSTOM 0",
"type": "WIREGUARD",
},
{
"ipv4": "https://221-123-121-112.hash.myunraid.net:4443/",
"name": "FQDN CUSTOM 1",
"type": "WIREGUARD",
},
]
`);
expect(urls.errors).toMatchInlineSnapshot(`
[
[Error: IP URL Resolver: Could not resolve any access URL for field: "lanIp6", is FQDN?: false],
]
`);
});

View File

@@ -0,0 +1,48 @@
import { beforeEach, expect, test, vi } from 'vitest';
// Preloading imports for faster tests
import '@app/mothership/utils/convert-to-fuzzy-time';
vi.mock('fs', () => ({
default: {
readFileSync: vi.fn().mockReturnValue('my-file'),
writeFileSync: vi.fn(),
existsSync: vi.fn(),
},
readFileSync: vi.fn().mockReturnValue('my-file'),
existsSync: vi.fn(),
}));
vi.mock('@graphql-tools/schema', () => ({
makeExecutableSchema: vi.fn(),
}));
vi.mock('@app/core/log', () => ({
default: { relayLogger: { trace: vi.fn() } },
relayLogger: { trace: vi.fn() },
logger: { trace: vi.fn() },
}));
beforeEach(() => {
vi.resetModules();
vi.clearAllMocks();
});
const generateTestCases = () => {
const cases: Array<{ min: number; max: number }> = [];
for (let i = 0; i < 15; i += 1) {
const min = Math.round(Math.random() * 100);
const max = min + (Math.round(Math.random() * 20));
cases.push({ min, max });
}
return cases;
};
test.each(generateTestCases())('Successfully converts to fuzzy time %o', async ({ min, max }) => {
const { convertToFuzzyTime } = await import('@app/mothership/utils/convert-to-fuzzy-time');
const res = convertToFuzzyTime(min, max);
expect(res).toBeGreaterThanOrEqual(min);
expect(res).toBeLessThanOrEqual(max);
});

View File

@@ -0,0 +1,6 @@
/* eslint-disable */
process.title = 'unraid-api';
setInterval(() => {
console.log('I NEED TO DIE');
}, 5_000);

View File

@@ -0,0 +1,10 @@
/* eslint-disable */
process.title = 'unraid-api';
setInterval(() => {
console.log('I NEED TO DIE (but i am very hard to kill)');
}, 5_000);
process.on('SIGTERM', () => {
// Do nothing
console.log('you cant kill me haha');
});

View File

@@ -0,0 +1,6 @@
import { config } from 'dotenv';
config({
path: './.env.test',
debug: false,
encoding: 'utf-8',
})

View File

@@ -6,7 +6,7 @@ exports[`loads notifications properly 1`] = `
"description": "Canceled",
"id": "/app/dev/notifications/unread/Unraid_Parity_check_1683971161.notify",
"importance": "WARNING",
"link": undefined,
"link": "/",
"subject": "Notice [UNRAID] - Parity check finished (0 errors)",
"timestamp": "2023-05-13T09:46:01.000Z",
"title": "Unraid Parity check",

View File

@@ -1,4 +1,5 @@
import { test, expect } from 'vitest';
import { expect, test } from 'vitest';
import { store } from '@app/store';
test('Before init returns default values for all fields', async () => {
@@ -13,16 +14,12 @@ test('Before init returns default values for all fields', async () => {
"minigraph": "PRE_INIT",
"upnpStatus": "",
},
"local": {
"2Fa": "",
"showT2Fa": "",
},
"local": {},
"nodeEnv": "test",
"notifier": {
"apikey": "",
},
"remote": {
"2Fa": "",
"accesstoken": "",
"allowedOrigins": "",
"apikey": "",
@@ -30,6 +27,7 @@ test('Before init returns default values for all fields', async () => {
"dynamicRemoteAccessType": "DISABLED",
"email": "",
"idtoken": "",
"localApiKey": "",
"refreshtoken": "",
"regWizTime": "",
"upnpEnabled": "",
@@ -56,23 +54,19 @@ test('After init returns values from cfg file for all fields', async () => {
expect(state).toMatchObject(
expect.objectContaining({
api: {
extraOrigins: '',
extraOrigins: expect.stringMatching('https://google.com,https://test.com'),
version: expect.any(String),
},
connectionStatus: {
minigraph: 'PRE_INIT',
upnpStatus: '',
},
local: {
'2Fa': '',
showT2Fa: '',
},
local: {},
nodeEnv: 'test',
notifier: {
apikey: 'unnotify_30994bfaccf839c65bae75f7fa12dd5ee16e69389f754c3b98ed7d5',
},
remote: {
'2Fa': '',
accesstoken: '',
allowedOrigins: '',
apikey: '_______________________BIG_API_KEY_HERE_________________________',
@@ -80,6 +74,7 @@ test('After init returns values from cfg file for all fields', async () => {
dynamicRemoteAccessType: 'DISABLED',
email: 'test@example.com',
idtoken: '',
localApiKey: '_______________________LOCAL_API_KEY_HERE_________________________',
refreshtoken: '',
regWizTime: '1611175408732_0951-1653-3509-FBA155FA23C0',
upnpEnabled: 'no',
@@ -96,9 +91,7 @@ test('After init returns values from cfg file for all fields', async () => {
});
test('updateUserConfig merges in changes to current state', async () => {
const { loadConfigFile, updateUserConfig } = await import(
'@app/store/modules/config'
);
const { loadConfigFile, updateUserConfig } = await import('@app/store/modules/config');
// Load cfg into store
await store.dispatch(loadConfigFile());
@@ -114,23 +107,19 @@ test('updateUserConfig merges in changes to current state', async () => {
expect(state).toMatchObject(
expect.objectContaining({
api: {
extraOrigins: '',
extraOrigins: expect.stringMatching('https://google.com,https://test.com'),
version: expect.any(String),
},
connectionStatus: {
minigraph: 'PRE_INIT',
upnpStatus: '',
},
local: {
'2Fa': '',
showT2Fa: '',
},
local: {},
nodeEnv: 'test',
notifier: {
apikey: 'unnotify_30994bfaccf839c65bae75f7fa12dd5ee16e69389f754c3b98ed7d5',
},
remote: {
'2Fa': '',
accesstoken: '',
allowedOrigins: '',
apikey: '_______________________BIG_API_KEY_HERE_________________________',
@@ -138,6 +127,7 @@ test('updateUserConfig merges in changes to current state', async () => {
dynamicRemoteAccessType: 'DISABLED',
email: 'test@example.com',
idtoken: '',
localApiKey: '_______________________LOCAL_API_KEY_HERE_________________________',
refreshtoken: '',
regWizTime: '1611175408732_0951-1653-3509-FBA155FA23C0',
upnpEnabled: 'no',

View File

@@ -104,10 +104,76 @@ test('After init returns values from cfg file for all fields', async () => {
"certificateName": "*.thisisfourtyrandomcharacters012345678900.myunraid.net",
"certificatePath": "/boot/config/ssl/certs/certificate_bundle.pem",
"defaultUrl": "https://Tower.local:4443",
"fqdnUrls": [
{
"fqdn": "192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net",
"id": null,
"interface": "LAN",
"isIpv6": false,
},
{
"fqdn": "85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net",
"id": null,
"interface": "WAN",
"isIpv6": false,
},
{
"fqdn": "10-252-0-1.hash.myunraid.net",
"id": 0,
"interface": "WG",
"isIpv6": false,
},
{
"fqdn": "10-252-1-1.hash.myunraid.net",
"id": 1,
"interface": "WG",
"isIpv6": false,
},
{
"fqdn": "10-253-3-1.hash.myunraid.net",
"id": 2,
"interface": "WG",
"isIpv6": false,
},
{
"fqdn": "10-253-4-1.hash.myunraid.net",
"id": 3,
"interface": "WG",
"isIpv6": false,
},
{
"fqdn": "10-253-5-1.hash.myunraid.net",
"id": 4,
"interface": "WG",
"isIpv6": false,
},
{
"fqdn": "10-100-0-1.hash.myunraid.net",
"id": 0,
"interface": "TAILSCALE",
"isIpv6": false,
},
{
"fqdn": "10-100-0-2.hash.myunraid.net",
"id": 1,
"interface": "TAILSCALE",
"isIpv6": false,
},
{
"fqdn": "10-123-1-2.hash.myunraid.net",
"id": 0,
"interface": "CUSTOM",
"isIpv6": false,
},
{
"fqdn": "221-123-121-112.hash.myunraid.net",
"id": 1,
"interface": "CUSTOM",
"isIpv6": true,
},
],
"httpPort": 8080,
"httpsPort": 4443,
"lanFqdn": "192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net",
"lanFqdn6": "",
"lanIp": "192.168.1.150",
"lanIp6": "",
"lanMdns": "Tower.local",
@@ -115,31 +181,7 @@ test('After init returns values from cfg file for all fields', async () => {
"sslEnabled": true,
"sslMode": "yes",
"wanAccessEnabled": false,
"wanFqdn": "85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net",
"wanFqdn6": "",
"wanIp": "",
"wgFqdns": [
{
"fqdn": "10-252-0-1.hash.myunraid.net",
"id": 0,
},
{
"fqdn": "10-252-1-1.hash.myunraid.net",
"id": 1,
},
{
"fqdn": "10-253-3-1.hash.myunraid.net",
"id": 3,
},
{
"fqdn": "10-253-4-1.hash.myunraid.net",
"id": 4,
},
{
"fqdn": "10-253-5-1.hash.myunraid.net",
"id": 55,
},
],
}
`);
expect(disks).toMatchInlineSnapshot(`
@@ -984,6 +1026,7 @@ test('After init returns values from cfg file for all fields', async () => {
"porttelnet": 23,
"queueDepth": "auto",
"regCheck": "Valid",
"regExp": "",
"regFile": "/app/dev/Unraid.net/Pro.key",
"regGen": "0",
"regGuid": "13FE-4200-C300-58C372A52B19",

View File

@@ -2,8 +2,8 @@ import { expect, test } from 'vitest';
import { store } from '@app/store';
test('Returns paths', async () => {
const { paths } = store.getState();
expect(Object.keys(paths)).toMatchInlineSnapshot(`
const { paths } = store.getState();
expect(Object.keys(paths)).toMatchInlineSnapshot(`
[
"core",
"unraid-api-base",
@@ -20,10 +20,13 @@ test('Returns paths', async () => {
"myservers-config",
"myservers-config-states",
"myservers-env",
"myservers-keepalive",
"keyfile-base",
"machine-id",
"log-base",
"var-run",
"auth-sessions",
"auth-keys",
]
`);
});

View File

@@ -0,0 +1,87 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`Returns parsed state file 1`] = `
{
"certificateName": "*.thisisfourtyrandomcharacters012345678900.myunraid.net",
"certificatePath": "/boot/config/ssl/certs/certificate_bundle.pem",
"defaultUrl": "https://Tower.local:4443",
"fqdnUrls": [
{
"fqdn": "192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net",
"id": null,
"interface": "LAN",
"isIpv6": false,
},
{
"fqdn": "85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net",
"id": null,
"interface": "WAN",
"isIpv6": false,
},
{
"fqdn": "10-252-0-1.hash.myunraid.net",
"id": 0,
"interface": "WG",
"isIpv6": false,
},
{
"fqdn": "10-252-1-1.hash.myunraid.net",
"id": 1,
"interface": "WG",
"isIpv6": false,
},
{
"fqdn": "10-253-3-1.hash.myunraid.net",
"id": 2,
"interface": "WG",
"isIpv6": false,
},
{
"fqdn": "10-253-4-1.hash.myunraid.net",
"id": 3,
"interface": "WG",
"isIpv6": false,
},
{
"fqdn": "10-253-5-1.hash.myunraid.net",
"id": 4,
"interface": "WG",
"isIpv6": false,
},
{
"fqdn": "10-100-0-1.hash.myunraid.net",
"id": 0,
"interface": "TAILSCALE",
"isIpv6": false,
},
{
"fqdn": "10-100-0-2.hash.myunraid.net",
"id": 1,
"interface": "TAILSCALE",
"isIpv6": false,
},
{
"fqdn": "10-123-1-2.hash.myunraid.net",
"id": 0,
"interface": "CUSTOM",
"isIpv6": false,
},
{
"fqdn": "221-123-121-112.hash.myunraid.net",
"id": 1,
"interface": "CUSTOM",
"isIpv6": true,
},
],
"httpPort": 8080,
"httpsPort": 4443,
"lanIp": "192.168.1.150",
"lanIp6": "",
"lanMdns": "Tower.local",
"lanName": "Tower",
"sslEnabled": true,
"sslMode": "yes",
"wanAccessEnabled": false,
"wanIp": "",
}
`;

View File

@@ -0,0 +1,16 @@
import { join } from 'path';
import { expect, test } from 'vitest';
import { store } from '@app/store';
import type { NginxIni } from '@app/store/state-parsers/nginx';
test('Returns parsed state file', async () => {
const { parse } = await import('@app/store/state-parsers/nginx');
const { parseConfig } = await import('@app/core/utils/misc/parse-config');
const { paths } = store.getState();
const filePath = join(paths.states, 'nginx.ini');
const stateFile = parseConfig<NginxIni>({
filePath,
type: 'ini',
});
expect(parse(stateFile)).toMatchSnapshot();
});

View File

@@ -103,6 +103,7 @@ test('Returns parsed state file', async () => {
"porttelnet": 23,
"queueDepth": "auto",
"regCheck": "Valid",
"regExp": "",
"regFile": "/app/dev/Unraid.net/Pro.key",
"regGen": "0",
"regGuid": "13FE-4200-C300-58C372A52B19",

View File

@@ -0,0 +1,71 @@
import { describe, expect, it } from 'vitest';
import { formatDatetime } from '@app/utils';
describe('formatDatetime', () => {
const testDate = new Date('2024-02-14T12:34:56');
it('formats with default system time format and omits timezone', () => {
const result = formatDatetime(testDate);
// Default format is %c with timezone omitted
expect(result).toMatch('Wed 14 Feb 2024 12:34:56 PM');
});
it('includes timezone when omitTimezone is false', () => {
const result = formatDatetime(testDate, { omitTimezone: false });
// Should include timezone at the end
expect(result).toMatch(/^Wed 14 Feb 2024 12:34:56 PM .+$/);
});
it('formats with custom date and time formats', () => {
const result = formatDatetime(testDate, {
dateFormat: '%Y-%m-%d',
timeFormat: '%H:%M',
});
expect(result).toBe('2024-02-14 12:34');
});
it('formats with custom date format and default time format', () => {
const result = formatDatetime(testDate, {
dateFormat: '%d/%m/%Y',
});
expect(result).toBe('14/02/2024 12:34 PM');
});
describe('Unraid-style date formats', () => {
const dateFormats = [
'%A, %Y %B %e', // Day, YYYY Month D
'%A, %e %B %Y', // Day, D Month YYYY
'%A, %B %e, %Y', // Day, Month D, YYYY
'%A, %m/%d/%Y', // Day, MM/DD/YYYY
'%A, %d-%m-%Y', // Day, DD-MM-YYYY
'%A, %d.%m.%Y', // Day, DD.MM.YYYY
'%A, %Y-%m-%d', // Day, YYYY-MM-DD
];
const timeFormats = [
'%I:%M %p', // 12 hours
'%R', // 24 hours
];
it.each(dateFormats)('formats date with %s', (dateFormat) => {
const result = formatDatetime(testDate, { dateFormat });
expect(result).toMatch(/^Wednesday.*2024.*12:34 PM$/);
});
it.each(timeFormats)('formats time with %s', (timeFormat) => {
// specify a non-system-time date format for this test
const result = formatDatetime(testDate, { timeFormat, dateFormat: dateFormats[1] });
const expectedTime = timeFormat === '%R' ? '12:34' : '12:34 PM';
expect(result).toContain(expectedTime);
});
it.each(dateFormats.flatMap((d) => timeFormats.map((t) => [d, t])))(
'formats with date format %s and time format %s',
(dateFormat, timeFormat) => {
const result = formatDatetime(testDate, { dateFormat, timeFormat });
expect(result).toMatch(/^Wednesday.*2024.*(?:12:34 PM|12:34)$/);
}
);
});
});

View File

@@ -1,11 +1,16 @@
import 'wtfnode';
#!/usr/bin/env node
import '@app/dotenv';
import { am } from 'am';
import { main } from '@app/cli/index';
import { internalLogger } from '@app/core/log';
void am(main, (error: unknown) => {
internalLogger.fatal((error as Error).message);
// Ensure process is exited
process.exit(1);
});
try {
await main();
} catch (error) {
console.log(error);
internalLogger.error({
message: 'Failed to start unraid-api',
error,
});
process.exit(1);
}

View File

@@ -1,33 +1,24 @@
import ipRegex from 'ip-regex';
import readLine from 'readline';
import { setEnv } from '@app/cli/set-env';
import { getUnraidApiPid } from '@app/cli/get-unraid-api-pid';
import { cliLogger } from '@app/core/log';
import { getters, store } from '@app/store';
import { stdout } from 'process';
import { loadConfigFile } from '@app/store/modules/config';
import { getApiApolloClient } from '../../graphql/client/api/get-api-client';
import {
getCloudDocument,
getServersDocument,
type getServersQuery,
type getCloudQuery,
} from '../../graphql/generated/api/operations';
import {
type ApolloQueryResult,
type ApolloClient,
type NormalizedCacheObject,
} from '@apollo/client/core/core.cjs';
import { MinigraphStatus } from '@app/graphql/generated/api/types';
import readLine from 'readline';
import { ApolloClient, ApolloQueryResult, NormalizedCacheObject } from '@apollo/client/core/index.js';
import ipRegex from 'ip-regex';
import { setEnv } from '@app/cli/set-env';
import { cliLogger } from '@app/core/log';
import { isUnraidApiRunning } from '@app/core/utils/pm2/unraid-api-running';
import { API_VERSION } from '@app/environment';
import { MinigraphStatus } from '@app/graphql/generated/api/types';
import { getters, store } from '@app/store';
import { loadConfigFile } from '@app/store/modules/config';
import { loadStateFiles } from '@app/store/modules/emhttp';
type CloudQueryResult = NonNullable<
ApolloQueryResult<getCloudQuery>['data']['cloud']
>;
type ServersQueryResultServer = NonNullable<
ApolloQueryResult<getServersQuery>['data']['servers']
>[0];
import type { getCloudQuery, getServersQuery } from '../../graphql/generated/api/operations';
import { getApiApolloClient } from '../../graphql/client/api/get-api-client';
import { getCloudDocument, getServersDocument } from '../../graphql/generated/api/operations';
type CloudQueryResult = NonNullable<ApolloQueryResult<getCloudQuery>['data']['cloud']>;
type ServersQueryResultServer = NonNullable<ApolloQueryResult<getServersQuery>['data']['servers']>[0];
type Verbosity = '' | '-v' | '-vv';
@@ -75,15 +66,10 @@ export const getCloudData = async (
const cloud = await client.query({ query: getCloudDocument });
return cloud.data.cloud ?? null;
} catch (error: unknown) {
cliLogger.addContext(
'error-stack',
error instanceof Error ? error.stack : error
);
cliLogger.trace(
'Failed fetching cloud from local graphql with "%s"',
error instanceof Error ? error.message : 'Unknown Error'
);
cliLogger.removeContext('error-stack');
return null;
}
@@ -122,12 +108,10 @@ export const getServersData = async ({
);
return foundServers;
} catch (error: unknown) {
cliLogger.addContext('error', error);
cliLogger.trace(
'Failed fetching servers from local graphql with "%s"',
error instanceof Error ? error.message : 'Unknown Error'
);
cliLogger.removeContext('error');
return {
online: [],
offline: [],
@@ -139,8 +123,7 @@ export const getServersData = async ({
const hashUrlRegex = () => /(.*)([a-z0-9]{40})(.*)/g;
export const anonymiseOrigins = (origins?: string[]): string[] => {
const originsWithoutSocks =
origins?.filter((url) => !url.endsWith('.sock')) ?? [];
const originsWithoutSocks = origins?.filter((url) => !url.endsWith('.sock')) ?? [];
return originsWithoutSocks
.map((origin) =>
origin
@@ -149,29 +132,17 @@ export const anonymiseOrigins = (origins?: string[]): string[] => {
// Replace ipv4 address using . separator with "IPV4ADDRESS"
.replace(ipRegex(), 'IPV4ADDRESS')
// Replace ipv4 address using - separator with "IPV4ADDRESS"
.replace(
new RegExp(ipRegex().toString().replace('\\.', '-')),
'/IPV4ADDRESS'
)
.replace(new RegExp(ipRegex().toString().replace('\\.', '-')), '/IPV4ADDRESS')
// Report WAN port
.replace(
`:${getters.config().remote.wanport || 443}`,
':WANPORT'
)
.replace(`:${getters.config().remote.wanport || 443}`, ':WANPORT')
)
.filter(Boolean);
};
const getAllowedOrigins = (
cloud: CloudQueryResult | null,
v: Verbosity
): string[] | null => {
const getAllowedOrigins = (cloud: CloudQueryResult | null, v: Verbosity): string[] | null => {
switch (v) {
case '-vv':
return (
cloud?.allowedOrigins.filter((url) => !url.endsWith('.sock')) ??
[]
);
return cloud?.allowedOrigins.filter((url) => !url.endsWith('.sock')) ?? [];
case '-v':
return anonymiseOrigins(cloud?.allowedOrigins ?? []);
default:
@@ -179,37 +150,23 @@ const getAllowedOrigins = (
}
};
const getReadableCloudDetails = (
reportObject: ReportObject,
v: Verbosity
): string => {
const error = reportObject.cloud.error
? `\n ERROR [${reportObject.cloud.error}]`
: '';
const status = reportObject.cloud.status
? reportObject.cloud.status
: 'disconnected';
const ip =
reportObject.cloud.ip && v !== ''
? `\n IP: [${reportObject.cloud.ip}]`
: '';
const getReadableCloudDetails = (reportObject: ReportObject, v: Verbosity): string => {
const error = reportObject.cloud.error ? `\n ERROR [${reportObject.cloud.error}]` : '';
const status = reportObject.cloud.status ? reportObject.cloud.status : 'disconnected';
const ip = reportObject.cloud.ip && v !== '' ? `\n IP: [${reportObject.cloud.ip}]` : '';
return `
STATUS: [${status}] ${ip} ${error}`;
};
const getReadableMinigraphDetails = (reportObject: ReportObject): string => {
const statusLine = `STATUS: [${reportObject.minigraph.status}]`;
const errorLine = reportObject.minigraph.error
? ` ERROR: [${reportObject.minigraph.error}]`
: null;
const errorLine = reportObject.minigraph.error ? ` ERROR: [${reportObject.minigraph.error}]` : null;
const timeoutLine = reportObject.minigraph.timeout
? ` TIMEOUT: [${(reportObject.minigraph.timeout || 1) / 1_000}s]`
: null; // 1 in case of divide by zero
return `
${statusLine}${errorLine ? `\n${errorLine}` : ''}${
timeoutLine ? `\n${timeoutLine}` : ''
}`;
${statusLine}${errorLine ? `\n${errorLine}` : ''}${timeoutLine ? `\n${timeoutLine}` : ''}`;
};
// Convert server to string output
@@ -222,10 +179,7 @@ const serverToString = (v: Verbosity) => (server: ServersQueryResultServer) =>
: ''
}`;
const getReadableServerDetails = (
reportObject: ReportObject,
v: Verbosity
): string => {
const getReadableServerDetails = (reportObject: ReportObject, v: Verbosity): string => {
if (!reportObject.servers) {
return '';
}
@@ -243,9 +197,7 @@ const getReadableServerDetails = (
return `
SERVERS:
ONLINE: ${reportObject.servers.online.map(serverToString(v)).join(',')}
OFFLINE: ${reportObject.servers.offline
.map(serverToString(v))
.join(',')}${invalid}`;
OFFLINE: ${reportObject.servers.offline.map(serverToString(v)).join(',')}${invalid}`;
};
const getReadableAllowedOrigins = (reportObject: ReportObject): string => {
@@ -270,7 +222,6 @@ const getVerbosity = (argv: string[]): Verbosity => {
return '';
};
// eslint-disable-next-line complexity
export const report = async (...argv: string[]) => {
// Check if the user has raw output enabled
const rawOutput = argv.includes('--raw');
@@ -302,7 +253,7 @@ export const report = async (...argv: string[]) => {
const v = getVerbosity(argv);
// Find all processes called "unraid-api" which aren't this process
const unraidApiPid = await getUnraidApiPid();
const unraidApiRunning = await isUnraidApiRunning();
// Load my servers config file into store
await store.dispatch(loadConfigFile());
@@ -311,7 +262,7 @@ export const report = async (...argv: string[]) => {
const { config, emhttp } = store.getState();
if (!config.upc.apikey) throw new Error('Missing UPC API key');
const client = getApiApolloClient({ upcApiKey: config.upc.apikey });
const client = getApiApolloClient({ localApiKey: config.remote.localApiKey || '' });
// Fetch the cloud endpoint
const cloud = await getCloudData(client);
@@ -328,43 +279,37 @@ export const report = async (...argv: string[]) => {
const reportObject: ReportObject = {
os: {
serverName: emhttp.var.name,
version: emhttp.var.version
version: emhttp.var.version,
},
api: {
version: API_VERSION,
status: unraidApiPid ? 'running' : 'stopped',
environment:
process.env.ENVIRONMENT ??
'THIS_WILL_BE_REPLACED_WHEN_BUILT',
status: unraidApiRunning ? 'running' : 'stopped',
environment: process.env.ENVIRONMENT ?? 'THIS_WILL_BE_REPLACED_WHEN_BUILT',
nodeVersion: process.version,
},
apiKey: isApiKeyValid ? 'valid' : cloud?.apiKey.error ?? 'invalid',
apiKey: isApiKeyValid ? 'valid' : (cloud?.apiKey.error ?? 'invalid'),
...(servers ? { servers } : {}),
myServers: {
status: config?.remote?.username
? 'authenticated'
: 'signed out',
status: config?.remote?.username ? 'authenticated' : 'signed out',
...(config?.remote?.username
? { myServersUsername: config?.remote?.username?.includes('@') ? 'REDACTED' : config?.remote.username }
? {
myServersUsername: config?.remote?.username?.includes('@')
? 'REDACTED'
: config?.remote.username,
}
: {}),
},
minigraph: {
status: cloud?.minigraphql.status ?? MinigraphStatus.PRE_INIT,
timeout: cloud?.minigraphql.timeout ?? null,
error:
cloud?.minigraphql.error ?? !cloud?.minigraphql.status
? 'API Disconnected'
: null,
(cloud?.minigraphql.error ?? !cloud?.minigraphql.status) ? 'API Disconnected' : null,
},
cloud: {
status: cloud?.cloud.status ?? 'error',
...(cloud?.cloud.error ? { error: cloud.cloud.error } : {}),
...(cloud?.cloud.status === 'ok'
? { ip: cloud.cloud.ip ?? 'NO_IP' }
: {}),
...(getAllowedOrigins(cloud, v)
? { allowedOrigins: getAllowedOrigins(cloud, v) }
: {}),
...(cloud?.cloud.status === 'ok' ? { ip: cloud.cloud.ip ?? 'NO_IP' } : {}),
...(getAllowedOrigins(cloud, v) ? { allowedOrigins: getAllowedOrigins(cloud, v) } : {}),
},
};
@@ -377,8 +322,8 @@ export const report = async (...argv: string[]) => {
if (jsonReport) {
stdout.write(JSON.stringify(reportObject) + '\n');
stdoutLogger.close();
return reportObject;
stdoutLogger.close();
return reportObject;
} else {
// Generate the actual report
const report = `
@@ -395,9 +340,7 @@ MY_SERVERS: ${reportObject.myServers.status}${
: ''
}
CLOUD: ${getReadableCloudDetails(reportObject, v)}
MINI-GRAPH: ${getReadableMinigraphDetails(
reportObject
)}${getReadableServerDetails(
MINI-GRAPH: ${getReadableMinigraphDetails(reportObject)}${getReadableServerDetails(
reportObject,
v
)}${getReadableAllowedOrigins(reportObject)}
@@ -412,9 +355,7 @@ MINI-GRAPH: ${getReadableMinigraphDetails(
console.log({ error });
if (error instanceof Error) {
cliLogger.trace(error);
stdoutLogger.write(
`\nFailed generating report with "${error.message}"\n`
);
stdoutLogger.write(`\nFailed generating report with "${error.message}"\n`);
return;
}

View File

@@ -0,0 +1,10 @@
import { start } from '@app/cli/commands/start';
import { stop } from '@app/cli/commands/stop';
/**
* Stop a running API process and then start it again.
*/
export const restart = async () => {
await stop();
await start();
};

View File

@@ -1,87 +1,16 @@
import { spawn } from 'child_process';
import { addExitCallback } from 'catch-exit';
import { PM2_PATH } from '@app/consts';
import { cliLogger } from '@app/core/log';
import { mainOptions } from '@app/cli/options';
import { logToSyslog } from '@app/cli/log-to-syslog';
import { getters } from '@app/store';
import { getAllUnraidApiPids } from '@app/cli/get-unraid-api-pid';
import { API_VERSION } from '@app/environment';
import { execSync } from 'child_process';
import { join } from 'node:path';
/**
* Start a new API process.
*/
export const start = async () => {
// Set process title
process.title = 'unraid-api';
const runningProcesses = await getAllUnraidApiPids();
if (runningProcesses.length > 0) {
cliLogger.info('unraid-api is Already Running!');
cliLogger.info('Run "unraid-api restart" to stop all running processes and restart');
process.exit(1);
}
cliLogger.info('Starting unraid-api with command', `${PM2_PATH} start ${join(import.meta.dirname, 'ecosystem.config.json')} --update-env`);
// Start API
cliLogger.info('Starting unraid-api@v%s', API_VERSION);
// If we're in debug mode or we're NOT
// in debug but ARE in the child process
if (mainOptions.debug || process.env._DAEMONIZE_PROCESS) {
// Log when the API exits
addExitCallback((signal, exitCode, error) => {
if (exitCode === 0 || exitCode === 130 || signal === 'SIGTERM') {
logToSyslog('👋 Farewell. UNRAID API shutting down!');
return;
}
// Log when the API crashes
if (signal === 'uncaughtException' && error) {
logToSyslog(`⚠️ Caught exception: ${error.message}`);
}
// Log when we crash
if (exitCode) {
logToSyslog(`⚠️ UNRAID API crashed with exit code ${exitCode}`);
return;
}
logToSyslog('🛑 UNRAID API crashed without an exit code?');
});
logToSyslog('✔️ UNRAID API started successfully!');
}
// Load bundled index file
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('../../index');
if (!mainOptions.debug) {
if ('_DAEMONIZE_PROCESS' in process.env) {
// In the child, clean up the tracking environment variable
delete process.env._DAEMONIZE_PROCESS;
} else {
cliLogger.debug('Daemonizing process. %s %o', process.execPath, process.argv);
// Spawn child
// First arg is path (inside PKG), second arg is restart, stop, etc, rest is args to main argument
const [path, , ...rest] = process.argv.slice(1);
const replacedCommand = [path, 'start', ...rest];
const child = spawn(process.execPath, replacedCommand, {
// In the parent set the tracking environment variable
env: Object.assign(process.env, { _DAEMONIZE_PROCESS: '1' }),
// The process MUST have it's cwd set to the
// path where it resides within the Nexe VFS
cwd: getters.paths()['unraid-api-base'],
stdio: 'ignore',
detached: true,
});
// Convert process into daemon
child.unref();
cliLogger.debug('Daemonized successfully!');
// Exit cleanly
process.exit(0);
}
}
execSync(`${PM2_PATH} start ${join(import.meta.dirname, '../../', 'ecosystem.config.json')} --update-env`, {
env: process.env,
stdio: 'inherit',
cwd: process.cwd()
});
};

View File

@@ -1,19 +1,7 @@
import prettyMs from 'pretty-ms';
import pidUsage from 'pidusage';
import { cliLogger } from '@app/core/log';
import { getUnraidApiPid } from '@app/cli/get-unraid-api-pid';
import { setEnv } from '@app/cli/set-env';
import { PM2_PATH } from '@app/consts';
import { execSync } from 'child_process';
export const status = async () => {
setEnv('LOG_TYPE', 'raw');
// Find all processes called "unraid-api" which aren't this process
const unraidApiPid = await getUnraidApiPid();
if (!unraidApiPid) {
cliLogger.info('Found no running processes.');
return;
}
const stats = await pidUsage(unraidApiPid);
cliLogger.info(`API has been running for ${prettyMs(stats.elapsed)} and is in "${process.env.ENVIRONMENT ?? 'ERR: Unknown Environment'}" mode!`);
execSync(`${PM2_PATH} status unraid-api`, { stdio: 'inherit' });
process.exit(0);
};

View File

@@ -1,47 +1,6 @@
import { cliLogger } from '@app/core/log';
import { getAllUnraidApiPids } from '@app/cli/get-unraid-api-pid';
import { setEnv } from '@app/cli/set-env';
import { sleep } from '@app/core/utils/misc/sleep';
import pRetry from 'p-retry';
/**
* Stop a running API process.
*/
import { PM2_PATH } from '@app/consts';
import { execSync } from 'child_process';
export const stop = async () => {
setEnv('LOG_TYPE', 'raw');
try {
await pRetry(async (attempts) => {
const runningApis = await getAllUnraidApiPids();
if (runningApis.length > 0) {
cliLogger.info('Stopping %s unraid-api process(es)...', runningApis.length);
runningApis.forEach(pid => process.kill(pid, 'SIGTERM'));
const newPids = await getAllUnraidApiPids();
if (newPids.length > 0) {
throw new Error('Not all processes have exited yet');
}
} else if (attempts < 1) {
cliLogger.info('Found no running processes.');
}
return true;
}, {
retries: 2,
minTimeout: 2_000,
factor: 1,
});
} catch (error: unknown) {
cliLogger.info('Process did not exit cleanly, forcing shutdown', error);
const processes = await getAllUnraidApiPids();
for (const pid of processes) {
process.kill(pid, 'SIGKILL');
await sleep(100);
}
}
await sleep(500);
execSync(`${PM2_PATH} stop unraid-api`, { stdio: 'inherit' });
};

View File

@@ -1,27 +1,17 @@
import { copyFile, readFile, writeFile } from 'fs/promises';
import { join } from 'path';
import { cliLogger } from '@app/core/log';
import { getUnraidApiPid } from '@app/cli/get-unraid-api-pid';
import { setEnv } from '@app/cli/set-env';
import { getters } from '@app/store';
import { start } from '@app/cli/commands/start';
import { stop } from '@app/cli/commands/stop';
export const switchEnv = async () => {
setEnv('LOG_TYPE', 'raw');
const paths = getters.paths();
const basePath = paths['unraid-api-base'];
const envFlashFilePath = paths['myservers-env'];
const envFile = await readFile(envFlashFilePath, 'utf-8').catch(() => '');
let shouldStartAfterRunning = false;
if (await getUnraidApiPid()) {
cliLogger.info('unraid-api is running, stopping...');
// Stop Running Process
await stop();
shouldStartAfterRunning = true;
}
await stop();
cliLogger.debug(
'Checking %s for current ENV, found %s',
@@ -70,11 +60,5 @@ export const switchEnv = async () => {
await copyFile(source, destination);
cliLogger.info('Now using %s', newEnv);
if (shouldStartAfterRunning) {
cliLogger.debug('Restarting unraid-api');
// Start Process
await start();
} else {
cliLogger.info('Run "unraid-api start" to start the API.');
}
await start();
};

102
api/src/cli/index.ts Normal file → Executable file
View File

@@ -1,72 +1,56 @@
import { parse } from 'ts-command-line-args';
import { cliLogger } from '@app/core/log';
import { type Flags, mainOptions, options, args } from '@app/cli/options';
import { execSync } from 'child_process';
import type { Flags } from '@app/cli/options';
import { args, mainOptions, options } from '@app/cli/options';
import { setEnv } from '@app/cli/set-env';
import { env } from '@app/dotenv';
import { getters } from '@app/store';
import { PM2_PATH } from '@app/consts';
const command = mainOptions.command as unknown as string;
export const main = async (...argv: string[]) => {
cliLogger.addContext('envs', env);
cliLogger.debug('Loading env file');
cliLogger.removeContext('envs');
if (mainOptions.debug) {
const { cliLogger } = await import('@app/core/log');
const { getters } = await import('@app/store');
const ENVIRONMENT = await import('@app/environment');
cliLogger.debug({ paths: getters.paths(), environment: ENVIRONMENT }, 'Starting CLI');
}
// Set envs
setEnv('LOG_TYPE', process.env.LOG_TYPE ?? (command === 'start' || mainOptions.debug ? 'pretty' : 'raw'));
cliLogger.addContext('paths', getters.paths());
cliLogger.debug('Starting CLI');
cliLogger.removeContext('paths');
setEnv('PORT', process.env.PORT ?? mainOptions.port ?? '9000');
setEnv('DEBUG', mainOptions.debug ?? false);
setEnv('ENVIRONMENT', process.env.ENVIRONMENT ?? 'production');
setEnv('PORT', process.env.PORT ?? mainOptions.port ?? '9000');
setEnv('LOG_LEVEL', process.env.LOG_LEVEL ?? mainOptions['log-level'] ?? 'INFO');
if (!process.env.LOG_TRANSPORT) {
if (process.env.ENVIRONMENT === 'production' && !mainOptions.debug) {
setEnv('LOG_TRANSPORT', 'file,errors');
setEnv('LOG_LEVEL', 'DEBUG');
} else if (!mainOptions.debug) {
// Staging Environment, backgrounded plugin
setEnv('LOG_TRANSPORT', 'file,errors');
setEnv('LOG_LEVEL', 'TRACE');
} else {
cliLogger.debug('In Debug Mode - Log Level Defaulting to: stdout');
}
}
if (!command) {
// Run help command
const { parse } = await import('ts-command-line-args');
parse<Flags>(args, {
...options,
partial: true,
stopAtFirstUnknown: true,
argv: ['-h'],
});
}
if (!command) {
// Run help command
parse<Flags>(args, { ...options, partial: true, stopAtFirstUnknown: true, argv: ['-h'] });
}
// Only import the command we need when we use it
const commands = {
start: import('@app/cli/commands/start').then((pkg) => pkg.start),
stop: import('@app/cli/commands/stop').then((pkg) => pkg.stop),
restart: import('@app/cli/commands/restart').then((pkg) => pkg.restart),
logs: async () => execSync(`${PM2_PATH} logs unraid-api --lines 200`, { stdio: 'inherit' }),
'switch-env': import('@app/cli/commands/switch-env').then((pkg) => pkg.switchEnv),
version: import('@app/cli/commands/version').then((pkg) => pkg.version),
status: import('@app/cli/commands/status').then((pkg) => pkg.status),
report: import('@app/cli/commands/report').then((pkg) => pkg.report),
'validate-token': import('@app/cli/commands/validate-token').then((pkg) => pkg.validateToken),
};
// Only import the command we need when we use it
const commands = {
start: import('@app/cli/commands/start').then(pkg => pkg.start),
stop: import('@app/cli/commands/stop').then(pkg => pkg.stop),
restart: import('@app/cli/commands/restart').then(pkg => pkg.restart),
'switch-env': import('@app/cli/commands/switch-env').then(pkg => pkg.switchEnv),
version: import('@app/cli/commands/version').then(pkg => pkg.version),
status: import('@app/cli/commands/status').then(pkg => pkg.status),
report: import('@app/cli/commands/report').then(pkg => pkg.report),
'validate-token': import('@app/cli/commands/validate-token').then(pkg => pkg.validateToken),
};
// Unknown command
if (!Object.keys(commands).includes(command)) {
throw new Error(`Invalid command "${command}"`);
}
// Unknown command
if (!Object.keys(commands).includes(command)) {
throw new Error(`Invalid command "${command}"`);
}
// Resolve the command import
const commandMethod = await commands[command];
// Resolve the command import
const commandMethod = await commands[command];
// Run the command
await commandMethod(...argv);
// Run the command
await commandMethod(...argv);
// Allow the process to exit
// Don't exit when we start though
if (!['start', 'restart'].includes(command)) {
// Ensure process is exited
process.exit(0);
}
process.exit(0);
};

View File

@@ -1,93 +1,112 @@
import { getters, type RootState, store } from '@app/store';
import { uniq } from 'lodash';
import { getServerIps, getUrlForField } from '@app/graphql/resolvers/subscription/network';
import uniq from 'lodash/uniq';
import {
getServerIps,
getUrlForField,
} from '@app/graphql/resolvers/subscription/network';
import { FileLoadStatus } from '@app/store/types';
import { logger } from '../core';
import { ENVIRONMENT, INTROSPECTION } from '@app/environment';
import { GRAPHQL_INTROSPECTION } from '@app/environment';
const getAllowedSocks = (): string[] => [
// Notifier bridge
'/var/run/unraid-notifications.sock',
// Notifier bridge
'/var/run/unraid-notifications.sock',
// Unraid PHP scripts
'/var/run/unraid-php.sock',
// Unraid PHP scripts
'/var/run/unraid-php.sock',
// CLI
'/var/run/unraid-cli.sock',
// CLI
'/var/run/unraid-cli.sock',
];
const getLocalAccessUrlsForServer = (state: RootState = store.getState()): string[] => {
const { emhttp } = state;
if (emhttp.status !== FileLoadStatus.LOADED) {
return [];
}
const getLocalAccessUrlsForServer = (
state: RootState = store.getState()
): string[] => {
const { emhttp } = state;
if (emhttp.status !== FileLoadStatus.LOADED) {
return [];
}
const { nginx } = emhttp;
try {
return [
getUrlForField({ url: 'localhost', port: nginx.httpPort }).toString(),
getUrlForField({ url: 'localhost', portSsl: nginx.httpsPort }).toString(),
];
} catch (error: unknown) {
logger.debug('Caught error in getLocalAccessUrlsForServer: \n%o', error);
return [];
}
const { nginx } = emhttp;
try {
return [
getUrlForField({
url: 'localhost',
port: nginx.httpPort,
}).toString(),
getUrlForField({
url: 'localhost',
portSsl: nginx.httpsPort,
}).toString(),
];
} catch (error: unknown) {
logger.debug(
'Caught error in getLocalAccessUrlsForServer: \n%o',
error
);
return [];
}
};
const getRemoteAccessUrlsForAllowedOrigins = (state: RootState = store.getState()): string[] => {
const { urls } = getServerIps(state);
const getRemoteAccessUrlsForAllowedOrigins = (
state: RootState = store.getState()
): string[] => {
const { urls } = getServerIps(state);
if (urls) {
return urls.reduce<string[]>((acc, curr) => {
if (curr.ipv4 && curr.ipv6) {
acc.push(curr.ipv4.toString());
} else if (curr.ipv4) {
acc.push(curr.ipv4.toString());
} else if (curr.ipv6) {
acc.push(curr.ipv6.toString());
}
if (urls) {
return urls.reduce<string[]>((acc, curr) => {
if (curr.ipv4 && curr.ipv6 || curr.ipv4) {
acc.push(curr.ipv4.toString());
} else if (curr.ipv6) {
acc.push(curr.ipv6.toString());
}
return acc;
}, []);
}
return acc;
}, []);
}
return [];
return [];
};
const getExtraOrigins = (): string[] => {
const { extraOrigins } = getters.config().api;
if (extraOrigins) {
return extraOrigins.split(', ').filter(origin => origin.startsWith('http://') || origin.startsWith('https://'));
}
export const getExtraOrigins = (): string[] => {
const { extraOrigins } = getters.config().api;
if (extraOrigins) {
return extraOrigins
.replaceAll(' ', '')
.split(',')
.filter(
(origin) =>
origin.startsWith('http://') ||
origin.startsWith('https://')
);
}
return [];
return [];
};
const getConnectOrigins = () : string[] => {
const connectMain = 'https://connect.myunraid.net';
const connectStaging = 'https://staging.connect.myunraid.net';
const connectDev = 'https://dev-my.myunraid.net:4000';
const getConnectOrigins = (): string[] => {
const connectMain = 'https://connect.myunraid.net';
const connectStaging = 'https://connect-staging.myunraid.net';
const connectDev = 'https://dev-my.myunraid.net:4000';
return [
connectMain,
connectStaging,
connectDev
]
}
return [connectMain, connectStaging, connectDev];
};
const getApolloSandbox = (): string[] => {
if (INTROSPECTION || ENVIRONMENT === 'development') {
return ['https://studio.apollographql.com'];
}
return [];
}
if (GRAPHQL_INTROSPECTION) {
return ['https://studio.apollographql.com'];
}
return [];
};
export const getAllowedOrigins = (state: RootState = store.getState()): string[] => uniq([
...getAllowedSocks(),
...getLocalAccessUrlsForServer(),
...getRemoteAccessUrlsForAllowedOrigins(state),
...getExtraOrigins(),
...getConnectOrigins(),
...getApolloSandbox()
]).map(url => url.endsWith('/') ? url.slice(0, -1) : url);
export const getAllowedOrigins = (
state: RootState = store.getState()
): string[] =>
uniq([
...getAllowedSocks(),
...getLocalAccessUrlsForServer(),
...getRemoteAccessUrlsForAllowedOrigins(state),
...getExtraOrigins(),
...getConnectOrigins(),
...getApolloSandbox(),
]).map((url) => (url.endsWith('/') ? url.slice(0, -1) : url));

View File

@@ -1,126 +0,0 @@
import { ConnectListAllDomainsFlags } from '@vmngr/libvirt';
import { getHypervisor } from '@app/core/utils/vms/get-hypervisor';
import display from '@app/graphql/resolvers/query/display';
import { getUnraidVersion } from '@app/common/dashboard/get-unraid-version';
import { getArray } from '@app/common/dashboard/get-array';
import { bootTimestamp } from '@app/common/dashboard/boot-timestamp';
import { dashboardLogger } from '@app/core/log';
import { getters, store } from '@app/store';
import { type DashboardServiceInput, type DashboardInput } from '@app/graphql/generated/client/graphql';
import { API_VERSION } from '@app/environment';
import { DynamicRemoteAccessType } from '@app/remoteAccess/types';
import { DashboardInputSchema } from '@app/graphql/generated/client/validators';
import { ZodError } from 'zod';
const getVmSummary = async (): Promise<DashboardInput['vms']> => {
try {
const hypervisor = await getHypervisor();
if (!hypervisor) {
return {
installed: 0,
started: 0,
};
}
const activeDomains = await hypervisor.connectListAllDomains(ConnectListAllDomainsFlags.ACTIVE) as unknown[];
const inactiveDomains = await hypervisor.connectListAllDomains(ConnectListAllDomainsFlags.INACTIVE) as unknown[];
return {
installed: activeDomains.length + inactiveDomains.length,
started: activeDomains.length,
};
} catch {
return {
installed: 0,
started: 0,
};
}
};
const getDynamicRemoteAccessService = (): DashboardServiceInput | null => {
const { config, dynamicRemoteAccess } = store.getState();
const enabledStatus = config.remote.dynamicRemoteAccessType;
return {
name: 'dynamic-remote-access',
online: enabledStatus !== DynamicRemoteAccessType.DISABLED,
version: dynamicRemoteAccess.runningType,
uptime: {
timestamp: bootTimestamp.toISOString(),
},
};
};
const services = (): DashboardInput['services'] => {
const dynamicRemoteAccess = getDynamicRemoteAccessService();
return [
{
name: 'unraid-api',
online: true,
uptime: {
timestamp: bootTimestamp.toISOString(),
},
version: API_VERSION,
},
...(dynamicRemoteAccess ? [dynamicRemoteAccess] : []),
];
};
const getData = async (): Promise<DashboardInput> => {
const emhttp = getters.emhttp();
const docker = getters.docker();
return {
vars: {
regState: emhttp.var.regState,
regTy: emhttp.var.regTy,
flashGuid: emhttp.var.flashGuid,
},
apps: {
installed: docker.installed ?? 0,
started: docker.running ?? 0
},
versions: {
unraid: await getUnraidVersion(),
},
os: {
hostname: emhttp.var.name,
uptime: bootTimestamp.toISOString()
},
vms: await getVmSummary(),
array: getArray(),
services: services(),
display: await display(),
config: emhttp.var.configValid ? { valid: true } : {
valid: false,
error: {
error: 'UNKNOWN_ERROR',
invalid: 'INVALID',
nokeyserver: 'NO_KEY_SERVER',
withdrawn: 'WITHDRAWN',
}[emhttp.var.configState] ?? 'UNKNOWN_ERROR',
},
};
};
export const generateData = async (): Promise<DashboardInput | null> => {
const data = await getData();
try {
// Validate generated data
// @TODO: Fix this runtype to use generated types from the Zod validators (as seen in mothership Codegen)
const result = DashboardInputSchema().parse(data)
return result
} catch (error: unknown) {
// Log error for user
if (error instanceof ZodError) {
dashboardLogger.error('Failed validation with issues: ' , error.issues.map(issue => ({ message: issue.message, path: issue.path.join(',') })))
} else {
dashboardLogger.error('Failed validating dashboard object: ', error, data);
}
}
return null;
};

View File

@@ -1,5 +1,6 @@
import { PORT } from '@app/environment';
import { type JSONWebKeySet } from 'jose';
import { join } from 'path';
export const getInternalApiAddress = (isHttp = true, nginxPort = 80) => {
const envPort = PORT;
@@ -34,6 +35,7 @@ export const FIVE_MINUTES_MS = 5 * ONE_MINUTE;
export const TEN_MINUTES_MS = 10 * ONE_MINUTE;
export const THIRTY_MINUTES_MS = 30 * ONE_MINUTE;
export const ONE_HOUR_MS = 60 * ONE_MINUTE;
export const ONE_DAY_MS = ONE_HOUR_MS * 24;
// Seconds
export const ONE_HOUR_SECS = 60 * 60;
@@ -45,11 +47,6 @@ export const KEEP_ALIVE_INTERVAL_MS = THREE_MINUTES_MS; // This is set to 45 sec
/**
* Graphql link.
*/
export const MOTHERSHIP_GRAPHQL_LINK =
process.env.MOTHERSHIP_GRAPHQL_LINK ??
(process.env.ENVIRONMENT === 'staging'
? 'https://staging.mothership.unraid.net/ws'
: 'https://mothership.unraid.net/ws');
export const JWKS_LOCAL_PAYLOAD: JSONWebKeySet = {
keys: [
@@ -83,3 +80,5 @@ export const KEYSERVER_VALIDATION_ENDPOINT =
/** Set the max retries for the GraphQL Client */
export const MAX_RETRIES_FOR_LINEAR_BACKOFF = 100;
export const PM2_PATH = join(import.meta.dirname, '../../', 'node_modules', '.bin', 'pm2');

View File

@@ -1,6 +0,0 @@
import NanoBus from 'nanobus';
/**
* Graphql event bus.
*/
export const bus = new NanoBus();

View File

@@ -1,122 +0,0 @@
export interface Permission { resource: string, action: string, attributes: string }
export interface Role {
permissions: Array<Permission>
extends?: string;
}
export const admin: Role = {
extends: 'user',
permissions: [
// @NOTE: Uncomment the first line to enable creation of api keys.
// See the README.md for more information.
// @WARNING: This is currently unsupported, please be careful.
// { resource: 'apikey', action: 'create:any', attributes: '*' },
{ resource: 'apikey', action: 'read:any', attributes: '*' },
{ resource: 'array', action: 'read:any', attributes: '*' },
{ resource: 'cpu', action: 'read:any', attributes: '*' },
{
resource: 'crash-reporting-enabled',
action: 'read:any',
attributes: '*',
},
{ resource: 'device', action: 'read:any', attributes: '*' },
{ resource: 'device/unassigned', action: 'read:any', attributes: '*' },
{ resource: 'disk', action: 'read:any', attributes: '*' },
{ resource: 'disk/settings', action: 'read:any', attributes: '*' },
{ resource: 'display', action: 'read:any', attributes: '*' },
{ resource: 'docker/container', action: 'read:any', attributes: '*' },
{ resource: 'docker/network', action: 'read:any', attributes: '*' },
{ resource: 'flash', action: 'read:any', attributes: '*' },
{ resource: 'info', action: 'read:any', attributes: '*' },
{ resource: 'license-key', action: 'read:any', attributes: '*' },
{ resource: 'machine-id', action: 'read:any', attributes: '*' },
{ resource: 'memory', action: 'read:any', attributes: '*' },
{ resource: 'notifications', action: 'read:any', attributes: '*' },
{ resource: 'online', action: 'read:any', attributes: '*' },
{ resource: 'os', action: 'read:any', attributes: '*' },
{ resource: 'owner', action: 'read:any', attributes: '*' },
{ resource: 'parity-history', action: 'read:any', attributes: '*' },
{ resource: 'permission', action: 'read:any', attributes: '*' },
{ resource: 'registration', action: 'read:any', attributes: '*' },
{ resource: 'servers', action: 'read:any', attributes: '*' },
{ resource: 'service', action: 'read:any', attributes: '*' },
{ resource: 'service/emhttpd', action: 'read:any', attributes: '*' },
{ resource: 'service/unraid-api', action: 'read:any', attributes: '*' },
{ resource: 'services', action: 'read:any', attributes: '*' },
{ resource: 'share', action: 'read:any', attributes: '*' },
{ resource: 'software-versions', action: 'read:any', attributes: '*' },
{ resource: 'unraid-version', action: 'read:any', attributes: '*' },
{ resource: 'uptime', action: 'read:any', attributes: '*' },
{ resource: 'user', action: 'read:any', attributes: '*' },
{ resource: 'vars', action: 'read:any', attributes: '*' },
{ resource: 'vms', action: 'read:any', attributes: '*' },
{ resource: 'vms/domain', action: 'read:any', attributes: '*' },
{ resource: 'vms/network', action: 'read:any', attributes: '*' },
],
};
export const user: Role = {
extends: 'guest',
permissions: [
{ resource: 'apikey', action: 'read:own', attributes: '*' },
{ resource: 'permission', action: 'read:any', attributes: '*' },
],
};
export const upc: Role = {
extends: 'guest',
permissions: [
{ resource: 'apikey', action: 'read:own', attributes: '*' },
{ resource: 'cloud', action: 'read:own', attributes: '*' },
{ resource: 'config', action: 'read:any', attributes: '*' },
{ resource: 'crash-reporting-enabled', action: 'read:any', attributes: '*' },
{ resource: 'disk', action: 'read:any', attributes: '*' },
{ resource: 'display', action: 'read:any', attributes: '*' },
{ resource: 'flash', action: 'read:any', attributes: '*' },
{ resource: 'os', action: 'read:any', attributes: '*' },
{ resource: 'owner', action: 'read:any', attributes: '*' },
{ resource: 'permission', action: 'read:any', attributes: '*' },
{ resource: 'registration', action: 'read:any', attributes: '*' },
{ resource: 'servers', action: 'read:any', attributes: '*' },
{ resource: 'vars', action: 'read:any', attributes: '*' },
{ resource: 'connect', action: 'read:own', attributes: '*' },
{ resource: 'connect', action: 'update:own', attributes: '*' }
],
};
export const my_servers: Role = {
extends: 'guest',
permissions: [
{ resource: 'dashboard', action: 'read:any', attributes: '*' },
{ resource: 'two-factor', action: 'read:own', attributes: '*' },
{ resource: 'array', action: 'read:any', attributes: '*' },
{ resource: 'docker/container', action: 'read:any', attributes: '*' },
{ resource: 'docker/network', action: 'read:any', attributes: '*' },
{ resource: 'notifications', action: 'read:any', attributes: '*' },
{ resource: 'vms/domain', action: 'read:any', attributes: '*' },
{ resource: 'unraid-version', action: 'read:any', attributes: '*' },
],
};
export const notifier: Role = {
extends: 'guest',
permissions: [
{ resource: 'notifications', action: 'create:own', attributes: '*' },
],
};
export const guest: Role = {
permissions: [
{ resource: 'me', action: 'read:any', attributes: '*' },
{ resource: 'welcome', action: 'read:any', attributes: '*' },
],
};
export const permissions: Record<string, Role> = {
guest,
user,
admin,
upc,
my_servers,
notifier,
};

View File

@@ -4,7 +4,7 @@ import { AppError } from '@app/core/errors/app-error';
* API key error.
*/
export class ApiKeyError extends AppError {
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor(message: string) {
super(message);
}

View File

@@ -1,7 +1,6 @@
export * as modules from '@app/core/modules';
export * as notifiers from '@app/core/notifiers';
export * as utils from '@app/core/utils';
export * from '@app/core/bus';
export * from '@app/core/log';
export * from '@app/core/permission-manager';
export * from '@app/core/permissions';

View File

@@ -1,137 +1,83 @@
import chalk from 'chalk';
import { configure, getLogger } from 'log4js';
import { serializeError } from 'serialize-error';
import { pino } from 'pino';
import { LOG_TYPE } from '@app/environment';
export const levels = ['ALL', 'TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', 'MARK', 'OFF'] as const;
import pretty from 'pino-pretty';
const contextEnabled = Boolean(process.env.LOG_CONTEXT);
const stackEnabled = Boolean(process.env.LOG_STACKTRACE);
const tracingEnabled = Boolean(process.env.LOG_TRACING);
const fullLoggingPattern = chalk`{gray [%d]} %x\{id\} %[[%p]%] %[[%c]%] %m{gray %x\{context\}}${tracingEnabled ? ' %[%f:%l%]' : ''}`;
const minimumLoggingPattern = '%m';
const appenders = process.env.LOG_TRANSPORT?.split(',').map(transport => transport.trim()) ?? ['out'];
const level = levels[levels.indexOf(process.env.LOG_LEVEL?.toUpperCase() as typeof levels[number])] ?? 'INFO';
const logLayout = {
type: 'pattern',
// Depending on what this env is set to we'll either get raw or pretty logs
// The reason we do this is to allow the app to change this value
// This way pretty logs can be turned off programmatically
pattern: process.env.LOG_TYPE === 'pretty' ? fullLoggingPattern : minimumLoggingPattern,
tokens: {
id() {
return chalk`{gray [${process.pid}]}`;
},
context({ context }: { context?: any }) {
if (!contextEnabled || !context) {
return '';
}
export const levels = [
'trace',
'debug',
'info',
'warn',
'error',
'fatal',
] as const;
try {
const contextEntries = Object.entries(context)
.map(([key, value]) => [key, value instanceof Error ? (stackEnabled ? serializeError(value) : value) : value])
.filter(([key]) => key !== 'pid');
const cleanContext = Object.fromEntries(contextEntries);
return `\n${Object.entries(cleanContext).map(([key, value]) => `${key}=${JSON.stringify(value, null, 2)}`).join(' ')}`;
} catch (error: unknown) {
const errorInfo = error instanceof Error ? `${error.message}: ${error.stack ?? 'no stack'}` : 'Error not instance of error';
return `Error generating context: ${errorInfo}`;
}
},
},
};
const level =
levels[
levels.indexOf(
process.env.LOG_LEVEL?.toLowerCase() as (typeof levels)[number]
)
] ?? 'info';
if (process.env.NODE_ENV !== 'test') {
// We log to both the stdout and log file
// The log file should be changed to errors only unless in debug mode
configure({
appenders: {
file: {
type: 'file',
filename: '/var/log/unraid-api/stdout.log',
maxLogSize: 10_000_000,
backups: 0,
layout: {
...logLayout,
// File logs should always be pretty
pattern: fullLoggingPattern,
},
},
errorFile: {
type: 'file',
filename: '/var/log/unraid-api/stderr.log',
maxLogSize: 2_500_000,
backups: 0,
layout: {
...logLayout,
// File logs should always be pretty
pattern: fullLoggingPattern,
},
},
out: {
type: 'stdout',
layout: logLayout,
},
errors: { type: 'logLevelFilter', appender: 'errorFile', level: 'error' },
},
categories: {
default: {
appenders,
level,
enableCallStack: tracingEnabled,
},
},
});
}
export const logDestination = pino.destination({
minLength: 1_024,
sync: true,
});
export const internalLogger = getLogger('internal');
export const logger = getLogger('app');
export const mothershipLogger = getLogger('mothership');
export const dashboardLogger = getLogger('dashboard');
export const emhttpLogger = getLogger('emhttp');
export const libvirtLogger = getLogger('libvirt');
export const graphqlLogger = getLogger('graphql');
export const dockerLogger = getLogger('docker');
export const cliLogger = getLogger('cli');
export const minigraphLogger = getLogger('minigraph');
export const cloudConnectorLogger = getLogger('cloud-connector');
export const upnpLogger = getLogger('upnp');
export const keyServerLogger = getLogger('key-server');
export const remoteAccessLogger = getLogger('remote-access');
export const remoteQueryLogger = getLogger('remote-query');
const stream =
LOG_TYPE === 'pretty'
? pretty({
singleLine: true,
hideObject: false,
colorize: true,
ignore: 'time,hostname,pid',
destination: logDestination,
})
: logDestination;
export const logger = pino(
{
level,
timestamp: () => `,"time":"${new Date().toISOString()}"`,
formatters: {
level: (label: string) => ({ level: label }),
},
},
stream
);
export const internalLogger = logger.child({ logger: 'internal' });
export const appLogger = logger.child({ logger: 'app' });
export const mothershipLogger = logger.child({ logger: 'mothership' });
export const dashboardLogger = logger.child({ logger: 'dashboard' });
export const emhttpLogger = logger.child({ logger: 'emhttp' });
export const libvirtLogger = logger.child({ logger: 'libvirt' });
export const graphqlLogger = logger.child({ logger: 'graphql' });
export const dockerLogger = logger.child({ logger: 'docker' });
export const cliLogger = logger.child({ logger: 'cli' });
export const minigraphLogger = logger.child({ logger: 'minigraph' });
export const cloudConnectorLogger = logger.child({ logger: 'cloud-connector' });
export const upnpLogger = logger.child({ logger: 'upnp' });
export const keyServerLogger = logger.child({ logger: 'key-server' });
export const remoteAccessLogger = logger.child({ logger: 'remote-access' });
export const remoteQueryLogger = logger.child({ logger: 'remote-query' });
export const apiLogger = logger.child({ logger: 'api' });
export const loggers = [
logger,
mothershipLogger,
dashboardLogger,
emhttpLogger,
libvirtLogger,
graphqlLogger,
dockerLogger,
cliLogger,
minigraphLogger,
cloudConnectorLogger,
upnpLogger,
keyServerLogger,
remoteAccessLogger,
remoteQueryLogger,
internalLogger,
appLogger,
mothershipLogger,
dashboardLogger,
emhttpLogger,
libvirtLogger,
graphqlLogger,
dockerLogger,
cliLogger,
minigraphLogger,
cloudConnectorLogger,
upnpLogger,
keyServerLogger,
remoteAccessLogger,
remoteQueryLogger,
apiLogger,
];
// Send SIGUSR1 to increase log level
process.on('SIGUSR1', () => {
const level = typeof logger.level === 'string' ? logger.level : logger.level.levelStr;
const nextLevel = levels[levels.findIndex(_level => _level === level) + 1] ?? levels[0];
loggers.forEach(logger => {
logger.level = nextLevel;
});
internalLogger.mark('Log level changed from %s to %s', level, nextLevel);
});
// Send SIGUSR1 to decrease log level
process.on('SIGUSR2', () => {
const level = typeof logger.level === 'string' ? logger.level : logger.level.levelStr;
const nextLevel = levels[levels.findIndex(_level => _level === level) - 1] ?? levels[levels.length - 1];
loggers.forEach(logger => {
logger.level = nextLevel;
});
internalLogger.mark('Log level changed from %s to %s', level, nextLevel);
});

View File

@@ -0,0 +1,22 @@
import { writeFile } from 'fs/promises';
import { fileExists } from '@app/core/utils/files/file-exists';
export const setupLogRotation = async () => {
if (await fileExists('/etc/logrotate.d/unraid-api')) {
return;
} else {
await writeFile(
'/etc/logrotate.d/unraid-api',
`
/var/log/unraid-api/*.log {
rotate 1
missingok
size 5M
su root root
}
`,
{ mode: '644' }
);
}
};

View File

@@ -1,126 +0,0 @@
// import fs from 'fs';
// import { log } from '../log';
import type { CoreContext, CoreResult } from '@app/core/types';
import { ensurePermission } from '@app/core/utils/permissions/ensure-permission';
import { NotImplementedError } from '@app/core/errors/not-implemented-error';
import { AppError } from '@app/core/errors/app-error';
import { getters } from '@app/store';
interface Context extends CoreContext {
data: {
keyUri?: string;
trial?: boolean;
replacement?: boolean;
email?: string;
keyFile?: string;
};
}
interface Result extends CoreResult {
json: {
key?: string;
type?: string;
};
}
/**
* Register a license key.
*/
export const addLicenseKey = async (context: Context): Promise<Result | void> => {
ensurePermission(context.user, {
resource: 'license-key',
action: 'create',
possession: 'any',
});
// Const { data } = context;
const emhttp = getters.emhttp();
const guid = emhttp.var.regGuid;
// Const timestamp = new Date();
if (!guid) {
throw new AppError('guid missing');
}
throw new NotImplementedError();
// // Connect to unraid.net to request a trial key
// if (data?.trial) {
// const body = new FormData();
// body.append('guid', guid);
// body.append('timestamp', timestamp.getTime().toString());
// const key = await got('https://keys.lime-technology.com/account/trial', { method: 'POST', body })
// .then(response => JSON.parse(response.body))
// .catch(error => {
// log.error(error);
// throw new AppError(`Sorry, a HTTP ${error.status} error occurred while registering USB Flash GUID ${guid}`);
// });
// // Update the trial key file
// await fs.promises.writeFile('/boot/config/Trial.key', Buffer.from(key, 'base64'));
// return {
// text: 'Thank you for registering, your trial key has been accepted.',
// json: {
// key
// }
// };
// }
// // Connect to unraid.net to request a new replacement key
// if (data?.replacement) {
// const { email, keyFile } = data;
// if (!email || !keyFile) {
// throw new AppError('email or keyFile is missing');
// }
// const body = new FormData();
// body.append('guid', guid);
// body.append('timestamp', timestamp.getTime().toString());
// body.append('email', email);
// body.append('keyfile', keyFile);
// const { body: key } = await got('https://keys.lime-technology.com/account/license/transfer', { method: 'POST', body })
// .then(response => JSON.parse(response.body))
// .catch(error => {
// log.error(error);
// throw new AppError(`Sorry, a HTTP ${error.status} error occurred while issuing a replacement for USB Flash GUID ${guid}`);
// });
// // Update the trial key file
// await fs.promises.writeFile('/boot/config/Trial.key', Buffer.from(key, 'base64'));
// return {
// text: 'Thank you for registering, your trial key has been registered.',
// json: {
// key
// }
// };
// }
// // Register a new server
// if (data?.keyUri) {
// const parts = data.keyUri.split('.key')[0].split('/');
// const { [parts.length - 1]: keyType } = parts;
// // Download key blob
// const { body: key } = await got(data.keyUri)
// .then(response => JSON.parse(response.body))
// .catch(error => {
// log.error(error);
// throw new AppError(`Sorry, a HTTP ${error.status} error occurred while registering your key for USB Flash GUID ${guid}`);
// });
// // Save key file
// await fs.promises.writeFile(`/boot/config/${keyType}.key`, Buffer.from(key, 'base64'));
// return {
// text: `Thank you for registering, your ${keyType} key has been accepted.`,
// json: {
// type: keyType
// }
// };
// }
};

View File

@@ -1,11 +1,11 @@
import type { CoreContext, CoreResult } from '@app/core/types';
import { bus } from '@app/core/bus';
import { AppError } from '@app/core/errors/app-error';
import { ensurePermission } from '@app/core/utils/permissions/ensure-permission';
import { hasFields } from '@app/core/utils/validation/has-fields';
import { FieldMissingError } from '@app/core/errors/field-missing-error';
import { emcmd } from '@app/core/utils/clients/emcmd';
import { getters } from '@app/store';
import { pubsub } from '@app/core/pubsub';
interface Context extends CoreContext {
readonly data: {
@@ -23,7 +23,6 @@ interface Context extends CoreContext {
*/
export const addUser = async (context: Context): Promise<CoreResult> => {
const { data } = context;
// Check permissions
ensurePermission(context.user, {
resource: 'user',
@@ -62,7 +61,7 @@ export const addUser = async (context: Context): Promise<CoreResult> => {
}
// Update users channel with new user
bus.emit('users', {
pubsub.publish('users', {
users: {
mutation: 'CREATED',
node: [user],
@@ -70,7 +69,7 @@ export const addUser = async (context: Context): Promise<CoreResult> => {
});
// Update user channel with new user
bus.emit('user', {
pubsub.publish('user', {
user: {
mutation: 'CREATED',
node: user,

View File

@@ -1,3 +1,4 @@
import { getServerIdentifier } from '@app/core/utils/server-identifier';
import {
ArrayDiskType,
type ArrayCapacity,
@@ -56,6 +57,7 @@ export const getArrayData = (getState = store.getState): ArrayType => {
};
return {
id: getServerIdentifier('array'),
state: emhttp.var.mdState,
capacity,
boot,

View File

@@ -1,7 +1,8 @@
import camelCaseKeys from 'camelcase-keys';
import { docker, ensurePermission } from '@app/core/utils';
import { docker } from '@app/core/utils';
import { type CoreContext, type CoreResult } from '@app/core/types';
import { catchHandlers } from '@app/core/utils/misc/catch-handlers';
import { ensurePermission } from '@app/core/utils/permissions/ensure-permission';
export const getDockerNetworks = async (context: CoreContext): Promise<CoreResult> => {
const { user } = context;

View File

@@ -1,30 +0,0 @@
import type { CoreResult, CoreContext } from '@app/core/types';
import { ensurePermission } from '@app/core/utils/permissions/ensure-permission';
import { getShares } from '@app/core/utils/shares/get-shares';
/**
* Get all shares.
*/
export const getAllShares = async (context: CoreContext): Promise<CoreResult> => {
const { user } = context;
// Check permissions
ensurePermission(user, {
resource: 'share',
action: 'read',
possession: 'any',
});
const userShares = getShares('users');
const diskShares = getShares('disks');
const shares = [
...userShares,
...diskShares,
];
return {
text: `Shares: ${JSON.stringify(shares, null, 2)}`,
json: shares,
};
};

View File

@@ -1,25 +0,0 @@
import { ensurePermission } from '@app/core/utils/permissions/ensure-permission';
import { store } from '@app/store';
import { type QueryResolvers } from '@app/graphql/generated/api/types';
import { getArrayData } from '@app/core/modules/array/get-array-data';
/**
* Get array info.
* @returns Array state and array/disk capacity.
*/
export const getArray: QueryResolvers['array'] = (
_,
__,
context
) => {
const { user } = context;
// Check permissions
ensurePermission(user, {
resource: 'array',
action: 'read',
possession: 'any',
});
return getArrayData(store.getState);
};

View File

@@ -4,15 +4,12 @@ import {
blockDevices,
diskLayout,
} from 'systeminformation';
import { map as asyncMap } from 'p-iteration';
import { ensurePermission } from '@app/core/utils/permissions/ensure-permission';
import { type Context } from '@app/graphql/schema/utils';
import {
type Disk,
DiskInterfaceType,
DiskSmartStatus,
DiskFsType,
} from '@app/graphql/generated/api/types';
import { DiskFsType } from '@app/graphql/generated/api/types';
import { graphqlLogger } from '@app/core/log';
const getTemperature = async (
@@ -86,25 +83,16 @@ const parseDisk = async (
* Get all disks.
*/
export const getDisks = async (
context: Context,
options?: { temperature: boolean }
): Promise<Disk[]> => {
const { user } = context;
// Check permissions
ensurePermission(user, {
resource: 'disk',
action: 'read',
possession: 'any',
});
// Return all fields but temperature
if (options?.temperature === false) {
const partitions = await blockDevices().then((devices) =>
devices.filter((device) => device.type === 'part')
);
const disks = await asyncMap(await diskLayout(), async (disk) =>
parseDisk(disk, partitions)
const diskLayoutData = await diskLayout();
const disks = await Promise.all(
diskLayoutData.map((disk) => parseDisk(disk, partitions))
);
return disks;

View File

@@ -30,7 +30,7 @@ export const getPermissions = async function (context: CoreContext): Promise<Cor
const grants = Object.entries(ac.getGrants())
.map(([name, grant]) => {
// @ts-expect-error - $extend and grants are any
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { $extend: _, ...grants } = grant;
return [name, grants];
})

View File

@@ -4,27 +4,22 @@ import type { CoreResult, CoreContext } from '@app/core/types';
import { getUnraidApiService } from '@app/core/modules/services/get-unraid-api';
import { NODE_ENV } from '@app/environment';
const devNames = [
'emhttpd',
'rest-api',
];
const devNames = ['emhttpd', 'rest-api'];
const coreNames = [
'unraid-api',
];
const coreNames = ['unraid-api'];
interface Service {
online: boolean;
uptime: string;
version: string;
online: boolean;
uptime: string;
version: string;
}
interface ServiceResult extends CoreResult {
json: Service;
json: Service;
}
interface ServiceWithName extends Service {
name: string;
name: string;
}
/**
@@ -33,39 +28,40 @@ interface ServiceWithName extends Service {
* @param services
* @param names
*/
const addNameToService = (services: ServiceResult[], names: string[]): ServiceWithName[] => services.map((service, index) => ({
name: names[index],
...service.json,
}));
const addNameToService = (services: ServiceResult[], names: string[]): ServiceWithName[] =>
services.map((service, index) => ({
name: names[index],
...service.json,
}));
interface Result extends CoreResult {
json: ServiceWithName[];
json: ServiceWithName[];
}
/**
* Get all services.
*/
export const getServices = async (context: CoreContext): Promise<Result> => {
const logErrorAndReturnEmptyArray = (error: Error) => {
logger.error(error);
return [];
};
const logErrorAndReturnEmptyArray = (error: Error) => {
logger.error(error);
return [];
};
const devServices: ServiceResult[] = NODE_ENV === 'development' ? await Promise.all([
getEmhttpdService(context),
]).catch(logErrorAndReturnEmptyArray) as ServiceResult[] : [];
const devServices: ServiceResult[] = (await Promise.all([getEmhttpdService(context)]).catch(
logErrorAndReturnEmptyArray
)) as ServiceResult[];
const coreServices: ServiceResult[] = await Promise.all([
getUnraidApiService(context),
]).catch(logErrorAndReturnEmptyArray) as ServiceResult[];
const coreServices: ServiceResult[] = (await Promise.all([getUnraidApiService(context)]).catch(
logErrorAndReturnEmptyArray
)) as ServiceResult[];
const result = [
...addNameToService(devServices, devNames),
...addNameToService(coreServices, coreNames),
];
const result = [
...addNameToService(devServices, devNames),
...addNameToService(coreServices, coreNames),
];
return {
text: `Services: ${JSON.stringify(result, null, 2)}`,
json: result,
};
return {
text: `Services: ${JSON.stringify(result, null, 2)}`,
json: result,
};
};

View File

@@ -1,28 +0,0 @@
import { AppError } from '@app/core/errors/app-error';
import type { CoreResult, CoreContext } from '@app/core/types';
import { ensurePermission } from '@app/core/utils/permissions/ensure-permission';
/**
* Get all unassigned devices.
*/
export const getUnassignedDevices = async (context: CoreContext): Promise<CoreResult> => {
const { user } = context;
// Bail if the user doesn't have permission
ensurePermission(user, {
resource: 'devices/unassigned',
action: 'read',
possession: 'any',
});
const devices = [];
if (devices.length === 0) {
throw new AppError('No devices found.', 404);
}
return {
text: `Unassigned devices: ${JSON.stringify(devices, null, 2)}`,
json: devices,
};
};

View File

@@ -1,26 +0,0 @@
import type { CoreContext, CoreResult } from '@app/core/types';
import { ensurePermission } from '@app/core/utils/permissions/ensure-permission';
import { getters } from '@app/store';
/**
* Get all system vars.
*/
export const getVars = async (context: CoreContext): Promise<CoreResult> => {
const { user } = context;
// Bail if the user doesn't have permission
ensurePermission(user, {
resource: 'vars',
action: 'read',
possession: 'any',
});
const emhttp = getters.emhttp();
return {
text: `Vars: ${JSON.stringify(emhttp.var, null, 2)}`,
json: {
...emhttp.var,
},
};
};

Some files were not shown because too many files have changed in this diff Show More