Compare commits

..

510 Commits

Author SHA1 Message Date
Ronald A. Richardson
0e4baa34e0 Hotfix: patch dropdown menu item isComponent
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-12-30 12:08:29 +08:00
Ronald A. Richardson
d6d078df62 Upgraded solid extension 2025-12-30 10:58:45 +08:00
Ronald A. Richardson
7252a95805 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-12-29 22:26:36 +08:00
Ron
b25da51496 Merge pull request #486 from fleetbase/dev-v0.7.25
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
feat: New SMS service to support multiple SMS providers + framework improvements
2025-12-29 21:02:03 +08:00
Ronald A. Richardson
7d776f2bd5 updated pnpm lockfile overrides 2025-12-29 20:48:29 +08:00
Ronald A. Richardson
ecfcec72e4 updated override versions 2025-12-29 20:39:25 +08:00
Ronald A. Richardson
ca1741a4b2 feat: New SMS service to support multiple SMS providers + framework improvements 2025-12-29 20:36:43 +08:00
Ronald A. Richardson
7ba7821fed Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-12-21 12:11:00 +08:00
Ron
947565bcf0 Merge pull request #483 from fleetbase/dev-v0.7.24
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
Fix: Critical cache key collision bug in ApiModelCache
2025-12-21 12:05:16 +08:00
Ronald A. Richardson
2d4cc5cf66 Fix: Critical cache key collision bug in ApiModelCache 2025-12-21 12:02:53 +08:00
Ronald A. Richardson
af3c60fc7c Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-12-19 23:25:46 +08:00
Ronald A. Richardson
53a87d6f38 Hotfix: load iam engine for user-form modal when creating driver
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
2025-12-19 23:17:51 +08:00
Ronald A. Richardson
a372b515da Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-12-19 23:00:09 +08:00
Ronald A. Richardson
d7f8f87315 Hotfix: onboarding wrapper stylings added back 2025-12-19 22:58:29 +08:00
Ronald A. Richardson
f8b9c0415b Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-12-19 22:54:30 +08:00
Ron
36673ef564 Merge pull request #482 from fleetbase/dev-v0.7.23
dev-v0.7.23
2025-12-19 22:41:13 +08:00
Ronald A. Richardson
19341c81e7 Minor tweaks to user model and profile page 2025-12-19 22:39:41 +08:00
Ronald A. Richardson
b4ecf5bda9 bump FLEETBASE_VERSION in Dockerfile 2025-12-19 22:24:38 +08:00
Ronald A. Richardson
1b714a7ef8 Release ready 2025-12-19 22:23:39 +08:00
Ron
e41cd62ea5 Merge pull request #481 from fleetbase/feature/onboarding-wrapper-architecture
feat: Add wrapper component support to onboarding orchestrator
2025-12-19 15:56:49 +08:00
Ronald A. Richardson
1ca1342052 feat: fixed optimization changes for octane, added deprecation workflow 2025-12-19 15:56:03 +08:00
roncodes
a5a5ddb0d5 perf: Optimize FrankenPHP/Octane configuration for high load
**Changes:**

1. **Caddyfile**:
   - Reduced num_threads from 24 to 20
   - Added request timeouts (read_body: 10s, write: 60s, idle: 120s)
   - With 4 containers: 20 × 4 = 80 total workers

2. **Dockerfile**:
   - Added explicit --workers=20 to octane:frankenphp command
   - Increased --max-requests from 250 to 1000
   - Applied to app-dev, app-release, and app stages

3. **Octane config**:
   - Enabled DisconnectFromDatabases listener
   - Enabled CollectGarbage listener
   - Prevents DB connection leaks and memory leaks

**Impact:**
- Better resource management under load
- Prevents connection pool exhaustion
- Requires db.t3.large (591 max connections) or better
- Supports up to 250 concurrent VUs

**Related:**
- Requires RDS upgrade from db.t4g.micro to db.t3.large
- Works with DB_CONNECTION_POOL_SIZE=25 (100 total connections)
- See configuration-analysis.md for details
2025-12-16 20:06:35 -05:00
Ronald A. Richardson
c51f3ca6c8 v0.7.23 2025-12-17 08:57:41 +08:00
roncodes
a9b172081a feat: Add lifecycle hooks support to onboarding orchestrator
- Add onFlowWillStart, onFlowDidStart, onStepWillChange, onStepDidChange, onFlowWillEnd, onFlowDidEnd hooks
- Hooks are optional and backward compatible with existing flows
- Add getCurrentPath() and isStepInPath() helper methods for multi-path flows
- Support dynamic next() functions (already existed, now documented)
- Maintain full backward compatibility with default@v1 flow
2025-12-11 23:10:23 -05:00
Ronald A. Richardson
a29ca0ecb9 feat: update onboarding-registry service to allow set default onboard flow on registration 2025-12-09 09:48:23 +08:00
roncodes
6442644438 feat: Add wrapper component support to onboarding orchestrator
- Add wrapper property to OnboardingOrchestratorService
- Update onboarding/yield component to render wrapper using lazy-engine-component
- Clean up onboard.hbs template to remove styling constraints
- Enable extensions to provide custom wrapper components for onboarding flows
2025-12-08 20:38:59 -05:00
Ronald A. Richardson
b525ad4b1a Upgraded Core-API & Fleet-Ops
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-12-08 18:39:28 +08:00
Ronald A. Richardson
b161b415d0 Upgraded core-api and fleetops api 2025-12-08 18:34:33 +08:00
Ronald A. Richardson
e444d7994c Upgraded Core-API to v1.6.29 & Fleet-Ops Engine to v0.6.30 2025-12-08 18:02:31 +08:00
Ronald A. Richardson
0e44375d32 Upgraded Core API to v1.6.29 2025-12-08 17:59:47 +08:00
Ronald A. Richardson
a9bb2f0166 Upgraded Fleet-Ops to v0.6.30 2025-12-08 17:39:06 +08:00
Ronald A. Richardson
ac02a6b6e0 Upgraded Storefront to v0.4.10
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-12-07 15:13:22 +08:00
Ronald A. Richardson
4a640561d6 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-12-07 14:50:12 +08:00
Ron
0238632fdd Merge pull request #477 from fleetbase/dev-v0.7.22
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
Organizations can now set their own alpha-numeric sender ID for SMS
2025-12-07 06:37:02 +00:00
Ronald A. Richardson
27652db9c3 Organizations can now set their own alpha-numeric sender ID for SMS 2025-12-07 14:15:31 +08:00
Ronald A. Richardson
5957bc6339 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-12-06 22:05:13 +08:00
Ronald A. Richardson
5eaf2039d4 Fix: correct version of ember-ui in console/package.json
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
2025-12-06 21:49:14 +08:00
Ron
d8c06ae0be Merge pull request #476 from fleetbase/dev-v0.7.21
v0.7.21 ~ 5x faster css compiling and flawless builds
2025-12-06 13:41:42 +00:00
Ronald A. Richardson
c9011b3ffa *critical* patch to load-extensions initializer 2025-12-06 21:38:02 +08:00
Ronald A. Richardson
520de0f6bc fixed formating on console/package.json 2025-12-06 19:39:24 +08:00
Ronald A. Richardson
ba6ed235e3 v0.7.21 ~ 5x faster css compiling and flawless builds 2025-12-06 19:26:17 +08:00
Ronald A. Richardson
9b15a6856f Pin all dependencies
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-12-06 00:53:53 +08:00
Ronald A. Richardson
0a4e5b31cc Pin core dependencies 2025-12-06 00:28:06 +08:00
Ronald A. Richardson
0d47ffc785 Reverted to v0.7.19 2025-12-06 00:07:12 +08:00
Ronald A. Richardson
777d84a7fe Hotfix: added fleetbase-extension-generator lib dependency to package.json
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
2025-12-05 23:20:04 +08:00
Ron
18fdfdf506 Merge pull request #475 from fleetbase/feat/remove-console-prebuild
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
Remove console prebuild script, bump docker fleetbase version
2025-12-05 14:06:36 +00:00
Ronald A. Richardson
7e898dd54b Remove console prebuild script, bump docker fleetbase version 2025-12-05 22:02:46 +08:00
Ron
761c752a8e Merge pull request #474 from fleetbase/feature/extension-boot-refactor
feat: refactoring extension build pipelines
2025-12-05 13:14:24 +00:00
Ron
74d02efaa0 Merge pull request #470 from fleetbase/docs/add-translation-guide
docs: Add comprehensive translation contribution guide
2025-12-05 12:59:04 +00:00
Ron
aa928b43ba Merge pull request #464 from PicoBaz/add-persian-language
Add Persian (Farsi) Language Support in fa-ir.yaml
2025-12-05 12:58:43 +00:00
Ron
7ed422d893 Merge pull request #471 from johnfelipe/main
latin american spanish translation
2025-12-05 12:58:22 +00:00
Ronald A. Richardson
064fa12a43 Upgraded api dependencies 2025-12-05 20:53:44 +08:00
Ronald A. Richardson
32f0b22ed1 Merge remote-tracking branch 'origin/main' into feature/extension-boot-refactor 2025-12-05 20:49:32 +08:00
Ronald A. Richardson
4f87434911 Upgraded core dependencies 2025-12-05 20:43:53 +08:00
Ronald A. Richardson
498d519c49 Hard reset dependency files to main 2025-12-05 20:39:09 +08:00
Ronald A. Richardson
e4b008093d Fix api/composer.lock 2025-12-05 20:37:47 +08:00
Ronald A. Richardson
c31377b194 Merge branch 'feature/extension-boot-refactor' of github.com:fleetbase/fleetbase into feature/extension-boot-refactor 2025-12-05 20:32:29 +08:00
Ronald A. Richardson
6f397ea3cb fixing dependency merge conflicts 2025-12-05 20:32:04 +08:00
Ron
015c24585b Merge pull request #449 from valentinMERCIER/fix/docker-socket-example
Fix/docker socket example
2025-12-05 12:25:10 +00:00
roncodes
1f4b25faee feat: Clean up app/extensions directory before each build
Added directory cleanup logic to remove ./app/extensions before generating
new extension files. This prevents old/stale/removed extensions from
remaining in subsequent builds.

Changes:
- Added fs.rmSync to remove extensions directory if it exists
- Cleanup happens at the start of generateExtensionFiles()
- Directory is recreated during generation process
- Logs cleanup action for visibility

This ensures each build starts with a clean slate and only includes
currently installed extensions.
2025-12-05 07:20:24 -05:00
Ronald A. Richardson
3a193e414c almost ready for release 2025-12-05 20:15:55 +08:00
Ronald A. Richardson
9719632289 Preparing major release 2025-12-05 10:57:18 +08:00
roncodes
08dabaf138 fix: pass appInstance instead of appInstance.application
- Change window.Fleetbase = appInstance (not appInstance.application)
- Change setApplicationInstance(appInstance) (not appInstance.application)
- appInstance IS the ApplicationInstance, not the Application class
- Remove comment about RegistryService cascade
2025-12-02 21:07:27 -05:00
roncodes
7ae3ea95a2 feat: add set-application-instance initializer to console
- Create app/instance-initializers/set-application-instance.js
- Sets window.Fleetbase = appInstance.application for global access
- Calls universeService.setApplicationInstance() to cascade to RegistryService
- Ensures all services have access to root application container
- Required for UniverseRegistry singleton to work across engines
2025-12-02 21:00:56 -05:00
Ronald A. Richardson
9653cfcaf0 refactor of universe and lazy loading fix contd. 2025-12-03 09:55:12 +08:00
Ronald A. Richardson
cb7a2fb05b minor syntax tweaks 2025-11-28 18:10:24 +08:00
roncodes
fd569cfeaf fix: ensure intl polyfills load before runtime config
- Added name to load-intl-polyfills initializer
- Made load-runtime-config run after load-intl-polyfills
- Fixes race condition where intl service initialized before polyfill data loaded
- Resolves MISSING_DATA errors for all locales (mn-mn, etc.)

Initialization order now:
1. load-intl-polyfills (loads formatjs polyfill data)
2. load-runtime-config (loads fleetbase.config.json)
3. load-socketcluster-client
4. Other initializers
2025-11-28 04:52:07 -05:00
roncodes
0f9cd52bb4 fix: correct locale format from en-us to en-US
- Fixed ember-intl locale format to use proper case (en-US)
- Renamed translation file: en-us.yaml → en-US.yaml
- Updated fallbackLocale in ember-intl config
- Updated default locale in application route
- Fixes MISSING_DATA error in Intl.NumberFormat

The Intl API requires proper locale format (en-US not en-us)
2025-11-28 04:46:06 -05:00
Ronald A. Richardson
72ce000786 Merge branch 'feature/extension-boot-refactor' of github.com:fleetbase/fleetbase into feature/extension-boot-refactor 2025-11-28 17:43:08 +08:00
Ronald A. Richardson
c9477b78f2 feat: updated ember-cli-build.js 2025-11-28 17:42:43 +08:00
roncodes
affa141c9d perf: optimize fleetbase.config.json loading with localStorage caching
- Added 1-hour localStorage cache for runtime config
- Reduces 750ms+ HTTP request to instant cache lookup
- Cache automatically expires and refreshes
- Includes cache clear utility function
- Uses browser cache as fallback
- Performance logging with debug()
- Excluded JSON files from fingerprinting

Expected improvement: 783ms → <5ms (99.4% faster)
2025-11-28 04:37:29 -05:00
roncodes
5726eb974f refactor: Move runtime config and router fix to proper Ember initializers
Refactored app.js boot sequence to follow Ember conventions:

1. Created app/initializers/load-runtime-config.js
   - Loads fleetbase.config.json before application boots
   - Uses deferReadiness/advanceReadiness pattern
   - Runs before all other initializers
   - Added performance timing with debug logging

2. Created app/instance-initializers/apply-router-fix.js
   - Applies router refresh bug fix patch
   - Runs as instance-initializer (needs app instance)
   - Runs before extension loading
   - Added performance timing with debug logging

3. Refactored app/app.js
   - Removed custom ready() hook
   - Removed document.addEventListener('DOMContentLoaded')
   - Removed manual deferReadiness/boot calls
   - Now uses standard Ember boot sequence
   - Clean, minimal implementation

Benefits:
- Follows Ember conventions and best practices
- Proper initialization order guaranteed
- Performance monitoring for boot phases
- Easier to debug and maintain
- No custom boot logic needed

Boot sequence:
1. load-runtime-config initializer (runs first)
2. Other initializers (socketcluster, etc.)
3. apply-router-fix instance-initializer
4. load-extensions instance-initializer
5. Other instance-initializers
6. Application ready
2025-11-27 23:12:14 -05:00
Ronald A. Richardson
ca3050905d feat: preparing for performance tweaking to page load sub 1s 2025-11-28 11:56:38 +08:00
roncodes
cf2ced1512 feat: Add ASCII logo header to generated files and improve console output
- Added Option 1 ASCII logo header to all generated files
- Header includes copyright notice and AGPL-3.0 license
- Improved console logging with [Fleetbase] prefix
- Better formatted output with separators and extension listing
- Cleaner file change notifications
- More professional and readable build output
2025-11-27 06:12:02 -05:00
roncodes
93b7224335 feat: Generate app/extensions/index.js with new format and cleanup
- Changed extension loader generation to create app/extensions/index.js
- New format uses direct imports instead of dynamic imports
- Added getExtensionLoader helper function
- Removed unused plugins directory
- Removed old extension-loaders.generated.js file
- Cleaner and simpler loader structure
2025-11-27 05:48:54 -05:00
roncodes
9a053cfd9f fix: Use exact working logic from prebuild.js in in-repo addon
- Copied all working functions from prebuild.js
- Adapted only for addon context (this.project.root instead of __dirname)
- No logic changes, just direct migration
- Should work exactly like prebuild.js did
2025-11-27 05:30:14 -05:00
roncodes
56897af057 Revert refactor - caused regression in extension discovery 2025-11-27 05:28:25 -05:00
roncodes
b27e485a44 fix: Router mount context issue and refactor into modular utilities
- Fixed 'this' context issue in addConsoleExtensions/addRootExtensions
- Refactored monolithic index.js into separate utility modules:
  - discover-extensions.js - Extension discovery logic
  - generate-extension-shims.js - Shim file generation
  - generate-extension-loaders.js - Loader map generation
  - generate-router.js - Router AST manipulation
  - generate-manifest.js - Manifest generation
  - watch-extensions.js - File watching logic
- Simplified index.js to orchestrate utilities
- Improved code organization and maintainability
2025-11-27 05:23:38 -05:00
Ronald A. Richardson
94c5407387 fix: syntax error in extensions generator lib 2025-11-27 18:15:27 +08:00
roncodes
54ac27b304 fix: Use correct router.map.js path (console/router.map.js not app/router.map.js) 2025-11-27 04:56:56 -05:00
roncodes
4fb596c866 fix: Router generation and add file watching for extension changes
**Router Generation Fixes:**
- Fix router.js parsing (was looking for non-existent router.map.js)
- Parse Router.map(function() {...}) structure correctly
- Fix console route detection (check for path: '/' config)
- Fix function expression location (3rd arg after path config)
- Fix root extensions to use this.mount() not router.mount()

**File Watching:**
- Add chokidar to watch extension.js files in development
- Regenerate shims and loaders when extension.js changes
- Cache discovered extensions for regeneration
- Only watch in development mode

**Issues Fixed:**
1. Router.js now properly contains engine mounts
2. Extension.js changes trigger automatic regeneration
2025-11-27 04:35:16 -05:00
roncodes
3f12e98448 refactor: Simplify extension generator to write directly to app directory
- Remove Broccoli tree complexity, use included() hook instead
- Write files directly to app/ using Node.js fs operations
- Generate extension shims in app/extensions/
- Generate extension loaders in app/utils/extension-loaders.generated.js
- Generate router.js with proper engine mounts using recast AST
- Generate extensions.json manifest in public/
- Add recast dependency for AST manipulation
- Much simpler and more reliable than Broccoli trees
2025-11-27 04:09:59 -05:00
roncodes
a1fc1e4ff8 fix: Correct Funnel srcDir configuration and add improved logging
- Fix BroccoliMergeTrees error by adding srcDir to Funnel calls
- extensionShims: srcDir 'extensions' (files in outputPath/extensions/)
- extensionLoaders: srcDir 'utils' (files in outputPath/utils/)
- routerGen: srcDir '/' (files at outputPath root)
- Add comprehensive debug logging to all plugins
- Add detailed logging to in-repo addon index.js
- Improves debugging and troubleshooting of build process
2025-11-27 03:25:56 -05:00
Ronald A. Richardson
d622b617c3 feat: migrate from plugins to in-app-repo with build hooks 2025-11-27 16:13:44 +08:00
roncodes
edba6c8396 fix: Correct Broccoli plugin wiring to merge into app.trees.app
- Merge generatedAppTree into app.trees.app before app.toTree()
- Fix Funnel srcDir/destDir configuration
- Remove prebuild extension generation (now handled by Broccoli)
- Add extensionManifestTree to expose dist/extensions.json
- Files now treated as real app source for ember-auto-import
2025-11-27 01:12:36 -05:00
roncodes
a0fc1ce402 feat: Implement extension boot refactor with prebuild approach
- Modified prebuild.js to generate extension shims in app/extensions/
- Generate extension-loaders.js with dynamic import map
- Added ember-auto-import allowAppImports configuration
- Extension setup code is now code-split into separate chunks
- Removed FleetbaseExtensionsIndexer in favor of prebuild generation
- Added generated files to .gitignore

Successfully tested: extension code is code-split into separate chunk
(chunk.app_extensions_fleetops_js.*.js)
2025-11-27 00:34:12 -05:00
Ronald A. Richardson
ffab66ac6c feat: refactoring extension build pipelines 2025-11-27 11:20:14 +08:00
roncodes
d3555c7c82 Revert "refactor: Migrate FleetbaseConsole to new Universe architecture"
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
This reverts commit 4b12efef41.
2025-11-26 01:08:33 -05:00
roncodes
4b12efef41 refactor: Migrate FleetbaseConsole to new Universe architecture
## Changes

### Removed Old Instance Initializers
- Deleted `app/instance-initializers/load-extensions.js` (used bootEngines)
- Deleted `app/instance-initializers/initialize-widgets.js` (now in initialize-universe)

### Created New Instance Initializer
- `app/instance-initializers/initialize-universe.js`
  - Creates console-specific registries
  - Registers default dashboard widgets using WidgetService
  - Loads extension.js files from enabled extensions
  - No longer calls bootEngines (enables lazy loading)

### Migrated Application Route
- `app/routes/application.js`
  - Replaced `@service universe` with specialized services
  - Uses `@service('universe/hook-service')` for hook execution
  - Uses `@service('universe/extension-manager')` for boot waiting
  - `universe.callHooks()` → `hookService.execute()`
  - `universe.booting()` → `extensionManager.waitForBoot()`

### Migrated Dashboard Widget Panel
- `app/components/dashboard/widget-panel.js`
  - Replaced `@service universe` with `@service('universe/widget-service')`
  - `universe.getDashboardWidgets()` → `widgetService.getWidgets('dashboard')`

### Migrated Dashboard Model
- `app/models/dashboard.js`
  - `universe.getDashboardRegistry()` → `widgetService.getRegistry()`
  - Looks up `service:universe/widget-service` instead of `service:universe`

### What Stayed the Same
- `app/controllers/console.js` - Event system usage unchanged
- `app/controllers/console/notifications.js` - Event system usage unchanged
- Event system (`on`, `trigger`) remains on Universe facade

## Benefits

-  Enables true lazy loading (engines load on-demand)
-  Separation of concerns via specialized services
-  Clearer service responsibilities
-  Better performance (no bootEngines at startup)
-  Maintains backward compatibility for events
2025-11-26 00:59:39 -05:00
Tu Nombre
c80f507720 latin american spanish translation 2025-11-19 08:02:28 -05:00
roncodes
2da7ee9c19 docs: add comprehensive translation contribution guide 2025-11-18 23:10:09 -05:00
Ronald A. Richardson
3f2c739810 fix: refresh lockfile
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-11-17 19:59:06 +08:00
Ronald A. Richardson
6b2ab28ec9 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-11-17 19:51:29 +08:00
Ronald A. Richardson
658568e4ec bump console/package.json version
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
2025-11-17 19:24:00 +08:00
Ron
8a487b2352 Merge pull request #469 from fleetbase/dev-v0.7.19
v0.7.19
2025-11-17 19:22:41 +08:00
Ronald A. Richardson
bc89218a26 add fleetops-data 2025-11-17 19:17:01 +08:00
Ronald A. Richardson
5a4f7e2ae3 upgraded dependencies 2025-11-17 18:43:28 +08:00
Ronald A. Richardson
9fa1bf54d2 v0.7.19 ~ A major leap forward in scheduling, reporting, and user interface capabilities. 2025-11-17 18:17:51 +08:00
mehdi
13cfe00958 Add Persian (Farsi) lang in api/resource/lang , fa folder 2025-11-10 11:47:50 +03:30
PicoBaz
6cab778f93 Create fa-ir.yaml (Add Persian (Farsi) translations in fa-ir.yaml) 2025-11-10 09:31:39 +03:30
Ronald A. Richardson
b98eb3adf5 Merge branch 'main' of github.com:fleetbase/fleetbase into ron/dev-v0.7.19 2025-11-10 11:30:12 +08:00
Ronald A. Richardson
5473b50c40 development in progress 2025-11-10 11:27:50 +08:00
Ronald A. Richardson
42df48c9b0 merge latest
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-11-10 11:12:50 +08:00
Ronald A. Richardson
268749fcd9 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-11-10 11:11:47 +08:00
Ronald A. Richardson
d9f415528e hotfix: update api/composer.json
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
2025-11-10 11:02:06 +08:00
Ron
76b0bfbfcd Merge pull request #463 from fleetbase/dev-v0.7.18
v0.7.18
2025-11-10 10:52:51 +08:00
Ronald A. Richardson
0432003163 latest storefront 2025-11-10 10:52:09 +08:00
Ronald A. Richardson
da420f0b4a ready for release 2025-11-10 10:49:29 +08:00
Ronald A. Richardson
e923a89719 v0.7.18 2025-11-10 10:35:47 +08:00
Ronald A. Richardson
0742603b43 added storefront release 2025-11-10 10:31:02 +08:00
Ronald A. Richardson
e1788a4ad6 v0.7.17 2025-11-10 10:29:26 +08:00
Ronald A. Richardson
50ae560409 refresh composer lockfile
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-11-06 22:06:21 +08:00
Ronald A. Richardson
2e48024949 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-11-06 22:00:22 +08:00
Ron
7cb4654c86 Merge pull request #460 from fleetbase/dev-v0.7.17
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.17 ~ hotfix router map
2025-11-06 21:59:37 +08:00
Ronald A. Richardson
a17aa3f5cc hotfix router map 2025-11-06 21:58:40 +08:00
Ronald A. Richardson
908f60aaac Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-11-06 21:29:34 +08:00
Ron
0bf1a7fadd Merge pull request #459 from fleetbase/dev-v0.7.16
v0.7.16
2025-11-06 21:17:49 +08:00
Ronald A. Richardson
aa1ea2de89 Merge branch 'main' of github.com:fleetbase/fleetbase into dev-v0.7.16 2025-11-06 21:10:23 +08:00
Ronald A. Richardson
235f1ce80c upgraded dependencies 2025-11-06 20:45:42 +08:00
Ronald A. Richardson
5aa50504a4 updated RELEASE.md 2025-11-06 20:34:56 +08:00
Ronald A. Richardson
5d1b2e1939 - Made the LogApiRequests middleware more robust
- Fixed controller validation handling
- Added microsoft365/graph mail driver
- Improved password requirements (including breached password check)
- Patched creating duplicate users by email in IAM
- Patch env mapper
- Vehicle/driver tracking API doesnt fire resource lifecycle events or log requests - only tracking events
- Patched `<ModelCoordinatesInput />` component
- Security patch on Storefront customers API
- Styling updates on Storefront
2025-11-06 20:33:23 +08:00
Ronald A. Richardson
a1f2992f18 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-11-01 14:21:29 +08:00
Ron
fc5d90189c Merge pull request #456 from fleetbase/dev-v0.7.15
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.15
2025-11-01 14:08:41 +08:00
Ronald A. Richardson
2fee78e534 performed upgrades 2025-11-01 14:07:55 +08:00
Ronald A. Richardson
83fc794702 v0.7.15 2025-11-01 14:00:59 +08:00
Ronald A. Richardson
0252b387e2 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-10-30 19:32:33 +08:00
Ron
66f669ad80 Merge pull request #454 from fleetbase/dev-v0.7.14
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.14
2025-10-30 18:53:33 +08:00
Ronald A. Richardson
a11b77592c fix console/package.json 2025-10-30 18:23:44 +08:00
Ronald A. Richardson
e5156829dc update release.md 2025-10-30 18:22:01 +08:00
Ronald A. Richardson
6cd7ddffcb v0.7.14 2025-10-30 18:20:04 +08:00
lapin
b9adb92fc1 Add Docker socket configuration examples and platform compatibility
This commit provides proper configuration examples for the SocketCluster
WebSocket service and improves platform compatibility.

Changes:
- Platform: Add linux/amd64 platform specification for Apple Silicon compatibility
- CORS: Remove hardcoded permissive origins and add secure configuration examples
- Examples: Create docker-compose.override.yml.example with proper WebSocket origins

The configuration now supports:
- Development: localhost-only origins (http/https/ws/wss protocols)
- Production: Domain-specific origins with WebSocket protocol support
- Security: Prevents unauthorized cross-origin WebSocket connections

