Compare commits

...

26 Commits

Author SHA1 Message Date
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
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
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
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
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
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
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
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
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
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
Nikolay Stankov
1e331d70b1 feature/translate-bulgarian 2025-01-30 08:54:08 -05:00
35 changed files with 2785 additions and 2229 deletions

View File

@@ -10,10 +10,10 @@
"require": { "require": {
"php": "^8.0", "php": "^8.0",
"appstract/laravel-opcache": "^4.0", "appstract/laravel-opcache": "^4.0",
"fleetbase/core-api": "^1.6.0", "fleetbase/core-api": "^1.6.5",
"fleetbase/fleetops-api": "^0.6.1", "fleetbase/fleetops-api": "^0.6.8",
"fleetbase/registry-bridge": "^0.0.18", "fleetbase/registry-bridge": "^0.0.19",
"fleetbase/storefront-api": "^0.3.29", "fleetbase/storefront-api": "^0.3.31",
"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",

877
api/composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@ return [
'allowed_methods' => ['*'], '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_origins_patterns' => [],

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

@@ -16,7 +16,7 @@
{{/if}} {{/if}}
</InputGroup> </InputGroup>
<InputGroup @wrapperClass="mb-0i"> <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> </InputGroup>
</ContentPanel> </ContentPanel>

View File

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

View File

@@ -2,27 +2,28 @@ import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking'; import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object'; import { action } from '@ember/object';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import createNotificationKey from '../../../utils/create-notification-key'; import createNotificationKey from '@fleetbase/ember-core/utils/create-notification-key';
import { task } from 'ember-concurrency';
export default class ConsoleAdminNotificationsController extends Controller { export default class ConsoleSettingsNotificationsController extends Controller {
/** /**
* Inject the notifications service. * Inject the notifications service.
* *
* @memberof ConsoleAdminNotificationsController * @memberof ConsoleSettingsNotificationsController
*/ */
@service notifications; @service notifications;
/** /**
* Inject the fetch service. * Inject the fetch service.
* *
* @memberof ConsoleAdminNotificationsController * @memberof ConsoleSettingsNotificationsController
*/ */
@service fetch; @service fetch;
/** /**
* The notification settings value JSON. * The notification settings value JSON.
* *
* @memberof ConsoleAdminNotificationsController * @memberof ConsoleSettingsNotificationsController
* @var {Object} * @var {Object}
*/ */
@tracked notificationSettings = {}; @tracked notificationSettings = {};
@@ -30,26 +31,18 @@ export default class ConsoleAdminNotificationsController extends Controller {
/** /**
* Notification transport methods enabled. * Notification transport methods enabled.
* *
* @memberof ConsoleAdminNotificationsController * @memberof ConsoleSettingsNotificationsController
* @var {Array} * @var {Array}
*/ */
@tracked notificationTransportMethods = ['email', 'sms']; @tracked notificationTransportMethods = ['email', 'sms'];
/** /**
* Tracked property for the loading state * Creates an instance of ConsoleSettingsNotificationsController.
* * @memberof ConsoleSettingsNotificationsController
* @memberof ConsoleAdminNotificationsController
* @var {Boolean}
*/
@tracked isLoading = false;
/**
* Creates an instance of ConsoleAdminNotificationsController.
* @memberof ConsoleAdminNotificationsController
*/ */
constructor() { constructor() {
super(...arguments); super(...arguments);
this.getSettings(); this.getSettings.perform();
} }
/** /**
@@ -57,7 +50,7 @@ export default class ConsoleAdminNotificationsController extends Controller {
* *
* @param {Object} notification * @param {Object} notification
* @param {Array} notifiables * @param {Array} notifiables
* @memberof ConsoleAdminNotificationsController * @memberof ConsoleSettingsNotificationsController
*/ */
@action onSelectNotifiable(notification, notifiables) { @action onSelectNotifiable(notification, notifiables) {
const notificationKey = createNotificationKey(notification.definition, notification.name); const notificationKey = createNotificationKey(notification.definition, notification.name);
@@ -83,7 +76,7 @@ export default class ConsoleAdminNotificationsController extends Controller {
* Mutates the notification settings property. * Mutates the notification settings property.
* *
* @param {Object} [_notificationSettings={}] * @param {Object} [_notificationSettings={}]
* @memberof ConsoleAdminNotificationsController * @memberof ConsoleSettingsNotificationsController
*/ */
mutateNotificationSettings(_notificationSettings = {}) { mutateNotificationSettings(_notificationSettings = {}) {
this.notificationSettings = { this.notificationSettings = {
@@ -93,44 +86,32 @@ export default class ConsoleAdminNotificationsController extends Controller {
} }
/** /**
* Save notification settings to the server. * Save notification settings.
* *
* @action * @memberof ConsoleSettingsNotificationsController
* @method saveSettings
* @returns {Promise}
* @memberof ConsoleAdminNotificationsController
*/ */
@action saveSettings() { @task *saveSettings() {
const { notificationSettings } = this; const { notificationSettings } = this;
this.isLoading = true; try {
yield this.fetch.post('notifications/save-settings', { notificationSettings });
return this.fetch
.post('notifications/save-settings', { notificationSettings })
.then(() => {
this.notifications.success('Notification settings successfully saved.'); this.notifications.success('Notification settings successfully saved.');
}) } catch (error) {
.catch((error) => {
this.notifications.serverError(error); this.notifications.serverError(error);
}) }
.finally(() => {
this.isLoading = false;
});
} }
/** /**
* Fetches and updates notification settings asynchronously. * Get notification settings.
* *
* @returns {Promise<void>} A promise for successful retrieval and update, or an error on failure. * @memberof ConsoleSettingsNotificationsController
*/ */
getSettings() { @task *getSettings() {
return this.fetch try {
.get('notifications/get-settings') const { notificationSettings } = yield this.fetch.get('notifications/get-settings');
.then(({ notificationSettings }) => {
this.notificationSettings = notificationSettings; this.notificationSettings = notificationSettings;
}) } catch (error) {
.catch((error) => {
this.notifications.serverError(error); this.notifications.serverError(error);
}); }
} }
} }

View File

@@ -1,6 +0,0 @@
import { helper } from '@ember/component/helper';
import createNotificationKey from '../utils/create-notification-key';
export default helper(function getNotificationKey([definition, name]) {
return createNotificationKey(definition, name);
});

View File

@@ -39,6 +39,9 @@ export default class ConsoleRoute extends Route {
async afterModel(model, transition) { async afterModel(model, transition) {
this.universe.callHooks('console:after-model', this.session, this.router, model, transition); this.universe.callHooks('console:after-model', this.session, this.router, model, transition);
removeBootLoader(); removeBootLoader();
// Reboot extensions
this.universe.bootEngines();
} }
/** /**

View File

@@ -3,7 +3,7 @@ import { inject as service } from '@ember/service';
import { hash } from 'rsvp'; import { hash } from 'rsvp';
import groupBy from '@fleetbase/ember-core/utils/group-by'; import groupBy from '@fleetbase/ember-core/utils/group-by';
export default class ConsoleAdminNotificationsRoute extends Route { export default class ConsoleSettingsNotificationsRoute extends Route {
@service fetch; @service fetch;
model() { model() {
@@ -14,6 +14,8 @@ export default class ConsoleAdminNotificationsRoute extends Route {
} }
setupController(controller, { registry, notifiables }) { setupController(controller, { registry, notifiables }) {
super.setupController(...arguments);
controller.groupedNotifications = groupBy(registry, 'package'); controller.groupedNotifications = groupBy(registry, 'package');
controller.notifiables = notifiables; controller.notifiables = notifiables;
} }

View File

@@ -4,7 +4,6 @@
<Layout::Sidebar::Item @route="console.admin.index" @icon="rectangle-list">{{t "common.overview"}}</Layout::Sidebar::Item> <Layout::Sidebar::Item @route="console.admin.index" @icon="rectangle-list">{{t "common.overview"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.organizations" @icon="building">{{t "common.organizations"}}</Layout::Sidebar::Item> <Layout::Sidebar::Item @route="console.admin.organizations" @icon="building">{{t "common.organizations"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.branding" @icon="palette">{{t "common.branding"}}</Layout::Sidebar::Item> <Layout::Sidebar::Item @route="console.admin.branding" @icon="palette">{{t "common.branding"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.notifications" @icon="bell">{{t "common.notifications"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.two-fa-settings" @icon="shield-halved">{{t "common.2fa-config"}}</Layout::Sidebar::Item> <Layout::Sidebar::Item @route="console.admin.two-fa-settings" @icon="shield-halved">{{t "common.2fa-config"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.schedule-monitor" @icon="calendar-check">{{t "console.admin.schedule-monitor.schedule-monitor"}}</Layout::Sidebar::Item> <Layout::Sidebar::Item @route="console.admin.schedule-monitor" @icon="calendar-check">{{t "console.admin.schedule-monitor.schedule-monitor"}}</Layout::Sidebar::Item>
{{#each this.universe.adminMenuItems as |menuItem|}} {{#each this.universe.adminMenuItems as |menuItem|}}

View File

@@ -3,6 +3,7 @@
<Layout::Sidebar::Panel @open={{true}} @title={{t "common.settings"}}> <Layout::Sidebar::Panel @open={{true}} @title={{t "common.settings"}}>
<Layout::Sidebar::Item @route="console.settings.index" @icon="cog">{{t "common.organization"}}</Layout::Sidebar::Item> <Layout::Sidebar::Item @route="console.settings.index" @icon="cog">{{t "common.organization"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.settings.two-fa" @icon="shield-halved">{{t "common.two-factor"}}</Layout::Sidebar::Item> <Layout::Sidebar::Item @route="console.settings.two-fa" @icon="shield-halved">{{t "common.two-factor"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.settings.notifications" @icon="bell">{{t "common.notifications"}}</Layout::Sidebar::Item>
{{#each this.universe.settingsMenuItems as |menuItem|}} {{#each this.universe.settingsMenuItems as |menuItem|}}
<Layout::Sidebar::Item <Layout::Sidebar::Item
@onClick={{fn this.universe.transitionMenuItem "console.settings.virtual" menuItem}} @onClick={{fn this.universe.transitionMenuItem "console.settings.virtual" menuItem}}

View File

@@ -1,6 +1,6 @@
{{page-title "Push Notifications"}} {{page-title "Notifications"}}
<Layout::Section::Header @title={{t "console.admin.notifications.title"}}> <Layout::Section::Header @title={{t "common.notifications"}}>
<Button @type="primary" @size="sm" @icon="save" @text={{t "common.save-button-text"}} @onClick={{this.saveSettings}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} /> <Button @type="primary" @size="sm" @icon="save" @text={{t "common.save-button-text"}} @onClick={{perform this.saveSettings}} @disabled={{this.saveSettings.isRunning}} @isLoading={{or this.saveSettings.isRunning this.getSettings.isRunning}} />
</Layout::Section::Header> </Layout::Section::Header>
<Layout::Section::Body class="overflow-y-scroll h-full"> <Layout::Section::Body class="overflow-y-scroll h-full">

View File

@@ -1,10 +1,12 @@
<div class="bg-white dark:bg-gray-800 py-5 px-4 shadow rounded-lg w-full"> <div class="bg-white dark:bg-gray-800 py-5 px-4 shadow rounded-lg w-full">
<div class="mb-4"> <div class="mb-4">
<Image src={{@model.logo_url}} @fallbackSrc="/images/fleetbase-logo-svg.svg" alt={{t "app.name"}} width="160" height="56" class="w-40 h-14 mx-auto" /> <Image src={{@model.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"> <h2 class="text-center text-lg font-extrabold text-gray-900 dark:text-white truncate">
{{t "onboard.index.title"}} {{t "onboard.index.title"}}
</h2> </h2>
</div> </div>
</div>
<div class="flex px-3 py-2 mb-4 rounded-md shadow-sm bg-blue-200"> <div class="flex px-3 py-2 mb-4 rounded-md shadow-sm bg-blue-200">
<div> <div>

View File

@@ -1,8 +0,0 @@
import { camelize } from '@ember/string';
export default function createNotificationKey(definition, name) {
const withoutSlashes = definition.replace(/[\W_]+/g, '');
const key = `${camelize(withoutSlashes)}__${camelize(name)}`;
return key;
}

View File

@@ -19,6 +19,8 @@ export default function getPermissionAction(permissionName) {
'notify', 'notify',
'assign_vehicle', 'assign_vehicle',
'assign_order_to', 'assign_order_to',
'assign_driver_to',
'assign_vehicle_to',
'dispatch_order_to', 'dispatch_order_to',
'dispatch', 'dispatch',
'assign', 'assign',

View File

@@ -1,6 +1,6 @@
{ {
"name": "@fleetbase/console", "name": "@fleetbase/console",
"version": "0.6.2", "version": "0.7.0",
"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",
@@ -29,18 +29,18 @@
}, },
"dependencies": { "dependencies": {
"@ember/legacy-built-in-components": "^0.4.2", "@ember/legacy-built-in-components": "^0.4.2",
"@fleetbase/dev-engine": "^0.2.9",
"@fleetbase/ember-core": "latest", "@fleetbase/ember-core": "latest",
"@fleetbase/ember-ui": "latest", "@fleetbase/ember-ui": "latest",
"@fleetbase/fleetops-data": "latest", "@fleetbase/fleetops-data": "latest",
"@fleetbase/fleetops-engine": "^0.6.1", "@fleetbase/fleetops-engine": "^0.6.8",
"@fleetbase/iam-engine": "^0.1.3", "@fleetbase/iam-engine": "^0.1.3",
"@fleetbase/dev-engine": "^0.2.9",
"@fleetbase/registry-bridge-engine": "^0.0.19",
"@fleetbase/storefront-engine": "^0.3.31",
"@fleetbase/leaflet-routing-machine": "^3.2.16", "@fleetbase/leaflet-routing-machine": "^3.2.16",
"@fleetbase/registry-bridge-engine": "^0.0.18",
"@fleetbase/storefront-engine": "^0.3.29",
"@fortawesome/ember-fontawesome": "^2.0.0", "@fortawesome/ember-fontawesome": "^2.0.0",
"ember-changeset": "^4.1.2", "ember-changeset": "4.1.2",
"ember-changeset-validations": "^4.1.1", "ember-changeset-validations": "4.1.2",
"ember-composable-helpers": "^5.0.0", "ember-composable-helpers": "^5.0.0",
"ember-concurrency": "^3.1.1", "ember-concurrency": "^3.1.1",
"ember-concurrency-decorators": "^2.0.3", "ember-concurrency-decorators": "^2.0.3",
@@ -56,6 +56,7 @@
"postcss-nth-list": "^1.0.2" "postcss-nth-list": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@embroider/macros": "1.16.12",
"@babel/core": "^7.25.2", "@babel/core": "^7.25.2",
"@babel/eslint-parser": "^7.25.1", "@babel/eslint-parser": "^7.25.1",
"@babel/plugin-proposal-decorators": "^7.24.7", "@babel/plugin-proposal-decorators": "^7.24.7",
@@ -127,7 +128,7 @@
"stylelint-prettier": "^4.1.0", "stylelint-prettier": "^4.1.0",
"tailwindcss": "^3.4.10", "tailwindcss": "^3.4.10",
"tracked-built-ins": "^3.3.0", "tracked-built-ins": "^3.3.0",
"webpack": "^5.94.0" "webpack": "^5.98.0"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 18"

3304
console/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,7 @@ Router.map(function () {
this.route('settings', function () { this.route('settings', function () {
this.route('virtual', { path: '/:slug' }); this.route('virtual', { path: '/:slug' });
this.route('two-fa'); this.route('two-fa');
this.route('notifications');
}); });
this.route('virtual', { path: '/:slug' }); this.route('virtual', { path: '/:slug' });
this.route('admin', function () { this.route('admin', function () {
@@ -49,7 +50,6 @@ Router.map(function () {
this.route('socket'); this.route('socket');
}); });
this.route('branding'); this.route('branding');
this.route('notifications');
this.route('two-fa-settings'); this.route('two-fa-settings');
this.route('virtual', { path: '/:slug' }); this.route('virtual', { path: '/:slug' });
this.route('organizations', function () { this.route('organizations', function () {

View File

@@ -1,17 +0,0 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from '@fleetbase/console/tests/helpers';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Helper | get-notification-key', function (hooks) {
setupRenderingTest(hooks);
// TODO: Replace this with your real tests.
test('it renders', async function (assert) {
this.set('inputValue', '1234');
await render(hbs`{{get-notification-key this.inputValue}}`);
assert.dom(this.element).hasText('1234');
});
});

View File

@@ -1,12 +1,12 @@
import { module, test } from 'qunit'; import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers'; import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Controller | console/admin/notifications', function (hooks) { module('Unit | Controller | console/settings/notifications', function (hooks) {
setupTest(hooks); setupTest(hooks);
// TODO: Replace this with your real tests. // TODO: Replace this with your real tests.
test('it exists', function (assert) { test('it exists', function (assert) {
let controller = this.owner.lookup('controller:console/admin/notifications'); let controller = this.owner.lookup('controller:console/settings/notifications');
assert.ok(controller); assert.ok(controller);
}); });
}); });

View File

@@ -1,11 +1,11 @@
import { module, test } from 'qunit'; import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers'; import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Route | console/admin/notifications', function (hooks) { module('Unit | Route | console/settings/notifications', function (hooks) {
setupTest(hooks); setupTest(hooks);
test('it exists', function (assert) { test('it exists', function (assert) {
let route = this.owner.lookup('route:console/admin/notifications'); let route = this.owner.lookup('route:console/settings/notifications');
assert.ok(route); assert.ok(route);
}); });
}); });

View File

@@ -1,10 +0,0 @@
import createNotificationKey from '@fleetbase/console/utils/create-notification-key';
import { module, test } from 'qunit';
module('Unit | Utility | create-notification-key', function () {
// TODO: Replace this with your real tests.
test('it works', function (assert) {
let result = createNotificationKey();
assert.ok(result);
});
});

View File

@@ -0,0 +1,365 @@
app:
name: Fleetbase
terms:
new: Ново
sort: Сортиране
filter: Филтър
columns: Колони
settings: Настройки
home: Начало
admin: Админ
logout: Изход
dashboard: Табло
search: Търсене
search-input: Поле за търсене
common:
confirm: Потвърждение
edit: Редактиране
save: Запазване
save-changes: Запази промените
cancel: Отказ
2fa-config: 2FA Конфигурация
account: Акаунт
admin: Админ
branding: Брандиране
columns: Колони
dashboard: Табло
date-of-birth: Дата на раждане
delete: Изтрий
email: Имейл
filesystem: Файлова система
filter: Филтър
home: Начало
logout: Изход
mail: Поща
name: Име
new: Ново
notification-channels: Канали за известия
notifications: Известия
organization: Организация
organizations: Организации
overview: Общ преглед
phone: Вашият телефонен номер
profile: Профил
queue: Опашка
save-button-text: Запази промените
search-input: Поле за търсене
search: Търсене
services: Услуги
settings: Настройки
socket: Сокет
sort: Сортиране
two-factor: Двуфакторно
uploading: Качване...
your-profile: Вашият профил
created-at: Създаден на
country: Държава
phone-number: Телефон
status: Статус
close-and-save: Затвори и запази
users: Потребители
changelog: Дневник на промените
ok: ОК
select-file: Избери файл
back: Назад
next: Напред
continue: Продължи
done: Готово
export: Експорт
reload: Презареди
reload-data: Презареди данните
unauthorized: Неразрешено
unauthorized-to: Нямате разрешение за
unauthorized-access: Неразрешен достъп
unauthorized-access-message: Неразрешен достъп, трябва да заявите необходимите разрешения.
permissions-required-for-changes: Нямате нужните разрешения, за да направите промени.
push-notifications: Push известия
role: Роля
component:
file:
dropdown-label: Действия с файла
import-modal:
loading-message: Обработване на импорта...
drop-upload: Пуснете, за да качите
invalid: Невалидно
ready-upload: готово за качване.
upload-spreadsheets: Качване на електронни таблици
drag-drop: Плъзнете и пуснете файлове с електронни таблици върху тази зона
button-text: или изберете електронни таблици за качване
spreadsheets: електронни таблици
upload-queue: Опашка за качване
dropzone:
file: файл
drop-to-upload: Пуснете, за да качите
invalid: Невалидно
files-ready-for-upload: >-
{numOfFiles} готови за качване.
upload-images-videos: Качване на изображения и видеа
upload-documents: Качване на документи
upload-documents-files: Качване на документи и файлове
upload-avatar-files: Качване на персонализирани аватари
dropzone-supported-images-videos: Плъзнете и пуснете изображения или видео файлове в тази зона
dropzone-supported-avatars: Плъзнете и пуснете SVG или PNG файлове
dropzone-supported-files: Плъзнете и пуснете файлове в тази зона
or-select-button-text: или изберете файлове за качване.
upload-queue: Опашка за качване
uploading: Качване...
two-fa-enforcement-alert:
message: За да подобрите сигурността на акаунта си, организацията ви изисква двуфакторно удостоверяване (2FA). Активирайте 2FA в настройките на акаунта си за допълнителен слой защита.
button-text: Настройте 2FA
comment-thread:
publish-comment-button-text: Публикувай коментар
publish-reply-button-text: Публикувай отговор
reply-comment-button-text: Отговори
edit-comment-button-text: Редактирай
delete-comment-button-text: Изтрий
comment-published-ago: >-
Преди {createdAgo}
comment-input-placeholder: Напишете нов коментар...
comment-reply-placeholder: Напишете вашия отговор...
comment-input-empty-notification: Не можете да публикувате празен коментар...
comment-min-length-notification: Коментарът трябва да е поне 2 символа
dashboard:
select-dashboard: Изберете табло
create-new-dashboard: Създайте ново табло
create-a-new-dashboard: Създайте ново табло
confirm-create-dashboard: Създаване на табло!
edit-layout: Редактиране на подредбата
add-widgets: Добавяне на джаджи
delete-dashboard: Изтрийте таблото
save-dashboard: Запазете таблото
you-cannot-delete-this-dashboard: Не можете да изтриете това табло.
are-you-sure-you-want-delete-dashboard: Сигурни ли сте, че искате да изтриете {dashboardName}?
dashboard-widget-panel:
widget-name: >-
Джаджа {widgetName}
select-widgets: Изберете джаджи
close-and-save: Затвори и запази
services:
dashboard-service:
create-dashboard-success-notification: Ново табло `{dashboardName}` е създадено успешно.
delete-dashboard-success-notification: Таблото `{dashboardName}` беше изтрито.
auth:
verification:
header-title: Верификация на акаунта
title: Потвърдете своя имейл адрес
message-text: <strong>Почти готово!</strong><br> Проверете имейла си за код за потвърждение.
verification-code-text: Въведете кода за потвърждение, който сте получили по имейл.
verification-input-label: Код за потвърждение
verify-button-text: Потвърдете и продължете
didnt-receive-a-code: Все още не сте получили код?
not-sent:
message: Все още не сте получили код?
alternative-choice: Използвайте алтернативните опции по-долу, за да потвърдите акаунта си.
resend-email: Изпратете имейл отново
send-by-sms: Изпратете по SMS
two-fa:
verify-code:
verification-code: Код за потвърждение
check-title: Проверете своя имейл или телефон
check-subtitle: Изпратихме ви код за потвърждение. Въведете го по-долу, за да завършите процеса на вход.
expired-help-text: Вашият 2FA код е изтекъл. Можете да заявите нов код, ако ви е нужно още време.
resend-code: Изпрати кода отново
verify-code: Потвърдете кода
cancel-two-factor: Откажи двуфакторното удостоверяване
invalid-session-error-notification: Невалидна сесия. Моля, опитайте отново.
verification-successful-notification: Успешна верификация!
verification-code-expired-notification: Кодът за потвърждение е изтекъл. Моля, заявете нов.
verification-code-failed-notification: Верификацията не беше успешна. Моля, опитайте отново.
resend-code:
verification-code-resent-notification: Изпратен е нов код за потвърждение.
verification-code-resent-error-notification: Възникна грешка при повторното изпращане на кода. Моля, опитайте отново.
forgot-password:
success-message: Проверете имейла си, за да продължите!
is-sent:
title: Почти готово!
message: <strong>Проверете имейла си!</strong><br> Изпратихме ви магически линк, който ще ви позволи да нулирате паролата си. Линкът изтича след 15 минути.
not-sent:
title: Забравена парола?
message: <strong>Не се притеснявайте, ние ще помогнем.</strong><br> Въведете имейла, който използвате за вход в {appName}, и ще ви изпратим сигурен линк за нулиране на паролата.
form:
email-label: Вашият имейл адрес
submit-button: Добре, изпратете ми магически линк!
nevermind-button: Отказ
login:
title: Влезте в акаунта си
no-identity-notification: Пропуснахте ли да въведете своя имейл?
no-password-notification: Пропуснахте ли да въведете своята парола?
unverified-notification: Акаунтът ви трябва да бъде потвърден, за да продължите.
password-reset-required: Необходимо е нулиране на паролата, за да продължите.
failed-attempt:
message: <strong>Забравихте паролата си?</strong><br> Кликнете върху бутона по-долу, за да я нулирате.
button-text: Добре, помогнете ми!
form:
email-label: Имейл адрес
password-label: Парола
remember-me-label: Запомни ме
forgot-password-label: Забравена парола?
sign-in-button: Вход
create-account-button: Създаване на нов акаунт
slow-connection-message: Забавена връзка.
reset-password:
success-message: Паролата ви е нулирана! Влезте, за да продължите.
invalid-verification-code: Тази връзка за нулиране на паролата е невалидна или е изтекла.
title: Нулирайте паролата си
form:
code:
label: Вашият код за нулиране
help-text: Кодът за потвърждение, който получихте по имейл.
password:
label: Нова парола
help-text: Въведете парола от поне 6 символа, за да продължите.
confirm-password:
label: Потвърдете новата парола
help-text: Въведете парола от поне 6 символа, за да продължите.
submit-button: Нулирай паролата
back-button: Назад
console:
create-or-join-organization:
modal-title: Създаване или присъединяване към организация
join-success-notification: Присъединихте се към нова организация!
create-success-notification: Създадохте нова организация!
switch-organization:
modal-title: Сигурни ли сте, че искате да превключите към организацията {organizationName}?
modal-body: При потвърждение акаунтът ви ще остане вписан, но основната ви организация ще бъде сменена.
modal-accept-button-text: Да, искам да превключа
success-notification: Превключихте организацията
account:
index:
upload-new: Качете нов
phone: Вашият телефонен номер.
photos: снимки
admin:
schedule-monitor:
schedule-monitor: Монитор на графика
task-logs-for: >-
Логове на задачите за:
showing-last-count: Показване на последните {count} записа
name: Име
type: Тип
timezone: Часова зона
last-started: Последно стартиране
last-finished: Последно приключване
last-failure: Последна грешка
date: Дата
memory: Памет
runtime: Времетраене
output: Резултат
no-output: Няма резултат
config:
database:
title: Конфигурация на базата данни
filesystem:
title: Конфигурация на файловата система
mail:
title: Конфигурация на пощата
notification-channels:
title: Конфигурация на Push известия
queue:
title: Конфигурация на опашката
services:
title: Конфигурация на услугите
socket:
title: Конфигурация на сокета
branding:
title: Брандиране
icon-text: Икона
upload-new: Качете нов
reset-default: Възстанови по подразбиране
logo-text: Лого
theme: Основна тема
index:
total-users: Общо потребители
total-organizations: Общо организации
total-transactions: Общо транзакции
notifications:
title: Известия
notification-settings: Настройки за известия
organizations:
index:
title: Организации
owner-name-column: Собственик
owner-phone-column: Телефон на собственика
owner-email-column: Имейл на собственика
users-count-column: Потребители
phone-column: Телефон
email-column: Имейл
users:
title: Потребители
settings:
index:
title: Настройки на организацията
organization-name: Име на организацията
organization-description: Описание на организацията
organization-phone: Телефонен номер на организацията
organization-currency: Валута на организацията
organization-id: Идентификатор на организацията
organization-branding: Брандиране на организацията
logo: Лого
logo-help-text: Лого на вашата организация.
upload-new-logo: Качете ново лого
backdrop: Фон
backdrop-help-text: По желание можете да зададете банер или фонова картинка за организацията.
upload-new-backdrop: Качете нов фон
extensions:
title: Разширенията идват скоро!
message: Моля, проверете отново в следващите версии, докато подготвяме хранилище и пазар за разширения.
notifications:
select-all: Избери всички
mark-as-read: Маркирай като прочетени
received: >-
Получено:
message: Няма известия за показване.
invite:
for-users:
invitation-message: Поканени сте да се присъедините към {companyName}
invitation-sent-message: Поканени сте да се присъедините към организацията {companyName} в {appName}. За да приемете тази покана, въведете кода за покана, който сте получили по имейл, и натиснете Продължи.
invitation-code-sent-text: Вашият код за покана
accept-invitation-text: Приемете поканата
onboard:
index:
title: Създайте своя акаунт
welcome-title: <strong>Добре дошли в {companyName}!</strong><br />
welcome-text: Попълнете изискваните данни по-долу, за да започнете.
full-name: Пълно име
full-name-help-text: Вашето пълно име
your-email: Имейл адрес
your-email-help-text: Вашият имейл адрес
phone: Телефонен номер
phone-help-text: Вашият телефонен номер
organization-name: Име на организацията
organization-help-text: Името на вашата организация; всички услуги и ресурси ще се управляват под тази организация. По-късно можете да създавате колкото организации желаете.
password: Въведете парола
password-help-text: Вашата парола; уверете се, че е достатъчно сигурна.
confirm-password: Потвърдете паролата
confirm-password-help-text: Просто за да я потвърдите, въведете я отново.
continue-button-text: Продължи
verify-email:
header-title: Верификация на акаунта
title: Потвърдете своя имейл адрес
message-text: <strong>Почти готово!</strong><br> Проверете имейла си за код за потвърждение.
verification-code-text: Въведете кода за потвърждение, който сте получили по имейл.
verification-input-label: Код за потвърждение
verify-button-text: Потвърдете и продължете
didnt-receive-a-code: Все още не сте получили код?
not-sent:
message: Все още не сте получили код?
alternative-choice: Използвайте алтернативните опции по-долу, за да потвърдите акаунта си.
resend-email: Изпратете имейл отново
send-by-sms: Изпратете по SMS
install:
installer-header: Инсталатор
failed-message-sent: Инсталацията не беше успешна! Кликнете бутона по-долу, за да опитате отново.
retry-install: Опитайте да инсталирате отново
start-install: Стартиране на инсталацията
layout:
header:
menus:
organization:
settings: Настройки на организацията
create-or-join: Създаване или присъединяване към организации
explore-extensions: Разгледайте разширенията
user:
view-profile: Преглед на профила
keyboard-shortcuts: Покажи клавишните комбинации
changelog: Дневник на промените

View File

@@ -59,8 +59,6 @@ services:
ENVIRONMENT: development ENVIRONMENT: development
ports: ports:
- "4200:4200" - "4200:4200"
volumes:
- console-build:/console
application: application:
build: build:
@@ -69,9 +67,6 @@ services:
target: app-dev target: app-dev
args: args:
ENVIRONMENT: development ENVIRONMENT: development
GITHUB_AUTH_KEY: ${GITHUB_AUTH_KEY}
volumes:
- console-build:/fleetbase/console
environment: environment:
ENVIRONMENT: development ENVIRONMENT: development
DATABASE_URL: "mysql://root@database/fleetbase" DATABASE_URL: "mysql://root@database/fleetbase"
@@ -101,6 +96,3 @@ services:
- "8000:80" - "8000:80"
depends_on: depends_on:
- application - application
volumes:
console-build:

View File

@@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.2 # syntax = docker/dockerfile:1.2
# Base stage # Base stage
FROM dunglas/frankenphp:1.5.0-php8.2-bookworm as base FROM dunglas/frankenphp:1.5.0-php8.2-bookworm AS base
# Install packages # Install packages
RUN apt-get update && apt-get install -y git bind9-utils mycli nodejs npm nano \ RUN apt-get update && apt-get install -y git bind9-utils mycli nodejs npm nano \
@@ -62,10 +62,10 @@ COPY --from=ghcr.io/springload/ssm-parent:1.8 /usr/bin/ssm-parent /sbin/ssm-pare
# Create the pnpm directory and set the PNPM_HOME environment variable # Create the pnpm directory and set the PNPM_HOME environment variable
RUN mkdir -p ~/.pnpm RUN mkdir -p ~/.pnpm
ENV PNPM_HOME /root/.pnpm ENV PNPM_HOME=/root/.pnpm
# Add the pnpm global bin to the PATH # Add the pnpm global bin to the PATH
ENV PATH /root/.pnpm/bin:$PATH ENV PATH=/root/.pnpm/bin:$PATH
# Set some build ENV variables # Set some build ENV variables
ENV LOG_CHANNEL=stdout ENV LOG_CHANNEL=stdout
@@ -80,9 +80,6 @@ ENV OCTANE_SERVER=frankenphp
ARG ENVIRONMENT=production ARG ENVIRONMENT=production
ENV APP_ENV=$ENVIRONMENT ENV APP_ENV=$ENVIRONMENT
# Setup github auth
ARG GITHUB_AUTH_KEY
# Copy Caddyfile # Copy Caddyfile
COPY --chown=www-data:www-data ./Caddyfile $CADDYFILE_PATH COPY --chown=www-data:www-data ./Caddyfile $CADDYFILE_PATH
@@ -92,9 +89,6 @@ RUN mkdir -p /fleetbase/api && mkdir -p /fleetbase/console && chown -R www-data:
# Set working directory # Set working directory
WORKDIR /fleetbase/api WORKDIR /fleetbase/api
# If GITHUB_AUTH_KEY is provided, create auth.json with it
RUN if [ -n "$GITHUB_AUTH_KEY" ]; then echo "{\"github-oauth\": {\"github.com\": \"$GITHUB_AUTH_KEY\"}}" > auth.json; fi
# Prepare composer cache directory # Prepare composer cache directory
RUN mkdir -p /var/www/.cache/composer && chown -R www-data:www-data /var/www/.cache/composer RUN mkdir -p /var/www/.cache/composer && chown -R www-data:www-data /var/www/.cache/composer
@@ -123,7 +117,7 @@ RUN chmod -R 755 /fleetbase/api/storage
RUN chmod +x /fleetbase/api/deploy.sh RUN chmod +x /fleetbase/api/deploy.sh
# Scheduler base stage # Scheduler base stage
FROM base as scheduler-base FROM base AS scheduler-base
# Install go-crond # Install go-crond
RUN curl -L https://github.com/webdevops/go-crond/releases/download/23.12.0/go-crond.linux.amd64 > /usr/local/bin/go-crond && chmod +x /usr/local/bin/go-crond RUN curl -L https://github.com/webdevops/go-crond/releases/download/23.12.0/go-crond.linux.amd64 > /usr/local/bin/go-crond && chmod +x /usr/local/bin/go-crond
@@ -131,31 +125,31 @@ COPY docker/crontab ./crontab
RUN chmod 0600 ./crontab RUN chmod 0600 ./crontab
# Scheduler dev stage # Scheduler dev stage
FROM scheduler-base as scheduler-dev FROM scheduler-base AS scheduler-dev
ENTRYPOINT [] ENTRYPOINT []
CMD ["go-crond", "--verbose", "root:./crontab"] CMD ["go-crond", "--verbose", "root:./crontab"]
# Scheduler stage # Scheduler stage
FROM scheduler-base as scheduler FROM scheduler-base AS scheduler
ENTRYPOINT ["/sbin/ssm-parent", "-c", ".ssm-parent.yaml", "run", "--"] ENTRYPOINT ["/sbin/ssm-parent", "-c", ".ssm-parent.yaml", "run", "--"]
CMD ["go-crond", "--verbose", "root:./crontab"] CMD ["go-crond", "--verbose", "root:./crontab"]
# Events stage # Events stage
FROM base as events FROM base AS events
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 ["php", "artisan", "queue:work"] CMD ["php", "artisan", "queue:work"]
# Events stage # Events stage
FROM base as events-dev FROM base AS events-dev
ENTRYPOINT [] ENTRYPOINT []
CMD ["php", "artisan", "queue:work"] 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=250 --port=8000 --host=0.0.0.0 --watch"]
# 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=250 --port=8000 --host=0.0.0.0"]