mirror of
https://github.com/fleetbase/fleetbase.git
synced 2026-01-08 07:16:49 +00:00
Compare commits
187 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6d34268e0 | ||
|
|
5a5ddad825 | ||
|
|
b25da51496 | ||
|
|
7d776f2bd5 | ||
|
|
ecfcec72e4 | ||
|
|
ca1741a4b2 | ||
|
|
947565bcf0 | ||
|
|
2d4cc5cf66 | ||
|
|
53a87d6f38 | ||
|
|
d7f8f87315 | ||
|
|
36673ef564 | ||
|
|
19341c81e7 | ||
|
|
b4ecf5bda9 | ||
|
|
1b714a7ef8 | ||
|
|
e41cd62ea5 | ||
|
|
1ca1342052 | ||
|
|
a5a5ddb0d5 | ||
|
|
c51f3ca6c8 | ||
|
|
a9b172081a | ||
|
|
a29ca0ecb9 | ||
|
|
6442644438 | ||
|
|
a74c2c94ea | ||
|
|
9b0222696e | ||
|
|
7a6f9f39e4 | ||
|
|
295be2257c | ||
|
|
4d28630470 | ||
|
|
ae19256fa6 | ||
|
|
46275a5f53 | ||
|
|
ee9fc56fcd | ||
|
|
b20b74140f | ||
|
|
bcfe690d26 | ||
|
|
ccc2fa6cbe | ||
|
|
30ef64c210 | ||
|
|
a55380c72e | ||
|
|
fe0194f6ea | ||
|
|
dee9aef7a2 | ||
|
|
a5f9550d50 | ||
|
|
ce3e4df484 | ||
|
|
df36449792 | ||
|
|
4fa6be74c6 | ||
|
|
81aa42f4cb | ||
|
|
7a6b3e3637 | ||
|
|
36d0e89ebf | ||
|
|
21ed248446 | ||
|
|
42a00010fd | ||
|
|
7ed51fb118 | ||
|
|
d8ceb83ec1 | ||
|
|
472533f5bf | ||
|
|
dd509db1b5 | ||
|
|
3bf6324eeb | ||
|
|
5f2b6395f3 | ||
|
|
b822327885 | ||
|
|
856e459e74 | ||
|
|
76f717ab42 | ||
|
|
7b48d47530 | ||
|
|
f5ccc2eab5 | ||
|
|
be0396ef0d | ||
|
|
73e0020f12 | ||
|
|
ee46f4ef1b | ||
|
|
9305d71c4d | ||
|
|
fceaee5a5a | ||
|
|
f7ef4e90b0 | ||
|
|
5d883456d8 | ||
|
|
f5873a714c | ||
|
|
815a0a55c2 | ||
|
|
188aeb111b | ||
|
|
bcd6e20c2a | ||
|
|
3cfe25d57d | ||
|
|
77bbfc4209 | ||
|
|
2574e6600a | ||
|
|
9a099879b6 | ||
|
|
759948fb7d | ||
|
|
d46501caaf | ||
|
|
909a3908d6 | ||
|
|
6acdb4cf8e | ||
|
|
eafa8987fa | ||
|
|
ff9db8c075 | ||
|
|
4416199aca | ||
|
|
2589d947c9 | ||
|
|
582a5f69fa | ||
|
|
ff02943f7b | ||
|
|
a3dc172c5f | ||
|
|
ade87a39bb | ||
|
|
4b2e93c7fc | ||
|
|
cc571e2622 | ||
|
|
59304c6d02 | ||
|
|
0b7859cb19 | ||
|
|
5202d31a9b | ||
|
|
a3967f451e | ||
|
|
4fd1778ed1 | ||
|
|
6980b44239 | ||
|
|
a349f20298 | ||
|
|
2b0735efbd | ||
|
|
fdabe55ce2 | ||
|
|
369fe0e66f | ||
|
|
2ee81c5c26 | ||
|
|
6951ee7003 | ||
|
|
a824e7da85 | ||
|
|
c85b761c28 | ||
|
|
9080265806 | ||
|
|
5a40d964fe | ||
|
|
2bcd29363c | ||
|
|
5894500121 | ||
|
|
fee801c38f | ||
|
|
151ce5d82d | ||
|
|
533f175de0 | ||
|
|
0d6b8edcc8 | ||
|
|
3f848fd9d8 | ||
|
|
182a5e5d45 | ||
|
|
253c68e0ac | ||
|
|
54bee62335 | ||
|
|
23a8c8596e | ||
|
|
18596450ee | ||
|
|
3c013a3817 | ||
|
|
4392c7e3ff | ||
|
|
97dfbedd1a | ||
|
|
6d13f22a98 | ||
|
|
2c09c87bb6 | ||
|
|
f7f6991ef3 | ||
|
|
73acd4833c | ||
|
|
1c3c4c16a5 | ||
|
|
5d01438dc9 | ||
|
|
9d004410ee | ||
|
|
3a396f3b54 | ||
|
|
e86b970fc8 | ||
|
|
122a0d186a | ||
|
|
7e258f698f | ||
|
|
65ef642315 | ||
|
|
d79f034dbd | ||
|
|
05b7d5e112 | ||
|
|
61779ab102 | ||
|
|
a287c05380 | ||
|
|
ecc41e587e | ||
|
|
166529f9b4 | ||
|
|
189547f9de | ||
|
|
90a42e8a93 | ||
|
|
d28b1d41fb | ||
|
|
b056ef62b0 | ||
|
|
e70cbacbc2 | ||
|
|
fbd4a7490a | ||
|
|
b9b0eb308b | ||
|
|
48e1b89ec8 | ||
|
|
5e02c95b66 | ||
|
|
db8b5c4d6a | ||
|
|
aa214ccad7 | ||
|
|
cdd5524cf3 | ||
|
|
d99cefd2a4 | ||
|
|
1c58fd43c3 | ||
|
|
9226394159 | ||
|
|
9b23b39f32 | ||
|
|
5310fc3ff3 | ||
|
|
9569053f50 | ||
|
|
b08c054b99 | ||
|
|
2e517f2f95 | ||
|
|
7038d375b0 | ||
|
|
d5ea7f7790 | ||
|
|
4eb4b04121 | ||
|
|
24c5b93005 | ||
|
|
80610b9a48 | ||
|
|
9e5551972e | ||
|
|
b784f890f3 | ||
|
|
797a3d61fe | ||
|
|
d2f0bfe83e | ||
|
|
f28ad85c1a | ||
|
|
d7b0826f3f | ||
|
|
dd6008a8aa | ||
|
|
6671fefaaa | ||
|
|
7136f6195c | ||
|
|
2384887620 | ||
|
|
a2778f1552 | ||
|
|
acfda5ed1a | ||
|
|
e08255007a | ||
|
|
41761ea50e | ||
|
|
5c623819ed | ||
|
|
2bd885b1a2 | ||
|
|
88c3842441 | ||
|
|
2c2a4121a8 | ||
|
|
aadd03f14b | ||
|
|
706e94270d | ||
|
|
1dabc375f9 | ||
|
|
0efec46155 | ||
|
|
8bb2c6b65d | ||
|
|
1c0af1a119 | ||
|
|
dd65ee619b | ||
|
|
e790a0e123 | ||
|
|
723e3ca3d1 | ||
|
|
4eb706d33e |
4
.github/workflows/cd.yml
vendored
4
.github/workflows/cd.yml
vendored
@@ -197,7 +197,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "STRIPE_KEY=${{ secrets.STRIPE_TEST_KEY }}" >> ./environments/.env.production
|
echo "STRIPE_KEY=${{ secrets.STRIPE_TEST_KEY }}" >> ./environments/.env.production
|
||||||
echo "LOGROCKET_APP_ID=${{ secrets.LOGROCKET_APP_ID }}" >> ./environments/.env.production
|
echo "LOGROCKET_APP_ID=${{ secrets.LOGROCKET_APP_ID }}" >> ./environments/.env.production
|
||||||
echo "EXTENSIONS=@fleetbase/billing-engine,@fleetbase/internals-engine" >> ./environments/.env.production
|
echo "EXTENSIONS=@fleetbase/billing-engine,@fleetbase/internals-engine,@fleetbase/aws-marketplace" >> ./environments/.env.production
|
||||||
working-directory: ./console
|
working-directory: ./console
|
||||||
|
|
||||||
- name: Set Env Variables for Production
|
- name: Set Env Variables for Production
|
||||||
@@ -205,7 +205,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "STRIPE_KEY=${{ secrets.STRIPE_KEY }}" >> ./environments/.env.production
|
echo "STRIPE_KEY=${{ secrets.STRIPE_KEY }}" >> ./environments/.env.production
|
||||||
echo "LOGROCKET_APP_ID=${{ secrets.LOGROCKET_APP_ID }}" >> ./environments/.env.production
|
echo "LOGROCKET_APP_ID=${{ secrets.LOGROCKET_APP_ID }}" >> ./environments/.env.production
|
||||||
echo "EXTENSIONS=@fleetbase/billing-engine,@fleetbase/internals-engine" >> ./environments/.env.production
|
echo "EXTENSIONS=@fleetbase/billing-engine,@fleetbase/internals-engine,@fleetbase/aws-marketplace" >> ./environments/.env.production
|
||||||
working-directory: ./console
|
working-directory: ./console
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
http://:8000 {
|
http://:8000 {
|
||||||
root * /fleetbase/api/public
|
root * /fleetbase/api/public
|
||||||
encode zstd br gzip
|
encode zstd br gzip
|
||||||
|
|
||||||
php_server {
|
php_server {
|
||||||
resolve_root_symlink
|
resolve_root_symlink
|
||||||
}
|
}
|
||||||
|
|||||||
11
RELEASE.md
11
RELEASE.md
@@ -1,14 +1,13 @@
|
|||||||
# 🚀 Fleetbase v0.7.22 — 2025-12-07
|
# 🚀 Fleetbase v0.7.25 — 2025-12-29
|
||||||
|
|
||||||
> "Organizations can now set their own alpha-numeric sender ID for SMS"
|
> "New SMS service to support multiple SMS providers + framework improvements"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ✨ Highlights
|
## ✨ Highlights
|
||||||
- **Custom Alphanumeric Sender ID for SMS:**
|
- Removed `window.Fleetbase` for improved frontend security
|
||||||
Organizations can now configure their own **Alphanumeric Sender ID** used when sending verification codes and other SMS notifications.
|
- Improved query optimizations
|
||||||
This feature improves brand recognition, enhances trust, and aligns outbound communication with each organization’s identity.
|
- Added new SMS service to support multiple SMS providers
|
||||||
Supported in regions/carriers where alphanumeric senders are allowed (e.g., Mongolia and others).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ class Kernel extends HttpKernel
|
|||||||
],
|
],
|
||||||
|
|
||||||
'api' => [
|
'api' => [
|
||||||
'throttle:api',
|
|
||||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -20,10 +20,18 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": ">=8.0 <=8.2.28",
|
"php": ">=8.0 <=8.2.28",
|
||||||
"appstract/laravel-opcache": "^4.0",
|
"appstract/laravel-opcache": "^4.0",
|
||||||
"fleetbase/core-api": "^1.6.28",
|
"fleetbase/core-api": "^1.6.32",
|
||||||
"fleetbase/fleetops-api": "^0.6.29",
|
"fleetbase/fleetops-api": "^0.6.32",
|
||||||
|
"fleetbase/flespi-integration": "^0.1.16",
|
||||||
|
"fleetbase/samsara-api": "^0.0.3",
|
||||||
|
"fleetbase/vroom-api": "^0.0.3",
|
||||||
|
"fleetbase/valhalla-api": "^0.0.3",
|
||||||
|
"fleetbase/billing-api": "^0.1.12",
|
||||||
|
"fleetbase/internals-api": "^0.0.23",
|
||||||
|
"fleetbase/aws-marketplace": "^0.0.8",
|
||||||
"fleetbase/registry-bridge": "^0.1.2",
|
"fleetbase/registry-bridge": "^0.1.2",
|
||||||
"fleetbase/storefront-api": "^0.4.9",
|
"fleetbase/storefront-api": "^0.4.10",
|
||||||
|
"fleetbase/customer-portal-api": "^0.0.10",
|
||||||
"guzzlehttp/guzzle": "^7.0.1",
|
"guzzlehttp/guzzle": "^7.0.1",
|
||||||
"laravel/framework": "^10.0",
|
"laravel/framework": "^10.0",
|
||||||
"laravel/octane": "^2.3",
|
"laravel/octane": "^2.3",
|
||||||
@@ -49,9 +57,25 @@
|
|||||||
"phpunit/phpunit": "^10.0"
|
"phpunit/phpunit": "^10.0"
|
||||||
},
|
},
|
||||||
"repositories": [
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/fleetbase/aws-marketplace"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/fleetbase/billing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/fleetbase/internals"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "https://github.com/fleetbase/customer-portal"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "composer",
|
"type": "composer",
|
||||||
"url": "https://registry.fleetbase.io"
|
"url": "https://registry.qa.fleetbase.io"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
|||||||
1299
api/composer.lock
generated
1299
api/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,7 @@ return [
|
|||||||
|
|
||||||
'allowed_headers' => ['*'],
|
'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,
|
'max_age' => 0,
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ return [
|
|||||||
'channels' => [
|
'channels' => [
|
||||||
'stack' => [
|
'stack' => [
|
||||||
'driver' => 'stack',
|
'driver' => 'stack',
|
||||||
'channels' => ['single'],
|
'channels' => ['single', 'stdout'],
|
||||||
'ignore_exceptions' => false,
|
'ignore_exceptions' => false,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ return [
|
|||||||
OperationTerminated::class => [
|
OperationTerminated::class => [
|
||||||
FlushOnce::class,
|
FlushOnce::class,
|
||||||
FlushTemporaryContainerInstances::class,
|
FlushTemporaryContainerInstances::class,
|
||||||
// DisconnectFromDatabases::class,
|
DisconnectFromDatabases::class,
|
||||||
// CollectGarbage::class,
|
CollectGarbage::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
WorkerErrorOccurred::class => [
|
WorkerErrorOccurred::class => [
|
||||||
|
|||||||
@@ -43,4 +43,10 @@ return [
|
|||||||
'secret' => env('STRIPE_SECRET', env('STRIPE_API_SECRET')),
|
'secret' => env('STRIPE_SECRET', env('STRIPE_API_SECRET')),
|
||||||
'webhook_secret' => env('STRIPE_WEBHOOK_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' ),
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import Application from '@ember/application';
|
|||||||
import Resolver from 'ember-resolver';
|
import Resolver from 'ember-resolver';
|
||||||
import loadInitializers from 'ember-load-initializers';
|
import loadInitializers from 'ember-load-initializers';
|
||||||
import config from '@fleetbase/console/config/environment';
|
import config from '@fleetbase/console/config/environment';
|
||||||
|
import './deprecation-workflow';
|
||||||
|
|
||||||
export default class App extends Application {
|
export default class App extends Application {
|
||||||
modulePrefix = config.modulePrefix;
|
modulePrefix = config.modulePrefix;
|
||||||
|
|||||||
@@ -1,42 +1,61 @@
|
|||||||
<div class="bg-white dark:bg-gray-800 py-5 px-4 shadow rounded-lg w-full">
|
<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="mb-4">
|
<div class="w-full max-w-md h-screen flex items-center justify-center py-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="bg-white dark:bg-gray-800 py-5 px-4 shadow rounded-lg w-full">
|
||||||
<div class="mt-2">
|
<div class="mb-4">
|
||||||
<h2 class="text-center text-lg font-extrabold text-gray-900 dark:text-white truncate">
|
<Image src={{@brand.logo_url}} @fallbackSrc="/images/fleetbase-logo-svg.svg" alt={{t "app.name"}} height="56" class="h-10 object-contain mx-auto" />
|
||||||
{{t "onboard.index.title"}}
|
<div class="mt-2">
|
||||||
</h2>
|
<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>
|
</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>
|
||||||
@@ -1,78 +1,82 @@
|
|||||||
{{page-title (t "onboard.verify-email.header-title")}}
|
{{page-title (t "onboard.verify-email.header-title")}}
|
||||||
|
|
||||||
{{#if this.initialized}}
|
<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="bg-white dark:bg-gray-800 py-8 px-4 shadow rounded-lg w-full">
|
<div class="w-full max-w-md h-screen flex items-center justify-center py-4">
|
||||||
<div class="mb-6">
|
{{#if this.initialized}}
|
||||||
<LinkTo @route="console" class="flex items-center justify-center">
|
<div class="bg-white dark:bg-gray-800 py-8 px-4 shadow rounded-lg w-full">
|
||||||
<LogoIcon @size="12" class="rounded-md" />
|
<div class="mb-6">
|
||||||
</LinkTo>
|
<LinkTo @route="console" class="flex items-center justify-center">
|
||||||
<h2 class="mt-6 text-center text-lg font-extrabold text-gray-900 dark:text-white truncate">
|
<LogoIcon @size="12" class="rounded-md" />
|
||||||
{{t "onboard.verify-email.title"}}
|
</LinkTo>
|
||||||
</h2>
|
<h2 class="mt-6 text-center text-lg font-extrabold text-gray-900 dark:text-white truncate">
|
||||||
</div>
|
{{t "onboard.verify-email.title"}}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<InfoBlock @type="info" @icon="shield-halved" @iconSize="lg">
|
<InfoBlock @type="info" @icon="shield-halved" @iconSize="lg">
|
||||||
{{t "onboard.verify-email.message-text" htmlSafe=true}}
|
{{t "onboard.verify-email.message-text" htmlSafe=true}}
|
||||||
</InfoBlock>
|
</InfoBlock>
|
||||||
|
|
||||||
<form class="mt-8 space-y-6" {{on "submit" (perform this.verify)}}>
|
<form class="mt-8 space-y-6" {{on "submit" (perform this.verify)}}>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
@type="tel"
|
@type="tel"
|
||||||
@name={{t "onboard.verify-email.verification-input-label"}}
|
@name={{t "onboard.verify-email.verification-input-label"}}
|
||||||
@value={{this.code}}
|
@value={{this.code}}
|
||||||
@helpText={{t "onboard.verify-email.verification-code-text"}}
|
@helpText={{t "onboard.verify-email.verification-code-text"}}
|
||||||
@inputClass="input-lg"
|
@inputClass="input-lg"
|
||||||
{{on "input" this.verification.validateInput}}
|
{{on "input" this.verification.validateInput}}
|
||||||
{{did-insert this.verification.validateInput}}
|
{{did-insert this.verification.validateInput}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="flex flex-row items-center space-x-4">
|
<div class="flex flex-row items-center space-x-4">
|
||||||
<Button
|
<Button
|
||||||
@icon="check"
|
@icon="check"
|
||||||
@iconPrefix="fas"
|
@iconPrefix="fas"
|
||||||
@buttonType="submit"
|
@buttonType="submit"
|
||||||
@type="primary"
|
@type="primary"
|
||||||
@size="lg"
|
@size="lg"
|
||||||
@text="Verify & Continue"
|
@text="Verify & Continue"
|
||||||
@isLoading={{this.verify.isRunning}}
|
@isLoading={{this.verify.isRunning}}
|
||||||
@disabled={{not this.verification.ready}}
|
@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>
|
<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>
|
</div>
|
||||||
|
|
||||||
{{#if this.verification.waiting}}
|
{{#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-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="flex flex-row items-start mb-2">
|
||||||
<div class="w-8 flex-grow-0 flex-shrink-0">
|
<div class="w-8 flex-grow-0 flex-shrink-0">
|
||||||
<FaIcon @icon="triangle-exclamation" @size="xl" class="pt-1" />
|
<FaIcon @icon="triangle-exclamation" @size="xl" class="pt-1" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="flex-1 text-sm text-yellow-100">
|
<div class="flex-1 text-sm text-yellow-100">
|
||||||
<div>{{t "auth.verification.didnt-receive-a-code" htmlSafe=true}}</div>
|
<div>{{t "auth.verification.didnt-receive-a-code" htmlSafe=true}}</div>
|
||||||
<div>{{t "auth.verification.not-sent.alternative-choice" 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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/if}}
|
||||||
<div class="flex items-center space-x-2">
|
</form>
|
||||||
<Button
|
</div>
|
||||||
@text={{t "auth.verification.not-sent.resend-email"}}
|
{{/if}}
|
||||||
@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>
|
</div>
|
||||||
{{/if}}
|
</div>
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
<section class="onboarding step-host">
|
<section class="onboarding step-host">
|
||||||
{{#if this.initialized}}
|
{{#if this.initialized}}
|
||||||
{{#if this.currentComponent}}
|
{{#if this.orchestrator.wrapper}}
|
||||||
{{component this.currentComponent context=this.context orchestrator=this.orchestrator brand=@brand}}
|
{{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}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="flex items-center justify-center min-h-24">
|
<div class="flex items-center justify-center min-h-24">
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export default class ConsoleAccountIndexController extends Controller {
|
|||||||
subject_uuid: this.user.id,
|
subject_uuid: this.user.id,
|
||||||
subject_type: 'user',
|
subject_type: 'user',
|
||||||
type: 'user_avatar',
|
type: 'user_avatar',
|
||||||
|
resize: 'md'
|
||||||
},
|
},
|
||||||
(uploadedFile) => {
|
(uploadedFile) => {
|
||||||
this.user.setProperties({
|
this.user.setProperties({
|
||||||
|
|||||||
9
console/app/deprecation-workflow.js
Normal file
9
console/app/deprecation-workflow.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import setupDeprecationWorkflow from 'ember-cli-deprecation-workflow';
|
||||||
|
|
||||||
|
setupDeprecationWorkflow({
|
||||||
|
workflow: [
|
||||||
|
{ handler: 'silence', matchId: 'ember-concurrency.deprecate-decorator-task' },
|
||||||
|
{ handler: 'silence', matchId: 'new-helper-names' },
|
||||||
|
{ handler: 'silence', matchId: 'ember-data:deprecate-non-strict-relationships' },
|
||||||
|
],
|
||||||
|
});
|
||||||
@@ -1,10 +1,4 @@
|
|||||||
export function initialize(appInstance) {
|
export function initialize(appInstance) {
|
||||||
// Set window.Fleetbase to the application instance for global access
|
|
||||||
// This is used by services and engines to access the root application instance
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
window.Fleetbase = appInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up UniverseService and set the application instance
|
// Look up UniverseService and set the application instance
|
||||||
const universeService = appInstance.lookup('service:universe');
|
const universeService = appInstance.lookup('service:universe');
|
||||||
if (universeService) {
|
if (universeService) {
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
|
|||||||
export default class UserSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {
|
export default class UserSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {
|
||||||
/**
|
/**
|
||||||
* Embedded relationship attributes
|
* Embedded relationship attributes
|
||||||
*
|
|
||||||
* @var {Object}
|
|
||||||
*/
|
*/
|
||||||
get attrs() {
|
get attrs() {
|
||||||
return {
|
return {
|
||||||
@@ -16,22 +14,45 @@ export default class UserSerializer extends ApplicationSerializer.extend(Embedde
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Customize serializer so that the password is never sent to the server via Ember Data
|
* Prevent partial payloads from overwriting fully-loaded
|
||||||
|
* user records in the store.
|
||||||
*
|
*
|
||||||
* @param {Snapshot} snapshot
|
* This runs ONLY on incoming data.
|
||||||
* @param {Object} options
|
*/
|
||||||
* @return {Object} json
|
normalize(modelClass, resourceHash, prop) {
|
||||||
|
let normalized = super.normalize(modelClass, resourceHash, prop);
|
||||||
|
|
||||||
|
// Existing user already loaded in the store?
|
||||||
|
let existing = this.store.peekRecord(normalized.data.type, normalized.data.id);
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
let attrs = normalized.data.attributes || {};
|
||||||
|
|
||||||
|
for (let key in attrs) {
|
||||||
|
if (attrs[key] === null || attrs[key] === undefined || key === 'avatar_url') {
|
||||||
|
delete attrs[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customize serializer so that sensitive or server-managed
|
||||||
|
* fields are never sent to the backend.
|
||||||
*/
|
*/
|
||||||
serialize() {
|
serialize() {
|
||||||
const json = super.serialize(...arguments);
|
const json = super.serialize(...arguments);
|
||||||
|
|
||||||
// delete the password always
|
// Never send password
|
||||||
delete json.password;
|
delete json.password;
|
||||||
// delete verification attributes
|
|
||||||
|
// Verification flags
|
||||||
delete json.email_verified_at;
|
delete json.email_verified_at;
|
||||||
delete json.phone_verified_at;
|
delete json.phone_verified_at;
|
||||||
|
|
||||||
// delete server managed dates
|
// Server-managed timestamps
|
||||||
delete json.deleted_at;
|
delete json.deleted_at;
|
||||||
delete json.created_at;
|
delete json.created_at;
|
||||||
delete json.updated_at;
|
delete json.updated_at;
|
||||||
|
|||||||
@@ -7,17 +7,31 @@ export default class OnboardingOrchestratorService extends Service {
|
|||||||
@service onboardingContext;
|
@service onboardingContext;
|
||||||
|
|
||||||
@tracked flow = null;
|
@tracked flow = null;
|
||||||
|
@tracked wrapper = null;
|
||||||
@tracked current = null;
|
@tracked current = null;
|
||||||
@tracked history = [];
|
@tracked history = [];
|
||||||
@tracked sessionId = null;
|
@tracked sessionId = null;
|
||||||
|
|
||||||
start(flowId = null, opts = {}) {
|
async start(flowId = null, opts = {}) {
|
||||||
const flow = this.onboardingRegistry.getFlow(flowId ?? this.onboardingRegistry.defaultFlow);
|
const flow = this.onboardingRegistry.getFlow(flowId ?? this.onboardingRegistry.defaultFlow);
|
||||||
if (!flow) throw new Error(`Onboarding flow '${flowId}' not found`);
|
if (!flow) throw new Error(`Onboarding flow '${flowId}' not found`);
|
||||||
|
|
||||||
this.flow = flow;
|
this.flow = flow;
|
||||||
|
this.wrapper = flow.wrapper || null;
|
||||||
this.sessionId = opts.sessionId || null;
|
this.sessionId = opts.sessionId || null;
|
||||||
this.history = [];
|
this.history = [];
|
||||||
this.goto(flow.entry);
|
|
||||||
|
// Execute onFlowWillStart hook if defined
|
||||||
|
if (typeof this.flow.onFlowWillStart === 'function') {
|
||||||
|
await this.flow.onFlowWillStart(this.flow, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.goto(flow.entry);
|
||||||
|
|
||||||
|
// Execute onFlowDidStart hook if defined
|
||||||
|
if (typeof this.flow.onFlowDidStart === 'function') {
|
||||||
|
await this.flow.onFlowDidStart(this.flow, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async goto(stepId) {
|
async goto(stepId) {
|
||||||
@@ -25,27 +39,43 @@ export default class OnboardingOrchestratorService extends Service {
|
|||||||
const step = this.flow.steps.find((s) => s.id === stepId);
|
const step = this.flow.steps.find((s) => s.id === stepId);
|
||||||
if (!step) throw new Error(`Step '${stepId}' not found`);
|
if (!step) throw new Error(`Step '${stepId}' not found`);
|
||||||
|
|
||||||
|
// Execute onStepWillChange hook if defined
|
||||||
|
const previousStep = this.current;
|
||||||
|
if (typeof this.flow.onStepWillChange === 'function') {
|
||||||
|
await this.flow.onStepWillChange(step, previousStep, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guard function - skip step if guard returns false
|
||||||
if (typeof step.guard === 'function' && !step.guard(this.onboardingContext)) {
|
if (typeof step.guard === 'function' && !step.guard(this.onboardingContext)) {
|
||||||
return this.next();
|
return this.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// beforeEnter lifecycle hook
|
||||||
if (typeof step.beforeEnter === 'function') {
|
if (typeof step.beforeEnter === 'function') {
|
||||||
await step.beforeEnter(this.onboardingContext);
|
await step.beforeEnter(this.onboardingContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.current = step;
|
this.current = step;
|
||||||
|
|
||||||
|
// Execute onStepDidChange hook if defined
|
||||||
|
if (typeof this.flow.onStepDidChange === 'function') {
|
||||||
|
await this.flow.onStepDidChange(this.current, previousStep, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async next() {
|
async next() {
|
||||||
if (!this.flow || !this.current) return;
|
if (!this.flow || !this.current) return;
|
||||||
|
|
||||||
const leaving = this.current;
|
const leaving = this.current;
|
||||||
|
|
||||||
|
// afterLeave lifecycle hook
|
||||||
if (typeof leaving.afterLeave === 'function') {
|
if (typeof leaving.afterLeave === 'function') {
|
||||||
await leaving.afterLeave(this.onboardingContext);
|
await leaving.afterLeave(this.onboardingContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.history.includes(leaving)) this.history.push(leaving);
|
if (!this.history.includes(leaving)) this.history.push(leaving);
|
||||||
|
|
||||||
|
// Support both string and function for next property
|
||||||
let nextId;
|
let nextId;
|
||||||
if (typeof leaving.next === 'function') {
|
if (typeof leaving.next === 'function') {
|
||||||
nextId = leaving.next(this.onboardingContext);
|
nextId = leaving.next(this.onboardingContext);
|
||||||
@@ -53,8 +83,20 @@ export default class OnboardingOrchestratorService extends Service {
|
|||||||
nextId = leaving.next;
|
nextId = leaving.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no next step, flow is complete
|
||||||
if (!nextId) {
|
if (!nextId) {
|
||||||
|
// Execute onFlowWillEnd hook if defined
|
||||||
|
if (typeof this.flow.onFlowWillEnd === 'function') {
|
||||||
|
await this.flow.onFlowWillEnd(leaving, this);
|
||||||
|
}
|
||||||
|
|
||||||
this.current = null; // finished
|
this.current = null; // finished
|
||||||
|
|
||||||
|
// Execute onFlowDidEnd hook if defined
|
||||||
|
if (typeof this.flow.onFlowDidEnd === 'function') {
|
||||||
|
await this.flow.onFlowDidEnd(leaving, this);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,4 +110,31 @@ export default class OnboardingOrchestratorService extends Service {
|
|||||||
this.history = this.history.slice(0, -1);
|
this.history = this.history.slice(0, -1);
|
||||||
await this.goto(prev.id);
|
await this.goto(prev.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current path (for flows with multiple paths)
|
||||||
|
* This is a helper method that can be used by flows to determine the current path
|
||||||
|
*/
|
||||||
|
getCurrentPath() {
|
||||||
|
if (!this.flow || !this.flow.paths) return null;
|
||||||
|
|
||||||
|
// Determine path based on context or current step
|
||||||
|
for (const [pathId, pathDef] of Object.entries(this.flow.paths)) {
|
||||||
|
if (pathDef.steps && pathDef.steps.some(s => s.id === this.current?.id)) {
|
||||||
|
return pathDef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a step is in the current path
|
||||||
|
*/
|
||||||
|
isStepInPath(stepId) {
|
||||||
|
const currentPath = this.getCurrentPath();
|
||||||
|
if (!currentPath) return true; // If no paths defined, all steps are valid
|
||||||
|
|
||||||
|
return currentPath.steps?.some(s => s.id === stepId) ?? false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default class OnboardingRegistryService extends Service {
|
|||||||
this.defaultFlow = flowId;
|
this.defaultFlow = flowId;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerFlow(flow) {
|
registerFlow(flow, options = {}) {
|
||||||
if (!flow || !flow.id || !flow.entry || !Array.isArray(flow.steps)) {
|
if (!flow || !flow.id || !flow.entry || !Array.isArray(flow.steps)) {
|
||||||
throw new Error('Invalid FlowDef: id, entry, steps are required');
|
throw new Error('Invalid FlowDef: id, entry, steps are required');
|
||||||
}
|
}
|
||||||
@@ -23,6 +23,11 @@ export default class OnboardingRegistryService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.flows.set(flow.id, flow);
|
this.flows.set(flow.id, flow);
|
||||||
|
|
||||||
|
// If specified, set as default flow
|
||||||
|
if (options.default) {
|
||||||
|
this.defaultFlow = flow.id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getFlow(id) {
|
getFlow(id) {
|
||||||
|
|||||||
@@ -4,21 +4,27 @@
|
|||||||
<div class="container mx-auto h-screen">
|
<div class="container mx-auto h-screen">
|
||||||
<div class="max-w-3xl my-10 mx-auto">
|
<div class="max-w-3xl my-10 mx-auto">
|
||||||
<ContentPanel @title={{t "common.your-profile"}} @open={{true}} @wrapperClass="bordered-classic">
|
<ContentPanel @title={{t "common.your-profile"}} @open={{true}} @wrapperClass="bordered-classic">
|
||||||
<form class="flex flex-col md:flex-row" {{on "submit" (perform this.saveProfile)}}>
|
<form class="flex flex-col items-start md:flex-row" {{on "submit" (perform this.saveProfile)}}>
|
||||||
<div class="w-32 flex flex-col justify-center mb-6 mr-6">
|
<div class="w-32 flex flex-col justify-center mb-6 mr-6">
|
||||||
<Image src={{this.user.avatar_url}} @fallbackSrc={{config "defaultValues.userImage"}} alt={{this.user.name}} class="w-32 h-32 rounded-md" />
|
<Image src={{this.user.avatar_url}} @fallbackSrc={{config "defaultValues.userImage"}} alt={{this.user.name}} class="w-32 h-32 rounded-md mt-1" />
|
||||||
<FileUpload @name={{t "console.account.index.photos"}} @accept="image/*" @onFileAdded={{this.uploadNewPhoto}} @labelClass="flex flex-row items-center justify-center" as |queue|>
|
<FileUpload
|
||||||
|
@name={{t "console.account.index.photos"}}
|
||||||
|
@accept="image/*"
|
||||||
|
@onFileAdded={{this.uploadNewPhoto}}
|
||||||
|
@labelClass="flex flex-row items-center justify-center"
|
||||||
|
as |queue|
|
||||||
|
>
|
||||||
<a tabindex={{0}} class="flex items-center px-0 mt-2 text-xs no-underline truncate btn btn-sm btn-default" disabled={{queue.files.length}}>
|
<a tabindex={{0}} class="flex items-center px-0 mt-2 text-xs no-underline truncate btn btn-sm btn-default" disabled={{queue.files.length}}>
|
||||||
{{#if queue.files.length}}
|
{{#if queue.files.length}}
|
||||||
<div class="mr-1.5">
|
<div class="mr-1.5">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<span>
|
||||||
{{t "common.uploading"}}
|
{{t "common.uploading"}}
|
||||||
</span>
|
</span>
|
||||||
{{else}}
|
{{else}}
|
||||||
<FaIcon @icon="image" class="mr-1.5" />
|
<FaIcon @icon="image" class="mr-1.5" />
|
||||||
<span>
|
<span>
|
||||||
{{t "console.account.index.upload-new"}}
|
{{t "console.account.index.upload-new"}}
|
||||||
</span>
|
</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@@ -34,11 +40,31 @@
|
|||||||
</InputGroup>
|
</InputGroup>
|
||||||
<InputGroup @name={{t "common.date-of-birth"}} @type="date" @value={{this.user.date_of_birth}} />
|
<InputGroup @name={{t "common.date-of-birth"}} @type="date" @value={{this.user.date_of_birth}} />
|
||||||
<InputGroup @name={{t "common.timezone"}} @helpText={{t "console.account.index.timezone"}}>
|
<InputGroup @name={{t "common.timezone"}} @helpText={{t "console.account.index.timezone"}}>
|
||||||
<Select @value={{this.user.timezone}} @options={{this.timezones}} @onSelect={{fn (mut this.user.timezone)}} @placeholder={{t "console.account.index.timezone"}} />
|
<div class="fleetbase-model-select fleetbase-power-select ember-model-select">
|
||||||
|
<PowerSelect
|
||||||
|
@options={{this.timezones}}
|
||||||
|
@selected={{this.user.timezone}}
|
||||||
|
@onChange={{fn (mut this.user.timezone)}}
|
||||||
|
@placeholder={{t "console.account.index.timezone"}}
|
||||||
|
@triggerClass="form-select form-input"
|
||||||
|
@searchEnabled={{true}}
|
||||||
|
as |option|
|
||||||
|
>
|
||||||
|
<div>{{option}}</div>
|
||||||
|
</PowerSelect>
|
||||||
|
</div>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 flex items-center justify-end">
|
<div class="mt-3 flex items-center justify-end">
|
||||||
<Button @buttonType="submit" @type="primary" @size="lg" @icon="save" @text={{t "common.save-changes"}} @onClick={{perform this.saveProfile}} @isLoading={{not this.saveProfile.isIdle}} />
|
<Button
|
||||||
|
@buttonType="submit"
|
||||||
|
@type="primary"
|
||||||
|
@size="lg"
|
||||||
|
@icon="save"
|
||||||
|
@text={{t "common.save-changes"}}
|
||||||
|
@onClick={{perform this.saveProfile}}
|
||||||
|
@isLoading={{not this.saveProfile.isIdle}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
<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="onboard-route-wrapper">
|
||||||
<div class="w-full max-w-md h-screen flex items-center justify-center py-4">
|
{{outlet}}
|
||||||
{{outlet}}
|
|
||||||
</div>
|
|
||||||
<Spacer @height="300px" />
|
|
||||||
</div>
|
</div>
|
||||||
@@ -23,7 +23,7 @@ module.exports = function (environment) {
|
|||||||
APP: {
|
APP: {
|
||||||
autoboot: true,
|
autoboot: true,
|
||||||
extensions: asArray(getenv('EXTENSIONS')),
|
extensions: asArray(getenv('EXTENSIONS')),
|
||||||
disableRuntimeConfig: toBoolean(getenv('DISABLE_RUNTIME_CONFIG')),
|
disableRuntimeConfig: toBoolean(getenv('DISABLE_RUNTIME_CONFIG', environment === 'production')),
|
||||||
},
|
},
|
||||||
|
|
||||||
API: {
|
API: {
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
API_HOST=
|
API_HOST=https://api.fleetbase.io
|
||||||
API_NAMESPACE=int/v1
|
API_NAMESPACE=int/v1
|
||||||
API_SECURE=true
|
API_SECURE=true
|
||||||
SOCKETCLUSTER_PATH=/socketcluster/
|
SOCKETCLUSTER_PATH=/socketcluster/
|
||||||
SOCKETCLUSTER_HOST=
|
SOCKETCLUSTER_HOST=socket.fleetbase.io
|
||||||
SOCKETCLUSTER_SECURE=true
|
SOCKETCLUSTER_SECURE=true
|
||||||
SOCKETCLUSTER_PORT=38000
|
SOCKETCLUSTER_PORT=8000
|
||||||
OSRM_HOST=https://router.project-osrm.org
|
OSRM_HOST=https://router.project-osrm.org
|
||||||
|
DISABLE_RUNTIME_CONFIG=true
|
||||||
|
|||||||
9
console/environments/.env.qa
Normal file
9
console/environments/.env.qa
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
API_HOST=https://api.qa.fleetbase.io
|
||||||
|
API_NAMESPACE=int/v1
|
||||||
|
API_SECURE=true
|
||||||
|
SOCKETCLUSTER_PATH=/socketcluster/
|
||||||
|
SOCKETCLUSTER_HOST=socket.qa.fleetbase.io
|
||||||
|
SOCKETCLUSTER_SECURE=true
|
||||||
|
SOCKETCLUSTER_PORT=8000
|
||||||
|
OSRM_HOST=https://router.project-osrm.org
|
||||||
|
DISABLE_RUNTIME_CONFIG=true
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@fleetbase/console",
|
"name": "@fleetbase/console",
|
||||||
"version": "0.7.22",
|
"version": "0.7.25",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Modular logistics and supply chain operating system (LSOS)",
|
"description": "Modular logistics and supply chain operating system (LSOS)",
|
||||||
"repository": "https://github.com/fleetbase/fleetbase",
|
"repository": "https://github.com/fleetbase/fleetbase",
|
||||||
@@ -33,15 +33,23 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ember/legacy-built-in-components": "^0.4.2",
|
"@ember/legacy-built-in-components": "^0.4.2",
|
||||||
|
"@fleetbase/aws-marketplace": "^0.0.8",
|
||||||
|
"@fleetbase/billing-engine": "^0.1.12",
|
||||||
|
"@fleetbase/customer-portal-engine": "^0.0.10",
|
||||||
"@fleetbase/dev-engine": "^0.2.12",
|
"@fleetbase/dev-engine": "^0.2.12",
|
||||||
"@fleetbase/ember-core": "^0.3.8",
|
"@fleetbase/ember-core": "^0.3.10",
|
||||||
"@fleetbase/ember-ui": "^0.3.14",
|
"@fleetbase/ember-ui": "^0.3.18",
|
||||||
"@fleetbase/fleetops-data": "^0.1.23",
|
"@fleetbase/fleetops-data": "^0.1.25",
|
||||||
"@fleetbase/fleetops-engine": "^0.6.29",
|
"@fleetbase/fleetops-engine": "^0.6.32",
|
||||||
|
"@fleetbase/flespi-engine": "^0.1.16",
|
||||||
"@fleetbase/iam-engine": "^0.1.6",
|
"@fleetbase/iam-engine": "^0.1.6",
|
||||||
|
"@fleetbase/internals-engine": "^0.0.23",
|
||||||
"@fleetbase/leaflet-routing-machine": "^3.2.17",
|
"@fleetbase/leaflet-routing-machine": "^3.2.17",
|
||||||
"@fleetbase/registry-bridge-engine": "^0.1.2",
|
"@fleetbase/registry-bridge-engine": "^0.1.2",
|
||||||
"@fleetbase/storefront-engine": "^0.4.9",
|
"@fleetbase/samsara-engine": "^0.0.3",
|
||||||
|
"@fleetbase/storefront-engine": "^0.4.10",
|
||||||
|
"@fleetbase/valhalla-engine": "^0.0.3",
|
||||||
|
"@fleetbase/vroom-engine": "^0.0.3",
|
||||||
"@formatjs/intl-datetimeformat": "^6.18.2",
|
"@formatjs/intl-datetimeformat": "^6.18.2",
|
||||||
"@formatjs/intl-numberformat": "^8.15.6",
|
"@formatjs/intl-numberformat": "^8.15.6",
|
||||||
"@formatjs/intl-pluralrules": "^5.4.6",
|
"@formatjs/intl-pluralrules": "^5.4.6",
|
||||||
@@ -93,6 +101,7 @@
|
|||||||
"ember-cli-babel": "^8.2.0",
|
"ember-cli-babel": "^8.2.0",
|
||||||
"ember-cli-clean-css": "^3.0.0",
|
"ember-cli-clean-css": "^3.0.0",
|
||||||
"ember-cli-dependency-checker": "^3.3.2",
|
"ember-cli-dependency-checker": "^3.3.2",
|
||||||
|
"ember-cli-deprecation-workflow": "^4.0.0",
|
||||||
"ember-cli-dotenv": "^3.1.0",
|
"ember-cli-dotenv": "^3.1.0",
|
||||||
"ember-cli-htmlbars": "^6.3.0",
|
"ember-cli-htmlbars": "^6.3.0",
|
||||||
"ember-cli-inject-live-reload": "^2.1.0",
|
"ember-cli-inject-live-reload": "^2.1.0",
|
||||||
@@ -149,9 +158,9 @@
|
|||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@fleetbase/ember-core": "latest",
|
"@fleetbase/ember-core": "^0.3.10",
|
||||||
"@fleetbase/ember-ui": "latest",
|
"@fleetbase/ember-ui": "^0.3.18",
|
||||||
"@fleetbase/fleetops-data": "latest"
|
"@fleetbase/fleetops-data": "^0.1.24"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
|
|||||||
1520
console/pnpm-lock.yaml
generated
1520
console/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -75,7 +75,7 @@ ENV QUEUE_CONNECTION=redis
|
|||||||
ENV CADDYFILE_PATH=/fleetbase/Caddyfile
|
ENV CADDYFILE_PATH=/fleetbase/Caddyfile
|
||||||
ENV CONSOLE_PATH=/fleetbase/console
|
ENV CONSOLE_PATH=/fleetbase/console
|
||||||
ENV OCTANE_SERVER=frankenphp
|
ENV OCTANE_SERVER=frankenphp
|
||||||
ENV FLEETBASE_VERSION=0.7.22
|
ENV FLEETBASE_VERSION=0.7.25
|
||||||
|
|
||||||
# Set environment
|
# Set environment
|
||||||
ARG ENVIRONMENT=production
|
ARG ENVIRONMENT=production
|
||||||
@@ -158,14 +158,14 @@ CMD ["php", "artisan", "queue:work"]
|
|||||||
# Application dev stage
|
# Application dev stage
|
||||||
FROM base AS app-dev
|
FROM base AS app-dev
|
||||||
ENTRYPOINT ["docker-php-entrypoint"]
|
ENTRYPOINT ["docker-php-entrypoint"]
|
||||||
CMD ["sh", "-c", "php artisan octane:frankenphp --max-requests=250 --port=8000 --host=0.0.0.0 --watch"]
|
CMD ["sh", "-c", "php artisan octane:frankenphp --max-requests=1000 --port=8000 --host=0.0.0.0 --watch"]
|
||||||
|
|
||||||
# Application release stage
|
# Application release stage
|
||||||
FROM base AS app-release
|
FROM base AS app-release
|
||||||
ENTRYPOINT ["docker-php-entrypoint"]
|
ENTRYPOINT ["docker-php-entrypoint"]
|
||||||
CMD ["sh", "-c", "php artisan octane:frankenphp --max-requests=250 --port=8000 --host=0.0.0.0"]
|
CMD ["sh", "-c", "php artisan octane:frankenphp --max-requests=1000 --port=8000 --host=0.0.0.0"]
|
||||||
|
|
||||||
# Application stage
|
# Application stage
|
||||||
FROM base AS app
|
FROM base AS app
|
||||||
ENTRYPOINT ["/sbin/ssm-parent", "-c", ".ssm-parent.yaml", "run", "--", "docker-php-entrypoint"]
|
ENTRYPOINT ["/sbin/ssm-parent", "-c", ".ssm-parent.yaml", "run", "--", "docker-php-entrypoint"]
|
||||||
CMD ["sh", "-c", "php artisan octane:frankenphp --max-requests=250 --port=8000 --host=0.0.0.0"]
|
CMD ["sh", "-c", "php artisan octane:frankenphp --max-requests=1000 --port=8000 --host=0.0.0.0"]
|
||||||
|
|||||||
Submodule packages/core-api updated: d964db3f42...04ae1ac455
Submodule packages/dev-engine updated: f11d032cb8...64a379ce12
Submodule packages/ember-core updated: 2999dcc4c0...54a45bbdaa
Submodule packages/ember-ui updated: 4f45d72386...c6694206e9
Submodule packages/fleetbase-extensions-indexer updated: db26b8add3...a6f2b4cde9
Submodule packages/fleetops updated: 0b5accee01...09487c1c50
Submodule packages/fleetops-data updated: f20408d663...08520b3981
Submodule packages/iam-engine updated: 5b12288f5b...99698152e2
Submodule packages/pallet updated: b343c621f1...9e7592eddb
Submodule packages/storefront updated: f7c6d42f8a...b5776acef6
Reference in New Issue
Block a user