Updated documentation explains how to configure WebSocket origins securely
for different deployment environments.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 10:17:37 +01:00
lapin
d81bd4e900 Merge remote-tracking branch 'upstream/main' 2025-10-28 09:47:55 +01:00
Ronald A. Richardson
12e1ec2cac Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-10-28 06:29:27 +08:00
Ron
cbdf1d489b Merge pull request #447 from fleetbase/dev-v0.7.13
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.13 ~ Connectivity Module + Positions Playback + Positions & Device Events Drawer
2025-10-28 05:48:35 +08:00
Ronald A. Richardson
785bc55bb7 v0.7.13 ~ Connectivity Module + Positions Playback + Positions & Device Events Drawer 2025-10-28 05:39:54 +08:00
lapin
8a21593d9a Update docker-compose.yml 2025-10-24 15:21:42 +02:00
Ronald A. Richardson
5f2003eec5 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-10-22 13:05:09 +08:00
Ron
d171d02aac Merge pull request #446 from fleetbase/dev-v0.7.12
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.12 ~ Patches and Order Board Improvement
2025-10-22 12:38:56 +08:00
Ronald A. Richardson
dfd4ee37df pin linux build version 2025-10-22 12:38:24 +08:00
Ronald A. Richardson
27c063fbfb v0.7.12 ~ Patches and Order Board Improvement 2025-10-22 12:21:58 +08:00
Ronald A. Richardson
e05d12dd87 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-10-15 23:55:21 +08:00
Ron
8e85dcff83 Merge pull request #443 from fleetbase/dev-v0.7.11
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.11 ~ Maintenance, Reports, Telematics Upgrade/Features
2025-10-15 23:13:21 +08:00
Ronald A. Richardson
e38923c461 added RELEASE and updated README 2025-10-15 23:09:04 +08:00
Ronald A. Richardson
9911c96c09 All packages upgraded 2025-10-15 22:15:33 +08:00
Ronald A. Richardson
284c62cd06 v0.7.11 ~ Maintenance, Reports, Telematics Upgrade/Features 2025-09-30 13:49:34 +08:00
Ronald A. Richardson
86378d3ede Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-09-02 16:52:59 +08:00
Ron
f8fd9f76fa Merge pull request #429 from fleetbase/dev-v0.7.10
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.10 - Maintenance capability overhaul, Storefront critical patches and improvements
2025-09-02 15:33:10 +08:00
Ronald A. Richardson
67aa793537 v0.7.10 - Maintenance capability overhaul, Storefront critical patches and improvements 2025-09-02 14:32:39 +08:00
Ronald A. Richardson
1d36bf144b Hotfix: autoboot aws-marketplace extension
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-08-13 18:31:53 +08:00
Ronald A. Richardson
293f67d6d1 Hotfix: autoboot aws-marketplace extension 2025-08-13 18:30:35 +08:00
Ronald A. Richardson
01e8298968 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-08-13 18:08:20 +08:00
Ron
5d0ae16cfd Merge pull request #424 from fleetbase/dev-v0.7.9
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.9 ~ shorter default data retention + template variable resolver + patched order vehicle update via api
2025-08-13 17:47:01 +08:00
Ronald A. Richardson
1d003ee31e v0.7.9 ~ shorter default data retention + template variable resolver + patched order vehicle update via api 2025-08-13 17:32:46 +08:00
Ron
9c9f3a994e Added one-click aws deploy details
Some checks are pending
Fleetbase CI / Build and Start Docker Services (push) Waiting to run
2025-08-13 14:21:18 +08:00
Ronald A. Richardson
094d1d375e Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-08-12 19:14:24 +08:00
Ron
b0ae302e81 Merge pull request #423 from fleetbase/dev-v0.7.8
Some checks are pending
Fleetbase CI / Build and Start Docker Services (push) Waiting to run
v0.7.8 - Fix OSX build script, removed awsmp ECR publish
2025-08-12 19:01:15 +08:00
Ronald A. Richardson
205fcf1480 Optimized maintenance script, added linux/arm64 to docker image platforms 2025-08-12 18:53:23 +08:00
Ronald A. Richardson
23bf7c5ac8 v0.7.8 - Fix OSX build script, removed awsmp ECR publish 2025-08-11 13:37:00 +08:00
Ronald A. Richardson
8a1dee0cbd Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-08-11 10:35:42 +08:00
Ron
ada7e0df92 Merge pull request #422 from fleetbase/dev-v0.7.7
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.7 - Configurable rate limiting and maintenance patches
2025-08-09 19:14:21 +08:00
Ronald A. Richardson
f3bc42ace5 upgraded dependencies 2025-08-09 18:56:38 +08:00
Ronald A. Richardson
b91cbed080 v0.7.7 - Configurable rate limiting and maintenance patches 2025-08-09 16:40:59 +08:00
Ron
9870b11a71 Merge pull request #418 from fleetbase/feature/aws-marketplace-ecr-publish-job
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
fix ecr authentication step
2025-07-25 16:13:39 +08:00
Ronald A. Richardson
1d62dbca6b fix ecr authentication step 2025-07-25 16:11:26 +08:00
Ron
db3bf46a02 Merge pull request #417 from fleetbase/feature/aws-marketplace-ecr-publish-job
fix ecr publish add registry env variable
2025-07-25 15:25:47 +08:00
Ronald A. Richardson
ec053f1d13 fix ecr publish add registry env variable 2025-07-25 15:24:18 +08:00
Ron
030ec2494d Merge pull request #416 from fleetbase/feature/aws-marketplace-ecr-publish-job
added workflow job to publish to aws ecr for marketplace distribution
2025-07-25 15:07:13 +08:00
Ronald A. Richardson
fe56bcac85 formatted action workflow template 2025-07-25 15:06:40 +08:00
Ronald A. Richardson
8b118d1ad9 minor workflow tweak 2025-07-25 15:05:43 +08:00
Ronald A. Richardson
724c1b49ab added workflow job to publish to aws ecr for marketplace distribution 2025-07-25 15:04:06 +08:00
Ronald A. Richardson
df2da8cea1 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-06-04 13:00:32 +08:00
Ron
8e5b2e1ae3 Merge pull request #402 from fleetbase/dev-v0.7.6
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.6 ~ Minor patches, WIP multi-order route optimization
2025-06-04 12:46:10 +08:00
Ronald A. Richardson
e141d4d3a3 update release title 2025-06-04 12:32:47 +08:00
Ronald A. Richardson
ab2e102e28 v0.7.6 ~ Minor patches, WIP multi-order route optimization 2025-06-04 12:30:02 +08:00
Ronald A. Richardson
ced5e6b6fd Fix v0.7.5 Deploy
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-05-30 17:55:34 +08:00
Ronald A. Richardson
de2cbd2ded v0.7.5 prod deploy 2025-05-30 17:32:58 +08:00
Ronald A. Richardson
894f4348dd Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-05-30 17:25:32 +08:00
Ron
723deff398 Merge pull request #401 from fleetbase/dev-v0.7.5
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.5 ~ Added route optimization and routing control registry and se…
2025-05-30 17:07:44 +08:00
Ronald A. Richardson
fd9adc3961 update composer.json 2025-05-30 17:07:03 +08:00
Ronald A. Richardson
4244a04052 upgraded fleetops 2025-05-30 16:57:31 +08:00
Ronald A. Richardson
e3c60a2232 fix release md typo 2025-05-30 16:15:44 +08:00
Ronald A. Richardson
1eaeb2c46e updated release file 2025-05-30 16:14:26 +08:00
Ronald A. Richardson
1d64d18b8b v0.7.5 ~ Added route optimization and routing control registry and settings & optimized environment/settings mapper 2025-05-30 16:10:56 +08:00
Ronald A. Richardson
2030a72a71 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-05-26 16:11:43 +08:00
Ron
1124ecb56c Merge pull request #400 from fleetbase/dev-v0.7.4
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.4 ~ new docker install script, added logic condition property sh…
2025-05-26 15:54:09 +08:00
Ronald A. Richardson
672f3d51ca docker installer: added 12 sec delay before deploy script run 2025-05-26 15:46:05 +08:00
Ronald A. Richardson
cd5af8dfc8 added feature to wait database running in docker install script 2025-05-26 15:32:49 +08:00
Ronald A. Richardson
1a0073eae0 few tweaks to readme and install script 2025-05-26 15:20:48 +08:00
Ronald A. Richardson
d24b1d6fbe update release and readme 2025-05-26 14:59:20 +08:00
Ronald A. Richardson
ebbc4b2bf8 v0.7.4 ~ new docker install script, added logic condition property shortcut keys 2025-05-26 14:52:32 +08:00
Ron
b531c18d65 Merge pull request #399 from fleetbase/hotfix/ci-macos-binary-build
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
attempt to patch macos binary build ci
2025-05-24 14:03:54 +08:00
Ronald A. Richardson
fded8b24df attempt to patch macos binary build ci 2025-05-24 13:59:57 +08:00
Ronald A. Richardson
41d20c41c5 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-05-24 13:43:57 +08:00
Ron
98d082c780 Merge pull request #398 from fleetbase/dev-v0.7.3
v0.7.3 ~ hotfix: route optimization w/ no driver, seeder command
2025-05-24 13:26:23 +08:00
Ronald A. Richardson
d905943511 bump fleetops api version 2025-05-24 13:19:52 +08:00
Ronald A. Richardson
5c73b6e76d v0.7.3 ~ hotfix: route optimization w/ no driver, seeder command 2025-05-24 13:16:47 +08:00
Ronald A. Richardson
9976075843 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-05-23 20:23:40 +08:00
Ron
cedf96fc97 Merge pull request #397 from fleetbase/dev-v0.7.2
Some checks are pending
Fleetbase CI / Build and Start Docker Services (push) Waiting to run
v0.7.2 ~ route optimization patch, telemetry patch, network store management patch
2025-05-23 20:07:15 +08:00
Ronald A. Richardson
854fa2e680 fixed release.md date 2025-05-23 20:00:58 +08:00
Ronald A. Richardson
91b01c8a17 updated release info 2025-05-23 19:59:24 +08:00
Ronald A. Richardson
a4033db36c fixed fleetops route optimization, fixed network store management 2025-05-23 19:57:38 +08:00
Ronald A. Richardson
b26f735fee DISABLE_RUNTIME_CONFIG=true v0.7.1 on Production
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-05-22 19:24:27 +08:00
Ronald A. Richardson
791cc7283d DISABLE_RUNTIME_CONFIG=true v0.7.1 on Production
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-05-22 18:54:39 +08:00
Ronald A. Richardson
21601737a1 DISABLE_RUNTIME_CONFIG=true v0.7.1 on Production 2025-05-22 18:00:09 +08:00
Ronald A. Richardson
0cd9e076b8 DISABLE_RUNTIME_CONFIG=true v0.7.1 on Production 2025-05-22 15:54:10 +08:00
Ronald A. Richardson
c54ef7fb30 v0.7.2 ~ Telemetry tweak patch 2025-05-22 15:19:01 +08:00
Ronald A. Richardson
5fe799b708 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-05-22 13:06:56 +08:00
Ronald A. Richardson
b5ec15f0bb fix discord announcement workflow, attempt 4
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
2025-05-22 12:47:27 +08:00
Ronald A. Richardson
1f609dd882 fix discord announcement workflow, attempt 3 2025-05-22 12:35:12 +08:00
Ronald A. Richardson
01883da5a2 attempt #2 to fix the discord announcement 2025-05-22 12:29:27 +08:00
Ronald A. Richardson
d2ab5b8a94 fix discord announcement workflow 2025-05-22 12:23:54 +08:00
Ronald A. Richardson
dca23f7e3f fix gh action workflows 2025-05-22 12:18:48 +08:00
Ron
d94dff7fbb Merge pull request #394 from fleetbase/dev-v0.7.1
v0.7.1 ~ Fleetbase console can now read in a runtime config
2025-05-22 12:09:47 +08:00
Ronald A. Richardson
e1ab6a3b11 use release.md for discord announcement 2025-05-22 12:06:58 +08:00
Ronald A. Richardson
c79fe67e44 ready to release, if macos doesnt build fix later 2025-05-22 11:59:09 +08:00
Ronald A. Richardson
d8adf42b24 revert back to previous curl patch 2025-05-22 11:51:05 +08:00
Ronald A. Richardson
80da5fe013 add SPC_OPT_DOWNLOAD_ARGS to attempt to fix osx build on gh runner 2025-05-22 11:25:45 +08:00
Ronald A. Richardson
06fd5e20e8 make osx build script gh runner friendly 2025-05-22 11:21:21 +08:00
Ronald A. Richardson
f04807de1e fixed upload to only run on release workflow, debug macos build on runer 2025-05-22 11:14:53 +08:00
Ronald A. Richardson
b7666eeb3e fix github workflows and setup to debug macos build 2025-05-22 10:45:37 +08:00
Ronald A. Richardson
dd895a0fd8 remove CURRENT_HASH file 2025-05-22 10:31:05 +08:00
Ronald A. Richardson
8c74c0fb99 release is almost ready 2025-05-22 10:30:10 +08:00
Ronald A. Richardson
92170c965e updated docker-compose to use latest images, patched osx binary build script, experimenting with artifact upload for binaries 2025-05-21 22:18:49 +08:00
Ronald A. Richardson
fcb3694874 added curl patch for gh runners 2025-05-21 21:33:45 +08:00
Ronald A. Richardson
aa46059bff minor tweak on php build of osx build script 2025-05-21 21:11:41 +08:00
Ronald A. Richardson
a5175bb11b fix php 8.4 detection in osx build script 2025-05-21 21:08:52 +08:00
Ronald A. Richardson
01816a1fe0 update osx build script to skip asdf install if php 8.4 is already installed 2025-05-21 21:02:04 +08:00
Ronald A. Richardson
15d500cd58 just install php via homebrew 2025-05-21 20:49:37 +08:00
Ronald A. Richardson
95d77a6ddd in osx build workflow use correct asdf commands 2025-05-21 20:45:46 +08:00
Ronald A. Richardson
eefc93e130 debug osx binary build workflow 2025-05-21 20:42:09 +08:00
Ronald A. Richardson
0f18ae85f1 debug osx binary build workflow 2025-05-21 20:35:22 +08:00
Ronald A. Richardson
a4812192da debug osx binary build workflow 2025-05-21 20:26:24 +08:00
Ronald A. Richardson
15d3c957b8 debug osx binary build workflow 2025-05-21 20:20:33 +08:00
Ronald A. Richardson
c2bd098d14 debug osx binary build workflow 2025-05-21 20:16:16 +08:00
Ronald A. Richardson
98511fd418 patch console route && debug osx action binary build 2025-05-21 20:13:14 +08:00
Ronald A. Richardson
225110c8dc attempt to patch binary build workflow 2025-05-21 19:39:04 +08:00
Ronald A. Richardson
1aa2a99763 added workflow to build fleetbase api binaries 2025-05-21 19:35:08 +08:00
Ron
6e888af772 Merge pull request #376 from fleetbase/feature/fleetbase-binary
Working static build script for a fleetbase binary (unix/linux/osx)
2025-05-21 19:24:49 +08:00
Ronald A. Richardson
d61205d898 added fleetbase config file, added ability to set tz for user and organization 2025-05-21 19:21:22 +08:00
Ronald A. Richardson
72078553cc remove hash tracking from docker build 2025-05-20 10:19:42 +08:00
Ronald A. Richardson
bfae04a645 attempt to fix current hash check in build 2025-05-20 10:16:43 +08:00
Ronald A. Richardson
c59f028755 fix docker build 2025-05-20 10:06:26 +08:00
Ronald A. Richardson
2b959db773 remove the current hash file 2025-05-19 19:36:05 +08:00
Ronald A. Richardson
a9354ccbfd removed EXPECTED_HASH checkin 2025-05-19 19:06:21 +08:00
Ronald A. Richardson
23e6d1e6b9 removed EXPECTED_HASH 2025-05-19 17:33:13 +08:00
Ronald A. Richardson
86da1bd095 Improvements to docker setups 2025-05-19 17:30:18 +08:00
Ronald A. Richardson
ae89600ae6 updated dockerhub publish workflow 2025-05-19 13:54:28 +08:00
Ronald A. Richardson
6697b79185 secured runtime config to only allow select config values to be set 2025-05-19 13:50:10 +08:00
Ronald A. Richardson
4dc9764853 v0.7.1 ~ Fleetbase console can now read in a runtime config 2025-05-19 13:12:57 +08:00
Ronald A. Richardson
878a70d328 Fix v0.7.0 cloud deploy
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-05-16 18:11:59 +08:00
Ronald A. Richardson
4c5487b6bb Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-05-16 17:35:29 +08:00
Ron
0626bc0171 Merge pull request #388 from fleetbase/dev-v0.7.0
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.0 🛠️
2025-05-16 17:19:57 +08:00
Ronald A. Richardson
a8adf3fd84 Merge branch 'dev-v0.7.0' of github.com:fleetbase/fleetbase into dev-v0.7.0 2025-05-16 16:22:18 +08:00
Ronald A. Richardson
7b8bc4a593 removed old docker settings and github auth arg 2025-05-16 16:21:22 +08:00
Ron
490f2f1b41 Merge pull request #345 from nstankov-bg/feature/translate-bulgarian
feature/translate-bulgarian
2025-05-16 16:07:25 +08:00
Ron
e1fc7850d3 Merge pull request #385 from thawaba/add-arabic-language
Add Arabic language support
2025-05-16 16:06:44 +08:00
Ronald A. Richardson
cc278bf1bb * Patched fuel report creation/ fixed coordinates input implementation for fuel report
* Added bulk assign driver
* Improved performance for order dispatch/ bulk order dispatch/ bulk assign driver
* Added new columns to order export
* Added downloadable import templates for all importable resources via Import Modal
* Patched custom field rendering for order viewing
* Patched custom field values reset after order creation
* Added notification settings to FleetOps
* Added bulk search by ID or Tracking Number for Orders
* Patched all filters and filter indicator component
* Patched issue unable to select driver after selecting facilitator
* Fixed extension booting when not authenticated
* Fixed Internal ID rendering on order view
* Added ability to filter orders without a driver
2025-05-16 16:03:26 +08:00
aanmth
af86aaba8b Add Arabic language support 2025-05-15 05:42:17 +03:00
Ronald A. Richardson
599fd0e8f7 fix: Updated with correct version indicator
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-05-08 20:13:19 +08:00
Ronald A. Richardson
64561c85a8 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-05-08 20:09:32 +08:00
Ronald A. Richardson
f35dcb1544 fix: update package.json version v0.6.10
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
2025-05-08 20:06:27 +08:00
Ronald A. Richardson
c8d8be11d2 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-05-08 12:47:07 +08:00
Ron
29c8f4340d Merge pull request #382 from fleetbase/dev-v0.6.10
Some checks are pending
Fleetbase CI / Build and Start Docker Services (push) Waiting to run
v0.6.10 ~ Added Product Update/Create API, Added `FRONTEND_HOSTS` ENV…
2025-05-08 12:33:02 +08:00
Ronald A. Richardson
1cb833e407 v0.6.10 ~ Added Product Update/Create API, Added FRONTEND_HOSTS ENV variable, other minor patches 2025-05-08 12:24:54 +08:00
Ronald A. Richardson
e372bc6396 minor update to linux build script 2025-05-07 14:32:17 +08:00
Ronald A. Richardson
2f432d148a Remove build artifacts; add dist & downloads to .gitignore 2025-05-07 14:26:57 +08:00
Ronald A. Richardson
12847437b0 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-05-01 12:29:12 +08:00
Ron
41bc6e39a7 Merge pull request #380 from fleetbase/dev-v0.6.9
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
Enhancements and bug fixes for order workflow, labels, notifications,…
2025-05-01 12:15:36 +08:00
Ronald A. Richardson
5dbe2fb5bb Enhancements and bug fixes for order workflow, labels, notifications, and route optimization
- Added support for downloading labels and barcodes per package
- Fixed proof of delivery behavior to ensure accurate completion records
- Updated waypoint activity flow to rely on the `complete` flag
- Added support for setting waypoints as either pickup or dropoff
- Enabled sending notifications to order customer, driver, and facilitator
- Added events and notifications for `order.completed` and `order.failed` states
- Fixed route optimization logic and minor issues during order creation
- Normalized `meta` response structure to always return an object (never array)
- Patched issue with order config: deleting custom field categories no longer breaks config
2025-05-01 12:08:27 +08:00
Ronald A. Richardson
8f66bc12e4 Working static build script for a fleetbase binary (unix/linux) 2025-04-16 14:22:07 +08:00
Ronald A. Richardson
53eadee8a6 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-04-14 16:17:27 +08:00
Ron
313b5ea3ba Merge pull request #374 from fleetbase/dev-v0.6.8
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.6.8 ~ View Proof of Delivery in FleetOps + API to get POD
2025-04-14 16:10:34 +08:00
Ronald A. Richardson
698f5979b1 v0.6.8 ~ View Proof of Delivery in FleetOps + API to get POD 2025-04-14 16:05:10 +08:00
Ronald A. Richardson
657de6c99d Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-04-11 13:05:20 +08:00
Ron
f6f6899650 Merge pull request #373 from fleetbase/dev-v0.6.7
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
Fix iOS Push Notifications for Production Environments
2025-04-11 12:51:25 +08:00
Ronald A. Richardson
83a7ab7338 Fix iOS Push Notifications for Production Environments 2025-04-11 12:43:09 +08:00
Ronald A. Richardson
db601606c5 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-04-11 10:21:07 +08:00
Ron
acf7b209af Merge pull request #372 from fleetbase/dev-v0.6.6
Patched Join Organization + Chat Push Notifications Added
2025-04-11 10:09:40 +08:00
Ronald A. Richardson
5c048a8238 Patched Join Organization + Chat Push Notifications Added 2025-04-11 10:02:33 +08:00
Ronald A. Richardson
6ec176011a Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-04-10 13:53:27 +08:00
Ron
de00ad31db Merge pull request #371 from fleetbase/dev-v0.6.5
Some checks are pending
Fleetbase CI / Build and Start Docker Services (push) Waiting to run
🤖 Patched Navigator App Instance Linking for Android
2025-04-10 13:44:34 +08:00
Ronald A. Richardson
8fe52c6157 🤖 Patched Navigator App Instance Linking for Android + Navigator App Identifier Configurable 2025-04-10 13:34:42 +08:00
Ronald A. Richardson
d416baf3cc Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-04-09 19:46:55 +08:00
Ron
a371e055ca Merge pull request #370 from fleetbase/dev-v0.6.4
Some checks are pending
Fleetbase CI / Build and Start Docker Services (push) Waiting to run
Upgraded FleetOps to v0.6.3
2025-04-09 19:34:52 +08:00
Ronald A. Richardson
bbec73fcef Upgraded FleetOps to v0.6.3 2025-04-09 19:03:42 +08:00
Ronald A. Richardson
d80b968eaa Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-04-01 21:24:48 +08:00
Ron
838a829a11 Merge pull request #367 from fleetbase/dev-v0.6.3
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
Patched AdHoc Pinging & Push Notifications
2025-04-01 21:17:49 +08:00
Ronald A. Richardson
dbb7bc793a removed console logs 2025-04-01 21:06:16 +08:00
Ronald A. Richardson
f0fa867ef9 Patched AdHoc Pinging & Push Notifications 2025-04-01 21:02:51 +08:00
Ronald A. Richardson
eef6847919 upgrade to v0.6.2
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-03-31 11:18:52 +08:00
Ronald A. Richardson
2ad569eaf6 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-03-31 11:16:12 +08:00
Ron
3cc64913ca Merge pull request #366 from fleetbase/hotfix/php-geos-404
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
hotfix php-geos install replace broken url with github mirror
2025-03-31 11:13:35 +08:00
Ronald A. Richardson
d034c4ad03 hotfix php-geos install replace broken url with github mirror 2025-03-31 11:05:47 +08:00
Ronald A. Richardson
dc18b48f6a Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-03-27 21:34:08 +08:00
Ron
b740cf035e Merge pull request #365 from fleetbase/dev-v0.6.1
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.6.1 ~ new driver online/offline toggle endpoint, improvements to tracker data api
2025-03-27 21:27:50 +08:00
Ronald A. Richardson
cc42779efc new driver online/offline toggle endpoint, improvements to tracker data api 2025-03-27 21:25:50 +08:00
Ronald A. Richardson
3e93e161dc Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-03-26 22:40:06 +08:00
Ron
4a5422e357 Merge pull request #364 from fleetbase/dev-v0.6.0
Some checks are pending
Fleetbase CI / Build and Start Docker Services (push) Waiting to run
v0.6.0 - Navigator App Refactor Support Release & Patches + Improvements
2025-03-26 22:14:02 +08:00
Ronald A. Richardson
21a0808b99 v0.6.0 - Navigator App Refactor Support Release & Patches + Improvements 2025-03-26 21:54:48 +08:00
Ronald A. Richardson
fac29308fd Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-02-26 20:34:13 +08:00
Ron
f6cb850219 Merge pull request #358 from fleetbase/dev-v0.5.30
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
🏁 Consumable API Patches, Perf Improvements
2025-02-26 20:22:51 +08:00
Ronald A. Richardson
80707774ac 🏁 Consumable API Patches, Perf Improvements 2025-02-26 20:03:09 +08:00
Ronald A. Richardson
7b62e992eb Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-02-25 20:32:19 +08:00
Ron
96318bb909 Merge pull request #356 from fleetbase/dev-v0.5.29
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.5.29 ~ ️ Performance Upgrades 10x Faster, Critical Patches
2025-02-25 20:27:01 +08:00
Ronald A. Richardson
2c10f3551e dont run octane reload on deploy 2025-02-25 20:06:51 +08:00
Ronald A. Richardson
41a469c983 fix static issues with octane 2025-02-25 20:05:21 +08:00
Ronald A. Richardson
edf7efe167 v0.5.29 ~ ️ Performance Upgrades 10x Faster, Critical Patches 2025-02-25 16:44:14 +08:00
Ronald A. Richardson
18af3b4515 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-02-21 16:37:13 +08:00
Ron
d7a2dd474a Merge pull request #355 from fleetbase/dev-v0.5.28
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.5.28 ~ patches for creating contact, and driver api hotfix
2025-02-21 16:29:47 +08:00
Ronald A. Richardson
2b0c6f793d patches for creating contact, and driver api hotfix 2025-02-21 16:24:23 +08:00
Ronald A. Richardson
264c564ad6 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-02-14 19:23:06 +08:00
Ron
3e60479130 Merge pull request #352 from fleetbase/dev-v0.5.27
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.5.27 ~ Update for improved storefront callbacks and patches
2025-02-14 19:15:52 +08:00
Ronald A. Richardson
215d5dc42e v0.5.27 ~ Update for improved storefront callbacks and patches 2025-02-14 19:10:35 +08:00
Ronald A. Richardson
dbf9a37ae9 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-02-13 14:58:27 +08:00
Ron
a57467539b Merge pull request #351 from fleetbase/dev-v0.5.26
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.5.26 ~ Hotfix dark tile source
2025-02-13 14:48:35 +08:00
Ronald A. Richardson
c612c97e43 v0.5.26 ~ Hotfix dark tile source 2025-02-13 14:47:22 +08:00
Ronald A. Richardson
46c4ac9dda Fix lockfile for v0.5.25 2025-02-13 13:02:01 +08:00
Ronald A. Richardson
e692bc3365 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-02-12 23:40:30 +08:00
Ron
683e93abe0 Merge pull request #350 from fleetbase/dev-v0.5.25
Some checks are pending
Fleetbase CI / Build and Start Docker Services (push) Waiting to run
v0.5.25 ~ Improved API, Performance and Design
2025-02-12 23:34:54 +08:00
Ronald A. Richardson
ba63441e7c v0.5.25 ~ Improved API, Performance and Design 2025-02-12 23:29:43 +08:00
Ronald A. Richardson
0b807011a3 Upgraded core-api to v1.5.27 and internals to v0.0.18
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-02-05 18:45:19 +08:00
Ronald A. Richardson
80d84e1c3b Upgraded internals to v0.0.17 2025-02-05 16:07:01 +08:00
Ronald A. Richardson
08c722359a Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-02-04 23:51:58 +08:00
Ron
879409d530 Merge pull request #348 from fleetbase/dev-v0.5.24
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
📖 Catalogs & 🚚 Food Trucks for Storefront + Patches
2025-02-04 23:44:40 +08:00
Ronald A. Richardson
6105b575c6 📖 Catalogs & 🚚 Food Trucks for Storefront + Patches 2025-02-04 23:34:44 +08:00
Nikolay Stankov
1e331d70b1 feature/translate-bulgarian 2025-01-30 08:54:08 -05:00
Ronald A. Richardson
ebd9b0d8cb Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-01-30 00:33:47 +08:00
Ron
57c22eccb7 Merge pull request #344 from fleetbase/dev-v0.5.23
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.5.23 ~ More Features, More Patches
2025-01-30 01:21:02 +09:00
Ronald A. Richardson
989ca4d35e More Features, More Patches 2025-01-30 00:03:04 +08:00
Ronald A. Richardson
ec5ace214c Upgrade internals to v0.0.14 #hotfix
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-01-27 18:07:35 +08:00
Ronald A. Richardson
396e0cbf36 Upgrade internals to v0.0.13 #hotfix 2025-01-27 17:15:42 +08:00
Ronald A. Richardson
3faac3481f Upgrade storefront to v0.3.23 #hotfix
Some checks are pending
Fleetbase CI/CD / Build and Deploy the Service (push) Waiting to run
Fleetbase CI/CD / Build and Deploy the Console (push) Blocked by required conditions
2025-01-27 15:49:44 +08:00
Ronald A. Richardson
36f837a4af Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-01-27 15:18:02 +08:00
Ron
afb1c1dbdc Merge pull request #341 from fleetbase/dev-v0.5.22
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.5.22 ~ Implemented Social OAuth, Critical Patches
2025-01-27 15:37:48 +09:00
Ronald A. Richardson
0ac52bc772 v0.5.22 ~ Implemented Social OAuth, Critical Patches 2025-01-27 14:32:03 +08:00
Ronald A. Richardson
094bd6c8ce Upgraded extension BE for customer portal and storefront
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-01-15 20:57:33 +08:00
Ronald A. Richardson
aea35f6f5f hotfix fix trial days remaining component
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-01-13 12:38:43 +08:00
Ronald A. Richardson
96fa0294bc Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2025-01-13 11:21:49 +08:00
Ron
50d8ffee33 Merge pull request #337 from fleetbase/dev-v0.5.21
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.5.21 - maintenance release
2025-01-13 12:11:48 +09:00
Ronald A. Richardson
015b87ba82 v0.5.21 - maintenance release 2025-01-13 11:04:55 +08:00
Ronald A. Richardson
72ed388cd6 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud
Some checks failed
Fleetbase CI/CD / Build and Deploy the Service (push) Has been cancelled
Fleetbase CI/CD / Build and Deploy the Console (push) Has been cancelled
2025-01-11 17:46:26 +08:00
Ron
983d4e5bae Merge pull request #335 from fleetbase/dev-v0.5.20
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.5.20
2025-01-11 18:31:43 +09:00
Ronald A. Richardson
9bc78c0bcc Several major patches and refactors for storefront and new data management capabilities 2025-01-11 17:26:27 +08:00
Ronald A. Richardson
5a79a06642 Hotfix: Console Lockfile 2024-12-24 16:25:02 +08:00
Ronald A. Richardson
010a6b0d05 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-12-24 15:31:40 +08:00
Ron
8f13603f4b Merge pull request #331 from fleetbase/dev-v0.5.19
🎄 Christmas Release - v0.5.19
2024-12-24 16:01:49 +09:00
Ronald A. Richardson
c6bef55839 fix api lockfile 2024-12-24 14:55:31 +08:00
Ronald A. Richardson
dcecbf2953 Upgraded all dependencies 2024-12-24 14:46:36 +08:00
Ronald A. Richardson
08b8566b90 hotfix issue fleetbase/fleetbase#326 2024-12-24 12:53:52 +08:00
Ronald A. Richardson
7f3aa5005d Christmas release stuff 2024-12-24 12:46:06 +08:00
Ronald A. Richardson
6d138761ee Upgraded Billing Extension 2024-11-16 19:37:26 +08:00
Ronald A. Richardson
1f59d8831b Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-11-09 14:34:47 +08:00
Ron
5e36ac0aa2 Merge pull request #321 from fleetbase/dev-v0.5.18
v0.5.18 - Stability and Optimization Patches + New Console Commands to fix Lega…
2024-11-09 15:29:49 +09:00
Ronald A. Richardson
da6e8e79ba Stability and Optimization Patches + New Console Commands to fix Legacy data 2024-11-09 14:19:27 +08:00
Ronald A. Richardson
746b2142f0 Upgraded internals and billing extension 2024-11-08 10:41:48 +08:00
Ronald A. Richardson
343e07e24d Disable response cache 2024-11-08 09:53:18 +08:00
Ronald A. Richardson
dd1271b1ce add LOGROCKET_APP_ID for QA deployment 2024-11-07 18:58:49 +08:00
Ronald A. Richardson
d6094b8e29 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-11-07 18:57:29 +08:00
Ronald A. Richardson
39f00789bf hotfix deploy.sh remove config and route cache 2024-11-07 18:57:11 +08:00
Ronald A. Richardson
ffc0d0fd1a update production deploy workflow to add LOGROCKET_APP_ID 2024-11-07 18:54:42 +08:00
Ronald A. Richardson
59d7fa3de9 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-11-07 18:45:30 +08:00
Ron
f8196ccc03 Merge pull request #320 from fleetbase/dev-v0.5.17
v0.5.17
2024-11-07 19:39:55 +09:00
Ronald A. Richardson
6f1664e123 ran linter 2024-11-07 18:33:47 +08:00
Ronald A. Richardson
687af92752 * Fixed: service areas/zones creation
* Tweaked: few styling improvements
* Added: view label functions to customer portal components
* Added: bulk dispatch
* Fixed: route caching by generating and providing unique name via Fleetbase `RESTRegistrar`
* Implemented: impersonation feature for system admin
* Fixed: mail settings for smtp and added support for mailgun, sendgrid, postmark and resend
* Removed: model cache
* Improved test email HTML
* Added: self hosted instance extension install instructions
* Improved: Webhooks UI
2024-11-07 18:30:30 +08:00
Shiv Thakker
eb3f706791 Update README.md 2024-10-21 12:26:31 +08:00
Ronald A. Richardson
14c05a6c6a Upgraded core-api to v1.5.18 2024-10-18 13:54:37 +08:00
Ronald A. Richardson
5c12254a58 upgrade core-api v1.5.17 2024-10-18 05:06:05 +08:00
Ronald A. Richardson
65416833ca Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-10-17 19:40:51 +08:00
Ron
5ceb3cbc84 Merge pull request #310 from fleetbase/dev-v05.16
fix logging of api request and webhook sending
2024-10-17 19:38:02 +08:00
Ronald A. Richardson
7792cf31e2 fix logging of api request and webhook sending 2024-10-17 19:37:12 +08:00
Ronald A. Richardson
40e0de6e6b Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-10-17 17:16:09 +08:00
Ron
50f30742a8 Merge pull request #309 from fleetbase/dev-v0.5.15
v0.5.15
2024-10-17 17:09:03 +08:00
Ronald A. Richardson
c7b1a876f5 v0.5.15 - Additional recovery actions added, added ability for admins to reset user password, patches to webhook handler and logging 2024-10-17 17:02:18 +08:00
Ronald A. Richardson
5986ced2c0 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-10-15 17:58:00 +08:00
Ron
892eaeeca0 Merge pull request #306 from fleetbase/dev-v0.5.14
v0.5.14
2024-10-15 17:53:05 +08:00
Ronald A. Richardson
32f4b69697 order list overlay revamp, ability to create customer with order in consumable api, few patches and fixes 2024-10-15 17:46:36 +08:00
Ronald A. Richardson
ca260bb94c Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-10-10 19:54:43 +08:00
Ron
6317c4b2e4 Merge pull request #304 from fleetbase/dev-v0.5.13
v0.1.3 - critical patches for driver creation flow on fleetops, added ability …
2024-10-10 19:46:55 +08:00
Ronald A. Richardson
e7c229ece5 critical patches for driver creation flow on fleetops, added ability for registry to handle tar/gz bundle uploads, added registry endpoint to upload bundles using auth token, few minor patches 2024-10-10 19:35:45 +08:00
Ronald A. Richardson
95ef8ef3c9 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-10-10 11:01:02 +08:00
Ron
983a3d22b5 Merge pull request #303 from fleetbase/dev-v0.5.12
v0.5.12 - bump version
2024-10-10 10:56:59 +08:00
Ronald A. Richardson
42105380ca bump version 2024-10-10 10:56:08 +08:00
Ron
8fd4a40016 Merge pull request #302 from fleetbase/dev-v0.5.12
v1.5.12 - critical hotfix to make sure session store is set for json resources
2024-10-10 10:55:42 +08:00
Ronald A. Richardson
331e98af20 critical hotfix to make sure session store is set for json resources 2024-10-10 10:52:37 +08:00
Ronald A. Richardson
df8513cf7b Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-10-10 00:55:54 +08:00
Ron
b1d226256a Merge pull request #301 from fleetbase/dev-v0.5.11
v0.5.11 - Added Manual Verify for Users [IAM], Added ability to Transfer Org Ow…
2024-10-10 00:50:23 +08:00
Ronald A. Richardson
f1ee8b0c99 Added Manual Verify for Users [IAM], Added ability to Transfer Org Ownership and Leave Orgs, Added recovery command, fixes and patches 2024-10-10 00:49:03 +08:00
Ronald A. Richardson
e2c544b0c9 hotfix internals engine 2024-10-08 22:45:34 +08:00
Ronald A. Richardson
77b39fccf9 hotfix registry-bridge 2024-10-08 22:26:13 +08:00
Ronald A. Richardson
eaa448f762 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-10-08 21:48:20 +08:00
Ron
23d5ecfdb8 Merge pull request #300 from fleetbase/dev-v0.5.10
patches and improvements
2024-10-08 21:42:07 +08:00
Ronald A. Richardson
2795a2f1be update app router.js 2024-10-08 21:41:07 +08:00
Ron
69afdee975 Merge pull request #299 from fleetbase/dev-v0.5.10
v0.5.10 - patches and improvements
2024-10-08 21:39:34 +08:00
Ronald A. Richardson
60845b9953 patches and improvements 2024-10-08 21:33:55 +08:00
Ronald A. Richardson
627522d61c Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-10-03 17:52:43 +08:00
Ron
f3997a1bb7 Merge pull request #298 from fleetbase/dev-v0.5.9
v0.5.9
2024-10-03 17:48:38 +08:00
Ronald A. Richardson
23a691e7e7 removed ember-leaflet patches, using perm fix and improved engine boot timeout and callbacks 2024-10-03 17:43:25 +08:00
Ronald A. Richardson
3dc562987a Hotfix release 2024-10-03 14:58:39 +08:00
Ronald A. Richardson
201ac84dc9 Installed Customer Portal Extension v0.0.1 2024-10-02 20:30:38 +08:00
Ronald A. Richardson
78b1f31053 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-10-02 19:24:25 +08:00
Ron
e8ac2a3796 Merge pull request #295 from fleetbase/dev-v0.5.8
v0.5.8 - Feature: Customer Portal, Order Tracking Page, New Translations, Improved UX
2024-10-02 18:43:09 +08:00
Ronald A. Richardson
b78c59ad89 updated README roadmap 2024-10-02 18:38:17 +08:00
Ronald A. Richardson
bd71b1921b v0.5.8 ready 2024-10-02 18:34:40 +08:00
Ron
2596ccbded Merge pull request #290 from CassioDalla/console-pt-br-translation
Create pt-br.yaml File
2024-10-02 13:57:54 +08:00
Ronald A. Richardson
81159b7411 preparing for major release w/ customer portal extension and order tracking page, real time ETAs and order progress tracker info 2024-10-02 00:15:13 +08:00
Ronald A. Richardson
acc4cfba35 fix as-array utility 2024-09-06 12:18:11 +08:00
Ronald A. Richardson
ea47bdc09d little progress and bugfixes 2024-09-06 12:17:30 +08:00
Ronald A. Richardson
63cf8128c0 Hotfix: patch CompanyObserver in billing module 2024-09-04 12:41:02 +08:00
Ronald A. Richardson
c60c460257 Feature: Customer Portal, improved Customer, Contact, and Vendor Management 2024-09-04 12:31:10 +08:00
Ronald A. Richardson
5d66c7a35f Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-08-31 16:26:51 +08:00
Ron
dc00ac3892 Merge pull request #294 from fleetbase/dev-v0.5.7
upgrade core-api
2024-08-31 15:22:56 +07:00
Ronald A. Richardson
f18ec886a7 upgrade core-api 2024-08-31 16:21:45 +08:00
Ronald A. Richardson
0603888393 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-08-31 16:15:52 +08:00
Ron
f039b61d79 Merge pull request #293 from fleetbase/dev-v0.5.7
hotfix for resource loading and relation loading for organizations
2024-08-31 15:01:36 +07:00
Ronald A. Richardson
248f70e31c hotfix for resource loading and relation loading for organizations 2024-08-31 15:51:30 +08:00
Ronald A. Richardson
cd50d349f8 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-08-30 18:21:55 +08:00
Ron
6bc76a1b33 Merge pull request #292 from fleetbase/dev-v0.5.6
v0.5.6 - hotfix only load organization with valid owners - no stale org
2024-08-30 17:18:07 +07:00
Ronald A. Richardson
30695b3ebe hotfix only load organization with valid owners - no stale org 2024-08-30 18:06:42 +08:00
Ronald A. Richardson
e478767a60 Fixed Composer Lockfile 2024-08-30 16:28:02 +08:00
Ronald A. Richardson
17cb0cd274 update lockfile for deployment 2024-08-30 15:58:14 +08:00
Ronald A. Richardson
a3289ddd41 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-08-30 15:36:39 +08:00
Ron
7ff9c24ad5 Merge pull request #288 from fleetbase/dev-v0.5.5
v0.5.5 - Documentation & README Updates
2024-08-30 14:20:57 +07:00
Ronald A. Richardson
1a9b9c06e5 fully implemented iam permission based restrictions and controls, few bugfixes and improvements 2024-08-30 15:14:56 +08:00
Ronald A. Richardson
5f949c3b7f implementing IAM permission controls, policies and roles 2024-08-13 20:26:32 +08:00
CassioDalla
211a3a9808 Create pt-br.yaml File
Added Brazilian Portuguese translation file to the project. It would be nice if another translator reviewed it to make sure everything is correct.
2024-08-10 16:04:45 -03:00
Ronald A. Richardson
0e5e4e07dd updating docs WIP, and updated README 2024-08-08 17:01:18 +08:00
Ronald A. Richardson
ff8986541c Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-08-06 14:00:56 +08:00
Ronald A. Richardson
2eabfc4698 version 0.5.4 2024-08-06 13:51:29 +08:00
Ron
77c2c01e58 Merge pull request #286 from fleetbase/dev-v0.5.5
v0.5.5
2024-08-06 12:48:41 +07:00
Ronald A. Richardson
7c5b5b5858 again, fix depn order 2024-08-06 13:33:29 +08:00
Ronald A. Richardson
aad072cf4c reverted dependency order in package.json 2024-08-06 13:32:39 +08:00
Ronald A. Richardson
c1c6dcafd8 ordered packages 2024-08-06 13:30:34 +08:00
Ronald A. Richardson
61992ee924 fix lockfile 2024-08-06 13:28:39 +08:00
Ronald A. Richardson
b18d6197bc upgraded registry bridge and updated erd 2024-08-06 13:25:32 +08:00
Ronald A. Richardson
04d0c126de added flespi extension 2024-08-01 10:55:20 +08:00
Ronald A. Richardson
ad43f74d5c Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-31 18:13:13 +08:00
Ronald A. Richardson
3c013a3817 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-30 22:54:57 +08:00
Ronald A. Richardson
4392c7e3ff Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-25 19:06:03 +08:00
Ronald A. Richardson
97dfbedd1a Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-25 18:43:36 +08:00
Ronald A. Richardson
6d13f22a98 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-23 13:32:42 +08:00
Ronald A. Richardson
2c09c87bb6 fix console depn install in cd 2024-07-23 12:31:29 +08:00
Ronald A. Richardson
f7f6991ef3 bump pnpm version in cd workflow 2024-07-23 11:46:44 +08:00
Ronald A. Richardson
73acd4833c fix cd workflow 2024-07-23 11:30:14 +08:00
Ronald A. Richardson
1c3c4c16a5 use node 18 in cd 2024-07-23 11:11:43 +08:00
Ronald A. Richardson
5d01438dc9 fix env set in workflow 2024-07-23 10:59:16 +08:00
Ronald A. Richardson
9d004410ee Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-23 10:46:47 +08:00
Ronald A. Richardson
3a396f3b54 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-23 10:34:32 +08:00
Ronald A. Richardson
e86b970fc8 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-06 13:18:22 +08:00
Ronald A. Richardson
122a0d186a Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-05 17:09:56 +08:00
Ronald A. Richardson
7e258f698f Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-02 17:53:20 +08:00
Ronald A. Richardson
65ef642315 fixed composer.lock 2024-07-02 16:00:17 +08:00
Ronald A. Richardson
d79f034dbd Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-02 15:41:58 +08:00
Ronald A. Richardson
05b7d5e112 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-07-02 15:40:58 +08:00
Ronald A. Richardson
61779ab102 Trigger Deploy 2024-07-01 16:42:55 +08:00
Ronald A. Richardson
a287c05380 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-05-30 19:57:16 +08:00
Ronald A. Richardson
ecc41e587e Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-05-17 16:58:14 +08:00
Ronald A. Richardson
166529f9b4 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-05-15 14:39:54 +08:00
Ronald A. Richardson
189547f9de Upgrade fleetbase/billing#^0.0.9 with hotfix for getSytemResourceModels utility function 2024-05-04 13:56:59 +08:00
Ronald A. Richardson
90a42e8a93 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-05-04 13:19:13 +08:00
Ronald A. Richardson
d28b1d41fb Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-04-30 19:40:08 +08:00
Ronald A. Richardson
b056ef62b0 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-04-30 18:11:33 +08:00
Ronald A. Richardson
e70cbacbc2 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-04-17 16:58:07 +08:00
Ronald A. Richardson
fbd4a7490a Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-04-13 20:28:50 +08:00
Ronald A. Richardson
b9b0eb308b Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-04-02 18:06:15 +08:00
Ronald A. Richardson
48e1b89ec8 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-03-27 21:09:51 +08:00
Ronald A. Richardson
5e02c95b66 Upgrade extension 'fleetops' to version v0.4.22 2024-03-19 19:25:51 +08:00
Ronald A. Richardson
db8b5c4d6a Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-03-17 12:32:42 +08:00
Ronald A. Richardson
aa214ccad7 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-03-15 17:33:37 +08:00
Ronald A. Richardson
cdd5524cf3 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-03-13 15:31:47 +08:00
Ronald A. Richardson
d99cefd2a4 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-03-12 18:25:56 +08:00
Ronald A. Richardson
1c58fd43c3 v0.4.10l fixed console lockfile 2024-03-11 21:56:26 +08:00
Ronald A. Richardson
9226394159 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-03-11 21:19:32 +08:00
Ronald A. Richardson
9b23b39f32 upgraded to v0.4.9 2024-02-24 17:07:49 +08:00
Ronald A. Richardson
5310fc3ff3 upgraded to v0.4.8 2024-02-23 13:52:21 +08:00
Ronald A. Richardson
9569053f50 upgraded to v0.4.7 2024-02-22 18:16:12 +08:00
Ronald A. Richardson
b08c054b99 upgraded to v0.4.6 2024-02-21 18:59:10 +08:00
Ronald A. Richardson
2e517f2f95 hotfix core-api w/ composer lock 2024-02-17 19:53:53 +08:00
Ronald A. Richardson
7038d375b0 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-02-17 19:31:14 +08:00
Ronald A. Richardson
d5ea7f7790 Upgraded fleetops-api v0.4.11 - Fixes deprecation error/warning which occurs in some environments Implicit conversion from float x to int loses precision when creating a DistanceMatrix object 2024-02-16 03:04:16 +07:00
Ronald A. Richardson
4eb4b04121 use fixed fleetbase/laravel-mysql-spatial v1.0.2 2024-02-16 01:34:01 +07:00
Ronald A. Richardson
24c5b93005 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-02-16 00:16:49 +07:00
Ronald A. Richardson
80610b9a48 Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-02-15 23:52:27 +07:00
Ronald A. Richardson
9e5551972e upgraded to v0.4.3 2024-02-13 17:02:37 +08:00
Ronald A. Richardson
b784f890f3 upgraded to v0.4.2 2024-02-13 14:45:20 +08:00
Ronald A. Richardson
797a3d61fe fix router 2024-02-13 13:55:57 +08:00
Ronald A. Richardson
d2f0bfe83e upgraded to v0.4.1 2024-02-13 13:54:46 +08:00
Ronald A. Richardson
f28ad85c1a Upgraded fleetops to v0.4.8 for LocationService minifcation hotfix 2024-02-09 19:07:32 +08:00
Ronald A. Richardson
d7b0826f3f upgrade core-api to v1.4.1 2024-02-08 19:07:10 +08:00
Ronald A. Richardson
dd6008a8aa dont copy auth.json 2024-02-08 17:44:52 +08:00
Ronald A. Richardson
6671fefaaa Upgraded to v0.4.0 2024-02-08 17:41:02 +08:00
Ronald A. Richardson
7136f6195c v0.3.10 upgraded lockfile 2024-02-01 20:19:52 +08:00
Ronald A. Richardson
2384887620 Upgraded to v0.3.10 2024-02-01 20:14:31 +08:00
Ronald A. Richardson
a2778f1552 Upgraded to v0.3.9 2024-01-25 20:10:39 +08:00
Ronald A. Richardson
acfda5ed1a Merge branch 'main' of github.com:fleetbase/fleetbase into cloud 2024-01-24 18:32:51 +08:00
Ronald A. Richardson
e08255007a remove later hook from extensions initializer 2024-01-23 21:37:22 +08:00
Ronald A. Richardson
41761ea50e add delay to extensions initialization step 2024-01-23 21:20:51 +08:00
Ronald A. Richardson
5c623819ed use node:18.15.0-alpine for console build 2024-01-23 20:13:23 +08:00
Ronald A. Richardson
2bd885b1a2 Upgraded fleetbase/core-api to v1.3.11 2024-01-19 20:16:06 +08:00
Ronald A. Richardson
88c3842441 Upgraded to v0.3.7 2024-01-19 19:55:47 +08:00
Ronald A. Richardson
2c2a4121a8 Upgraded fleetbase/core-api to v1.3.9 with critical patches 2024-01-19 17:02:47 +08:00
Ronald A. Richardson
aadd03f14b upgrade fleetbase/core-api to v1.3.8 2024-01-18 20:00:32 +08:00
Ronald A. Richardson
706e94270d upgraded to v0.3.6 2024-01-18 19:18:52 +08:00
Ronald A. Richardson
1dabc375f9 upgraded to v0.3.5 2024-01-12 18:44:52 +08:00
Ronald A. Richardson
0efec46155 updated production env backend vars 2024-01-08 14:42:58 +08:00
Ronald A. Richardson
8bb2c6b65d fix socketcluster port for environments 2024-01-03 17:37:35 +08:00
Ronald A. Richardson
1c0af1a119 set correct values in .env files for console 2024-01-03 13:27:10 +08:00
Ronald A. Richardson
dd65ee619b upgraded to v0.3.4 2023-12-27 12:01:39 +08:00
Ronald A. Richardson
e790a0e123 upgraded to v0.3.3 2023-12-27 11:07:33 +08:00
Ronald A. Richardson
723e3ca3d1 fix composer file 2023-11-27 10:23:44 +08:00
Ronald A. Richardson
4eb706d33e upgraded to v0.3.1 / cloud version 2023-11-27 10:19:56 +08:00
314 changed files with 37576 additions and 20399 deletions

64
.github/workflows/build-binaries.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: Build Fleetbase Binaries
on:
workflow_dispatch:
workflow_run:
workflows: ["Create Release"]
types: [completed]
permissions:
contents: write
env:
DIST_DIR: builds/dist
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build-linux:
name: Linux Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Linux binary
run: |
chmod +x ./builds/linux/build-linux.sh
./builds/linux/build-linux.sh
- name: Upload Linux binary
if: github.event_name == 'workflow_run'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.event.workflow_run.head_branch }}
files: |
${{ env.DIST_DIR }}/fleetbase-linux-x86_64
draft: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-macos:
name: macOS (ARM64) Build
needs: build-linux
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Install build dependencies
run: |
brew update
brew install autoconf automake coreutils asdf php@8.4
source "$(brew --prefix asdf)/libexec/asdf.sh"
asdf plugin add php https://github.com/asdf-community/asdf-php.git
- name: Build macOS binary
run: |
chmod +x ./builds/osx/build-osx.sh
./builds/osx/build-osx.sh
- name: Upload Linux binary
if: github.event_name == 'workflow_run'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.event.workflow_run.head_branch }}
files: |
${{ env.DIST_DIR }}/fleetbase-darwin-arm64
draft: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -58,6 +58,43 @@ jobs:
files: |
./docker-bake.hcl
- name: Resolve ECS Targets
run: |
set -euo pipefail
# Detect naming scheme by checking if new cluster exists
NEW_CLUSTER="${PROJECT}-${STACK}-cluster"
if aws ecs describe-clusters --region "${AWS_REGION}" --clusters "${NEW_CLUSTER}" \
--query "clusters[?status=='ACTIVE'].clusterArn" --output text 2>/dev/null | grep -q .; then
# New scheme: use cluster suffix and service prefixes
CLUSTER="${NEW_CLUSTER}"
SERVICE_PREFIX="${PROJECT}-${STACK}-"
SERVICE_BASE="api"
else
# Legacy scheme: no suffixes/prefixes
CLUSTER="${PROJECT}-${STACK}"
SERVICE_PREFIX=""
SERVICE_BASE="app"
fi
# Build service names
API_SERVICE="${SERVICE_PREFIX}${SERVICE_BASE}"
SCHEDULER_SERVICE="${SERVICE_PREFIX}scheduler"
EVENTS_SERVICE="${SERVICE_PREFIX}events"
TASK_DEF="${PROJECT}-${STACK}-${SERVICE_BASE}"
# Get container name from task definition
CONTAINER_NAME="$(aws ecs describe-task-definition --task-definition "$TASK_DEF" \
--query 'taskDefinition.containerDefinitions[0].name' --output text 2>/dev/null || echo "$SERVICE_BASE")"
{
echo "CLUSTER=$CLUSTER"
echo "API_SERVICE=$API_SERVICE"
echo "SCHEDULER_SERVICE=$SCHEDULER_SERVICE"
echo "EVENTS_SERVICE=$EVENTS_SERVICE"
echo "TASK_DEF=$TASK_DEF"
echo "CONTAINER_NAME=$CONTAINER_NAME"
} >> "$GITHUB_ENV"
- name: Download ecs-tool
run: |
wget -O ecs-tool.tar.gz https://github.com/springload/ecs-tool/releases/download/1.9.6/ecs-tool_1.9.6_linux_amd64.tar.gz && tar -xvf ecs-tool.tar.gz ecs-tool
@@ -65,9 +102,21 @@ jobs:
- name: Deploy the images 🚀
run: |-
set -eu
# run deploy.sh script before deployments
env "ECS_RUN.SERVICE=app" "ECS_RUN.LAUNCH_TYPE=FARGATE" ./ecs-tool run -l "ecs-tool" --image_tag '{container_name}-${{ env.VERSION }}' --cluster ${{ env.PROJECT }}-${{ env.STACK }} --task_definition ${{ env.PROJECT }}-${{ env.STACK }}-app --container_name app ./deploy.sh
./ecs-tool deploy --image_tag '{container_name}-${{ env.VERSION }}' --cluster ${{ env.PROJECT }}-${{ env.STACK }} -s app -s scheduler -s events
# Run deploy.sh script before deployments
env "ECS_RUN.SERVICE=${API_SERVICE}" "ECS_RUN.LAUNCH_TYPE=FARGATE" \
./ecs-tool run -l "ecs-tool" \
--image_tag '{container_name}-${{ env.VERSION }}' \
--cluster "${CLUSTER}" \
--task_definition "${TASK_DEF}" \
--container_name "${CONTAINER_NAME}" \
./deploy.sh
# Deploy services
./ecs-tool deploy \
--image_tag '{container_name}-${{ env.VERSION }}' \
--cluster "${CLUSTER}" \
-s "${API_SERVICE}" -s "${SCHEDULER_SERVICE}" -s "${EVENTS_SERVICE}"
build_frontend:
name: Build and Deploy the Console
@@ -132,25 +181,32 @@ jobs:
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Check for _GITHUB_AUTH_TOKEN and create .npmrc
- name: Create and Setup .npmrc
run: |
if [[ -n "${{ secrets._GITHUB_AUTH_TOKEN }}" ]]; then
echo "//npm.pkg.github.com/:_authToken=${{ secrets._GITHUB_AUTH_TOKEN }}" > .npmrc
fi
if [[ -n "${{ secrets.FLEETBASE_REGISTRY_TOKEN }}" ]]; then
echo "//registry.fleetbase.io/:_authToken=${{ secrets.FLEETBASE_REGISTRY_TOKEN }}" >> .npmrc
echo "@fleetbase:registry=https://registry.fleetbase.io" >> .npmrc
fi
working-directory: ./console
- name: Set Env Variables for QA
if: startsWith(github.ref, 'refs/heads/deploy/qa')
run: |
echo "STRIPE_KEY=${{ secrets.STRIPE_TEST_KEY }}" >> ./environments/.env.production
echo "EXTENSIONS=@fleetbase/billing-engine,@fleetbase/internals-engine" >> ./environments/.env.production
echo "LOGROCKET_APP_ID=${{ secrets.LOGROCKET_APP_ID }}" >> ./environments/.env.production
echo "EXTENSIONS=@fleetbase/billing-engine,@fleetbase/internals-engine,@fleetbase/aws-marketplace" >> ./environments/.env.production
working-directory: ./console
- name: Set Env Variables for Production
if: startsWith(github.ref, 'refs/heads/deploy/production')
run: |
echo "STRIPE_KEY=${{ secrets.STRIPE_KEY }}" >> ./environments/.env.production
echo "EXTENSIONS=@fleetbase/billing-engine,@fleetbase/internals-engine" >> ./environments/.env.production
echo "LOGROCKET_APP_ID=${{ secrets.LOGROCKET_APP_ID }}" >> ./environments/.env.production
echo "EXTENSIONS=@fleetbase/billing-engine,@fleetbase/internals-engine,@fleetbase/aws-marketplace" >> ./environments/.env.production
echo "DISABLE_RUNTIME_CONFIG=true" >> ./environments/.env.production
working-directory: ./console
- name: Install dependencies
@@ -169,6 +225,11 @@ jobs:
set -u
DEPLOY_BUCKET=${STATIC_DEPLOY_BUCKET:-${{ env.PROJECT }}-${{ env.STACK }}}
NEW_BUCKET="${PROJECT}-${STACK}-console"
if aws s3api head-bucket --bucket "$NEW_BUCKET" 2>/dev/null; then
DEPLOY_BUCKET="$NEW_BUCKET"
fi
# this value will come from the dotenv above
echo "Deploying to $DEPLOY_BUCKET"
wget -O- https://github.com/bep/s3deploy/releases/download/v2.11.0/s3deploy_2.11.0_linux-amd64.tar.gz | tar xzv -f - s3deploy

21
.github/workflows/create-release.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Create Release
on:
push:
tags:
- 'v*'
jobs:
create:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Publish GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
body_path: RELEASE.md
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -0,0 +1,61 @@
name: Discord Announcement
on:
workflow_run:
workflows: ["Create Release"]
types: [completed]
workflow_dispatch:
inputs:
tag:
description: "Release tag to announce (e.g. v0.7.1)"
required: true
jobs:
discord_announcement:
runs-on: ubuntu-latest
steps:
# 1⃣ Figure out which tag were talking about
- id: vars
shell: bash
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
TAG="${{ github.event.inputs.tag }}"
else
TAG="${{ github.event.workflow_run.head_branch }}"
fi
echo "TAG=$TAG" >> "$GITHUB_ENV"
# 2⃣ Check out the exact commit for that tag
- uses: actions/checkout@v3
with:
ref: ${{ env.TAG }}
fetch-depth: 1
# 3⃣ Stash RELEASE.md in an env var (one atomic write → no EOF error)
- id: prep-body
shell: bash
run: |
body=$(<RELEASE.md)
max=4000
[[ ${#body} -gt $max ]] && body="${body:0:$max}…" # add ellipsis if trimmed
{
echo "body<<EOF"
echo "$body"
echo "EOF"
} >> "$GITHUB_OUTPUT"
# 4⃣ Fire the webhook
- uses: tsickert/discord-webhook@v5.3.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
username: Fleetbase
content: |
@everyone
📦 **Fleetbase ${{ env.TAG }} released!**
<https://github.com/${{ github.repository }}/releases/tag/${{ env.TAG }}>
embed-title: "Fleetbase ${{ env.TAG }} — release notes"
embed-url: "https://github.com/fleetbase/fleetbase/releases/tag/${{ env.TAG }}"
embed-description: ${{ steps.prep-body.outputs.body }}
embed-color: 4362730 # 0x4291EA (Fleetbase Blue)

View File

@@ -1,48 +0,0 @@
name: Discord Announcement
on:
push:
tags:
- "v*"
jobs:
discord_announcement:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Get tag message
id: tag
run: |
echo "::set-output name=version::$(git describe --tags --abbrev=0)"
if [[ "${ACT}" == "true" ]]; then
# If running with act, use an environment variable for the tag message
echo "::set-output name=message::$(echo -e "${TAG_MESSAGE}" | base64)"
else
# If running on GitHub, use git to get the tag message
echo "::set-output name=message::$(git tag -l --format='%(contents)' $(git describe --tags --abbrev=0) | base64)"
fi
- name: Print tag message
run: echo "${{ steps.tag.outputs.message }}"
- name: Get tag name
id: get_tag
run: echo "::set-output name=tag::${GITHUB_REF/refs\/tags\//}"
- name: Decode message
id: decode
run: |
echo "Decoding message..."
echo "::set-output name=message::$(echo '${{ steps.tag.outputs.message }}' | base64 --decode)"
- name: Send message to Discord
uses: tsickert/discord-webhook@v5.3.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
content: "@everyone \n📦 New Fleetbase Version ${{ steps.get_tag.outputs.tag }} Released!\n${{ steps.decode.outputs.message }} \nVersion: ${{ steps.get_tag.outputs.tag }} \n[Release Notes for ${{ steps.get_tag.outputs.tag }}](https://github.com/fleetbase/fleetbase/releases/tag/${{ steps.get_tag.outputs.tag }})"
username: Fleetbase

View File

@@ -1,4 +1,4 @@
name: Fleetbase CI/CD
name: Fleetbase GCP CI/CD
on:
push:

View File

@@ -0,0 +1,50 @@
name: Fleetbase Docker Images
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
branch:
description: 'Branch to build from'
required: false
default: 'main'
version:
description: 'Image version tag (e.g., v0.7.1-beta)'
required: false
jobs:
docker-release:
name: Build and Push Docker Images
runs-on: ubuntu-latest
env:
REGISTRY: fleetbase
VERSION: ${{ github.event.inputs.version || (github.ref_type == 'tag' && startsWith(github.ref_name, 'v') && github.ref_name) || 'manual' }}
steps:
- name: Checkout Repo
uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.branch || github.ref_name }}
submodules: recursive
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Build and Push Console & API Images
uses: docker/bake-action@v2
with:
push: true
targets: |
fleetbase-console
fleetbase-api
files: |
./docker-bake.hcl

25
.gitignore vendored
View File

@@ -3,6 +3,7 @@
.env.backup
.phpunit.result.cache
.pnpm-store
.tool-versions
docker-compose.override.yml
npm-debug.log
yarn-error.log
@@ -16,6 +17,8 @@ api/composer.dev.json
api/composer-install-dev.sh
api/auth.json
api/crontab
api/go-crond
api/.fleetbase-id
act.sh
composer-auth.json
docker/database/*
@@ -30,7 +33,25 @@ packages/flespi
packages/loconav
packages/internals
packages/projectargus-engine
# wip
packages/customer-portal
packages/solid
packages/aws-marketplace
packages/countries
packages/fliit
packages/samsara
packages/solid*
packages/valhalla
packages/vroom
solid
verdaccio
verdaccio
# asdf
.tools-versions
# binary build resources
builds/osx/frankenphp
# build artifacts
/builds/dist/
/builds/linux/spc/downloads/*
*.exe
*.dll
*.so
*.dylib

View File

@@ -8,6 +8,7 @@
http://:8000 {
root * /fleetbase/api/public
encode zstd br gzip
php_server {
resolve_root_symlink
}

143
README.md
View File

@@ -7,13 +7,13 @@
<p align="center" dir="auto">
Modular logistics and supply chain operating system
<br>
<a href="https://docs.fleetbase.io/" rel="nofollow">Documentation</a>
<a href="https://docs.fleetbase.io/" rel="nofollow" target="_fleetbase_docs">Documentation</a>
·
<a href="https://console.fleetbase.io" rel="nofollow">Cloud Version</a>
<a href="https://console.fleetbase.io" rel="nofollow" target="_fleetbase_console">Cloud Version</a>
·
<a href="https://fleetbase.apichecker.com" target="_api_status" rel="nofollow">API Status</a>
<a href="https://console.fleetbase.io/aws-marketplace" rel="nofollow" target="_aws_marketplace">Deploy on AWS</a>
·
<a href="https://meetings.hubspot.com/shiv-thakker" rel="nofollow">Book a Demo</a>
<a href="https://tally.so/r/3NBpAW" rel="nofollow">Book a Demo</a>
·
<a href="https://discord.gg/V7RVWRQ2Wm" target="discord" rel="nofollow">Discord</a>
</p>
@@ -25,23 +25,49 @@
Fleetbase is a modular logistics and supply chain operating system designed to streamline management, planning, optimization, and operational control across various sectors of the supply chain industry.
<p align="center" dir="auto">
<img src="https://github.com/fleetbase/fleetbase/assets/816371/125348c9-c88a-49fe-b098-9abec9d7dff8" alt="Fleetbase Console" width="1200" style="max-width: 100%;" />
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/fleetbase_overview.png" alt="Fleetbase Console" width="1200" style="max-width: 100%;" />
</p>
## Visual Feature Showcase
<p align="center" dir="auto">
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/order-board-kanban.png" alt="Fleetbase Order Board" width="1200" style="max-width: 100%;" />
<em>Visualize and manage your orders with a dynamic Kanban board.</em>
</p>
<p align="center" dir="auto">
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/order-workflow-config.png" alt="Fleetbase Order Workflow Configuration" width="1200" style="max-width: 100%;" />
<em>Create custom order flows and automation with the intuitive workflow builder.</em>
</p>
<p align="center" dir="auto">
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/order-map-view.png" alt="Fleetbase Order Map View" width="1200" style="max-width: 100%;" />
<em>Track individual orders in real-time on an interactive map.</em>
</p>
<p align="center" dir="auto">
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/live-map-tracking.png" alt="Fleetbase Live Map Tracking" width="1200" style="max-width: 100%;" />
<em>Get a complete overview of your fleet and active orders on a live map.</em>
</p>
<p align="center" dir="auto">
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/fleet-map-zones.png" alt="Fleetbase Fleet Map with Zones" width="1200" style="max-width: 100%;" />
<em>Define and manage service areas and zones for your fleet.</em>
</p>
**Quickstart**
```bash
git clone git@github.com:fleetbase/fleetbase.git
cd fleetbase
docker-compose up -d
docker exec -ti fleetbase-application-1 bash
sh deploy.sh
cd fleetbase && ./scripts/docker-install.sh
```
## 📖 Table of contents
- [Features](#-features)
- [Install](#-install)
- [Deploy on AWS](#-deploy-on-aws-in-one-click)
- [Extensions](#-extensions)
- [Apps](#-apps)
- [Roadmap](#-roadmap)
- [Bugs and Feature Requests](#-bugs-and--feature-requests)
@@ -74,10 +100,7 @@ Make sure you have both the latest versions of docker and docker-compose install
```bash
git clone git@github.com:fleetbase/fleetbase.git
cd fleetbase
docker-compose up -d
docker exec -ti fleetbase-application-1 bash
sh deploy.sh
cd fleetbase && ./scripts/docker-install.sh
```
### Accessing Fleetbase
@@ -88,30 +111,100 @@ Fleetbase API: http://localhost:8000
### Additional Configurations
**CORS:** If youre installing directly on a server you may need to add your IP address or domain to the `api/config/cors.php` file in the `allowed_hosts` array.
**CORS:** If youre installing directly on a server you will need to configure the environment variables to the application container:
```
CONSOLE_HOST=http://{yourhost}:4200
```
If you have additional applications or frontends you can use the environment variable `FRONTEND_HOSTS` to add a comma delimited list of additioal frontend hosts.
**Application Key** If you get an issue about a missing application key just run:
```bash
docker compose exec application bash -c "php artisan key:generate --show"
```
Next copy this value to the `APP_KEY` environment variable in the application container and restart.
**Routing:** Fleetbase ships with its own OSRM server hosted at `[bundle.routing.fleetbase.io](https://bundle.routing.fleetbase.io)` but youre able to use your own or any other OSRM compatible server. You can modify this in the `console/environments` directory by modifying the env file of the environment youre deploying and setting the `OSRM_HOST` to the OSRM server for Fleetbase to use.
**Routing:** Fleetbase ships with a default OSRM server hosted by `[router.project-osrm.org](https://router.project-osrm.org)` but youre able to use your own or any other OSRM compatible server. You can modify this in the `console/environments` directory by modifying the .env file of the environment youre deploying and setting the `OSRM_HOST` to the OSRM server for Fleetbase to use.
**Services:** There are a few environment variables which need to be set for Fleetbase to function with full features. If youre deploying with docker then its easiest to just create a `docker-compose.override.yml` and supply the environment variables in this file.
**Services:** There are a few environment variables which need to be set for Fleetbase to function with full features. If you're deploying with docker then it's easiest to just create a `docker-compose.override.yml` and supply the environment variables in this file.
```yaml
version: 3.8
version: "3.8"
services:
application:
environment:
CONSOLE_HOST: http://localhost:4200
MAIL_MAILER: (ses, smtp, mailgun, postmark, sendgrid)
OSRM_HOST: https://bundle.routing.fleetbase.io
OSRM_HOST: https://router.project-osrm.org
IPINFO_API_KEY:
GOOGLE_MAPS_API_KEY:
GOOGLE_MAPS_LOCALE: us
TWILIO_SID:
TWILIO_TOKEN:
TWILIO_FROM:
CONSOLE_HOST: http://localhost:4200
socket:
environment:
# IMPORTANT: Configure WebSocket origins for security
# Development (localhost only - include WebSocket protocols):
SOCKETCLUSTER_OPTIONS: '{"origins":"http://localhost:*,https://localhost:*,ws://localhost:*,wss://localhost:*"}'
# Production (replace with your actual domain):
# SOCKETCLUSTER_OPTIONS: '{"origins":"https://yourdomain.com:*,wss://yourdomain.com:*"}'
```
**WebSocket Security:** The `SOCKETCLUSTER_OPTIONS` environment variable controls which domains can connect to the WebSocket server. Always restrict origins to your specific domains in production to prevent security vulnerabilities.
You can learn more about full installation, and configuration in the [official documentation](https://docs.fleetbase.io/getting-started/install).
## 🚀 Deploy on AWS in One Click
Deploy your complete Fleetbase logistics platform on AWS with enterprise-grade security, scalability, and reliability. No DevOps expertise required!
[![Deploy to AWS](https://img.shields.io/badge/Deploy%20to%20AWS-FF9900?style=for-the-badge&logo=amazon-aws&logoColor=white)](https://console.fleetbase.io/aws-marketplace)
### ✨ What You Get
- **Complete AWS Infrastructure**: ECS Fargate, RDS MySQL, ElastiCache Redis, S3, CloudFront, and more
- **25-Minute Setup**: From zero to production-ready logistics platform
- **Enterprise Security**: VPC isolation, encrypted storage, secrets management
- **Auto-Scaling**: Handle traffic spikes with ECS Fargate auto-scaling
- **High Availability**: Multi-AZ deployment with 99.9% uptime SLA
- **Cost Optimized**: Pay-as-you-use with optimized resource allocation
### 🏗️ Infrastructure Included
Your AWS deployment includes a complete, production-ready infrastructure stack:
- **Compute**: ECS Fargate cluster with auto-scaling services
- **Database**: RDS MySQL 8.0 with automated backups and Multi-AZ support
- **Cache**: ElastiCache Redis for high-performance caching
- **Storage**: S3 object storage with CloudFront CDN for global distribution
- **Networking**: VPC with private subnets, NAT gateways, and security groups
- **Load Balancing**: Application Load Balancer with SSL certificates
- **Monitoring**: CloudWatch logs, container insights, and health monitoring
- **Messaging**: SQS message queues for background job processing
[**🚀 Deploy Now**](https://console.fleetbase.io/aws-marketplace) | [**📖 Learn More**](https://docs.fleetbase.io/category/deploying/aws)
# 🧩 Extensions
Extensions are modular components that enhance the functionality of your Fleetbase instance. They allow you to add new features, customize existing behavior, or integrate with external systems.
You can find extensions available from the official [Fleetbase Console](https://console.fleetbase.io), here you will also be able get your registry token to install extensions to a self-hosted Fleetbase instance.
Additionally you're able to develop and publish your own extensions as well which you can read more about developing extensions via the [extension building guide](https://docs.fleetbase.io/developers/building-an-extension).
## ⌨️ Fleetbase CLI
The Fleetbase CLI is a powerful tool designed to simplify the management of extensions for your Fleetbase instance. With the CLI, you can effortlessly handle authentication, install and uninstall extensions, and scaffold new extensions if you are developing your own.
Get started with the CLI with npm:
```bash
npm i -g @fleetbase/cli
```
Once installed, you can access a variety of commands to manage your Fleetbase extensions.
# 📱 Apps
Fleetbase offers a few open sourced apps which are built on Fleetbase which can be cloned and customized. Every app is built so that the Fleetbase instance can be switched out whether on-premise install or cloud hosted.
@@ -122,13 +215,10 @@ Fleetbase offers a few open sourced apps which are built on Fleetbase which can
</ul>
## 🛣️ Roadmap
1. **Extensions Registry and Marketplace** ~ Allows users to publish and sell installable extensions on Fleetbase instances.
2. **Inventory and Warehouse Management** ~ Pallet will be Fleetbases first official extension for WMS & Inventory.
3. **Customer Facing Views** ~ Extensions will be able to create public/customer facing views tracking and management from outside of the console UI.
4. **Binary Builds** ~ Run Fleetbase from a single binary.
5. **Fleetbase CLI** ~ Official CLI for publishing and managing extensions, as well as scaffolding extensions.
6. **Fleetbase for Desktop** ~ Desktop builds for OSX and Windows.
7. **Custom Maps and Routing Engines** ~ Feature to enable easy integrations with custom maps and routing engines like Google Maps or Mapbox etc…
1. **Inventory and Warehouse Management** ~ Pallet will be Fleetbases first official extension for WMS & Inventory.
2. **Accounting and Invoicing** ~ Ledger will be Fleetbases first official extension accounting and invoicing.
3. **AI** ~ AI Agent intrgation for system and workflows.
4. **Dynamic Rules System** ~ Trigger events, tasks jobs from a rule builder on resources.
## 🪲 Bugs and 💡 Feature Requests
@@ -164,3 +254,4 @@ Get updates on Fleetbase's development and chat with the project maintainers and
# License & Copyright
Fleetbase is made available under the terms of the <a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank">GNU Affero General Public License 3.0 (AGPL 3.0)</a>. For other licenses <a href="mailto:hello@fleetbase.io" target="_blank">contact us</a>.

36
RELEASE.md Normal file
View File

@@ -0,0 +1,36 @@
# 🚀 Fleetbase v0.7.25 — 2025-12-29
> "New SMS service to support multiple SMS providers + framework improvements"
---
## ✨ Highlights
- Removed `window.Fleetbase` for improved frontend security
- Improved query optimizations
- Added new SMS service to support multiple SMS providers
---
## ⚠️ Breaking Changes
- None 🙂
---
## 🔧 Upgrade Steps
```bash
# Pull latest version
git pull origin main --no-rebase
# Update docker
docker compose pull
docker compose down && docker compose up -d
# Run deploy script
docker compose exec application bash -c "./deploy.sh"
```
---
## Need help?
Join the discussion on [GitHub Discussions](https://github.com/fleetbase/ember-ui/discussions) or drop by [#fleetbase on Discord](https://discord.com/invite/HnTqQ6zAVn)

100
TRANSLATING.md Normal file
View File

@@ -0,0 +1,100 @@
# Contributing to Fleetbase Translations
First off, thank you for considering contributing to Fleetbase translations! Your efforts help make Fleetbase accessible to a global audience. This guide will walk you through the process of adding or updating language translations for the Fleetbase platform and its various extensions.
## Understanding the Structure
Fleetbase is a modular system. The main application, known as Fleetbase Console, has its own set of translations. Additionally, each extension (like FleetOps or Storefront) also contains its own translation files. This means that to provide a complete translation for a specific language, you may need to contribute to multiple repositories.
- **Main Application (`fleetbase/fleetbase`)**: Contains the core translation files for the Fleetbase Console.
- **Extensions/Modules**: Each extension has its own repository and its own set of translation files.
## File Format and Location
All translation files are in the **YAML** format (`.yaml` or `.yml`). The base language for all translations is American English (`en-us.yaml`).
- In the main `fleetbase/fleetbase` repository, the translation files are located at `./console/translations/`.
- In each extension repository, the translation files are located at `./translations/`.
Translation files are named using the language and region code, for example:
- `en-us.yaml` (American English)
- `fr-fr.yaml` (French, France)
- `zh-cn.yaml` (Chinese, Simplified)
## How to Contribute Translations
Follow these steps to contribute a new translation or update an existing one.
### Step 1: Fork and Clone the Repository
First, you need to fork the repository you want to contribute to. This could be the main `fleetbase/fleetbase` repository or one of the extension repositories. After forking, clone it to your local machine.
### Step 2: Create or Update a Language File
Navigate to the appropriate translations directory (`./console/translations/` or `./translations/`).
- **To add a new language**: Copy the `en-us.yaml` file and rename it to your target language code (e.g., `es-es.yaml`).
- **To update an existing language**: Open the existing language file. You can compare it with `en-us.yaml` to find missing keys or phrases that need updating.
### Step 3: Translate the Content
Open the YAML file in a text editor. You will see a structure of nested keys and values.
```yaml
# Example from en-us.yaml
common:
new: New
create: Create
delete-selected-count: Delete {count} Selected
```
When translating, you should:
- **Only translate the values**, not the keys. For example, in `new: New`, you would only translate `New`.
- **Keep placeholders intact**. Some phrases contain placeholders like `{count}` or `{resource}`. These should not be translated. They are used by the application to insert dynamic values.
Here is an example of the French translation for the keys above:
```yaml
# Example from fr-fr.yaml
common:
new: Nouveau
create: Créer
delete-selected-count: Supprimer {count} sélectionné(s)
```
### Step 4: Submit a Pull Request
Once you have finished translating, commit your changes and push them to your forked repository. Then, open a pull request to the original Fleetbase repository.
- Make sure your pull request has a clear title and description of the changes you made.
- If you are translating an extension, you may need to submit a pull request to the extension's repository. If your changes also affect the main console, a separate PR to the `fleetbase/fleetbase` repository might be necessary.
Your contribution will be reviewed by the Fleetbase team, and once approved, it will be merged into the project.
## Translation Repositories
Here is a list of the primary repositories that accept translation contributions:
| Repository | Translation Path |
| ---------------------------------------- | ----------------------------- |
| [fleetbase/fleetbase][1] | `./console/translations/` |
| [fleetbase/fleetops][2] | `./translations/` |
| [fleetbase/storefront][3] | `./translations/` |
| [fleetbase/dev-engine][4] | `./translations/` |
| [fleetbase/iam-engine][5] | `./translations/` |
| [fleetbase/pallet][6] | `./translations/` |
| [fleetbase/ledger][7] | `./translations/` |
| [fleetbase/registry-bridge][8] | `./translations/` |
[1]: https://github.com/fleetbase/fleetbase
[2]: https://github.com/fleetbase/fleetops
[3]: https://github.com/fleetbase/storefront
[4]: https://github.com/fleetbase/dev-engine
[5]: https://github.com/fleetbase/iam-engine
[6]: https://github.com/fleetbase/pallet
[7]: https://github.com/fleetbase/ledger
[8]: https://github.com/fleetbase/registry-bridge
Thank you again for your contribution to the Fleetbase community!

View File

@@ -40,8 +40,6 @@ class Kernel extends HttpKernel
],
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];

View File

@@ -2,10 +2,8 @@
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
@@ -17,17 +15,15 @@ class RouteServiceProvider extends ServiceProvider
*/
public function boot()
{
$this->configureRateLimiting();
$this->routes(
function () {
Route::get(
'/status',
function () {
'/health',
function (Request $request) {
return response()->json(
[
'status' => 'ok',
'time' => microtime(true) - LARAVEL_START
'time' => microtime(true) - $request->attributes->get('request_start_time')
]
);
}
@@ -35,19 +31,4 @@ class RouteServiceProvider extends ServiceProvider
}
);
}
/**
* Configure the rate limiters for the application.
*
* @return void
*/
protected function configureRateLimiting()
{
RateLimiter::for(
'api',
function (Request $request) {
return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
}
);
}
}

View File

@@ -7,40 +7,68 @@
"laravel"
],
"license": "AGPL-3.0-or-later",
"authors": [
{
"name": "Fleetbase Pte Ltd.",
"email": "hello@fleetbase.io"
},
{
"name": "Ronald A. Richardson",
"email": "ron@fleetbase.io"
}
],
"require": {
"php": "^8.0",
"fleetbase/core-api": "^1.5.1",
"fleetbase/fleetops-api": "^0.5.5",
"fleetbase/registry-bridge": "^0.0.11",
"fleetbase/storefront-api": "^0.3.13",
"php": ">=8.0 <=8.2.28",
"appstract/laravel-opcache": "^4.0",
"fleetbase/aws-marketplace": "^0.0.8",
"fleetbase/billing-api": "^0.1.12",
"fleetbase/core-api": "^1.6.32",
"fleetbase/customer-portal-api": "^0.0.10",
"fleetbase/fleetops-api": "^0.6.32",
"fleetbase/flespi-integration": "^0.1.16",
"fleetbase/internals-api": "^0.0.23",
"fleetbase/registry-bridge": "^0.1.2",
"fleetbase/samsara-api": "^0.0.3",
"fleetbase/solid-api": "^0.0.7",
"fleetbase/storefront-api": "^0.4.10",
"fleetbase/valhalla-api": "^0.0.3",
"fleetbase/vroom-api": "^0.0.3",
"guzzlehttp/guzzle": "^7.0.1",
"laravel/framework": "^10.0",
"laravel/octane": "^2.3",
"laravel/tinker": "^2.9",
"league/flysystem-aws-s3-v3": "^3.0",
"maatwebsite/excel": "^3.1",
"maennchen/zipstream-php": "3.1.2",
"phpoffice/phpspreadsheet": "^1.28",
"predis/predis": "^2.1",
"psr/http-factory-implementation": "*",
"s-ichikawa/laravel-sendgrid-driver": "^4.0"
"resend/resend-php": "^0.14.0",
"s-ichikawa/laravel-sendgrid-driver": "^4.0",
"stripe/stripe-php": "13.13.0",
"symfony/mailgun-mailer": "^7.1",
"symfony/postmark-mailer": "^7.1"
},
"require-dev": {
"spatie/laravel-ignition": "^2.0",
"fakerphp/faker": "^1.9.1",
"kitloong/laravel-migrations-generator": "^6.10",
"laravel/sail": "^1.0.1",
"mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^7.0",
"phpunit/phpunit": "^10.0"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/fleetbase/laravel-model-caching"
},
{
"type": "composer",
"url": "https://registry.fleetbase.io"
},
{
"type": "vcs",
"url": "https://github.com/fleetbase/aws-marketplace"
},
{
"type": "vcs",
"url": "https://github.com/fleetbase/internals"
}
],
"autoload": {
@@ -78,15 +106,6 @@
],
"clean-logs": [
"composer run-script clear-logs"
],
"dock": [
"docker exec -it fleetbase_os_application_1 /usr/bin/tmux -u new"
],
"dock-server": [
"docker exec -it fleetbase_os_httpd_1 /bin/sh"
],
"tunnel": [
"ngrok http --region=ap --hostname=fleetbase.ap.ngrok.io 8000"
]
},
"extra": {

7434
api/composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ return [
|
*/
'env' => env('APP_ENV', 'production'),
'env' => env('APP_ENV', env('ENVIRONMENT', 'production')),
/*
|--------------------------------------------------------------------------

View File

@@ -17,17 +17,17 @@ return [
|
*/
'paths' => ['/*', 'sanctum/csrf-cookie'],
'paths' => ['*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => array_filter(['http://localhost:4200', env('CONSOLE_HOST'), Utils::addWwwToUrl(env('CONSOLE_HOST'))]),
'allowed_origins' => array_filter(['http://localhost:4200', env('CONSOLE_HOST'), Utils::addWwwToUrl(env('CONSOLE_HOST')), ...Utils::arrayFrom(env('FRONTEND_HOSTS', ''))]),
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => ['x-compressed-json', 'access-console-sandbox', 'access-console-sandbox-key'],
'exposed_headers' => ['x-compressed-json', 'access-console-sandbox', 'access-console-sandbox-key', 'content-disposition'],
'max_age' => 0,

View File

@@ -51,7 +51,7 @@ return [
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single'],
'channels' => ['single', 'stdout'],
'ignore_exceptions' => false,
],

View File

@@ -64,6 +64,20 @@ return [
'transport' => 'sendgrid',
],
'resend' => [],
'microsoft-graph' => [
'transport' => 'microsoft-graph',
'client_id' => env('MICROSOFT_GRAPH_CLIENT_ID'),
'client_secret' => env('MICROSOFT_GRAPH_CLIENT_SECRET'),
'tenant_id' => env('MICROSOFT_GRAPH_TENANT_ID'),
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'hello@fleetbase.io'),
'name' => env('MAIL_FROM_NAME', env('APP_NAME', 'Fleetbase')),
],
'save_to_sent_items' => env('MAIL_SAVE_TO_SENT_ITEMS', false),
],
'sendmail' => [
'transport' => 'sendmail',
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -t -i'),

View File

@@ -1,5 +1,6 @@
<?php
use Fleetbase\Support\Utils;
use Laravel\Octane\Contracts\OperationTerminated;
use Laravel\Octane\Events\RequestHandled;
use Laravel\Octane\Events\RequestReceived;
@@ -104,8 +105,8 @@ return [
OperationTerminated::class => [
FlushOnce::class,
FlushTemporaryContainerInstances::class,
// DisconnectFromDatabases::class,
// CollectGarbage::class,
DisconnectFromDatabases::class,
CollectGarbage::class,
],
WorkerErrorOccurred::class => [
@@ -192,6 +193,7 @@ return [
'routes',
'composer.lock',
'.env',
...Utils::arrayFrom(env('OCTANE_WATCH_DIRS'))
],
/*

30
api/config/opcache.php Normal file
View File

@@ -0,0 +1,30 @@
<?php
return [
'url' => env('OPCACHE_URL', config('app.url')),
'prefix' => 'opcache-api',
'verify' => true,
'headers' => [],
'directories' => [
base_path('app'),
base_path('bootstrap'),
base_path('public'),
base_path('resources'),
base_path('routes'),
base_path('storage'),
base_path('vendor'),
],
'exclude' => [
'test',
'Test',
'tests',
'Tests',
'stub',
'Stub',
'stubs',
'Stubs',
'dumper',
'Dumper',
'Autoload',
],
];

View File

@@ -34,4 +34,19 @@ return [
'api_key' => env('SENDGRID_API_KEY'),
],
'resend' => [
'key' => env('RESEND_KEY'),
],
'stripe' => [
'key' => env('STRIPE_KEY', env('STRIPE_API_KEY')),
'secret' => env('STRIPE_SECRET', env('STRIPE_API_SECRET')),
'webhook_secret' => env('STRIPE_WEBHOOK_SECRET'),
],
'callpromn' => [
'api_key' => env('CALLPROMN_API_KEY', ''),
'from' => env('CALLPROMN_FROM', ''),
'base_url' => env('CALLPROMN_BASE_URL', 'https://api.messagepro.mn' ),
],
];

View File

@@ -15,6 +15,9 @@ php artisan sandbox:migrate --force
# Seed database
php artisan fleetbase:seed
# Create permissions, policies, and roles
php artisan fleetbase:create-permissions
# Restart queue
php artisan queue:restart
@@ -23,6 +26,14 @@ php artisan schedule-monitor:sync
# Clear cache
php artisan cache:clear
php artisan route:clear
# Optimize
php artisan config:cache
php artisan route:cache
# Initialize registry
php artisan registry:init
# Restart octane
# php artisan octane:reload

View File

@@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| أسطر لغة المصادقة
|--------------------------------------------------------------------------
|
| تحتوي الأسطر التالية على رسائل المصادقة التي نعرضها للمستخدم أثناء
| عمليات تسجيل الدخول أو غيرها. يمكنك تعديل هذه الرسائل حسب متطلباتك.
|
*/
'failed' => 'بيانات الاعتماد هذه غير متطابقة مع سجلاتنا.',
'password' => 'كلمة المرور التي تم إدخالها غير صحيحة.',
'throttle' => 'عدد كبير جداً من محاولات الدخول. يرجى المحاولة مرة أخرى خلال :seconds ثانية.',
];

View File

@@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| أسطر لغة الترقيم الصفحي
|--------------------------------------------------------------------------
|
| تُستخدم الأسطر التالية من قبل مكتبة الترقيم الصفحي لبناء روابط
| الترقيم البسيطة. يمكنك تعديلها كما تشاء لتخصيص العرض بما يناسب
| تطبيقك بشكل أفضل.
|
*/
'previous' => '&laquo; السابق',
'next' => 'التالي &raquo;',
];

View File

@@ -0,0 +1,21 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| أسطر لغة إعادة تعيين كلمة المرور
|--------------------------------------------------------------------------
|
| الأسطر التالية هي الرسائل الافتراضية التي يقدمها نظام إعادة تعيين
| كلمة المرور عند فشل المحاولة، مثل رمز التحقق غير صالح أو كلمة مرور جديدة غير صحيحة.
|
*/
'reset' => 'تم إعادة تعيين كلمة المرور الخاصة بك!',
'sent' => 'لقد أرسلنا رابط إعادة تعيين كلمة المرور إلى بريدك الإلكتروني!',
'throttled' => 'يرجى الانتظار قبل المحاولة مرة أخرى.',
'token' => 'رمز إعادة تعيين كلمة المرور هذا غير صالح.',
'user' => 'لا يمكننا العثور على مستخدم بهذا العنوان الإلكتروني.',
];

View File

@@ -0,0 +1,168 @@
<?php
return [
/*
|--------------------------------------------------------------------------<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'يجب قبول :attribute.',
'accepted_if' => 'يجب قبول :attribute عندما يكون :other يساوي :value.',
'active_url' => ':attribute ليس عنوان URL صالحًا.',
'after' => 'يجب أن يكون :attribute تاريخًا بعد :date.',
'after_or_equal' => 'يجب أن يكون :attribute تاريخًا بعد أو يساوي :date.',
'alpha' => 'يجب أن يحتوي :attribute على أحرف فقط.',
'alpha_dash' => 'يجب أن يحتوي :attribute على أحرف وأرقام وشرطات فقط.',
'alpha_num' => 'يجب أن يحتوي :attribute على أحرف وأرقام فقط.',
'array' => 'يجب أن يكون :attribute مصفوفة.',
'before' => 'يجب أن يكون :attribute تاريخًا قبل :date.',
'before_or_equal' => 'يجب أن يكون :attribute تاريخًا قبل أو يساوي :date.',
'between' => [
'numeric' => 'يجب أن يكون :attribute بين :min و :max.',
'file' => 'يجب أن يكون :attribute بين :min و :max كيلوبايت.',
'string' => 'يجب أن يكون :attribute بين :min و :max حرفًا.',
'array' => 'يجب أن يحتوي :attribute على عدد عناصر بين :min و :max.',
],
'boolean' => 'يجب أن يكون حقل :attribute صحيحًا أو خاطئًا.',
'confirmed' => 'تأكيد :attribute غير متطابق.',
'current_password' => 'كلمة المرور غير صحيحة.',
'date' => ':attribute ليس تاريخًا صالحًا.',
'date_equals' => 'يجب أن يكون :attribute تاريخًا يساوي :date.',
'date_format' => 'لا يتطابق :attribute مع الصيغة :format.',
'declined' => 'يجب رفض :attribute.',
'declined_if' => 'يجب رفض :attribute عندما يكون :other يساوي :value.',
'different' => 'يجب أن يكون :attribute و :other مختلفين.',
'digits' => 'يجب أن يتكون :attribute من :digits أرقام.',
'digits_between' => 'يجب أن يتكون :attribute من :min إلى :max أرقام.',
'dimensions' => ':attribute يحتوي على أبعاد صورة غير صالحة.',
'distinct' => 'حقل :attribute يحتوي على قيمة مكررة.',
'email' => 'يجب أن يكون :attribute عنوان بريد إلكتروني صالحًا.',
'ends_with' => 'يجب أن ينتهي :attribute بأحد القيم التالية: :values.',
'enum' => ':attribute المحدد غير صالح.',
'exists' => ':attribute المحدد غير صالح.',
'file' => 'يجب أن يكون :attribute ملفًا.',
'filled' => 'يجب أن يحتوي حقل :attribute على قيمة.',
'gt' => [
'numeric' => 'يجب أن يكون :attribute أكبر من :value.',
'file' => 'يجب أن يكون :attribute أكبر من :value كيلوبايت.',
'string' => 'يجب أن يكون :attribute أكبر من :value حرفًا.',
'array' => 'يجب أن يحتوي :attribute على أكثر من :value عنصر.',
],
'gte' => [
'numeric' => 'يجب أن يكون :attribute أكبر من أو يساوي :value.',
'file' => 'يجب أن يكون :attribute أكبر من أو يساوي :value كيلوبايت.',
'string' => 'يجب أن يكون :attribute أكبر من أو يساوي :value حرفًا.',
'array' => 'يجب أن يحتوي :attribute على :value عنصر أو أكثر.',
],
'image' => 'يجب أن يكون :attribute صورة.',
'in' => ':attribute المحدد غير صالح.',
'in_array' => 'حقل :attribute غير موجود في :other.',
'integer' => 'يجب أن يكون :attribute عددًا صحيحًا.',
'ip' => 'يجب أن يكون :attribute عنوان IP صالحًا.',
'ipv4' => 'يجب أن يكون :attribute عنوان IPv4 صالحًا.',
'ipv6' => 'يجب أن يكون :attribute عنوان IPv6 صالحًا.',
'json' => 'يجب أن يكون :attribute نصًا بصيغة JSON صالحة.',
'lt' => [
'numeric' => 'يجب أن يكون :attribute أقل من :value.',
'file' => 'يجب أن يكون :attribute أقل من :value كيلوبايت.',
'string' => 'يجب أن يكون :attribute أقل من :value حرفًا.',
'array' => 'يجب أن يحتوي :attribute على أقل من :value عنصر.',
],
'lte' => [
'numeric' => 'يجب أن يكون :attribute أقل من أو يساوي :value.',
'file' => 'يجب أن يكون :attribute أقل من أو يساوي :value كيلوبايت.',
'string' => 'يجب أن يكون :attribute أقل من أو يساوي :value حرفًا.',
'array' => 'يجب ألا يحتوي :attribute على أكثر من :value عنصر.',
],
'mac_address' => 'يجب أن يكون :attribute عنوان MAC صالحًا.',
'max' => [
'numeric' => 'يجب ألا يتجاوز :attribute :max.',
'file' => 'يجب ألا يتجاوز :attribute :max كيلوبايت.',
'string' => 'يجب ألا يتجاوز :attribute :max حرفًا.',
'array' => 'يجب ألا يحتوي :attribute على أكثر من :max عنصر.',
],
'mimes' => 'يجب أن يكون :attribute ملفًا من النوع: :values.',
'mimetypes' => 'يجب أن يكون :attribute ملفًا من النوع: :values.',
'min' => [
'numeric' => 'يجب أن يكون :attribute على الأقل :min.',
'file' => 'يجب أن يكون :attribute على الأقل :min كيلوبايت.',
'string' => 'يجب أن يكون :attribute على الأقل :min حرفًا.',
'array' => 'يجب أن يحتوي :attribute على الأقل على :min عنصر.',
],
'multiple_of' => 'يجب أن يكون :attribute مضاعفًا لـ :value.',
'not_in' => ':attribute المحدد غير صالح.',
'not_regex' => 'صيغة :attribute غير صالحة.',
'numeric' => 'يجب أن يكون :attribute رقمًا.',
'password' => 'كلمة المرور غير صحيحة.',
'present' => 'يجب أن يكون حقل :attribute موجودًا.',
'prohibited' => 'حقل :attribute محظور.',
'prohibited_if' => 'حقل :attribute محظور عندما يكون :other يساوي :value.',
'prohibited_unless' => 'حقل :attribute محظور إلا إذا كان :other ضمن :values.',
'prohibits' => 'حقل :attribute يحظر وجود :other.',
'regex' => 'صيغة :attribute غير صالحة.',
'required' => 'حقل :attribute مطلوب.',
'required_array_keys' => 'يجب أن يحتوي حقل :attribute على إدخالات لـ: :values.',
'required_if' => 'حقل :attribute مطلوب عندما يكون :other يساوي :value.',
'required_unless' => 'حقل :attribute مطلوب إلا إذا كان :other ضمن :values.',
'required_with' => 'حقل :attribute مطلوب عند وجود :values.',
'required_with_all' => 'حقل :attribute مطلوب عند وجود جميع القيم :values.',
'required_without' => 'حقل :attribute مطلوب عند عدم وجود :values.',
'required_without_all' => 'حقل :attribute مطلوب عند عدم وجود أي من القيم :values.',
'same' => 'يجب أن يتطابق :attribute مع :other.',
'size' => [
'numeric' => 'يجب أن يكون :attribute مساويًا لـ :size.',
'file' => 'يجب أن يكون :attribute مساويًا لـ :size كيلوبايت.',
'string' => 'يجب أن يكون :attribute مساويًا لـ :size حرفًا.',
'array' => 'يجب أن يحتوي :attribute على :size عنصر.',
],
'starts_with' => 'يجب أن يبدأ :attribute بأحد القيم التالية: :values.',
'string' => 'يجب أن يكون :attribute نصًا.',
'timezone' => 'يجب أن يكون :attribute منطقة زمنية صالحة.',
'unique' => 'تم استخدام :attribute مسبقًا.',
'uploaded' => 'فشل تحميل :attribute.',
'url' => 'يجب أن يكون :attribute عنوان URL صالحًا.',
'uuid' => 'يجب أن يكون :attribute UUID صالحًا.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'رسالة مخصصة',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap our attribute placeholder
| with something more reader friendly such as "E-Mail Address" instead
| of "email". This simply helps us make our message more expressive.
|
*/
'attributes' => [],
];

View File

@@ -0,0 +1,20 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'Estas credenciales no coinciden con nuestros registros.',
'password' => 'La contraseña proporcionada es incorrecta.',
'throttle' => 'Demasiados intentos de inicio de sesión. Por favor, intenta de nuevo en :seconds segundos.',
];

View File

@@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '&laquo; Anterior',
'next' => 'Siguiente &raquo;',
];

View File

@@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reset Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'reset' => '¡Tu contraseña ha sido restablecida!',
'sent' => '¡Te hemos enviado por correo el enlace para restablecer tu contraseña!',
'throttled' => 'Por favor espera antes de volver a intentar.',
'token' => 'Este token de restablecimiento de contraseña es inválido.',
'user' => "No podemos encontrar un usuario con esa dirección de correo electrónico.",
];

View File

@@ -0,0 +1,163 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'El campo :attribute debe ser aceptado.',
'accepted_if' => 'El campo :attribute debe ser aceptado cuando :other sea :value.',
'active_url' => 'El campo :attribute no es una URL válida.',
'after' => 'El campo :attribute debe ser una fecha posterior a :date.',
'after_or_equal' => 'El campo :attribute debe ser una fecha posterior o igual a :date.',
'alpha' => 'El campo :attribute solo debe contener letras.',
'alpha_dash' => 'El campo :attribute solo debe contener letras, números, guiones y guiones bajos.',
'alpha_num' => 'El campo :attribute solo debe contener letras y números.',
'array' => 'El campo :attribute debe ser un arreglo.',
'before' => 'El campo :attribute debe ser una fecha anterior a :date.',
'before_or_equal' => 'El campo :attribute debe ser una fecha anterior o igual a :date.',
'between' => [
'numeric' => 'El campo :attribute debe estar entre :min y :max.',
'file' => 'El campo :attribute debe estar entre :min y :max kilobytes.',
'string' => 'El campo :attribute debe tener entre :min y :max caracteres.',
'array' => 'El campo :attribute debe tener entre :min y :max elementos.',
],
'boolean' => 'El campo :attribute debe ser verdadero o falso.',
'confirmed' => 'La confirmación de :attribute no coincide.',
'current_password' => 'La contraseña es incorrecta.',
'date' => 'El campo :attribute no es una fecha válida.',
'date_equals' => 'El campo :attribute debe ser una fecha igual a :date.',
'date_format' => 'El campo :attribute no coincide con el formato :format.',
'declined' => 'El campo :attribute debe ser rechazado.',
'declined_if' => 'El campo :attribute debe ser rechazado cuando :other sea :value.',
'different' => 'El campo :attribute y :other deben ser diferentes.',
'digits' => 'El campo :attribute debe tener :digits dígitos.',
'digits_between' => 'El campo :attribute debe tener entre :min y :max dígitos.',
'dimensions' => 'El campo :attribute tiene dimensiones de imagen inválidas.',
'distinct' => 'El campo :attribute tiene un valor duplicado.',
'email' => 'El campo :attribute debe ser una dirección de correo electrónico válida.',
'ends_with' => 'El campo :attribute debe terminar con uno de los siguientes: :values.',
'enum' => 'El :attribute seleccionado es inválido.',
'exists' => 'El :attribute seleccionado es inválido.',
'file' => 'El campo :attribute debe ser un archivo.',
'filled' => 'El campo :attribute debe tener un valor.',
'gt' => [
'numeric' => 'El campo :attribute debe ser mayor que :value.',
'file' => 'El campo :attribute debe ser mayor que :value kilobytes.',
'string' => 'El campo :attribute debe ser mayor que :value caracteres.',
'array' => 'El campo :attribute debe tener más de :value elementos.',
],
'gte' => [
'numeric' => 'El campo :attribute debe ser mayor o igual a :value.',
'file' => 'El campo :attribute debe ser mayor o igual a :value kilobytes.',
'string' => 'El campo :attribute debe ser mayor o igual a :value caracteres.',
'array' => 'El campo :attribute debe tener :value elementos o más.',
],
'image' => 'El campo :attribute debe ser una imagen.',
'in' => 'El :attribute seleccionado es inválido.',
'in_array' => 'El campo :attribute no existe en :other.',
'integer' => 'El campo :attribute debe ser un número entero.',
'ip' => 'El campo :attribute debe ser una dirección IP válida.',
'ipv4' => 'El campo :attribute debe ser una dirección IPv4 válida.',
'ipv6' => 'El campo :attribute debe ser una dirección IPv6 válida.',
'json' => 'El campo :attribute debe ser una cadena JSON válida.',
'lt' => [
'numeric' => 'El campo :attribute debe ser menor que :value.',
'file' => 'El campo :attribute debe ser menor que :value kilobytes.',
'string' => 'El campo :attribute debe ser menor que :value caracteres.',
'array' => 'El campo :attribute debe tener menos de :value elementos.',
],
'lte' => [
'numeric' => 'El campo :attribute debe ser menor o igual a :value.',
'file' => 'El campo :attribute debe ser menor o igual a :value kilobytes.',
'string' => 'El campo :attribute debe ser menor o igual a :value caracteres.',
'array' => 'El campo :attribute no debe tener más de :value elementos.',
],
'mac_address' => 'El campo :attribute debe ser una dirección MAC válida.',
'max' => [
'numeric' => 'El campo :attribute no debe ser mayor que :max.',
'file' => 'El campo :attribute no debe ser mayor que :max kilobytes.',
'string' => 'El campo :attribute no debe ser mayor que :max caracteres.',
'array' => 'El campo :attribute no debe tener más de :max elementos.',
],
'mimes' => 'El campo :attribute debe ser un archivo de tipo: :values.',
'mimetypes' => 'El campo :attribute debe ser un archivo de tipo: :values.',
'min' => [
'numeric' => 'El campo :attribute debe ser al menos :min.',
'file' => 'El campo :attribute debe ser al menos :min kilobytes.',
'string' => 'El campo :attribute debe tener al menos :min caracteres.',
'array' => 'El campo :attribute debe tener al menos :min elementos.',
],
'multiple_of' => 'El campo :attribute debe ser un múltiplo de :value.',
'not_in' => 'El :attribute seleccionado es inválido.',
'not_regex' => 'El formato del campo :attribute es inválido.',
'numeric' => 'El campo :attribute debe ser un número.',
'password' => 'La contraseña es incorrecta.',
'present' => 'El campo :attribute debe estar presente.',
'prohibited' => 'El campo :attribute está prohibido.',
'prohibited_if' => 'El campo :attribute está prohibido cuando :other sea :value.',
'prohibited_unless' => 'El campo :attribute está prohibido a menos que :other esté en :values.',
'prohibits' => 'El campo :attribute prohíbe que :other esté presente.',
'regex' => 'El formato del campo :attribute es inválido.',
'required' => 'El campo :attribute es obligatorio.',
'required_array_keys' => 'El campo :attribute debe contener entradas para: :values.',
'required_if' => 'El campo :attribute es obligatorio cuando :other sea :value.',
'required_unless' => 'El campo :attribute es obligatorio a menos que :other esté en :values.',
'required_with' => 'El campo :attribute es obligatorio cuando :values está presente.',
'required_with_all' => 'El campo :attribute es obligatorio cuando :values están presentes.',
'required_without' => 'El campo :attribute es obligatorio cuando :values no está presente.',
'required_without_all' => 'El campo :attribute es obligatorio cuando ninguno de :values están presentes.',
'same' => 'El campo :attribute y :other deben coincidir.',
'size' => [
'numeric' => 'El campo :attribute debe ser :size.',
'file' => 'El campo :attribute debe ser :size kilobytes.',
'string' => 'El campo :attribute debe tener :size caracteres.',
'array' => 'El campo :attribute debe contener :size elementos.',
],
'starts_with' => 'El campo :attribute debe comenzar con uno de los siguientes: :values.',
'string' => 'El campo :attribute debe ser una cadena de texto.',
'timezone' => 'El campo :attribute debe ser una zona horaria válida.',
'unique' => 'El campo :attribute ya ha sido tomado.',
'uploaded' => 'El campo :attribute falló al subir.',
'url' => 'El campo :attribute debe ser una URL válida.',
'uuid' => 'El campo :attribute debe ser un UUID válido.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap our attribute placeholder
| with something more reader friendly such as "E-Mail Address" instead
| of "email". This simply helps us make our message more expressive.
|
*/
'attributes' => [],
];

View File

@@ -0,0 +1,15 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| خطوط زبان احراز هویت
|--------------------------------------------------------------------------
|
| خطوط زبان زیر در طول احراز هویت برای پیام‌های مختلفی که باید به کاربر نمایش دهیم استفاده می‌شوند.
| شما می‌توانید این خطوط زبان را بر اساس نیازهای برنامه خود تغییر دهید.
|
*/
'failed' => 'این اطلاعات ورود با سوابق ما مطابقت ندارد.',
'password' => 'رمز عبور ارائه‌شده نادرست است.',
'throttle' => 'تعداد تلاش‌های ورود بیش از حد زیاد است. لطفاً پس از :seconds ثانیه دوباره تلاش کنید.',
];

View File

@@ -0,0 +1,18 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| خطوط زبان صفحه‌بندی
|--------------------------------------------------------------------------
|
| خطوط زبان زیر توسط کتابخانه صفحه‌بندی برای ساخت لینک‌های صفحه‌بندی ساده استفاده می‌شوند.
| شما می‌توانید این خطوط را به دلخواه تغییر دهید تا با نیازهای برنامه خود سازگار شوند.
|
*/
'previous' => '&laquo; قبلی',
'next' => 'بعدی &raquo;',
];

View File

@@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| خطوط زبان بازنشانی رمز عبور
|--------------------------------------------------------------------------
|
| خطوط زبان زیر خطوط پیش‌فرضی هستند که با دلایلی که توسط کارگزار رمز عبور
| برای تلاش‌های ناموفق به‌روزرسانی رمز عبور ارائه می‌شوند، مطابقت دارند،
| مانند توکن نامعتبر یا رمز عبور جدید نامعتبر.
|
*/
'reset' => 'رمز عبور شما بازنشانی شد!',
'sent' => 'لینک بازنشانی رمز عبور به ایمیل شما ارسال شد!',
'throttled' => 'لطفاً قبل از تلاش مجدد صبر کنید.',
'token' => 'این توکن بازنشانی رمز عبور نامعتبر است.',
'user' => 'کاربری با این آدرس ایمیل یافت نشد.',
];

View File

@@ -0,0 +1,163 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| خطوط زبان اعتبارسنجی
|--------------------------------------------------------------------------
|
| خطوط زبان زیر شامل پیام‌های خطای پیش‌فرض استفاده‌شده توسط کلاس اعتبارسنجی هستند.
| برخی از این قوانین نسخه‌های متعددی دارند، مانند قوانین مربوط به اندازه.
| شما می‌توانید این پیام‌ها را در اینجا به دلخواه تنظیم کنید.
|
*/
'accepted' => 'فیلد :attribute باید پذیرفته شود.',
'accepted_if' => 'فیلد :attribute باید پذیرفته شود وقتی :other برابر با :value باشد.',
'active_url' => 'فیلد :attribute یک URL معتبر نیست.',
'after' => 'فیلد :attribute باید تاریخی پس از :date باشد.',
'after_or_equal' => 'فیلد :attribute باید تاریخی پس از یا برابر با :date باشد.',
'alpha' => 'فیلد :attribute فقط باید شامل حروف باشد.',
'alpha_dash' => 'فیلد :attribute فقط باید شامل حروف، اعداد، خط تیره و زیرخط باشد.',
'alpha_num' => 'فیلد :attribute فقط باید شامل حروف و اعداد باشد.',
'array' => 'فیلد :attribute باید یک آرایه باشد.',
'before' => 'فیلد :attribute باید تاریخی قبل از :date باشد.',
'before_or_equal' => 'فیلد :attribute باید تاریخی قبل از یا برابر با :date باشد.',
'between' => [
'numeric' => 'فیلد :attribute باید بین :min و :max باشد.',
'file' => 'فیلد :attribute باید بین :min و :max کیلوبایت باشد.',
'string' => 'فیلد :attribute باید بین :min و :max کاراکتر باشد.',
'array' => 'فیلد :attribute باید بین :min و :max آیتم داشته باشد.',
],
'boolean' => 'فیلد :attribute باید true یا false باشد.',
'confirmed' => 'تأیید فیلد :attribute مطابقت ندارد.',
'current_password' => 'رمز عبور نادرست است.',
'date' => 'فیلد :attribute یک تاریخ معتبر نیست.',
'date_equals' => 'فیلد :attribute باید تاریخی برابر با :date باشد.',
'date_format' => 'فیلد :attribute با فرمت :format مطابقت ندارد.',
'declined' => 'فیلد :attribute باید رد شود.',
'declined_if' => 'فیلد :attribute باید رد شود وقتی :other برابر با :value باشد.',
'different' => 'فیلد :attribute و :other باید متفاوت باشند.',
'digits' => 'فیلد :attribute باید :digits رقم باشد.',
'digits_between' => 'فیلد :attribute باید بین :min و :max رقم باشد.',
'dimensions' => 'فیلد :attribute دارای ابعاد تصویر نامعتبر است.',
'distinct' => 'فیلد :attribute دارای مقدار تکراری است.',
'email' => 'فیلد :attribute باید یک آدرس ایمیل معتبر باشد.',
'ends_with' => 'فیلد :attribute باید با یکی از مقادیر زیر پایان یابد: :values.',
'enum' => 'مقدار انتخاب‌شده برای :attribute نامعتبر است.',
'exists' => 'مقدار انتخاب‌شده برای :attribute نامعتبر است.',
'file' => 'فیلد :attribute باید یک فایل باشد.',
'filled' => 'فیلد :attribute باید دارای مقدار باشد.',
'gt' => [
'numeric' => 'فیلد :attribute باید بزرگ‌تر از :value باشد.',
'file' => 'فیلد :attribute باید بزرگ‌تر از :value کیلوبایت باشد.',
'string' => 'فیلد :attribute باید بیش از :value کاراکتر باشد.',
'array' => 'فیلد :attribute باید بیش از :value آیتم داشته باشد.',
],
'gte' => [
'numeric' => 'فیلد :attribute باید بزرگ‌تر یا برابر با :value باشد.',
'file' => 'فیلد :attribute باید بزرگ‌تر یا برابر با :value کیلوبایت باشد.',
'string' => 'فیلد :attribute باید بیش از یا برابر با :value کاراکتر باشد.',
'array' => 'فیلد :attribute باید :value آیتم یا بیشتر داشته باشد.',
],
'image' => 'فیلد :attribute باید یک تصویر باشد.',
'in' => 'مقدار انتخاب‌شده برای :attribute نامعتبر است.',
'in_array' => 'فیلد :attribute در :other وجود ندارد.',
'integer' => 'فیلد :attribute باید یک عدد صحیح باشد.',
'ip' => 'فیلد :attribute باید یک آدرس IP معتبر باشد.',
'ipv4' => 'فیلد :attribute باید یک آدرس IPv4 معتبر باشد.',
'ipv6' => 'فیلد :attribute باید یک آدرس IPv6 معتبر باشد.',
'json' => 'فیلد :attribute باید یک رشته JSON معتبر باشد.',
'lt' => [
'numeric' => 'فیلد :attribute باید کمتر از :value باشد.',
'file' => 'فیلد :attribute باید کمتر از :value کیلوبایت باشد.',
'string' => 'فیلد :attribute باید کمتر از :value کاراکتر باشد.',
'array' => 'فیلد :attribute باید کمتر از :value آیتم داشته باشد.',
],
'lte' => [
'numeric' => 'فیلد :attribute باید کمتر یا برابر با :value باشد.',
'file' => 'فیلد :attribute باید کمتر یا برابر با :value کیلوبایت باشد.',
'string' => 'فیلد :attribute باید کمتر یا برابر با :value کاراکتر باشد.',
'array' => 'فیلد :attribute نباید بیش از :value آیتم داشته باشد.',
],
'mac_address' => 'فیلد :attribute باید یک آدرس MAC معتبر باشد.',
'max' => [
'numeric' => 'فیلد :attribute نباید بزرگ‌تر از :max باشد.',
'file' => 'فیلد :attribute نباید بزرگ‌تر از :max کیلوبایت باشد.',
'string' => 'فیلد :attribute نباید بیش از :max کاراکتر باشد.',
'array' => 'فیلد :attribute نباید بیش از :max آیتم داشته باشد.',
],
'mimes' => 'فیلد :attribute باید یک فایل از نوع: :values باشد.',
'mimetypes' => 'فیلد :attribute باید یک فایل از نوع: :values باشد.',
'min' => [
'numeric' => 'فیلد :attribute باید حداقل :min باشد.',
'file' => 'فیلد :attribute باید حداقل :min کیلوبایت باشد.',
'string' => 'فیلد :attribute باید حداقل :min کاراکتر باشد.',
'array' => 'فیلد :attribute باید حداقل :min آیتم داشته باشد.',
],
'multiple_of' => 'فیلد :attribute باید مضربی از :value باشد.',
'not_in' => 'مقدار انتخاب‌شده برای :attribute نامعتبر است.',
'not_regex' => 'فرمت فیلد :attribute نامعتبر است.',
'numeric' => 'فیلد :attribute باید یک عدد باشد.',
'password' => 'رمز عبور نادرست است.',
'present' => 'فیلد :attribute باید وجود داشته باشد.',
'prohibited' => 'فیلد :attribute ممنوع است.',
'prohibited_if' => 'فیلد :attribute وقتی :other برابر با :value باشد ممنوع است.',
'prohibited_unless' => 'فیلد :attribute ممنوع است مگر اینکه :other در :values باشد.',
'prohibits' => 'فیلد :attribute مانع حضور :other می‌شود.',
'regex' => 'فرمت فیلد :attribute نامعتبر است.',
'required' => 'فیلد :attribute الزامی است.',
'required_array_keys' => 'فیلد :attribute باید شامل ورودی‌هایی برای: :values باشد.',
'required_if' => 'فیلد :attribute وقتی :other برابر با :value باشد الزامی است.',
'required_unless' => 'فیلد :attribute الزامی است مگر اینکه :other در :values باشد.',
'required_with' => 'فیلد :attribute وقتی :values وجود دارد الزامی است.',
'required_with_all' => 'فیلد :attribute وقتی همه :values وجود دارند الزامی است.',
'required_without' => 'فیلد :attribute وقتی :values وجود ندارد الزامی است.',
'required_without_all' => 'فیلد :attribute وقتی هیچ‌کدام از :values وجود ندارند الزامی است.',
'same' => 'فیلد :attribute و :other باید یکسان باشند.',
'size' => [
'numeric' => 'فیلد :attribute باید :size باشد.',
'file' => 'فیلد :attribute باید :size کیلوبایت باشد.',
'string' => 'فیلد :attribute باید :size کاراکتر باشد.',
'array' => 'فیلد :attribute باید شامل :size آیتم باشد.',
],
'starts_with' => 'فیلد :attribute باید با یکی از مقادیر زیر شروع شود: :values.',
'string' => 'فیلد :attribute باید یک رشته باشد.',
'timezone' => 'فیلد :attribute باید یک منطقه زمانی معتبر باشد.',
'unique' => 'فیلد :attribute قبلاً استفاده شده است.',
'uploaded' => 'فیلد :attribute در آپلود ناموفق بود.',
'url' => 'فیلد :attribute باید یک URL معتبر باشد.',
'uuid' => 'فیلد :attribute باید یک UUID معتبر باشد.',
/*
|--------------------------------------------------------------------------
| خطوط زبان اعتبارسنجی سفارشی
|--------------------------------------------------------------------------
|
| در اینجا می‌توانید پیام‌های اعتبارسنجی سفارشی برای ویژگی‌ها را با استفاده از
| قرارداد "attribute.rule" برای نام‌گذاری خطوط مشخص کنید. این کار امکان
| تعیین سریع یک خط زبان سفارشی برای یک قانون خاص ویژگی را فراهم می‌کند.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'پیام سفارشی',
],
],
/*
|--------------------------------------------------------------------------
| ویژگی‌های اعتبارسنجی سفارشی
|--------------------------------------------------------------------------
|
| خطوط زبان زیر برای جایگزینی placeholder ویژگی‌های ما با چیزی کاربرپسندتر
| مانند "آدرس ایمیل" به جای "email" استفاده می‌شوند. این کار به ما کمک می‌کند
| پیام‌هایمان را گویاتر کنیم.
|
*/
'attributes' => [],
];

View File

@@ -0,0 +1,47 @@
#!/bin/bash
set -e
# Resolve the directory the script is located in
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
APP_NAME="Fleetbase"
IMAGE_NAME="fleetbase-linux-static"
CONTAINER_NAME="fleetbase-linux-build"
DIST_DIR="$ROOT_DIR/builds/dist"
BINARY_NAME="fleetbase-linux-x86_64"
DOCKERFILE="$ROOT_DIR/builds/linux/static-build.Dockerfile"
# Ensure pkg-config archive is available
SPC_DOWNLOADS_DIR="$SCRIPT_DIR/spc/downloads"
PKG_TAR="pkg-config-0.29.2.tar.gz"
PKG_URL="https://static-php-cli.fra1.digitaloceanspaces.com/static-php-cli/deps/pkg-config/${PKG_TAR}"
if [[ ! -f "${SPC_DOWNLOADS_DIR}/${PKG_TAR}" ]]; then
echo "📥 pkg-config archive missing downloading..."
mkdir -p "${SPC_DOWNLOADS_DIR}"
curl -L --retry 3 -o "${SPC_DOWNLOADS_DIR}/${PKG_TAR}" "${PKG_URL}"
else
echo "✅ pkg-config archive already present."
fi
# Build the image
echo "📦 Building static Linux binary for ${APP_NAME}..."
docker build -f "$DOCKERFILE" -t "$IMAGE_NAME" .
# Create a container from the built image
echo "📦 Creating container to extract binary..."
docker create --name "$CONTAINER_NAME" "$IMAGE_NAME"
# Make sure dist folder exist
mkdir -p "$DIST_DIR"
# Copy binary from container to local dist folder
echo "📂 Extracting binary..."
docker cp "$CONTAINER_NAME:/go/src/app/dist/frankenphp-linux-x86_64" "$DIST_DIR/$BINARY_NAME"
# Cleanup the temp container
docker rm "$CONTAINER_NAME"
echo "✅ Build complete! Binary is located at: $DIST_DIR/$BINARY_NAME"

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\linux\library;
class libgeos extends LinuxLibraryBase
{
use \SPC\builder\unix\library\libgeos;
public const NAME = 'libgeos';
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait libgeos
{
/**
* @throws FileSystemException
* @throws RuntimeException
*/
protected function build(): void
{
FileSystem::resetDir($this->source_dir . '/build');
shell()->cd($this->source_dir . '/build')
->setEnv([
'CFLAGS' => $this->getLibExtraCFlags(),
'LDFLAGS' => $this->getLibExtraLdFlags(),
'LIBS' => $this->getLibExtraLibs(),
])
->execWithEnv("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF ..")
->execWithEnv("make -j{$this->builder->concurrency}")
->execWithEnv('make install');
$this->patchPkgconfPrefix(['geos.pc']);
}
}

View File

@@ -0,0 +1,93 @@
# FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
FROM --platform=linux/amd64 docker.io/dunglas/frankenphp:static-builder@sha256:821526b776a26502735d83890cc0a0d579348c510ba6c777df0762cb1c50d967
WORKDIR /go/src/app
# Copy Fleetbase app
COPY ../../api ./dist/app
# Set working directory to the embedded Fleetbase app
WORKDIR /go/src/app/dist/app
# Setup for production environment
ENV APP_ENV=production
ENV APP_DEBUG=false
ENV BROADCAST_DRIVER=socketcluster
ENV OSRM_HOST="https://router.project-osrm.org"
ENV REGISTRY_PREINSTALLED_EXTENSIONS=true
# Optional: Ensure writable storage
RUN chmod -R 775 bootstrap/cache storage
# Set permissions for deploy script
RUN chmod +x ./deploy.sh
# Move back to main app directory before running build-static.sh
WORKDIR /go/src/app
# Install geos lib
RUN apk add --no-cache geos geos-dev
# Inject the libgeos library handlers
COPY ./builds/linux/spc/libgeos-linux.php ./dist/static-php-cli/src/SPC/builder/linux/library/libgeos.php
COPY ./builds/linux/spc/libgeos-unix.php ./dist/static-php-cli/src/SPC/builder/unix/library/libgeos.php
# Patch source.json to add geos extension source
RUN jq '. + {"php-geos": {"type": "url", "url": "https://github.com/libgeos/php-geos/archive/dfe1ab17b0f155cc315bc13c75689371676e02e1.zip", "license": [{"type": "file", "path": "php-geos-dfe1ab17b0f155cc315bc13c75689371676e02e1/MIT-LICENSE"}, {"type": "file", "path": "php-geos-dfe1ab17b0f155cc315bc13c75689371676e02e1/LGPL-2"}]}}' \
./dist/static-php-cli/config/source.json > ./dist/static-php-cli/config/source.tmp.json && \
mv ./dist/static-php-cli/config/source.tmp.json ./dist/static-php-cli/config/source.json
# Pathc source.json to add libgeos library
RUN jq '. + {"libgeos": {"type": "url", "url": "https://download.osgeo.org/geos/geos-3.12.1.tar.bz2", "filename": "geos-3.12.1.tar.bz2", "extract": "geos-3.12.1", "build-dir": "build", "license": [{"type": "file", "path": "COPYING"}]}}' \
./dist/static-php-cli/config/source.json > ./dist/static-php-cli/config/source.tmp.json && \
mv ./dist/static-php-cli/config/source.tmp.json ./dist/static-php-cli/config/source.json
# Patch ext.json to add geos extension dynamically
RUN jq '. + {"geos": {"type": "external", "arg-type": "enable", "source": "php-geos", "lib-depends": ["libgeos"]}}' \
./dist/static-php-cli/config/ext.json > ./dist/static-php-cli/config/ext.tmp.json && \
mv ./dist/static-php-cli/config/ext.tmp.json ./dist/static-php-cli/config/ext.json
# Patch lib.json to add libgeos
RUN jq '. + {"libgeos": {"source": "libgeos", "static-libs-unix": ["libgeos.a", "libgeos_c.a"]}}' \
./dist/static-php-cli/config/lib.json > ./dist/static-php-cli/config/lib.tmp.json && \
mv ./dist/static-php-cli/config/lib.tmp.json ./dist/static-php-cli/config/lib.json
# Install dependencies for SPC CLI
WORKDIR /go/src/app/dist/static-php-cli
RUN composer install --no-dev -a
# Set PHP extensions to be built (including geos!)
ENV PHP_EXTENSIONS="pdo_mysql,gd,bcmath,redis,intl,zip,gmp,apcu,opcache,imagick,sockets,pcntl,geos,iconv,mbstring,fileinfo,ctype,tokenizer,simplexml,dom,filter,session"
ENV PHP_EXTENSION_LIBS="libgeos,libzip,bzip2,libxml2,openssl,zlib"
# Force SPC to use the local source version (not download binary)
ENV SPC_REL_TYPE=source
# Debug build
ENV SPC_LOG_LEVEL=debug
# Skip compression
ENV NO_COMPRESS=1
# set PHP version
ENV PHP_VERSION=8.2
# Move to the app directory
WORKDIR /go/src/app
# Make sure pkg-config is available within the static build container
COPY ./builds/linux/spc/downloads/pkg-config-0.29.2.tar.gz ./dist/static-php-cli/downloads/pkg-config-0.29.2.tar.gz
# Pre-build pkg-config using the existing tarball
RUN apk add --no-cache build-base && \
tar -xzf ./dist/static-php-cli/downloads/pkg-config-0.29.2.tar.gz -C /tmp && \
cd /tmp/pkg-config-0.29.2 && \
./configure --with-internal-glib --prefix=/go/src/app/dist/static-php-cli/build/bin && \
make && make install && \
rm -rf /tmp/pkg-config-0.29.2
# Do not run git pull
RUN sed -i 's/^[ \t]*git pull/# git pull/' ./build-static.sh
# Build the FrankenPHP static binary
RUN EMBED=dist/app ./build-static.sh

188
builds/osx/build-osx.sh Executable file
View File

@@ -0,0 +1,188 @@
#!/bin/bash
set -e
log() {
echo -e "\033[1;34m[🔧 $1]\033[0m"
}
log_success() {
echo -e "\033[1;32m[✅ $1]\033[0m"
}
log_warn() {
echo -e "\033[1;33m[⚠️ $1]\033[0m"
}
log_error() {
echo -e "\033[1;31m[❌ $1]\033[0m"
}
# Define base paths
log "Resolving directories..."
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
OSX_DIR="$ROOT_DIR/builds/osx"
DIST_DIR="$ROOT_DIR/builds/dist"
APP_DIR="$ROOT_DIR/api"
BREW_PREFIX="/opt/homebrew"
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m)"
BINARY_NAME="fleetbase-$OS-$ARCH"
log "Binary will be: $BINARY_NAME"
# Setup PHP 8.4
log "Detecting current PHP version..."
ORIGINAL_PHP_PATH="$(which php)"
ORIGINAL_PHP_VERSION="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION.".".PHP_RELEASE_VERSION;' 2>/dev/null)"
IS_ASDF_MANAGED=false
if [[ "$ORIGINAL_PHP_PATH" == *".asdf"* ]]; then
IS_ASDF_MANAGED=true
fi
# 🔁 Trap to restore PHP when script exits
trap 'if [ "$IS_ASDF_MANAGED" = true ]; then
log "Restoring asdf-managed PHP version: $ORIGINAL_PHP_VERSION"
asdf set php "$ORIGINAL_PHP_VERSION" || true
log "Reverted to PHP $(php -v | head -n 1)"
else
log "Unsetting asdf set to restore system PHP"
asdf set php system || true
log "Reverted to PHP $(php -v | head -n 1)"
fi' EXIT
log "Detected PHP version: $ORIGINAL_PHP_VERSION"
log "Detected PHP binary: $ORIGINAL_PHP_PATH"
# ───────────────────────────────────────────────────────────────────────────────
# If the *current* php is already 8.4.x, we skip the entire asdf install step
# ───────────────────────────────────────────────────────────────────────────────
if [[ "$ORIGINAL_PHP_PATH" == "$BREW_PREFIX/bin/php" && "$ORIGINAL_PHP_VERSION" =~ ^8\.4\. ]]; then
log "Homebrew PHP $ORIGINAL_PHP_VERSION detected at $ORIGINAL_PHP_PATH — skipping asdf build/install."
else
# Only install under asdf if we dont already have 8.4.0 installed
log "No Homebrew PHP 8.4 detected (found $ORIGINAL_PHP_PATH $ORIGINAL_PHP_VERSION), using asdf to build/install."
if ! asdf list php | grep -q "8.4.0"; then
# Use brew to install required dependencies for asdf php management
log "Checking and installing Homebrew packages required for PHP 8.4 build..."
for pkg in autoconf automake bison freetype gd gettext icu4c krb5 libedit libiconv libjpeg libpng libxml2 libzip pkg-config re2c zlib sqlite3 libsodium oniguruma openssl@3 nasm; do
if ! brew list "$pkg" &>/dev/null; then
log_warn "$pkg not found. Installing..."
arch -arm64 brew install "$pkg"
else
log "$pkg already installed. Skipping."
fi
done
# Set necessary env flags/paths for PHP build on OSX ARM64
export CPPFLAGS="-I$BREW_PREFIX/opt/oniguruma/include -I$BREW_PREFIX/opt/libsodium/include -I$BREW_PREFIX/opt/bzip2/include -I$BREW_PREFIX/opt/zlib/include -I$BREW_PREFIX/opt/openssl@3/include -I$BREW_PREFIX/opt/libxml2/include -I$BREW_PREFIX/opt/libedit/include -I$BREW_PREFIX/opt/curl/include -I$BREW_PREFIX/opt/sqlite3/include -I$BREW_PREFIX/opt/freetype/include -I$BREW_PREFIX/opt/jpeg/include -I$BREW_PREFIX/opt/libpng/include -I$BREW_PREFIX/opt/libzip/include"
export LDFLAGS="-L$BREW_PREFIX/opt/openssl@3/lib -lssl -lcrypto -lz -L$BREW_PREFIX/opt/oniguruma/lib -lonig -L$BREW_PREFIX/opt/libsodium/lib -lsodium -L$BREW_PREFIX/opt/bzip2/lib -Wl,-rpath,$BREW_PREFIX/opt/bzip2/lib -lbz2 -L$BREW_PREFIX/opt/zlib/lib -L$BREW_PREFIX/opt/openssl@3/lib -L$BREW_PREFIX/opt/libxml2/lib -L$BREW_PREFIX/opt/libedit/lib -L$BREW_PREFIX/opt/sqlite3/lib -lsqlite3 -L$BREW_PREFIX/opt/curl/lib -lcurl -L$BREW_PREFIX/opt/freetype/lib -L$BREW_PREFIX/opt/jpeg/lib -L$BREW_PREFIX/opt/libpng/lib -L$BREW_PREFIX/opt/libzip/lib -lzip -lz"
export PKG_CONFIG_PATH="$BREW_PREFIX/opt/openssl/lib/pkgconfig:$BREW_PREFIX/opt/oniguruma/lib/pkgconfig:$BREW_PREFIX/opt/libsodium/lib/pkgconfig:$BREW_PREFIX/opt/libzip/lib/pkgconfig:$BREW_PREFIX/opt/gd/lib/pkgconfig:$BREW_PREFIX/opt/zlib/lib/pkgconfig:$BREW_PREFIX/opt/openssl@3/lib/pkgconfig:$BREW_PREFIX/opt/libxml2/lib/pkgconfig:$BREW_PREFIX/opt/curl/lib/pkgconfig:$BREW_PREFIX/opt/sqlite3/lib/pkgconfig:$BREW_PREFIX/opt/freetype/lib/pkgconfig:$BREW_PREFIX/opt/jpeg/lib/pkgconfig:$BREW_PREFIX/opt/libpng/lib/pkgconfig"
export PHP_CONFIGURE_OPTIONS="--with-openssl=$(brew --prefix openssl) --with-iconv=$(brew --prefix libiconv)"
log "Installing PHP 8.4.0 with asdf..."
asdf install php 8.4.0 --verbose
else
log "asdf already has PHP 8.4.0 installed, skipping"
fi
log "Switching to PHP 8.4.0 with asdf set..."
asdf set php 8.4.0 --home
fi
# Clone FrankenPHP
if [ ! -d "$OSX_DIR/frankenphp" ]; then
log "Cloning FrankenPHP..."
git clone https://github.com/dunglas/frankenphp "$OSX_DIR/frankenphp"
else
log_warn "FrankenPHP already cloned. Skipping."
fi
cd "$OSX_DIR/frankenphp"
# Patch build script
log "Patching build-static.sh to skip git pull..."
sed -i '' 's/^[ \t]*git pull/# git pull/' ./build-static.sh
# Set environment variables
log "Exporting build environment variables..."
export PHP_VERSION=8.2
export PHP_EXTENSIONS="pdo_mysql,gd,bcmath,redis,intl,zip,gmp,apcu,opcache,imagick,sockets,pcntl,geos,iconv,mbstring,fileinfo,ctype,tokenizer,simplexml,dom,filter,session"
export PHP_EXTENSION_LIBS="libgeos,libzip,bzip2,libxml2,openssl,zlib"
export SPC_REL_TYPE=source
export NO_COMPRESS=1
export SPC_OPT_BUILD_ARGS="--debug"
export CMAKE_OSX_ARCHITECTURES=arm64
# Clone and prepare static-php-cli in dist/
STATIC_PHP_CLI_DIR="$OSX_DIR/frankenphp/dist/static-php-cli"
if [ ! -d "$STATIC_PHP_CLI_DIR" ]; then
log "Cloning static-php-cli into dist/..."
git clone --depth 1 --branch 2.5.2 https://github.com/crazywhalecc/static-php-cli.git "$STATIC_PHP_CLI_DIR"
else
log_warn "static-php-cli already exists in dist/. Skipping clone."
fi
# Inject libgeos support
log "Injecting libgeos patch files..."
cp "$ROOT_DIR/builds/osx/spc/libgeos-unix.php" "$STATIC_PHP_CLI_DIR/src/SPC/builder/unix/library/libgeos.php"
cp "$ROOT_DIR/builds/osx/spc/libgeos-macos.php" "$STATIC_PHP_CLI_DIR/src/SPC/builder/macos/library/libgeos.php"
cp "$ROOT_DIR/builds/osx/spc/UnixBuilderBase-macos.php" "$STATIC_PHP_CLI_DIR/src/SPC/builder/unix/UnixBuilderBase.php"
# Patch SPC config
log "Patching SPC config files (source.json, ext.json, lib.json)..."
jq '. + {"php-geos": {"type": "url", "url": "https://github.com/libgeos/php-geos/archive/dfe1ab17b0f155cc315bc13c75689371676e02e1.zip", "license": [{"type": "file", "path": "php-geos-dfe1ab17b0f155cc315bc13c75689371676e02e1/MIT-LICENSE"}, {"type": "file", "path": "php-geos-dfe1ab17b0f155cc315bc13c75689371676e02e1/LGPL-2"}]}}' \
"$STATIC_PHP_CLI_DIR/config/source.json" > "$STATIC_PHP_CLI_DIR/config/source.tmp.json" && \
mv "$STATIC_PHP_CLI_DIR/config/source.tmp.json" "$STATIC_PHP_CLI_DIR/config/source.json"
jq '. + {"libgeos": {"type": "url", "url": "https://download.osgeo.org/geos/geos-3.12.1.tar.bz2", "filename": "geos-3.12.1.tar.bz2", "extract": "geos-3.12.1", "build-dir": "build", "license": [{"type": "file", "path": "COPYING"}]}}' \
"$STATIC_PHP_CLI_DIR/config/source.json" > "$STATIC_PHP_CLI_DIR/config/source.tmp.json" && \
mv "$STATIC_PHP_CLI_DIR/config/source.tmp.json" "$STATIC_PHP_CLI_DIR/config/source.json"
jq '. + {"libgeos": {"source": "libgeos", "static-libs-unix": ["libgeos.a", "libgeos_c.a"]}}' \
"$STATIC_PHP_CLI_DIR/config/lib.json" > "$STATIC_PHP_CLI_DIR/config/lib.tmp.json" && \
mv "$STATIC_PHP_CLI_DIR/config/lib.tmp.json" "$STATIC_PHP_CLI_DIR/config/lib.json"
jq '. + {"geos": {"type": "external", "arg-type": "enable", "source": "php-geos", "lib-depends": ["libgeos"]}}' \
"$STATIC_PHP_CLI_DIR/config/ext.json" > "$STATIC_PHP_CLI_DIR/config/ext.tmp.json" && \
mv "$STATIC_PHP_CLI_DIR/config/ext.tmp.json" "$STATIC_PHP_CLI_DIR/config/ext.json"
# Prepare app embed folder
log "📦 Preparing embedded app directory..."
rm -rf ./dist/app
mkdir -p ./dist/app
cp -R "$APP_DIR"/* ./dist/app/
log "Patching build-static.sh to skip git pull and composer install..."
# Skip `git pull`
sed -i '' 's/^[[:space:]]*git pull/# git pull/' "$OSX_DIR/frankenphp/build-static.sh"
# Patch add CoreServices framework for Caddy build on OSX
sed -i '' 's/-framework CoreFoundation -framework SystemConfiguration/& -framework CoreServices/' "$OSX_DIR/frankenphp/build-static.sh"
# ── work around 403 on GH macOS runners ────────────────────────────────────────
log "Patching curl to use a browser-like User-Agent (to avoid 403s)…"
curl() {
command curl -sSL -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6 Safari/605.1.15" "$@"
}
export -f curl
# Build the binary
log "⚙️ Running FrankenPHP build-static.sh..."
EMBED=dist/app ./build-static.sh
# Move built binary to dist
log "Moving built binary to output folder..."
mkdir -p "$DIST_DIR"
mv dist/frankenphp-mac-$ARCH "$DIST_DIR/$BINARY_NAME"
log_success "✅ macOS binary built at: $DIST_DIR/$BINARY_NAME"
# Clean up frankenphp build and app embed folder
log "🧹 Cleaning temporary app directory..."
rm -rf "$OSX_DIR/frankenphp"

View File

@@ -0,0 +1,271 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix;
use SPC\builder\BuilderBase;
use SPC\builder\linux\LinuxBuilder;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\exception\WrongUsageException;
use SPC\store\Config;
use SPC\store\FileSystem;
use SPC\util\DependencyUtil;
use SPC\util\SPCConfigUtil;
abstract class UnixBuilderBase extends BuilderBase
{
/** @var string cflags */
public string $arch_c_flags;
/** @var string C++ flags */
public string $arch_cxx_flags;
/** @var string cmake toolchain file */
public string $cmake_toolchain_file;
/**
* @throws WrongUsageException
* @throws FileSystemException
*/
public function getAllStaticLibFiles(): array
{
$libs = [];
// reorder libs
foreach ($this->libs as $lib) {
foreach ($lib->getDependencies() as $dep) {
$libs[] = $dep;
}
$libs[] = $lib;
}
$libFiles = [];
$libNames = [];
// merge libs
foreach ($libs as $lib) {
if (!in_array($lib::NAME, $libNames, true)) {
$libNames[] = $lib::NAME;
array_unshift($libFiles, ...$lib->getStaticLibs());
}
}
return array_map(fn ($x) => realpath(BUILD_LIB_PATH . "/{$x}"), $libFiles);
}
/**
* Return generic cmake options when configuring cmake projects
*/
public function makeCmakeArgs(): string
{
$extra = $this instanceof LinuxBuilder ? '-DCMAKE_C_COMPILER=' . getenv('CC') . ' ' : '';
// NEW: allow env-variable override
$arch = getenv('CMAKE_OSX_ARCHITECTURES') ?: 'arm64';
return $extra .
'-DCMAKE_BUILD_TYPE=Release ' .
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
'-DCMAKE_INSTALL_BINDIR=bin ' .
'-DCMAKE_INSTALL_LIBDIR=lib ' .
'-DCMAKE_INSTALL_INCLUDEDIR=include ' .
"-DCMAKE_OSX_ARCHITECTURES={$arch} " .
"-DCMAKE_TOOLCHAIN_FILE={$this->cmake_toolchain_file}";
}
/**
* Generate configure flags
*/
public function makeAutoconfFlags(int $flag = AUTOCONF_ALL): string
{
$extra = '';
// TODO: add auto pkg-config support
if (($flag & AUTOCONF_LIBS) === AUTOCONF_LIBS) {
$extra .= 'LIBS="' . BUILD_LIB_PATH . '" ';
}
if (($flag & AUTOCONF_CFLAGS) === AUTOCONF_CFLAGS) {
$extra .= 'CFLAGS="-I' . BUILD_INCLUDE_PATH . '" ';
}
if (($flag & AUTOCONF_CPPFLAGS) === AUTOCONF_CPPFLAGS) {
$extra .= 'CPPFLAGS="-I' . BUILD_INCLUDE_PATH . '" ';
}
if (($flag & AUTOCONF_LDFLAGS) === AUTOCONF_LDFLAGS) {
$extra .= 'LDFLAGS="-L' . BUILD_LIB_PATH . '" ';
}
return $extra;
}
public function proveLibs(array $sorted_libraries): void
{
// search all supported libs
$support_lib_list = [];
$classes = FileSystem::getClassesPsr4(
ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library',
'SPC\builder\\' . osfamily2dir() . '\library'
);
foreach ($classes as $class) {
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {
$support_lib_list[$class::NAME] = $class;
}
}
// if no libs specified, compile all supported libs
if ($sorted_libraries === [] && $this->isLibsOnly()) {
$libraries = array_keys($support_lib_list);
$sorted_libraries = DependencyUtil::getLibs($libraries);
}
// add lib object for builder
foreach ($sorted_libraries as $library) {
if (!in_array(Config::getLib($library, 'type', 'lib'), ['lib', 'package'])) {
continue;
}
// if some libs are not supported (but in config "lib.json", throw exception)
if (!isset($support_lib_list[$library])) {
throw new WrongUsageException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
}
$lib = new ($support_lib_list[$library])($this);
$this->addLib($lib);
}
// calculate and check dependencies
foreach ($this->libs as $lib) {
$lib->calcDependency();
}
$this->lib_list = $sorted_libraries;
}
/**
* Sanity check after build complete
*
* @throws RuntimeException
*/
protected function sanityCheck(int $build_target): void
{
// sanity check for php-cli
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
logger()->info('running cli sanity check');
[$ret, $output] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n -r "echo \"hello\";"');
$raw_output = implode('', $output);
if ($ret !== 0 || trim($raw_output) !== 'hello') {
throw new RuntimeException("cli failed sanity check: ret[{$ret}]. out[{$raw_output}]");
}
foreach ($this->getExts(false) as $ext) {
logger()->debug('testing ext: ' . $ext->getName());
$ext->runCliCheckUnix();
}
}
// sanity check for phpmicro
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
$test_task = $this->getMicroTestTasks();
foreach ($test_task as $task_name => $task) {
$test_file = SOURCE_PATH . '/' . $task_name . '.exe';
if (file_exists($test_file)) {
@unlink($test_file);
}
file_put_contents($test_file, file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') . $task['content']);
chmod($test_file, 0755);
[$ret, $out] = shell()->execWithResult($test_file);
foreach ($task['conditions'] as $condition => $closure) {
if (!$closure($ret, $out)) {
$raw_out = trim(implode('', $out));
throw new RuntimeException("micro failed sanity check: {$task_name}, condition [{$condition}], ret[{$ret}], out[{$raw_out}]");
}
}
}
}
// sanity check for embed
if (($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED) {
logger()->info('running embed sanity check');
$sample_file_path = SOURCE_PATH . '/embed-test';
if (!is_dir($sample_file_path)) {
@mkdir($sample_file_path);
}
// copy embed test files
copy(ROOT_DIR . '/src/globals/common-tests/embed.c', $sample_file_path . '/embed.c');
copy(ROOT_DIR . '/src/globals/common-tests/embed.php', $sample_file_path . '/embed.php');
$util = new SPCConfigUtil($this);
$config = $util->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
$lens = "{$config['cflags']} {$config['ldflags']} {$config['libs']}";
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') {
$lens .= ' -static';
}
[$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens);
if ($ret !== 0) {
throw new RuntimeException('embed failed sanity check: build failed. Error message: ' . implode("\n", $out));
}
// if someone changed to --enable-embed=shared, we need to add LD_LIBRARY_PATH
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') {
$ext_path = 'LD_LIBRARY_PATH=' . BUILD_ROOT_PATH . '/lib:$LD_LIBRARY_PATH ';
FileSystem::removeFileIfExists(BUILD_ROOT_PATH . '/lib/libphp.a');
} else {
$ext_path = '';
FileSystem::removeFileIfExists(BUILD_ROOT_PATH . '/lib/libphp.so');
}
[$ret, $output] = shell()->cd($sample_file_path)->execWithResult($ext_path . './embed');
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
throw new RuntimeException('embed failed sanity check: run failed. Error message: ' . implode("\n", $output));
}
}
}
/**
* 将编译好的二进制文件发布到 buildroot
*
* @param int $type 发布类型
* @throws RuntimeException
* @throws FileSystemException
*/
protected function deployBinary(int $type): bool
{
$src = match ($type) {
BUILD_TARGET_CLI => SOURCE_PATH . '/php-src/sapi/cli/php',
BUILD_TARGET_MICRO => SOURCE_PATH . '/php-src/sapi/micro/micro.sfx',
BUILD_TARGET_FPM => SOURCE_PATH . '/php-src/sapi/fpm/php-fpm',
default => throw new RuntimeException('Deployment does not accept type ' . $type),
};
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
FileSystem::createDir(BUILD_ROOT_PATH . '/bin');
shell()->exec('cp ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_ROOT_PATH . '/bin/'));
return true;
}
/**
* Run php clean
*
* @throws RuntimeException
*/
protected function cleanMake(): void
{
logger()->info('cleaning up');
shell()->cd(SOURCE_PATH . '/php-src')->exec('make clean');
}
/**
* Patch phpize and php-config if needed
* @throws FileSystemException
*/
protected function patchPhpScripts(): void
{
// patch phpize
if (file_exists(BUILD_BIN_PATH . '/phpize')) {
logger()->debug('Patching phpize prefix');
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
}
// patch php-config
if (file_exists(BUILD_BIN_PATH . '/php-config')) {
logger()->debug('Patching php-config prefix and libs order');
$php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
$php_config_str = str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str);
// move mimalloc to the beginning of libs
$php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str);
// move lstdc++ to the end of libs
$php_config_str = preg_replace('/(libs=")(.*?)\s*(-lstdc\+\+)\s*(.*?)"/', '$1$2 $4 $3"', $php_config_str);
FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
}
}
}

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace SPC\builder\macos\library;
class libgeos extends MacOSLibraryBase
{
use \SPC\builder\unix\library\libgeos;
public const NAME = 'libgeos';
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace SPC\builder\unix\library;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
use SPC\store\FileSystem;
trait libgeos
{
/**
* @throws FileSystemException
* @throws RuntimeException
*/
protected function build(): void
{
FileSystem::resetDir($this->source_dir . '/build');
shell()->cd($this->source_dir . '/build')
->setEnv([
'CFLAGS' => $this->getLibExtraCFlags(),
'LDFLAGS' => $this->getLibExtraLdFlags(),
'LIBS' => $this->getLibExtraLibs(),
])
->execWithEnv("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF ..")
->execWithEnv("make -j{$this->builder->concurrency}")
->execWithEnv('make install');
$this->patchPkgconfPrefix(['geos.pc']);
}
}

4
console/.gitignore vendored
View File

@@ -26,3 +26,7 @@
# broccoli-debug
/DEBUG/
# Auto-generated extension files
/app/extensions/
/app/utils/extension-loaders.js

View File

@@ -1,24 +1,24 @@
# ---- Build Stage ----
FROM node:18.15.0-alpine
FROM node:18.15.0-alpine as builder
# Set the working directory in the container to /console
WORKDIR /console
# Create the pnpm directory and set the PNPM_HOME environment variable
RUN mkdir -p ~/.pnpm
ENV PNPM_HOME /root/.pnpm
ENV PNPM_HOME=/root/.pnpm
# Set environment
ARG ENVIRONMENT=production
# Add the pnpm global bin to the PATH
ENV PATH /root/.pnpm/bin:$PATH
ENV PATH=/root/.pnpm/bin:$PATH
# Copy pnpm-lock.yaml (or package.json) into the directory /console in the container
COPY console/package.json console/pnpm-lock.yaml ./
COPY package.json pnpm-lock.yaml ./
# Copy over .npmrc if applicable
COPY console/.npmr[c] ./
COPY .npmr[c] ./
# Install global dependencies
RUN npm install -g ember-cli pnpm
@@ -33,25 +33,22 @@ RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
RUN pnpm install
# Copy the console directory contents into the container at /console
COPY console .
COPY . .
# Build the application
RUN pnpm build --environment $ENVIRONMENT
# # Make sure the build output is available in /console/dist
# RUN ls -la /console/dist
# ---- Serve Stage ----
FROM nginx:alpine
# # ---- Serve Stage ----
# FROM nginx:alpine
# Copy the built app to our served directory
COPY --from=builder /console/dist /usr/share/nginx/html
# # Copy the built app to our served directory
# COPY --from=builder /console/dist /usr/share/nginx/html
# Expose the port nginx is bound to
EXPOSE 4200
# # Expose the port nginx is bound to
# EXPOSE 4201
# Use custom nginx.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
# # Use custom nginx.conf
# COPY console/nginx.conf /etc/nginx/conf.d/default.conf
# # Start Nginx server
# CMD ["nginx", "-g", "daemon off;"]
# Start Nginx server
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,54 +0,0 @@
# ---- Build Stage ----
FROM node:18.15.0-alpine as builder
# Set the working directory in the container to /console
WORKDIR /console
# Create the pnpm directory and set the PNPM_HOME environment variable
RUN mkdir -p ~/.pnpm
ENV PNPM_HOME /root/.pnpm
# Set environment
ARG ENVIRONMENT=production
# Add the pnpm global bin to the PATH
ENV PATH /root/.pnpm/bin:$PATH
# Copy pnpm-lock.yaml (or package.json) into the directory /console in the container
COPY console/package.json console/pnpm-lock.yaml ./
# Copy over .npmrc if applicable
COPY console/.npmr[c] ./
# Install global dependencies
RUN npm install -g ember-cli pnpm
# Install git
RUN apk update && apk add git openssh-client
# Trust GitHub's RSA host key
RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
# Install app dependencies
RUN pnpm install
# Copy the console directory contents into the container at /console
COPY console .
# Build the application
RUN pnpm build --environment $ENVIRONMENT
# ---- Serve Stage ----
FROM nginx:alpine
# Copy the built app to our served directory
COPY --from=builder /console/dist /usr/share/nginx/html
# Expose the port nginx is bound to
EXPOSE 4200
# Use custom nginx.conf
COPY console/nginx.conf /etc/nginx/conf.d/default.conf
# Start Nginx server
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -2,8 +2,7 @@ import Application from '@ember/application';
import Resolver from 'ember-resolver';
import loadInitializers from 'ember-load-initializers';
import config from '@fleetbase/console/config/environment';
import loadExtensions from '@fleetbase/ember-core/utils/load-extensions';
import mapEngines from '@fleetbase/ember-core/utils/map-engines';
import './deprecation-workflow';
export default class App extends Application {
modulePrefix = config.modulePrefix;
@@ -11,13 +10,6 @@ export default class App extends Application {
Resolver = Resolver;
extensions = [];
engines = {};
async ready() {
const extensions = await loadExtensions();
this.extensions = extensions;
this.engines = mapEngines(extensions);
}
}
loadInitializers(App, config.modulePrefix);

View File

@@ -1,4 +1,4 @@
<ContentPanel @title="Filesystem" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Filesystem" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Driver" @helpText="Select the default filesystem driver for Fleetbase to use.">
<Select @options={{this.disks}} @value={{this.driver}} @onSelect={{this.setDriver}} @placeholder="Select filesystem driver" class="w-full" disabled={{this.isLoading}} />
</InputGroup>
@@ -33,7 +33,7 @@
</InputGroup>
{{/if}}
{{#if this.testResponse}}
<div class="animate-pulse flex flex-row items-center rounded-lg border {{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<div class="flex flex-row items-center rounded-lg border {{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<FaIcon @icon={{if (eq this.testResponse.status 'error') 'triangle-exclamation' 'circle-check'}} class="mr-1.5 {{if (eq this.testResponse.status 'error') 'text-red-200' 'text-green-200'}}" />
<span class="text-xs">{{this.this.testResponse.message}}</span>
</div>

View File

@@ -106,10 +106,8 @@ export default class ConfigureFilesystemComponent extends Component {
type: 'gcs_credentials',
},
(uploadedFile) => {
console.log('uploadedFile', uploadedFile);
this.gcsCredentialsFileId = uploadedFile.id;
this.gcsCredentialsFile = uploadedFile;
console.log('this.gcsCredentialsFile', this.gcsCredentialsFile);
}
);
} catch (error) {

View File

@@ -1,27 +1,64 @@
<ContentPanel @title="Mail" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Mail" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Mailer" @helpText="Select the default mailer for Fleetbase to use.">
<Select @options={{this.mailers}} @value={{this.mailer}} @onSelect={{this.setMailer}} @placeholder="Select mailer" class="w-full" />
</InputGroup>
{{#if (eq this.mailer "smtp")}}
<InputGroup @name="SMTP Host" @value={{this.smtpHost}} disabled={{this.isLoading}} />
<InputGroup @name="SMTP Port" @type="number" @value={{this.smtpPort}} disabled={{this.isLoading}} />
<InputGroup @name="SMTP Encryption" @value={{this.smtpEncryption}} disabled={{this.isLoading}} />
<InputGroup @name="SMTP Username" @value={{this.smtpUsername}} disabled={{this.isLoading}} />
<InputGroup @name="SMTP Password" @type="password" @value={{this.smtpPassword}} disabled={{this.isLoading}} />
<InputGroup @name="SMTP Timeout" @value={{this.smtpTimeout}} disabled={{this.isLoading}} />
<InputGroup @name="SMTP Auth Mode" @value={{this.smtpAuth_mode}} disabled={{this.isLoading}} />
<InputGroup @name="SMTP Host" @value={{this.smtpHost}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="SMTP Port" @type="number" @value={{this.smtpPort}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup>
<Toggle @isToggled={{eq this.smtpEncryption "tls"}} @onToggle={{this.enableSmtpEncryption}} @label="SMTP Encryption" @helpText="Enabled TLS Encryption" />
</InputGroup>
<InputGroup @name="SMTP Username" @value={{this.smtpUsername}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="SMTP Password" @value={{this.smtpPassword}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="SMTP Timeout" @value={{this.smtpTimeout}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="SMTP Auth Mode" @value={{this.smtpAuth_mode}} disabled={{this.loadConfigValues.isRunning}} />
{{/if}}
<InputGroup @name="From Address" @helpText="Input the email address for Fleetbase to send emails from." @value={{this.fromAddress}} @placeholder="From Address" disabled={{this.isLoading}} />
{{#if (eq this.mailer "microsoft-graph")}}
<InputGroup @name="Client ID" @value={{this.microsoftGraphClient_id}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="Client Secret" @value={{this.microsoftGraphClient_secret}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="Tenant ID" @value={{this.microsoftGraphTenant_id}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup>
<Toggle @isToggled={{this.microsoftGraphSave_to_sent_items}} @onToggle={{fn (mut this.microsoftGraphSave_to_sent_items)}} @label="Save to sent items" />
</InputGroup>
{{/if}}
{{#if (eq this.mailer "mailgun")}}
<InputGroup @name="Mailgun Domain" @value={{this.mailgunDomain}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="Mailgun Endpoint" @value={{this.mailgunEndpoint}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="Mailgun Secret" @value={{this.mailgunSecret}} disabled={{this.loadConfigValues.isRunning}} />
{{/if}}
{{#if (eq this.mailer "postmark")}}
<InputGroup @name="Postmark Token" @value={{this.postmarkToken}} disabled={{this.loadConfigValues.isRunning}} />
{{/if}}
{{#if (eq this.mailer "sendgrid")}}
<InputGroup @name="Sendgrid API Key" @value={{this.sendgridApi_key}} disabled={{this.loadConfigValues.isRunning}} />
{{/if}}
{{#if (eq this.mailer "resend")}}
<InputGroup @name="Resend API Key" @value={{this.resendKey}} disabled={{this.loadConfigValues.isRunning}} />
{{/if}}
<InputGroup
@name="From Address"
@helpText="Input the email address for Fleetbase to send emails from."
@value={{this.fromAddress}}
@placeholder="From Address"
disabled={{this.isLoading}}
/>
<InputGroup @name="From Name" @helpText="Input the name for Fleetbase to send emails from." @value={{this.fromName}} @placeholder="From Name" disabled={{this.isLoading}} />
{{#if this.testResponse}}
<div class="animate-pulse flex flex-row items-center rounded-lg border {{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<FaIcon @icon={{if (eq this.testResponse.status 'error') 'triangle-exclamation' 'circle-check'}} class="mr-1.5 {{if (eq this.testResponse.status 'error') 'text-red-200' 'text-green-200'}}" />
<span class="text-xs">{{this.this.testResponse.message}}</span>
<div
class="flex flex-row items-center rounded-lg border
{{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}}
shadow-sm my-2 px-4 py-2"
>
<FaIcon
@icon={{if (eq this.testResponse.status "error") "triangle-exclamation" "circle-check"}}
class="mr-1.5 {{if (eq this.testResponse.status 'error') 'text-red-200' 'text-green-200'}}"
/>
<span class="text-xs">{{this.testResponse.message}}</span>
</div>
{{/if}}
<Button @wrapperClass="mt-3" @icon="plug" @text="Test Config" @onClick={{this.test}} @isLoading={{this.isLoading}} />
<Button @wrapperClass="mt-3" @icon="plug" @text="Test Config" @onClick={{perform this.test}} @isLoading={{this.test.isRunning}} />
</ContentPanel>
<EmberWormhole @to="next-view-section-subheader-actions">
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{perform this.save}} @disabled={{this.save.isRunning}} @isLoading={{this.save.isRunning}} />
</EmberWormhole>

View File

@@ -2,6 +2,7 @@ import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { task } from 'ember-concurrency';
export default class ConfigureMailComponent extends Component {
@service fetch;
@@ -14,11 +15,21 @@ export default class ConfigureMailComponent extends Component {
@tracked fromName = null;
@tracked smtpHost = 'smtp.mailgun.org';
@tracked smtpPort = 587;
@tracked smtpEncryption = 'tls';
@tracked smtpEncryption = null;
@tracked smtpUsername = null;
@tracked smtpPassword = null;
@tracked smtpTimeout = null;
@tracked smtpAuth_mode = null;
@tracked mailgunDomain = null;
@tracked mailgunEndpoint = 'api.mailgun.net';
@tracked mailgunSecret = null;
@tracked postmarkToken = null;
@tracked sendgridApi_key = null;
@tracked resendKey = null;
@tracked microsoftGraphClient_id = null;
@tracked microsoftGraphClient_secret = null;
@tracked microsoftGraphTenant_id = null;
@tracked microsoftGraphSave_to_sent_items = false;
/**
* Creates an instance of ConfigureFilesystemComponent.
@@ -26,7 +37,7 @@ export default class ConfigureMailComponent extends Component {
*/
constructor() {
super(...arguments);
this.loadConfigValues();
this.loadConfigValues.perform();
}
@action setConfigValues(config) {
@@ -37,6 +48,10 @@ export default class ConfigureMailComponent extends Component {
}
}
@action enableSmtpEncryption(enabled) {
this.smtpEncryption = enabled ? 'tls' : null;
}
@action setMailer(mailer) {
this.mailer = mailer;
}
@@ -53,56 +68,92 @@ export default class ConfigureMailComponent extends Component {
};
}
@action loadConfigValues() {
this.isLoading = true;
this.fetch
.get('settings/mail-config')
.then((response) => {
this.setConfigValues(response);
})
.finally(() => {
this.isLoading = false;
});
@action serializeMicrosoftGraphConfig() {
return {
client_id: this.microsoftGraphClient_id,
client_secret: this.microsoftGraphClient_secret,
tenant_id: this.microsoftGraphTenant_id,
save_to_sent_items: this.microsoftGraphSave_to_sent_items,
from: {
address: this.fromAddress,
name: this.fromName,
},
};
}
@action test() {
this.isLoading = true;
@action serializeMailgunConfig() {
return {
domain: this.mailgunDomain,
secret: this.mailgunSecret,
endpoint: this.mailgunEndpoint,
};
}
this.fetch
.post('settings/test-mail-config', {
@action serializePostmarkConfig() {
return {
token: this.postmarkToken,
};
}
@action serializeSendgridConfig() {
return {
api_key: this.sendgridApi_key,
};
}
@action serializeResendConfig() {
return {
key: this.resendKey,
};
}
@task *loadConfigValues() {
try {
const config = yield this.fetch.get('settings/mail-config');
this.setConfigValues(config);
} catch (error) {
this.notifications.serverError(error);
}
}
@task *test() {
try {
this.testResponse = yield this.fetch.post('settings/test-mail-config', {
mailer: this.mailer,
from: {
address: this.fromAddress,
name: this.fromName,
},
smtp: this.serializeSmtpConfig(),
})
.then((response) => {
this.testResponse = response;
})
.finally(() => {
this.isLoading = false;
mailgun: this.serializeMailgunConfig(),
postmark: this.serializePostmarkConfig(),
sendgrid: this.serializeSendgridConfig(),
resend: this.serializeResendConfig(),
microsoftGraph: this.serializeMicrosoftGraphConfig(),
});
} catch (error) {
this.notifications.serverError(error);
}
}
@action save() {
this.isLoading = true;
this.fetch
.post('settings/mail-config', {
@task *save() {
try {
yield this.fetch.post('settings/mail-config', {
mailer: this.mailer,
from: {
address: this.fromAddress,
name: this.fromName,
},
smtp: this.serializeSmtpConfig(),
})
.then(() => {
this.notifications.success('Mail configuration saved.');
})
.finally(() => {
this.isLoading = false;
mailgun: this.serializeMailgunConfig(),
postmark: this.serializePostmarkConfig(),
sendgrid: this.serializeSendgridConfig(),
resend: this.serializeResendConfig(),
microsoftGraph: this.serializeMicrosoftGraphConfig(),
});
this.notifications.success('Mail configuration saved.');
} catch (error) {
this.notifications.serverError(error);
}
}
}

View File

@@ -1,4 +1,4 @@
<ContentPanel @title="APN Configutation" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="APN Configutation" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="APN Key ID" @value={{this.apn.key_id}} disabled={{this.isLoading}} />
<InputGroup @name="APN Team ID" @value={{this.apn.team_id}} disabled={{this.isLoading}} />
<InputGroup @name="APN App Bundle ID" @value={{this.apn.app_bundle_id}} disabled={{this.isLoading}} />
@@ -16,11 +16,11 @@
{{/if}}
</InputGroup>
<InputGroup @wrapperClass="mb-0i">
<Checkbox @label="APN Production" @value={{this.apn.production}} @onToggle={{fn (mut this.apn.production)}} @disabled={{this.isLoading}} />
<Checkbox @label="APN Production" @value={{this.apn.production}} @onToggle={{this.toggleApnProduction}} />
</InputGroup>
</ContentPanel>
<ContentPanel @title="Firebase Configutation" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Firebase Configutation" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @wrapperClass="flex flex-row items-center mb-0i">
<UploadButton @name="firebase-service-account" @accept="text/plain,text/javascript,application/json" @onFileAdded={{this.uploadFirebaseCredentials}} @buttonText="Upload Service Account JSON" @icon="upload" class="w-auto m-0i mt-0i" />
{{#if this.firebase.credentials_file}}
@@ -33,9 +33,9 @@
</InputGroup>
</ContentPanel>
<ContentPanel @title="Test Push Notification" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-900">
<ContentPanel @title="Test Push Notification" @open={{true}} @wrapperClass="bordered-classic">
{{#if this.testResponse}}
<div class="animate-pulse flex flex-row items-center rounded-lg border {{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<div class="flex flex-row items-center rounded-lg border {{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<FaIcon @icon={{if (eq this.testResponse.status 'error') 'triangle-exclamation' 'circle-check'}} class="mr-1.5 {{if (eq this.testResponse.status 'error') 'text-red-200' 'text-green-200'}}" />
<span class="text-xs">{{this.this.testResponse.message}}</span>
</div>

View File

@@ -32,6 +32,13 @@ export default class ConfigureNotificationChannelsComponent extends Component {
this.loadConfigValues();
}
@action toggleApnProduction(checked) {
this.apn = {
...this.apn,
production: checked,
};
}
@action removeApnFile() {
const apnConfig = this.apn;
apnConfig.private_key_file = null;

View File

@@ -1,4 +1,4 @@
<ContentPanel @title="Queue" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Queue" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Driver" @helpText="Select the default queue driver for Fleetbase to use.">
<Select @options={{this.connections}} @value={{this.driver}} @onSelect={{this.setDriver}} @placeholder="Select queue driver" disabled={{this.isLoading}} class="w-full" />
</InputGroup>
@@ -12,7 +12,7 @@
<InputGroup @name="SQS Suffix" @value={{this.sqsSuffix}} disabled={{this.isLoading}} />
{{/if}}
{{#if this.testResponse}}
<div class="animate-pulse flex flex-row items-center rounded-lg border {{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<div class="flex flex-row items-center rounded-lg border {{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<FaIcon @icon={{if (eq this.testResponse.status 'error') 'triangle-exclamation' 'circle-check'}} class="mr-1.5 {{if (eq this.testResponse.status 'error') 'text-red-200' 'text-green-200'}}" />
<span class="text-xs">{{this.this.testResponse.message}}</span>
</div>

View File

@@ -1,45 +1,47 @@
<ContentPanel @title="AWS" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="AWS" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="AWS Access Key" @value={{this.awsKey}} disabled={{this.isLoading}} />
<InputGroup @name="AWS Access Secret" @value={{this.awsSecret}} disabled={{this.isLoading}} />
<InputGroup @name="AWS Region" @value={{this.awsRegion}} disabled={{this.isLoading}} />
</ContentPanel>
<ContentPanel @title="Google Maps" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Google Maps" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Google Maps API Key" @value={{this.googleMapsApiKey}} disabled={{this.isLoading}} />
<InputGroup @name="Google Maps Locale" @value={{this.googleMapsLocale}} disabled={{this.isLoading}} />
</ContentPanel>
<ContentPanel @title="Twilio" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Twilio" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Twilio SID" @value={{this.twilioSid}} disabled={{this.isLoading}} />
<InputGroup @name="Twilio Token" @value={{this.twilioToken}} disabled={{this.isLoading}} />
<InputGroup @name="Twilio From" @value={{this.twilioFrom}} disabled={{this.isLoading}} />
{{#if this.twilioTestResponse}}
<div class="animate-pulse flex flex-row items-center rounded-lg border {{if (eq this.twilioTestResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<div class="flex flex-row items-center rounded-lg border {{if (eq this.twilioTestResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<FaIcon @icon={{if (eq this.twilioTestResponse.status 'error') 'triangle-exclamation' 'circle-check'}} class="mr-1.5 {{if (eq this.twilioTestResponse.status 'error') 'text-red-200' 'text-green-200'}}" />
<span class="text-xs">{{this.this.twilioTestResponse.message}}</span>
</div>
{{/if}}
<div class="flex flex-row items-center mt-3">
<Input @value={{this.twilioTestPhone}} @type="tel" placeholder="Send Test SMS Here" class="form-input form-input-sm" />
<Button @wrapperClass="ml-2" @icon="plug" @text="Test Twilio Config" @onClick={{this.testTwilio}} @isLoading={{this.isLoading}} @disabled={{not this.twilioTestPhone}} />
<Button @wrapperClass="ml-2" @icon="plug" @text="Test Twilio Config" @onClick={{perform this.testTwilio}} @isLoading={{this.testTwilio.isRunning}} @disabled={{not this.twilioTestPhone}} />
</div>
</ContentPanel>
<ContentPanel @title="Sentry" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Sentry" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Sentry DSN" @value={{this.sentryDsn}} disabled={{this.isLoading}} />
{{#if this.sentryTestResponse}}
<div class="animate-pulse flex flex-row items-center rounded-lg border {{if (eq this.sentryTestResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<div class="flex flex-row items-center rounded-lg border {{if (eq this.sentryTestResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<FaIcon @icon={{if (eq this.sentryTestResponse.status 'error') 'triangle-exclamation' 'circle-check'}} class="mr-1.5 {{if (eq this.sentryTestResponse.status 'error') 'text-red-200' 'text-green-200'}}" />
<span class="text-xs">{{this.this.sentryTestResponse.message}}</span>
</div>
{{/if}}
<Button @wrapperClass="mt-3" @icon="plug" @text="Test Sentry Config" @onClick={{this.testSentry}} @isLoading={{this.isLoading}} />
<Button @wrapperClass="mt-3" @icon="plug" @text="Test Sentry Config" @onClick={{perform this.testSentry}} @isLoading={{this.testSentry.isRunning}} @disabled={{not this.sentryDsn}} />
</ContentPanel>
<ContentPanel @title="IP Info" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="IP Info" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="IP Info API Key" @value={{this.ipinfoApiKey}} disabled={{this.isLoading}} />
</ContentPanel>
<Spacer @height="200px" />
<EmberWormhole @to="next-view-section-subheader-actions">
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{perform this.save}} @disabled={{or this.save.isRunning this.loadConfigValues.isRunning}} @isLoading={{or this.save.isRunning this.loadConfigValues.isRunning}} />
</EmberWormhole>

View File

@@ -2,6 +2,7 @@ import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { task } from 'ember-concurrency';
export default class ConfigureServicesComponent extends Component {
@service fetch;
@@ -37,7 +38,7 @@ export default class ConfigureServicesComponent extends Component {
*/
constructor() {
super(...arguments);
this.loadConfigValues();
this.loadConfigValues.perform();
}
@action setConfigValues(config) {
@@ -48,24 +49,19 @@ export default class ConfigureServicesComponent extends Component {
}
}
@action loadConfigValues() {
this.isLoading = true;
this.fetch
.get('settings/services-config')
.then((response) => {
this.setConfigValues(response);
})
.finally(() => {
this.isLoading = false;
});
@task *loadConfigValues() {
try {
const config = yield this.fetch.get('settings/services-config');
this.setConfigValues(config);
return config;
} catch (error) {
this.notifications.serverError(error);
}
}
@action save() {
this.isLoading = true;
this.fetch
.post('settings/services-config', {
@task *save() {
try {
yield this.fetch.post('settings/services-config', {
aws: {
key: this.awsKey,
secret: this.awsSecret,
@@ -86,45 +82,36 @@ export default class ConfigureServicesComponent extends Component {
sentry: {
dsn: this.sentryDsn,
},
})
.then(() => {
this.notifications.success('Services configuration saved.');
})
.finally(() => {
this.isLoading = false;
});
} catch (error) {
this.notifications.serverError(error);
}
}
@action testTwilio() {
this.isLoading = true;
this.fetch
.post('settings/test-twilio-config', {
@task *testTwilio() {
try {
const twilioTestResponse = yield this.fetch.post('settings/test-twilio-config', {
sid: this.twilioSid,
token: this.twilioToken,
from: this.twilioFrom,
phone: this.twilioTestPhone,
})
.then((response) => {
this.twilioTestResponse = response;
})
.finally(() => {
this.isLoading = false;
});
this.twilioTestResponse = twilioTestResponse;
return twilioTestResponse;
} catch (error) {
this.notifications.serverError(error);
}
}
@action testSentry() {
this.isLoading = true;
this.fetch
.post('settings/test-sentry-config', {
@task *testSentry() {
try {
const sentryTestResponse = yield this.fetch.post('settings/test-sentry-config', {
dsn: this.sentryDsn,
})
.then((response) => {
this.sentryTestResponse = response;
})
.finally(() => {
this.isLoading = false;
});
this.sentryTestResponse = sentryTestResponse;
return sentryTestResponse;
} catch (error) {
this.notifications.serverError(error);
}
}
}

View File

@@ -1,4 +1,4 @@
<ContentPanel @title="SocketCluster Connection" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="SocketCluster Connection" @open={{true}} @wrapperClass="bordered-classic">
<p class="mb-4">The SocketCluster configuration cannot be changed at this time.</p>
<div id="output" class="font-mono rounded-lg max-h-full px-6 py-4 overflow-y-scroll bg-black shadow-inner dark:shadow-none">
<div class="flex items-center justify-between mb-4">
@@ -37,7 +37,7 @@
</div>
</div>
{{#if this.testResponse}}
<div class="animate-pulse flex flex-row items-center rounded-lg border {{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<div class="flex flex-row items-center rounded-lg border {{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
<FaIcon @icon={{if (eq this.testResponse.status 'error') 'triangle-exclamation' 'circle-check'}} class="mr-1.5 {{if (eq this.testResponse.status 'error') 'text-red-200' 'text-green-200'}}" />
<span class="text-xs">{{this.this.testResponse.message}}</span>
</div>

View File

@@ -1,99 +0,0 @@
<div class="fleetbase-dashboard-grid flex items-center justify-between mb-4 mt-6 px-14">
<div class="left-section">
<h1 class="text-lg font-bold">{{this.dashboard.currentDashboard.name}}</h1>
</div>
<div class="fleetbase-dashboard-actions right-section ml-4 flex items-center">
<div class="fleetbase-model-select fleetbase-power-select ember-model-select h-10">
<DropdownButton
class="h-10"
@text={{if this.dashboard.currentDashboard.name this.dashboard.currentDashboard.name (t "component.dashboard.select-dashboard")}}
@textClass="text-sm mr-2"
@buttonClass="flex-row-reverse w-44 justify-between"
@icon="caret-down"
@iconClass="mr-0i"
@size="sm"
@iconPrefix="fas"
@triggerClass="hidden md:flex"
as |dd|
>
<div class="next-dd-menu mt-1 mx-0" aria-labelledby="user-menu">
<div class="p-1">
{{#each this.dashboard.dashboards as |dashboard|}}
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.selectDashboard dashboard)}}>
<div class="flex-1 flex flex-row items-center">
<div class="w-6">
<FaIcon @icon="desktop" />
</div>
<span>{{dashboard.name}}</span>
</div>
<div>
{{#if (eq this.dashboard.currentDashboard.id dashboard.id)}}
<FaIcon @icon="check" class="text-green-500" />
{{/if}}
</div>
</a>
{{/each}}
</div>
</div>
</DropdownButton>
</div>
<div class="ml-2 relative h-10">
<DropdownButton class="h-10" @icon="ellipsis-h" @size="sm" @iconPrefix="fas" @triggerClass="hidden md:flex" as |dd|>
<div class="next-dd-menu mt-1 mx-0" aria-labelledby="user-menu">
<div class="p-1">
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.createDashboard)}}>
<div class="w-6">
<FaIcon @icon="add" />
</div>
<span>{{t "component.dashboard.create-new-dashboard"}}</span>
</a>
{{#unless (eq this.dashboard.currentDashboard.user_uuid "system")}}
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.onChangeEdit true)}}>
<div class="w-6">
<FaIcon @icon="edit" />
</div>
<span>{{t "component.dashboard.edit-layout"}}</span>
</a>
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.onAddingWidget true)}}>
<div class="w-6">
<FaIcon @icon="add" />
</div>
<span>{{t "component.dashboard.add-widgets"}}</span>
</a>
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.deleteDashboard this.dashboard.currentDashboard)}}>
<div class="w-6">
<FaIcon @icon="trash" />
</div>
<span>{{t "component.dashboard.delete-dashboard"}}</span>
</a>
{{/unless}}
</div>
</div>
</DropdownButton>
</div>
{{#if this.dashboard.isEditingDashboard}}
<div class="ml-2 h-10">
<Button @type="magic" @icon="save" @helpText={{t "component.dashboard.save-dashboard"}} @onClick={{fn this.onChangeEdit false}} class="h-10" />
</div>
{{/if}}
</div>
</div>
<div class="px-10">
<Dashboard::Create @isEdit={{this.dashboard.isEditingDashboard}} @isAddingWidget={{this.dashboard.isAddingWidget}} @dashboard={{this.dashboard.currentDashboard}} />
{{#if this.dashboard.isAddingWidget}}
<EmberWormhole @to="console-home-wormhole">
<Dashboard::WidgetPanel
@isOpen={{this.dashboard.isAddingWidget}}
@onLoad={{this.setWidgetSelectorPanelContext}}
@dashboard={{this.dashboard.currentDashboard}}
@onClose={{fn this.onAddingWidget false}}
/>
</EmberWormhole>
{{/if}}
</div>

View File

@@ -1,140 +0,0 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
/**
* DashboardComponent for managing dashboards in an Ember application.
* This component handles actions such as selecting, creating, deleting dashboards,
* and managing widget selectors and dashboard editing states.
*
* @extends Component
*/
export default class DashboardComponent extends Component {
/**
* Ember Data store service.
* @type {Service}
*/
@service store;
/**
* Internationalization service for managing translations.
* @type {Service}
*/
@service intl;
/**
* Notifications service for displaying alerts or confirmations.
* @type {Service}
*/
@service notifications;
/**
* Modals manager service for handling modal dialogs.
* @type {Service}
*/
@service modalsManager;
/**
* Fetch service for handling HTTP requests.
* @type {Service}
*/
@service fetch;
/**
* Dashboard service for business logic related to dashboards.
* @type {Service}
*/
@service dashboard;
/**
* Creates an instance of DashboardComponent.
* @memberof DashboardComponent
*/
constructor() {
super(...arguments);
this.dashboard.loadDashboards.perform();
}
/**
* Action to select a dashboard.
* @param {Object} dashboard - The dashboard to be selected.
*/
@action selectDashboard(dashboard) {
this.dashboard.selectDashboard.perform(dashboard);
}
/**
* Sets the context for the widget selector panel.
* @param {Object} widgetSelectorContext - The context object for the widget selector.
*/
@action setWidgetSelectorPanelContext(widgetSelectorContext) {
this.widgetSelectorContext = widgetSelectorContext;
}
/**
* Creates a new dashboard.
* @param {Object} dashboard - The dashboard to be created.
* @param {Object} [options={}] - Optional parameters for dashboard creation.
*/
@action createDashboard(dashboard, options = {}) {
this.modalsManager.show('modals/create-dashboard', {
title: this.intl.t('component.dashboard.create-a-new-dashboard'),
acceptButtonText: this.intl.t('component.dashboard.confirm-create-dashboard'),
confirm: async (modal, done) => {
modal.startLoading();
// Get the name from the modal options
const { name } = modal.getOptions();
await this.dashboard.createDashboard.perform(name);
done();
},
...options,
});
}
/**
* Deletes a dashboard.
* @param {Object} dashboard - The dashboard to be deleted.
* @param {Object} [options={}] - Optional parameters for dashboard deletion.
*/
@action deleteDashboard(dashboard, options = {}) {
if (this.dashboard.dashboards?.length === 1) {
return this.notifications.error(this.intl.t('component.dashboard.you-cannot-delete-this-dashboard'));
}
this.modalsManager.confirm({
title: this.intl.t('component.dashboard.are-you-sure-you-want-delete-dashboard', { dashboardName: dashboard.name }),
confirm: async (modal, done) => {
modal.startLoading();
await this.dashboard.deleteDashboard.perform(dashboard);
done();
},
...options,
});
}
/**
* Action to handle the addition of a widget.
* @param {boolean} [state=true] - The state to set for adding a widget.
*/
@action onAddingWidget(state = true) {
this.dashboard.onAddingWidget(state);
}
/**
* Sets the current dashboard.
* @param {Object} dashboard - The dashboard to be set as current.
*/
@action setCurrentDashboard(dashboard) {
this.dashboard.setCurrentDashboard.perform(dashboard);
}
/**
* Changes the editing state of the dashboard.
* @param {boolean} [state=true] - The state to set for editing the dashboard.
*/
@action onChangeEdit(state = true) {
this.dashboard.onChangeEdit(state);
}
}

View File

@@ -27,9 +27,10 @@ export default class DashboardCountComponent extends Component {
* @param {Object} { options }
* @memberof WidgetKeyMetricsCountComponent
*/
constructor(owner, { options, title }) {
constructor(owner, { options, title, value = null }) {
super(...arguments);
this.title = title;
this.value = value;
this.createRenderValueFromOptions(options);
}
@@ -40,6 +41,10 @@ export default class DashboardCountComponent extends Component {
* @memberof WidgetKeyMetricsCountComponent
*/
createRenderValueFromOptions(options = {}) {
if (value !== null) {
return;
}
let { format, currency, dateFormat, value } = options;
switch (format) {

View File

@@ -1,14 +0,0 @@
<div class="fleetbase-dashboard-grid" ...attributes>
<GridStack @options={{this.gridOptions}} @onChange={{this.onChangeGrid}}>
{{#each @dashboard.widgets as |widget|}}
<GridStackItem id={{widget.id}} @options={{spread-widget-options (hash id=widget.id options=widget.grid_options)}} class="relative">
{{component widget.component options=widget.options}}
{{#if @isEdit}}
<div class="absolute top-2 right-2">
<Button @type="default" @icon="trash" @helpText={{"Remove widget from the dashboard"}} @onClick={{fn this.removeWidget widget}} />
</div>
{{/if}}
</GridStackItem>
{{/each}}
</GridStack>
</div>

View File

@@ -1,99 +0,0 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action, computed } from '@ember/object';
import { inject as service } from '@ember/service';
/**
* Component responsible for creating and managing the dashboard layout.
* Provides functionalities such as toggling widget float, changing grid layout, and removing widgets.
*
* @extends Component
*/
export default class DashboardCreateComponent extends Component {
/**
* Notifications service for displaying alerts or errors.
* @type {Service}
*/
@service notifications;
/**
* Tracked array to keep track of widgets that have been updated.
* @type {Array}
*/
@tracked updatedWidgets = [];
/**
* Action to toggle the floating state of widgets on the grid.
*/
@action toggleFloat() {
this.shouldFloat = !this.shouldFloat;
}
/**
* Handles changes to the grid layout, such as repositioning or resizing widgets.
* Iterates over each widget event detail and updates the corresponding widget's properties if necessary.
*
* @param {Event} event - Event containing details about the grid change.
* @action
*/
@action onChangeGrid(event) {
const { dashboard } = this.args;
event.detail.forEach((currentWidgetEvent) => {
const alreadyUpdated = this.updatedWidgets.find((item) => item.id === currentWidgetEvent.id);
if (alreadyUpdated || !this.dashboard) {
return;
}
const changedWidget = dashboard.widgets.find((widget) => widget.id === currentWidgetEvent.id);
if (!changedWidget) {
return;
}
const { x, y, w, h } = currentWidgetEvent;
const response = changedWidget.updateProperties({
grid_options: { x, y, w, h },
});
if (response) {
this.updatedWidgets.push(changedWidget);
}
});
}
/**
* Removes a specified widget from the dashboard.
* Performs a removal operation on the dashboard and handles any errors that occur during the process.
*
* @param {Object} widget - The widget object to be removed.
* @action
*/
@action removeWidget(widget) {
const { dashboard } = this.args;
if (dashboard) {
dashboard.removeWidget(widget.id).catch((error) => {
this.notifications.serverError(error);
});
}
}
/**
* Computed property that returns grid options based on the current edit state.
* Configures grid behavior such as floating, animation, and drag and resize capabilities.
*
* @computed
* @returns {Object} An object containing grid configuration options.
*/
@computed('args.isEdit') get gridOptions() {
return {
float: true,
animate: true,
acceptWidgets: true,
alwaysShowResizeHandle: this.args.isEdit,
disableDrag: !this.args.isEdit,
disableResize: !this.args.isEdit,
resizable: { handles: 'all' },
cellHeight: 30,
};
}
}

View File

@@ -3,7 +3,7 @@ import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { isArray } from '@ember/array';
import { task } from 'ember-concurrency-decorators';
import { task } from 'ember-concurrency';
export default class MetricComponent extends Component {
@service fetch;

View File

@@ -1,31 +0,0 @@
<Overlay @isOpen={{@isOpen}} @onLoad={{this.setOverlayContext}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width={{or this.width @width "400px"}}>
<Overlay::Header @title={{t "component.dashboard-widget-panel.select-widgets"}} @hideStatusDot={{true}} @titleWrapperClass="leading-5">
<div class="flex flex-1 justify-end">
<Button @type="default" @icon="times" @helpText={{t "component.dashboard-widget-panel.close-and-save"}} @onClick={{this.onPressClose}} />
</div>
</Overlay::Header>
<Overlay::Body @wrapperClass="new-service-rate-overlay-body px-4 space-y-4 pt-4">
<div class="grid grid-cols-1 gap-4 text-xs dark:text-gray-100">
{{#each this.availableWidgets as |widget|}}
<div
class="rounded-lg border border-gray-300 bg-white dark:border-gray-700 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700 transition-all duration-300 ease-in-out shadow-md px-4 py-2 cursor-pointer"
{{on "click" (fn this.addWidgetToDashboard widget)}}
>
<div class="flex flex-row items-center leading-6 mb-2.5">
<div class="w-8 flex items-center justify-start">
<FaIcon @icon={{widget.icon}} class="text-lg text-gray-600 dark:text-gray-300" />
</div>
<p class="text-sm truncate font-semibold dark:text-gray-100 text-gray-800">
{{t "component.dashboard-widget-panel.widget-name" widgetName=widget.name}}
</p>
</div>
<div>
<p class="text-xs dark:text-gray-100 text-gray-800">{{widget.description}}</p>
</div>
</div>
{{/each}}
</div>
<Spacer @height="300px" />
</Overlay::Body>
</Overlay>

View File

@@ -1,60 +0,0 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
export default class DashboardWidgetPanelComponent extends Component {
@service universe;
@tracked availableWidgets = [];
@tracked dashboard;
@tracked isOpen = true;
@service notifications;
/**
* Constructs the component and applies initial state.
*/
constructor(owner, { dashboard }) {
super(...arguments);
this.availableWidgets = this.universe.getDashboardWidgets();
this.dashboard = dashboard;
}
/**
* Sets the overlay context.
*
* @action
* @param {OverlayContextObject} overlayContext
*/
@action setOverlayContext(overlayContext) {
this.context = overlayContext;
if (typeof this.args.onLoad === 'function') {
this.args.onLoad(...arguments);
}
}
@action addWidgetToDashboard(widget) {
// If widget is a component definition/class
if (typeof widget.component === 'function') {
widget.component = widget.component.name;
}
this.args.dashboard.addWidget(widget).catch((error) => {
this.notifications.serverError(error);
});
}
/**
* Handles cancel button press.
*
* @action
*/
@action onPressClose() {
this.isOpen = false;
if (typeof this.args.onClose === 'function') {
this.args.onClose();
}
}
}

View File

@@ -8,7 +8,7 @@
</a>
</div>
<div class="px-4 py-2.5">
{{#if this.isLoading}}
{{#if this.loadBlogPosts.isRunning}}
<Spinner />
{{else}}
<ul class="space-y-2">

View File

@@ -1,28 +1,42 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { isArray } from '@ember/array';
import { storageFor } from 'ember-local-storage';
import { add, isPast } from 'date-fns';
import { task } from 'ember-concurrency';
export default class FleetbaseBlogComponent extends Component {
@storageFor('local-cache') localCache;
@service fetch;
@tracked posts = [];
@tracked isLoading = false;
constructor() {
super(...arguments);
this.loadBlogPosts();
this.loadBlogPosts.perform();
}
@action loadBlogPosts() {
this.isLoading = true;
@task *loadBlogPosts() {
// Check if cached data and expiration are available
const cachedData = this.localCache.get('fleetbase-blog-data');
const expiration = this.localCache.get('fleetbase-blog-data-expiration');
return this.fetch
.get('lookup/fleetbase-blog')
.then((response) => {
this.posts = response;
})
.finally(() => {
this.isLoading = false;
});
// Check if the cached data is still valid
if (cachedData && isArray(cachedData) && expiration && !isPast(new Date(expiration))) {
// Use cached data
this.posts = cachedData;
} else {
// Fetch new data
try {
const data = yield this.fetch.get('lookup/fleetbase-blog');
this.posts = isArray(data) ? data : [];
if (data) {
this.localCache.set('fleetbase-blog-data', data);
this.localCache.set('fleetbase-blog-data-expiration', add(new Date(), { hours: 6 }));
}
} catch (err) {
debug('Failed to load blog: ' + err.message);
}
}
}
}

View File

@@ -1,6 +1,6 @@
<div class="fleetbase-github-card relative flex-1 w-full" ...attributes>
<div class="border dark:border-gray-700 border-gray-200 dark:bg-gray-800 bg-gray-50 rounded-lg shadow-sm flex flex-col">
{{#if this.isLoading}}
{{#if this.getRepositoryData.isRunning}}
<div class="p-4">
<Spinner />
</div>

View File

@@ -10,9 +10,12 @@ import fetch from 'fetch';
export default class GithubCardComponent extends Component {
@storageFor('local-cache') localCache;
@tracked data;
@tracked tags;
@tracked isLoading = false;
@tracked data = {
owner: {
avatar_url: 'https://avatars.githubusercontent.com/u/38091894?v=4',
},
};
@tracked tags = [];
@computed('tags.length') get latestRelease() {
if (isArray(this.tags) && this.tags.length) {
@@ -49,7 +52,7 @@ export default class GithubCardComponent extends Component {
this.data = cachedData;
} else {
// Fetch new data
const response = yield fetch('https://api.github.com/repos/fleetbase/fleetbase');
const response = yield fetch('https://api.github.com/repos/fleetbase/fleetbase', { cache: 'default' });
if (response.ok) {
this.data = yield response.json();
this.localCache.set('fleetbase-github-data', this.data);
@@ -69,7 +72,7 @@ export default class GithubCardComponent extends Component {
this.tags = cachedTags;
} else {
// Fetch new tags
const response = yield fetch('https://api.github.com/repos/fleetbase/fleetbase/tags');
const response = yield fetch('https://api.github.com/repos/fleetbase/fleetbase/tags', { cache: 'default' });
if (response.ok) {
this.tags = yield response.json();
this.localCache.set('fleetbase-github-tags', this.tags);

View File

@@ -0,0 +1,36 @@
{{#if this.isImpersonator}}
<EmberWormhole @to="view-header-actions">
<div class="next-user-button locale-selector-tray" ...attributes>
<BasicDropdown
class={{@wrapperClass}}
@onOpen={{@onOpen}}
@onClose={{@onClose}}
@calculatePosition={{this.calculatePosition}}
@verticalPosition={{@verticalPosition}}
@horizontalPosition={{@horizontalPosition}}
@renderInPlace={{or @renderInPlace (not (media "isMobile"))}}
as |dd|
>
<dd.Trigger class="{{@triggerClass}} local-selector-tray-trigger {{if (media 'isMobile') 'is-mobile'}}">
<div class="next-org-button-trigger flex-shrink-0 {{if dd.isOpen 'is-open'}}">
<FaIcon @icon="user-secret" @size="sm" />
</div>
</dd.Trigger>
<dd.Content class="{{@contentClass}} locale-selector-tray-content {{if (media 'isMobile') 'is-mobile'}}">
<div class="next-dd-menu {{@dropdownMenuClass}} {{if dd.isOpen 'is-open'}}">
<div class="px-1">
<a href="javascript:;" class="next-dd-item" {{on "click" this.restoreSession}}>
<div class="flex flex-row items-centerw-full">
<div class="w-6">
<FaIcon @icon="person-walking-arrow-loop-left" @size="sm" />
</div>
<div>End Impersonation</div>
</div>
</a>
</div>
</div>
</dd.Content>
</BasicDropdown>
</div>
</EmberWormhole>
{{/if}}

View File

@@ -0,0 +1,39 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { later } from '@ember/runloop';
export default class ImpersonatorTrayComponent extends Component {
@service session;
@service notifications;
@service router;
@service fetch;
get isImpersonator() {
return typeof this.session.data?.authenticated?.impersonator === 'string';
}
/**
* Restore session
*
* @memberof ConsoleAdminOrganizationsIndexUsersController
*/
@action async restoreSession() {
try {
const { token } = await this.fetch.delete('auth/impersonate');
await this.router.transitionTo('console');
this.session.manuallyAuthenticate(token);
this.notifications.info(`Ending impersonation session.`);
later(
this,
() => {
window.location.reload();
},
600
);
} catch (error) {
this.notifications.serverError(error);
}
}
}

View File

@@ -0,0 +1,12 @@
<Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
<div class="modal-body-container pt-0i text-gray-900 dark:text-white">
<InputGroup @name="Organization name" @value={{@options.organization.name}} />
<InputGroup @name="Organization description" @value={{@options.organization.description}} />
<InputGroup @name="Organization phone number">
<PhoneInput @value={{@options.organization.phone}} @onInput={{fn (mut @options.organization.phone)}} class="form-input w-full" />
</InputGroup>
<InputGroup @name="Organization currency">
<CurrencySelect @value={{@options.organization.currency}} @onSelect={{fn (mut @options.organization.currency)}} @triggerClass="w-full form-select" />
</InputGroup>
</div>
</Modal::Default>

View File

@@ -0,0 +1,3 @@
import Component from '@glimmer/component';
export default class ModalsEditOrganizationComponent extends Component {}

View File

@@ -0,0 +1,43 @@
<Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
<div class="modal-body-container pt-0i text-gray-900 dark:text-white">
{{#if @options.isOwner}}
{{#if @options.hasOtherMembers}}
<p>
<div class="text-base mb-2">
As the owner of
<strong>{{@options.organization.name}}</strong>, leaving the organization requires you to nominate a new owner.
</div>
<div>Please select a member from the dropdown below to transfer ownership before you can proceed.</div>
</p>
<InputGroup @name="Select a New Owner" @wrapperClass="mt-2 mb-0i">
<Select
@options={{@options.organization.users}}
@value={{@options.newOwnerId}}
@onSelect={{@options.selectNewOwner}}
@optionLabel="name"
@optionValue="id"
@placeholder="Select a member"
/>
</InputGroup>
{{else if @options.willBeDeleted}}
<p>
<div class="text-base mb-2">
You are the sole owner of
<strong>{{@options.organization.name}}</strong>.
</div>
<div>By leaving, the organization will be permanently deleted along with all its data.</div>
<div>Are you sure you want to proceed?</div>
</p>
<p class="mt-3"><em>This action cannot be undone.</em></p>
{{/if}}
{{else}}
<p>
<div class="text-base mb-2">
Are you sure you want to leave the organization
<strong>{{@options.organization.name}}</strong>?
</div>
<div>You will no longer have access to its resources and settings.</div>
</p>
{{/if}}
</div>
</Modal::Default>

View File

@@ -0,0 +1,3 @@
import Component from '@glimmer/component';
export default class ModalsLeaveOrganizationComponent extends Component {}

View File

@@ -0,0 +1,61 @@
<div class="flex items-center justify-center h-screen min-h-screen px-4 py-12 bg-gray-50 dark:bg-gray-900 sm:px-6 lg:px-8 overflow-y-scroll">
<div class="w-full max-w-md h-screen flex items-center justify-center py-4">
<div class="bg-white dark:bg-gray-800 py-5 px-4 shadow rounded-lg w-full">
<div class="mb-4">
<Image src={{@brand.logo_url}} @fallbackSrc="/images/fleetbase-logo-svg.svg" alt={{t "app.name"}} height="56" class="h-10 object-contain mx-auto" />
<div class="mt-2">
<h2 class="text-center text-lg font-extrabold text-gray-900 dark:text-white truncate">
{{t "onboard.index.title"}}
</h2>
</div>
</div>
<div class="flex px-3 py-2 mb-4 rounded-md shadow-sm bg-blue-200">
<div>
<FaIcon @icon="hand-spock" @size="lg" class="text-blue-900 mr-4" />
</div>
<p class="flex-1 text-sm text-blue-900 dark:text-blue-900">
{{t "onboard.index.welcome-title" htmlSafe=true companyName=(t "app.name")}}
{{t "onboard.index.welcome-text"}}
</p>
</div>
<form {{on "submit" (perform this.onboard)}}>
{{#if this.error}}
<InfoBlock @icon="exclamation-triangle" @text={{this.error}} class="mb-6 px-3 py-2 bg-red-300 text-red-900" @textClass="text-red-900" />
{{/if}}
<InputGroup @name={{t "onboard.index.full-name"}} @value={{this.name}} @helpText={{t "onboard.index.full-name-help-text"}} @inputClass="input-lg" />
<InputGroup @name={{t "onboard.index.your-email"}} @type="email" @value={{this.email}} @helpText={{t "onboard.index.your-email-help-text"}} @inputClass="input-lg" />
<InputGroup @name={{t "onboard.index.phone"}} @helpText={{t "onboard.index.phone-help-text"}}>
<PhoneInput @onInput={{fn (mut this.phone)}} class="form-input input-lg w-full" />
</InputGroup>
<InputGroup @name={{t "onboard.index.organization-name"}} @value={{this.organization_name}} @helpText={{t "onboard.index.organization-help-text"}} @inputClass="input-lg" />
<InputGroup @name={{t "onboard.index.password"}} @value={{this.password}} @type="password" @helpText={{t "onboard.index.password-help-text"}} @inputClass="input-lg" />
<InputGroup
@name={{t "onboard.index.confirm-password"}}
@value={{this.password_confirmation}}
@type="password"
@helpText={{t "onboard.index.confirm-password-help-text"}}
@inputClass="input-lg"
/>
<div class="flex items-center justify-end mt-5">
<Button
@buttonType="submit"
@icon="check"
@iconPrefix="fas"
@type="primary"
@size="lg"
@text={{t "onboard.index.continue-button-text"}}
@isLoading={{this.onboard.isRunning}}
@disabled={{not this.filled}}
/>
</div>
</form>
<RegistryYield @registry="onboard" as |YieldedComponent ctx|>
<YieldedComponent @context={{ctx}} />
</RegistryYield>
</div>
</div>
</div>

View File

@@ -0,0 +1,77 @@
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action, getProperties } from '@ember/object';
import { isBlank } from '@ember/utils';
import { task } from 'ember-concurrency';
import OnboardValidations from '../../validations/onboard';
import lookupValidator from 'ember-changeset-validations';
import Changeset from 'ember-changeset';
export default class OnboardingFormComponent extends Component {
@service fetch;
@service session;
@service router;
@service notifications;
@service urlSearchParams;
@tracked name;
@tracked email;
@tracked phone;
@tracked organization_name;
@tracked password;
@tracked password_confirmation;
@tracked error;
get filled() {
// eslint-disable-next-line ember/no-get
const input = getProperties(this, 'name', 'email', 'phone', 'organization_name', 'password', 'password_confirmation');
return Object.values(input).every((val) => !isBlank(val));
}
@task *onboard(event) {
event?.preventDefault?.();
// eslint-disable-next-line ember/no-get
const input = getProperties(this, 'name', 'email', 'phone', 'organization_name', 'password', 'password_confirmation');
const changeset = new Changeset(input, lookupValidator(OnboardValidations), OnboardValidations);
yield changeset.validate();
if (changeset.get('isInvalid')) {
const errorMessage = changeset.errors.firstObject.validation.firstObject;
this.notifications.error(errorMessage);
return;
}
// Set user timezone
input.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
try {
const { status, skipVerification, token, session } = yield this.fetch.post('onboard/create-account', input);
if (status !== 'success') {
this.notifications.error('Onboard failed');
return;
}
// save session
this.args.context.persist('session', session);
if (skipVerification === true && token) {
// only manually authenticate if skip verification
this.session.isOnboarding().manuallyAuthenticate(token);
yield this.router.transitionTo('console');
return this.notifications.success('Welcome to Fleetbase!');
} else {
this.args.orchestrator.next();
this.urlSearchParams.setParamsToCurrentUrl({
step: this.args.orchestrator?.current?.id,
session,
});
}
} catch (err) {
this.notifications.serverError(err);
}
}
}

View File

@@ -0,0 +1,82 @@
{{page-title (t "onboard.verify-email.header-title")}}
<div class="flex items-center justify-center h-screen min-h-screen px-4 py-12 bg-gray-50 dark:bg-gray-900 sm:px-6 lg:px-8 overflow-y-scroll">
<div class="w-full max-w-md h-screen flex items-center justify-center py-4">
{{#if this.initialized}}
<div class="bg-white dark:bg-gray-800 py-8 px-4 shadow rounded-lg w-full">
<div class="mb-6">
<LinkTo @route="console" class="flex items-center justify-center">
<LogoIcon @size="12" class="rounded-md" />
</LinkTo>
<h2 class="mt-6 text-center text-lg font-extrabold text-gray-900 dark:text-white truncate">
{{t "onboard.verify-email.title"}}
</h2>
</div>
<InfoBlock @type="info" @icon="shield-halved" @iconSize="lg">
{{t "onboard.verify-email.message-text" htmlSafe=true}}
</InfoBlock>
<form class="mt-8 space-y-6" {{on "submit" (perform this.verify)}}>
<InputGroup
@type="tel"
@name={{t "onboard.verify-email.verification-input-label"}}
@value={{this.code}}
@helpText={{t "onboard.verify-email.verification-code-text"}}
@inputClass="input-lg"
{{on "input" this.verification.validateInput}}
{{did-insert this.verification.validateInput}}
/>
<div class="flex flex-row items-center space-x-4">
<Button
@icon="check"
@iconPrefix="fas"
@buttonType="submit"
@type="primary"
@size="lg"
@text="Verify & Continue"
@isLoading={{this.verify.isRunning}}
@disabled={{not this.verification.ready}}
/>
<a href="#" {{on "click" this.verification.didntReceiveCode}} class="text-sm text-blue-400 hover:text-blue-300">{{t "onboard.verify-email.didnt-receive-a-code"}}</a>
</div>
{{#if this.verification.waiting}}
<div class="flex flex-col flex-grow-0 flex-shrink-0 text-sm bg-yellow-800 border border-yellow-600 px-2 py-2 rounded-md text-yellow-100 my-4 transition-all">
<div class="flex flex-row items-start mb-2">
<div class="w-8 flex-grow-0 flex-shrink-0">
<FaIcon @icon="triangle-exclamation" @size="xl" class="pt-1" />
</div>
<div class="flex-1">
<div class="flex-1 text-sm text-yellow-100">
<div>{{t "auth.verification.didnt-receive-a-code" htmlSafe=true}}</div>
<div>{{t "auth.verification.not-sent.alternative-choice" htmlSafe=true}}</div>
</div>
</div>
</div>
<div class="flex items-center space-x-2">
<Button
@text={{t "auth.verification.not-sent.resend-email"}}
@buttonType="button"
@type="link"
class="text-yellow-100"
@wrapperClass="px-4 py-2 bg-gray-900 bg-opacity-25 hover:opacity-50"
@onClick={{this.verification.resendEmail}}
/>
<Button
@text={{t "auth.verification.not-sent.send-by-sms"}}
@buttonType="button"
@type="link"
class="text-yellow-100"
@wrapperClass="px-4 py-2 bg-gray-900 bg-opacity-25 hover:opacity-50"
@onClick={{this.verification.resendBySms}}
/>
</div>
</div>
{{/if}}
</form>
</div>
{{/if}}
</div>
</div>

View File

@@ -0,0 +1,53 @@
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { later, next } from '@ember/runloop';
import { not } from '@ember/object/computed';
import { task } from 'ember-concurrency';
export default class OnboardingVerifyEmailComponent extends Component {
@service('session') authSession;
@service('user-verification') verification;
@service fetch;
@service notifications;
@service router;
@service urlSearchParams;
@tracked code;
@tracked session;
@tracked initialized = false;
constructor() {
super(...arguments);
next(() => this.#initialize());
}
#initialize() {
this.code = this.urlSearchParams.get('code');
this.session = this.args.context.get('session') ?? this.urlSearchParams.get('session');
this.initialized = true;
this.verification.start();
}
@task *verify(event) {
event?.preventDefault?.();
try {
const { status, token } = yield this.fetch.post('onboard/verify-email', { session: this.session, code: this.code });
if (status === 'ok') {
this.notifications.success('Email successfully verified!');
if (token) {
this.notifications.info('Welcome to Fleetbase!');
this.authSession.manuallyAuthenticate(token);
return this.router.transitionTo('console');
}
return this.router.transitionTo('auth.login');
}
} catch (error) {
this.notifications.serverError(error);
}
}
}

View File

@@ -0,0 +1,13 @@
<section class="onboarding step-host">
{{#if this.initialized}}
{{#if this.orchestrator.wrapper}}
{{component (lazy-engine-component this.orchestrator.wrapper) currentStepComponent=this.currentComponent context=this.context orchestrator=this.orchestrator brand=@brand}}
{{else if this.currentComponent}}
{{component (lazy-engine-component this.currentComponent) context=this.context orchestrator=this.orchestrator brand=@brand}}
{{/if}}
{{else}}
<div class="flex items-center justify-center min-h-24">
<Spinner />
</div>
{{/if}}
</section>

View File

@@ -0,0 +1,27 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { next } from '@ember/runloop';
export default class OnboardingYieldComponent extends Component {
@service('onboarding-orchestrator') orchestrator;
@service('onboarding-context') context;
@tracked initialized = false;
get currentComponent() {
return this.orchestrator.current && this.orchestrator.current.component;
}
constructor(owner, { step, session, code }) {
super(...arguments);
next(() => this.#initialize(step, session, code));
}
#initialize(step, session, code) {
if (step) this.orchestrator.goto(step);
if (session) this.context.persist('session', session);
if (code) this.context.set('code', code);
this.initialized = true;
}
}

View File

@@ -1,6 +1,6 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { task } from 'ember-concurrency-decorators';
import { task } from 'ember-concurrency';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';

View File

@@ -1,28 +1,11 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { task } from 'ember-concurrency';
export default class AuthForgotPasswordController extends Controller {
/**
* Inject the `fetch` service
*
* @memberof AuthForgotPasswordController
*/
@service fetch;
/**
* Inject the `notifications` service
*
* @memberof AuthForgotPasswordController
*/
@service notifications;
/**
* Inject the `intl` service
*
* @memberof AuthForgotPasswordController
*/
@service intl;
/**
@@ -32,13 +15,6 @@ export default class AuthForgotPasswordController extends Controller {
*/
@tracked email;
/**
* The loading state
*
* @memberof AuthForgotPasswordController
*/
@tracked isLoading;
/**
* Indicator if request has been sent.
*
@@ -46,30 +22,27 @@ export default class AuthForgotPasswordController extends Controller {
*/
@tracked isSent = false;
/**
* Query parameters.
*
* @memberof AuthForgotPasswordController
*/
queryParams = ['email'];
/**
* Sends a secure magic reset link to the user provided email.
*
* @memberof AuthForgotPasswordController
*/
@action sendSecureLink(event) {
// firefox patch
@task *sendSecureLink(event) {
event.preventDefault();
const { email } = this;
this.isLoading = true;
this.fetch
.post('auth/get-magic-reset-link', { email })
.then(() => {
this.notifications.success(this.intl.t('auth.forgot-password.success-message'));
this.isSent = true;
})
.catch((error) => {
this.notifications.serverError(error);
})
.finally(() => {
this.isLoading = false;
});
try {
yield this.fetch.post('auth/get-magic-reset-link', { email: this.email });
this.notifications.success(this.intl.t('auth.forgot-password.success-message'));
this.isSent = true;
} catch (error) {
this.notifications.serverError(error);
}
}
}

View File

@@ -5,53 +5,12 @@ import { action } from '@ember/object';
import pathToRoute from '@fleetbase/ember-core/utils/path-to-route';
export default class AuthLoginController extends Controller {
/**
* Inject the `forgotPassword` controller
*
* @var {Controller}
*/
@controller('auth.forgot-password') forgotPasswordController;
/**
* Inject the `notifications` service
*
* @var {Service}
*/
@service notifications;
/**
* Inject the `urlSearchParams` service
*
* @var {Service}
*/
@service urlSearchParams;
/**
* Inject the `session` service
*
* @var {Service}
*/
@service session;
/**
* Inject the `router` service
*
* @var {Service}
*/
@service router;
/**
* Inject the `intl` service
*
* @var {Service}
*/
@service intl;
/**
* Inject the `fetch` service
*
* @var {Service}
*/
@service fetch;
/**
@@ -110,8 +69,20 @@ export default class AuthLoginController extends Controller {
*/
@tracked failedAttempts = 0;
/**
* Authentication token.
*
* @memberof AuthLoginController
*/
@tracked token;
/**
* Action to login user.
*
* @param {Event} event
* @return {void}
* @memberof AuthLoginController
*/
@action async login(event) {
// firefox patch
event.preventDefault();
@@ -166,6 +137,11 @@ export default class AuthLoginController extends Controller {
return this.sendUserForEmailVerification(identity);
}
// Handle password reset required
if (error.toString().includes('reset required')) {
return this.sendUserForPasswordReset(identity);
}
return this.failure(error);
}
@@ -210,6 +186,20 @@ export default class AuthLoginController extends Controller {
});
}
/**
* Sends user to forgot password flow.
*
* @param {String} email
* @return {Promise<Transition>}
* @memberof AuthLoginController
*/
@action sendUserForPasswordReset(email) {
this.notifications.warning(this.intl.t('auth.login.password-reset-required'));
return this.router.transitionTo('auth.forgot-password', { queryParams: { email } }).then(() => {
this.reset('error');
});
}
/**
* Sets correct route to send user to after login.
*

View File

@@ -4,32 +4,9 @@ import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency';
export default class AuthResetPasswordController extends Controller {
/**
* Inject the `fetch` service
*
* @memberof AuthResetPasswordController
*/
@service fetch;
/**
* Inject the `notifications` service
*
* @memberof AuthResetPasswordController
*/
@service notifications;
/**
* Inject the `router` service
*
* @memberof AuthResetPasswordController
*/
@service router;
/**
* Inject the `intl` service
*
* @memberof AuthResetPasswordController
*/
@service intl;
/**
@@ -53,6 +30,13 @@ export default class AuthResetPasswordController extends Controller {
*/
@tracked password_confirmation;
/**
* Query parameters.
*
* @memberof AuthResetPasswordController
*/
queryParams = ['code'];
/**
* The reset password task.
*

View File

@@ -3,118 +3,27 @@ import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { later } from '@ember/runloop';
import { not } from '@ember/object/computed';
import { task } from 'ember-concurrency';
export default class AuthVerificationController extends Controller {
/**
* Inject the `fetch` service
*
* @memberof OnboardIndexController
*/
@service fetch;
/**
* Inject the `notifications` service
*
* @memberof OnboardIndexController
*/
@service notifications;
/**
* Inject the `modalsManager` service
*
* @memberof OnboardIndexController
*/
@service modalsManager;
/**
* Inject the `currentUser` service
*
* @memberof OnboardIndexController
*/
@service currentUser;
/**
* Inject the `router` service
*
* @memberof OnboardIndexController
*/
@service router;
/**
* Inject the `session` service
*
* @memberof OnboardIndexController
*/
@service session;
@service intl;
/**
* The session paramerer.
*
* @memberof OnboardVerifyEmailController
*/
/** props */
@tracked hello;
/**
* The token paramerer.
*
* @memberof OnboardVerifyEmailController
*/
@tracked token;
/**
* The loading state of the verification request.
*
* @memberof OnboardVerifyEmailController
*/
@tracked isLoading = false;
/**
* Validation state tracker.
*
* @memberof OnboardVerifyEmailController
*/
@tracked isReadyToSubmit = false;
/**
* The request timeout to trigger alternative verification options.
*
* @memberof OnboardVerifyEmailController
*/
@tracked waitTimeout = 1000 * 60 * 1.25;
/**
* Determines if Fleetbase is still awaiting verification after a certain time.
*
* @memberof OnboardVerifyEmailController
*/
@tracked stillWaiting = false;
/**
* the input code.
*
* @memberof OnboardVerifyEmailController
*/
@tracked code;
@tracked email;
@tracked isReadyToSubmit = false;
@tracked waitTimeout = 1000 * 60 * 1.25;
@tracked stillWaiting = false;
@tracked queryParams = ['hello', 'token', 'code'];
/**
* The query param for the session token.
*
* @memberof OnboardVerifyEmailController
*/
@tracked queryParams = ['hello', 'token'];
/**
* The boolean opposite of `isReadyToSubmit`
*
* @memberof OnboardVerifyEmailController
*/
@not('isReadyToSubmit') isNotReadyToSubmit;
/**
* Creates an instance of OnboardVerifyEmailController.
* @memberof OnboardVerifyEmailController
*/
constructor() {
super(...arguments);
@@ -127,21 +36,10 @@ export default class AuthVerificationController extends Controller {
);
}
/**
* Allow user to manually trigger no code received prompt.
*
* @memberof AuthVerificationController
*/
@action onDidntReceiveCode() {
this.stillWaiting = true;
}
/**
* Validates the input
*
* @param {InputEvent} { target: { value } }
* @memberof OnboardVerifyEmailController
*/
@action validateInput({ target: { value } }) {
if (value.length > 5) {
this.isReadyToSubmit = true;
@@ -150,12 +48,6 @@ export default class AuthVerificationController extends Controller {
}
}
/**
* Validates input on the first render
*
* @param {HTMLElement} el
* @memberof AuthVerificationController
*/
@action validateInitInput(el) {
const value = el.value;
if (value.length > 5) {
@@ -165,89 +57,70 @@ export default class AuthVerificationController extends Controller {
}
}
/**
* Submits to verify code.
*
* @return {Promise}
* @memberof OnboardVerifyEmailController
*/
@action verifyCode() {
const { token, code, email } = this;
@task *verifyCode() {
try {
const { status, token } = yield this.fetch.post('auth/verify-email', { token: this.token, code: this.code, email: this.email, authenticate: true });
if (status === 'ok') {
this.notifications.success('Email successfully verified!');
this.isLoading = true;
if (token) {
this.notifications.info(`Welcome to ${this.intl.t('app.name')}`);
this.session.manuallyAuthenticate(token);
return this.fetch
.post('auth/verify-email', { token, code, email, authenticate: true })
.then(({ status, token }) => {
if (status === 'ok') {
this.notifications.success('Email successfully verified!');
if (token) {
this.notifications.info('Welcome to Fleetbase!');
this.session.manuallyAuthenticate(token);
return this.router.transitionTo('console');
}
return this.router.transitionTo('auth.login');
return this.router.transitionTo('console');
}
})
.catch((error) => {
this.notifications.serverError(error);
})
.finally(() => {
this.isLoading = false;
});
return this.router.transitionTo('auth.login');
}
} catch (error) {
this.notifications.serverError(error);
}
}
/**
* Action to resend verification code by SMS.
*
* @memberof OnboardVerifyEmailController
*/
@action resendBySms() {
this.modalsManager.show('modals/verify-by-sms', {
title: 'Verify Account by Phone',
acceptButtonText: 'Send',
phone: this.currentUser.phone,
confirm: (modal) => {
confirm: async (modal) => {
modal.startLoading();
const phone = modal.getOption('phone');
if (!phone) {
this.notifications.error('No phone number provided.');
}
return this.fetch
.post('onboard/send-verification-sms', { phone, session: this.hello })
.then(() => {
this.notifications.success('Verification code SMS sent!');
})
.catch((error) => {
this.notifications.serverError(error);
});
try {
await this.fetch.post('onboard/send-verification-sms', { phone, session: this.hello });
this.notifications.success('Verification code SMS sent!');
modal.done();
} catch (error) {
this.notifications.serverError(error);
modal.stopLoading();
}
},
});
}
/**
* Action to resend verification code by email.
*
* @memberof OnboardVerifyEmailController
*/
@action resendEmail() {
this.modalsManager.show('modals/resend-verification-email', {
title: 'Resend Verification Code',
acceptButtonText: 'Send',
email: this.currentUser.email,
confirm: (modal) => {
confirm: async (modal) => {
modal.startLoading();
const email = modal.getOption('email');
if (!email) {
this.notifications.error('No email number provided.');
}
return this.fetch
.post('onboard/send-verification-email', { email, session: this.hello })
.then(() => {
this.notifications.success('Verification code email sent!');
})
.catch((error) => {
this.notifications.serverError(error);
});
try {
await this.fetch.post('onboard/send-verification-email', { email, session: this.hello });
this.notifications.success('Verification code email sent!');
modal.done();
} catch (error) {
this.notifications.serverError(error);
modal.stopLoading();
}
},
});
}

View File

@@ -1,125 +1,35 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { getOwner } from '@ember/application';
import { later } from '@ember/runloop';
import { action, computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import { action } from '@ember/object';
import { isArray } from '@ember/array';
import { dasherize } from '@ember/string';
import first from '@fleetbase/ember-core/utils/first';
export default class ConsoleController extends Controller {
/**
* Inject the `currentUser` service.
*
* @var {Service}
*/
@service currentUser;
/**
* Inject the `modalsManager` service.
*
* @var {Service}
*/
@service modalsManager;
/**
* Inject the `session` service.
*
* @var {Service}
*/
@service session;
/**
* Inject the `fetch` service.
*
* @var {Service}
*/
@service fetch;
/**
* Inject the `notifications` service.
*
* @var {Service}
*/
@service notifications;
/**
* Inject the `router` service.
*
* @var {Service}
*/
@service router;
/**
* Inject the `intl` service.
*
* @var {Service}
*/
@service intl;
/**
* Inject the `universe` service.
*
* @var {Service}
*/
@service universe;
/**
* Authenticated user organizations.
*
* @var {Array}
*/
@service abilities;
@service sidebar;
@tracked organizations = [];
/**
* Sidebar Context Controls
*
* @var {SidebarContext}
*/
@tracked sidebarContext;
/**
* State of sidebar toggle icon
*
* @var {SidebarContext}
*/
@tracked sidebarToggleEnabled = true;
/**
* The sidebar toggle state.
*
* @var {SidebarContext}
*/
@tracked sidebarToggleState = {};
@tracked hiddenSidebarRoutes = ['console.home', 'console.notifications', 'console.virtual'];
@tracked menuItems = [];
@tracked userMenuItems = [];
@tracked organizationMenuItems = [];
/**
* Routes which should hide the sidebar menu.
*
* @var {Array}
*/
@tracked hiddenSidebarRoutes = ['console.home', 'console.extensions', 'console.notifications'];
/**
* Installed extensions.
*
* @var {Array}
*/
@computed() get extensions() {
return getOwner(this).application.extensions;
get currentRouteClass() {
return dasherize(this.router.currentRouteName.replace(/\./g, ' '));
}
/**
* Get the currently authenticated user
*
* @var {Model}
*/
@alias('currentUser.user') user;
/**
* Creates an instance of ConsoleController.
* @memberof ConsoleController
*/
constructor() {
super(...arguments);
this.router.on('routeDidChange', (transition) => {
@@ -132,17 +42,17 @@ export default class ConsoleController extends Controller {
// Hide the sidebar if the current route is in hiddenSidebarRoutes
if (shouldHideSidebar) {
this.sidebarContext.hideNow();
this.sidebar.hideNow();
this.sidebarToggleEnabled = false;
return; // Exit early as no further action is required
}
// If the sidebar was manually closed and not on a hidden route, keep it closed
if (isSidebarManuallyClosed) {
this.sidebarContext.hideNow();
this.sidebar.hideNow();
} else {
// Otherwise, show the sidebar
this.sidebarContext.show();
this.sidebar.show();
}
// Ensure toggle is enabled unless on a hidden route
@@ -177,7 +87,7 @@ export default class ConsoleController extends Controller {
this.universe.trigger('sidebarContext.available', sidebarContext);
if (this.hiddenSidebarRoutes.includes(this.router.currentRouteName)) {
this.sidebarContext.hideNow();
this.sidebar.hideNow();
this.sidebarToggleEnabled = false;
}
}
@@ -198,13 +108,13 @@ export default class ConsoleController extends Controller {
*
* @void
*/
@action invalidateSession(noop, event) {
@action async invalidateSession(noop, event) {
event.preventDefault();
this.session.invalidateWithLoader();
await this.session.invalidateWithLoader();
}
/**
* Action to invalidate and log user out
* Action to create or join an organization.
*
* @void
*/
@@ -228,53 +138,51 @@ export default class ConsoleController extends Controller {
changeAction: (action) => {
this.modalsManager.setOption('action', action);
},
confirm: (modal) => {
confirm: async (modal) => {
modal.startLoading();
const { action, next, name, description, phone, currency, country, timezone } = modal.getOptions();
if (action === 'join') {
return this.fetch
.post('auth/join-organization', { next })
.then(() => {
this.fetch.flushRequestCache('auth/organizations');
this.notifications.success(this.intl.t('console.create-or-join-organization.join-success-notification'));
later(
this,
() => {
window.location.reload();
},
900
);
})
.catch((error) => {
this.notifications.serverError(error);
});
}
return this.fetch
.post('auth/create-organization', {
name,
description,
phone,
currency,
country,
timezone,
})
.then(() => {
try {
await this.fetch.post('auth/join-organization', { next });
this.fetch.flushRequestCache('auth/organizations');
this.notifications.success(this.intl.t('console.create-or-join-organization.create-success-notification'));
later(
this.notifications.success(this.intl.t('console.create-or-join-organization.join-success-notification'));
return later(
this,
() => {
window.location.reload();
},
900
);
})
.catch((error) => {
this.notifications.serverError(error);
} catch (error) {
modal.stopLoading();
return this.notifications.serverError(error);
}
}
try {
await this.fetch.post('auth/create-organization', {
name,
description,
phone,
currency,
country,
timezone,
});
this.fetch.flushRequestCache('auth/organizations');
this.notifications.success(this.intl.t('console.create-or-join-organization.create-success-notification'));
return later(
this,
() => {
window.location.reload();
},
900
);
} catch (error) {
modal.stopLoading();
return this.notifications.serverError(error);
}
},
});
}
@@ -294,25 +202,24 @@ export default class ConsoleController extends Controller {
body: this.intl.t('console.switch-organization.modal-body'),
acceptButtonText: this.intl.t('console.switch-organization.modal-accept-button-text'),
acceptButtonScheme: 'primary',
confirm: (modal) => {
confirm: async (modal) => {
modal.startLoading();
return this.fetch
.post('auth/switch-organization', { next: organization.uuid })
.then(() => {
this.fetch.flushRequestCache('auth/organizations');
this.notifications.success(this.intl.t('console.switch-organization.success-notification'));
later(
this,
() => {
window.location.reload();
},
900
);
})
.catch((error) => {
this.notifications.serverError(error);
});
try {
await this.fetch.post('auth/switch-organization', { next: organization.uuid });
this.fetch.flushRequestCache('auth/organizations');
this.notifications.success(this.intl.t('console.switch-organization.success-notification'));
return later(
this,
() => {
window.location.reload();
},
900
);
} catch (error) {
modal.stopLoading();
return this.notifications.serverError(error);
}
},
});
}

View File

@@ -2,10 +2,6 @@ import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default class ConsoleAccountController extends Controller {
/**
* Inject the `universe` service.
*
* @memberof ConsoleAdminController
*/
@service('universe/menu-service') menuService;
@service universe;
}

View File

@@ -2,7 +2,7 @@ import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import { task } from 'ember-concurrency-decorators';
import { task } from 'ember-concurrency';
import getTwoFaMethods from '@fleetbase/console/utils/get-two-fa-methods';
/**
@@ -12,32 +12,9 @@ import getTwoFaMethods from '@fleetbase/console/utils/get-two-fa-methods';
* @extends Controller
*/
export default class ConsoleAccountAuthController extends Controller {
/**
* Service for handling data fetching.
*
* @type {fetch}
*/
@service fetch;
/**
* Service for displaying notifications.
*
* @type {notifications}
*/
@service notifications;
/**
* Service for managing application routing.
*
* @type {router}
*/
@service router;
/**
* Service for managing modals.
*
* @type {router}
*/
@service modalsManager;
/**
@@ -187,14 +164,12 @@ export default class ConsoleAccountAuthController extends Controller {
* @param {Object} twoFaSettings - User-specific two-factor authentication settings.
*/
@task *saveUserTwoFaSettings(twoFaSettings = {}) {
yield this.fetch
.post('users/two-fa', { twoFaSettings })
.then(() => {
this.notifications.success('2FA Settings saved successfully.');
})
.catch((error) => {
this.notifications.serverError(error);
});
try {
yield this.fetch.post('users/two-fa', { twoFaSettings });
this.notifications.success('2FA Settings saved successfully.');
} catch (error) {
this.notifications.serverError(error);
}
}
/**
@@ -203,13 +178,17 @@ export default class ConsoleAccountAuthController extends Controller {
* @method loadUserTwoFaSettings
*/
@task *loadUserTwoFaSettings() {
const twoFaSettings = yield this.fetch.get('users/two-fa');
try {
const twoFaSettings = yield this.fetch.get('users/two-fa');
if (twoFaSettings) {
this.isUserTwoFaEnabled = twoFaSettings.enabled;
this.twoFaSettings = twoFaSettings;
}
if (twoFaSettings) {
this.isUserTwoFaEnabled = twoFaSettings.enabled;
this.twoFaSettings = twoFaSettings;
return twoFaSettings;
} catch (error) {
this.notifications.serverError(error);
}
return twoFaSettings;
}
/**
@@ -218,12 +197,16 @@ export default class ConsoleAccountAuthController extends Controller {
* @method loadSystemTwoFaConfig
*/
@task *loadSystemTwoFaConfig() {
const twoFaConfig = yield this.fetch.get('two-fa/config');
try {
const twoFaConfig = yield this.fetch.get('two-fa/config');
if (twoFaConfig) {
this.isSystemTwoFaEnabled = twoFaConfig.enabled;
this.twoFaConfig = twoFaConfig;
}
if (twoFaConfig) {
this.isSystemTwoFaEnabled = twoFaConfig.enabled;
this.twoFaConfig = twoFaConfig;
return twoFaConfig;
} catch (error) {
this.notifications.serverError(error);
}
return twoFaConfig;
}
}

View File

@@ -1,7 +1,9 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { alias } from '@ember/object/computed';
import { debug } from '@ember/debug';
import { task } from 'ember-concurrency';
export default class ConsoleAccountIndexController extends Controller {
@@ -40,6 +42,18 @@ export default class ConsoleAccountIndexController extends Controller {
*/
@alias('currentUser.user') user;
/**
* Available timezones for selection.
*
* @memberof ConsoleAccountIndexController
*/
@tracked timezones = [];
constructor() {
super(...arguments);
this.loadTimezones.perform();
}
/**
* Handle upload of new photo
*
@@ -54,6 +68,7 @@ export default class ConsoleAccountIndexController extends Controller {
subject_uuid: this.user.id,
subject_type: 'user',
type: 'user_avatar',
resize: 'md'
},
(uploadedFile) => {
this.user.setProperties({
@@ -116,6 +131,19 @@ export default class ConsoleAccountIndexController extends Controller {
return isPasswordValid;
}
/**
* Load all available timezones from lookup.
*
* @memberof ConsoleAccountIndexController
*/
@task *loadTimezones() {
try {
this.timezones = yield this.fetch.get('lookup/timezones');
} catch (error) {
debug(`Unable to load timezones : ${error.message}`);
}
}
/**
* Checks if any user attribute has been changed
*

View File

@@ -0,0 +1,203 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { later } from '@ember/runloop';
import { htmlSafe } from '@ember/template';
export default class ConsoleAccountOrganizationsController extends Controller {
@service currentUser;
@service modalsManager;
@service crud;
@service notifications;
@service intl;
@service fetch;
@service router;
@action async leaveOrganization(organization) {
const isOwner = this.currentUser.id === organization.owner_uuid;
const hasOtherMembers = organization.users_count > 1;
const willBeDeleted = isOwner && organization.users_count === 1;
if (this.model.length === 1) {
return this.notifications.warning('Unable to leave your only organization.');
}
if (hasOtherMembers) {
organization.loadUsers({ exclude: [this.currentUser.id] });
}
this.modalsManager.show('modals/leave-organization', {
title: isOwner ? (willBeDeleted ? 'Delete Organization' : 'Transfer Ownership and Leave') : 'Leave Organization',
acceptButtonText: isOwner ? (willBeDeleted ? 'Delete Organization' : 'Transfer Ownership and Leave') : 'Leave Organization',
acceptButtonScheme: 'danger',
acceptButtonIcon: isOwner ? (willBeDeleted ? 'trash' : 'person-walking-arrow-right') : 'person-walking-arrow-right',
acceptButtonDisabled: isOwner && hasOtherMembers,
isOwner,
hasOtherMembers,
willBeDeleted,
organization,
newOwnerId: null,
selectNewOwner: (newOwnerId) => {
this.modalsManager.setOption('newOwnerId', newOwnerId);
this.modalsManager.setOption('acceptButtonDisabled', false);
},
confirm: async (modal) => {
modal.startLoading();
if (isOwner) {
if (hasOtherMembers) {
const newOwnerId = this.modalsManager.getOption('newOwnerId');
try {
await organization.transferOwnership(newOwnerId, { leave: true });
} catch (error) {
this.notifications.serverError(error);
}
return this.router.refresh();
}
if (willBeDeleted) {
try {
await organization.destroyRecord();
} catch (error) {
this.notifications.serverError(error);
}
return this.router.refresh();
}
}
try {
await organization.leave();
} catch (error) {
this.notifications.serverError(error);
}
return this.router.refresh();
},
});
}
@action switchOrganization(organization) {
this.modalsManager.confirm({
title: this.intl.t('console.switch-organization.modal-title', { organizationName: organization.name }),
body: this.intl.t('console.switch-organization.modal-body'),
acceptButtonText: this.intl.t('console.switch-organization.modal-accept-button-text'),
acceptButtonScheme: 'primary',
confirm: async (modal) => {
modal.startLoading();
try {
await this.fetch.post('auth/switch-organization', { next: organization.uuid });
this.fetch.flushRequestCache('auth/organizations');
this.notifications.success(this.intl.t('console.switch-organization.success-notification'));
return later(
this,
() => {
window.location.reload();
},
900
);
} catch (error) {
modal.stopLoading();
return this.notifications.serverError(error);
}
},
});
}
@action deleteOrganization(organization) {
const isOwner = this.currentUser.id === organization.owner_uuid;
if (this.model.length === 1) {
return this.notifications.warning('Unable to delete your only organization.');
}
if (!isOwner) {
return this.notifications.warning('You do not have rights to delete this organization.');
}
this.crud.delete(organization, {
title: `Are you sure you want to delete the organization ${organization.name}?`,
body: htmlSafe(
`This action will permanently remove all data, including orders, members, and settings associated with the organization. <br /><br /><strong>This action cannot be undone.</strong>`
),
acceptButtonText: 'Delete Organization',
acceptButtonScheme: 'danger',
acceptButtonIcon: 'trash',
confirm: async (modal) => {
modal.startLoading();
try {
await organization.destroyRecord();
return this.router.refresh();
} catch (error) {
this.notifications.serverError(error);
}
},
});
}
@action editOrganization(organization) {
this.modalsManager.show('modals/edit-organization', {
title: 'Edit Organization',
acceptButtonText: 'Save Changes',
acceptButtonIcon: 'save',
isOwner: this.currentUser.id === organization.owner_uuid,
organization,
confirm: async (modal) => {
modal.startLoading();
try {
await organization.save();
return this.router.refresh();
} catch (error) {
this.notifications.serverError(error);
}
},
});
}
@action createOrganization() {
const currency = this.currentUser.currency;
const country = this.currentUser.country;
this.modalsManager.show('modals/edit-organization', {
title: 'Create Organization',
acceptButtonText: this.intl.t('common.confirm'),
acceptButtonIcon: 'check',
acceptButtonIconPrefix: 'fas',
organization: {
name: null,
decription: null,
phone: null,
currency,
country,
timezone: null,
},
confirm: async (modal) => {
modal.startLoading();
const organization = modal.getOption('organization');
const { name, description, phone, currency, country, timezone } = organization;
try {
await this.fetch.post('auth/create-organization', {
name,
description,
phone,
currency,
country,
timezone,
});
this.fetch.flushRequestCache('auth/organizations');
this.notifications.success(this.intl.t('console.create-or-join-organization.create-success-notification'));
return this.router.refresh();
} catch (error) {
modal.stopLoading();
return this.notifications.serverError(error);
}
},
});
}
}

View File

@@ -0,0 +1,7 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
export default class ConsoleAccountVirtualController extends Controller {
@tracked view;
queryParams = ['view'];
}

View File

@@ -2,10 +2,6 @@ import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default class ConsoleAdminController extends Controller {
/**
* Inject the `universe` service.
*
* @memberof ConsoleAdminController
*/
@service('universe/menu-service') menuService;
@service universe;
}

View File

@@ -1,136 +0,0 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import createNotificationKey from '../../../utils/create-notification-key';
export default class ConsoleAdminNotificationsController extends Controller {
/**
* Inject the notifications service.
*
* @memberof ConsoleAdminNotificationsController
*/
@service notifications;
/**
* Inject the fetch service.
*
* @memberof ConsoleAdminNotificationsController
*/
@service fetch;
/**
* The notification settings value JSON.
*
* @memberof ConsoleAdminNotificationsController
* @var {Object}
*/
@tracked notificationSettings = {};
/**
* Notification transport methods enabled.
*
* @memberof ConsoleAdminNotificationsController
* @var {Array}
*/
@tracked notificationTransportMethods = ['email', 'sms'];
/**
* Tracked property for the loading state
*
* @memberof ConsoleAdminNotificationsController
* @var {Boolean}
*/
@tracked isLoading = false;
/**
* Creates an instance of ConsoleAdminNotificationsController.
* @memberof ConsoleAdminNotificationsController
*/
constructor() {
super(...arguments);
this.getSettings();
}
/**
* Selectes notifiables for settings.
*
* @param {Object} notification
* @param {Array} notifiables
* @memberof ConsoleAdminNotificationsController
*/
@action onSelectNotifiable(notification, notifiables) {
const notificationKey = createNotificationKey(notification.definition, notification.name);
const _notificationSettings = { ...this.notificationSettings };
if (!_notificationSettings[notificationKey]) {
_notificationSettings[notificationKey] = {};
}
_notificationSettings[notificationKey].notifiables = notifiables;
_notificationSettings[notificationKey].definition = notification.definition;
_notificationSettings[notificationKey].via = notifiables.map((notifiable) => {
return {
identifier: notifiable.value,
methods: this.notificationTransportMethods,
};
});
this.mutateNotificationSettings(_notificationSettings);
}
/**
* Mutates the notification settings property.
*
* @param {Object} [_notificationSettings={}]
* @memberof ConsoleAdminNotificationsController
*/
mutateNotificationSettings(_notificationSettings = {}) {
this.notificationSettings = {
...this.notificationSettings,
..._notificationSettings,
};
}
/**
* Save notification settings to the server.
*
* @action
* @method saveSettings
* @returns {Promise}
* @memberof ConsoleAdminNotificationsController
*/
@action saveSettings() {
const { notificationSettings } = this;
this.isLoading = true;
return this.fetch
.post('notifications/save-settings', { notificationSettings })
.then(() => {
this.notifications.success('Notification settings successfully saved.');
})
.catch((error) => {
this.notifications.serverError(error);
})
.finally(() => {
this.isLoading = false;
});
}
/**
* Fetches and updates notification settings asynchronously.
*
* @returns {Promise<void>} A promise for successful retrieval and update, or an error on failure.
*/
getSettings() {
return this.fetch
.get('notifications/get-settings')
.then(({ notificationSettings }) => {
this.notificationSettings = notificationSettings;
})
.catch((error) => {
this.notifications.serverError(error);
});
}
}

View File

@@ -10,41 +10,10 @@ import { action } from '@ember/object';
* @extends Controller
*/
export default class ConsoleAdminOrganizationsController extends Controller {
/**
* The Ember Data service for interacting with the store.
*
* @property {Service} store
* @type {Object}
*/
@service store;
/**
* Inject the `intl` service
*
* @var {Service}
*/
@service intl;
/**
* The Ember Router service for handling transitions between routes.
*
* @property {Service} router
* @type {Object}
*/
@service router;
/**
* Inject the `filters` service
*
* @var {Service}
*/
@service filters;
/**
* Inject the `crud` service
*
* @var {Service}
*/
@service crud;
/**

View File

@@ -2,28 +2,16 @@ import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { later } from '@ember/runloop';
export default class ConsoleAdminOrganizationsIndexUsersController extends Controller {
/**
* Inject the `filters` service
*
* @var {Service}
*/
@service filters;
/**
* Inject the `intl` service
*
* @var {Service}
*/
@service intl;
/**
* Inject the `router` service
*
* @var {Service}
*/
@service router;
@service fetch;
@service notifications;
@service modalsManager;
@service session;
/**
* The current page of data being viewed
@@ -84,6 +72,10 @@ export default class ConsoleAdminOrganizationsIndexUsersController extends Contr
label: this.intl.t('common.name'),
valuePath: 'name',
},
{
label: this.intl.t('common.role'),
valuePath: 'roleName',
},
{
label: this.intl.t('common.phone-number'),
valuePath: 'phone',
@@ -97,8 +89,71 @@ export default class ConsoleAdminOrganizationsIndexUsersController extends Contr
valuePath: 'status',
cellComponent: 'table/cell/status',
},
{
label: '',
cellComponent: 'table/cell/dropdown',
ddButtonText: false,
ddButtonIcon: 'ellipsis-h',
ddButtonIconPrefix: 'fas',
ddMenuLabel: 'User Actions',
cellClassNames: 'overflow-visible',
wrapperClass: 'flex items-center justify-end mx-2',
width: '9%',
actions: [
{
label: 'Impersonate',
icon: 'user-secret',
fn: this.impersonateUser,
},
{
label: 'Change Password',
icon: 'lock-open',
fn: this.changeUserPassword,
},
],
sortable: false,
filterable: false,
resizable: false,
searchable: false,
},
];
/**
* Impersonate the selected user.
*
* @param {UserModel} user
* @memberof ConsoleAdminOrganizationsIndexUsersController
*/
@action async impersonateUser(user) {
try {
const { token } = await this.fetch.post('auth/impersonate', { user: user.id });
await this.router.transitionTo('console');
this.session.manuallyAuthenticate(token);
this.notifications.info(`Now impersonating ${user.email}...`);
later(
this,
() => {
window.location.reload();
},
600
);
} catch (error) {
this.notifications.serverError(error);
}
}
/**
* Change password for a user
*
* @void
*/
@action changeUserPassword(user) {
this.modalsManager.show('modals/change-user-password', {
keepOpen: true,
user,
});
}
/**
* Update search query param and reset page to 1
*

View File

@@ -2,7 +2,7 @@ import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { task } from 'ember-concurrency-decorators';
import { task } from 'ember-concurrency';
import getTwoFaMethods from '@fleetbase/console/utils/get-two-fa-methods';
/**

View File

@@ -0,0 +1,7 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
export default class ConsoleAdminVirtualController extends Controller {
@tracked view;
queryParams = ['view'];
}

View File

@@ -1,3 +1,26 @@
import Controller from '@ember/controller';
export default class ConsoleHomeController extends Controller {}
export default class ConsoleHomeController extends Controller {
rows = [
{
name: 'Jason',
age: 24,
vehicle: 'Honda',
},
];
columns = [
{
label: 'Name',
valuePath: 'name',
},
{
label: 'Age',
valuePath: 'age',
},
{
label: 'Vehicle',
valuePath: 'vehicle',
},
];
}

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