Compare commits

..

31 Commits

Author SHA1 Message Date
Ronald A. Richardson
da420f0b4a ready for release 2025-11-10 10:49:29 +08:00
Ronald A. Richardson
e923a89719 v0.7.18 2025-11-10 10:35:47 +08:00
Ronald A. Richardson
0742603b43 added storefront release 2025-11-10 10:31:02 +08:00
Ronald A. Richardson
e1788a4ad6 v0.7.17 2025-11-10 10:29:26 +08:00
Ronald A. Richardson
a17aa3f5cc hotfix router map 2025-11-06 21:58:40 +08:00
Ron
0bf1a7fadd Merge pull request #459 from fleetbase/dev-v0.7.16
v0.7.16
2025-11-06 21:17:49 +08:00
Ronald A. Richardson
aa1ea2de89 Merge branch 'main' of github.com:fleetbase/fleetbase into dev-v0.7.16 2025-11-06 21:10:23 +08:00
Ronald A. Richardson
235f1ce80c upgraded dependencies 2025-11-06 20:45:42 +08:00
Ronald A. Richardson
5aa50504a4 updated RELEASE.md 2025-11-06 20:34:56 +08:00
Ronald A. Richardson
5d1b2e1939 - Made the LogApiRequests middleware more robust
- Fixed controller validation handling
- Added microsoft365/graph mail driver
- Improved password requirements (including breached password check)
- Patched creating duplicate users by email in IAM
- Patch env mapper
- Vehicle/driver tracking API doesnt fire resource lifecycle events or log requests - only tracking events
- Patched `<ModelCoordinatesInput />` component
- Security patch on Storefront customers API
- Styling updates on Storefront
2025-11-06 20:33:23 +08:00
Ron
fc5d90189c Merge pull request #456 from fleetbase/dev-v0.7.15
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.15
2025-11-01 14:08:41 +08:00
Ronald A. Richardson
2fee78e534 performed upgrades 2025-11-01 14:07:55 +08:00
Ronald A. Richardson
83fc794702 v0.7.15 2025-11-01 14:00:59 +08:00
Ron
66f669ad80 Merge pull request #454 from fleetbase/dev-v0.7.14
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.14
2025-10-30 18:53:33 +08:00
Ronald A. Richardson
a11b77592c fix console/package.json 2025-10-30 18:23:44 +08:00
Ronald A. Richardson
e5156829dc update release.md 2025-10-30 18:22:01 +08:00
Ronald A. Richardson
6cd7ddffcb v0.7.14 2025-10-30 18:20:04 +08:00
Ron
cbdf1d489b Merge pull request #447 from fleetbase/dev-v0.7.13
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.13 ~ Connectivity Module + Positions Playback + Positions & Device Events Drawer
2025-10-28 05:48:35 +08:00
Ronald A. Richardson
785bc55bb7 v0.7.13 ~ Connectivity Module + Positions Playback + Positions & Device Events Drawer 2025-10-28 05:39:54 +08:00
Ron
d171d02aac Merge pull request #446 from fleetbase/dev-v0.7.12
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.12 ~ Patches and Order Board Improvement
2025-10-22 12:38:56 +08:00
Ronald A. Richardson
dfd4ee37df pin linux build version 2025-10-22 12:38:24 +08:00
Ronald A. Richardson
27c063fbfb v0.7.12 ~ Patches and Order Board Improvement 2025-10-22 12:21:58 +08:00
Ron
8e85dcff83 Merge pull request #443 from fleetbase/dev-v0.7.11
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.11 ~ Maintenance, Reports, Telematics Upgrade/Features
2025-10-15 23:13:21 +08:00
Ronald A. Richardson
e38923c461 added RELEASE and updated README 2025-10-15 23:09:04 +08:00
Ronald A. Richardson
9911c96c09 All packages upgraded 2025-10-15 22:15:33 +08:00
Ronald A. Richardson
284c62cd06 v0.7.11 ~ Maintenance, Reports, Telematics Upgrade/Features 2025-09-30 13:49:34 +08:00
Ron
f8fd9f76fa Merge pull request #429 from fleetbase/dev-v0.7.10
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.10 - Maintenance capability overhaul, Storefront critical patches and improvements
2025-09-02 15:33:10 +08:00
Ronald A. Richardson
67aa793537 v0.7.10 - Maintenance capability overhaul, Storefront critical patches and improvements 2025-09-02 14:32:39 +08:00
Ron
5d0ae16cfd Merge pull request #424 from fleetbase/dev-v0.7.9
Some checks failed
Fleetbase CI / Build and Start Docker Services (push) Has been cancelled
v0.7.9 ~ shorter default data retention + template variable resolver + patched order vehicle update via api
2025-08-13 17:47:01 +08:00
Ronald A. Richardson
1d003ee31e v0.7.9 ~ shorter default data retention + template variable resolver + patched order vehicle update via api 2025-08-13 17:32:46 +08:00
Ron
9c9f3a994e Added one-click aws deploy details
Some checks are pending
Fleetbase CI / Build and Start Docker Services (push) Waiting to run
2025-08-13 14:21:18 +08:00
117 changed files with 12171 additions and 3958 deletions

View File

@@ -58,6 +58,43 @@ jobs:
files: |
./docker-bake.hcl
- name: Resolve ECS Targets
run: |
set -euo pipefail
# Detect naming scheme by checking if new cluster exists
NEW_CLUSTER="${PROJECT}-${STACK}-cluster"
if aws ecs describe-clusters --region "${AWS_REGION}" --clusters "${NEW_CLUSTER}" \
--query "clusters[?status=='ACTIVE'].clusterArn" --output text 2>/dev/null | grep -q .; then
# New scheme: use cluster suffix and service prefixes
CLUSTER="${NEW_CLUSTER}"
SERVICE_PREFIX="${PROJECT}-${STACK}-"
SERVICE_BASE="api"
else
# Legacy scheme: no suffixes/prefixes
CLUSTER="${PROJECT}-${STACK}"
SERVICE_PREFIX=""
SERVICE_BASE="app"
fi
# Build service names
API_SERVICE="${SERVICE_PREFIX}${SERVICE_BASE}"
SCHEDULER_SERVICE="${SERVICE_PREFIX}scheduler"
EVENTS_SERVICE="${SERVICE_PREFIX}events"
TASK_DEF="${PROJECT}-${STACK}-${SERVICE_BASE}"
# Get container name from task definition
CONTAINER_NAME="$(aws ecs describe-task-definition --task-definition "$TASK_DEF" \
--query 'taskDefinition.containerDefinitions[0].name' --output text 2>/dev/null || echo "$SERVICE_BASE")"
{
echo "CLUSTER=$CLUSTER"
echo "API_SERVICE=$API_SERVICE"
echo "SCHEDULER_SERVICE=$SCHEDULER_SERVICE"
echo "EVENTS_SERVICE=$EVENTS_SERVICE"
echo "TASK_DEF=$TASK_DEF"
echo "CONTAINER_NAME=$CONTAINER_NAME"
} >> "$GITHUB_ENV"
- name: Download ecs-tool
run: |
wget -O ecs-tool.tar.gz https://github.com/springload/ecs-tool/releases/download/1.9.6/ecs-tool_1.9.6_linux_amd64.tar.gz && tar -xvf ecs-tool.tar.gz ecs-tool
@@ -65,9 +102,21 @@ jobs:
- name: Deploy the images 🚀
run: |-
set -eu
# run deploy.sh script before deployments
env "ECS_RUN.SERVICE=app" "ECS_RUN.LAUNCH_TYPE=FARGATE" ./ecs-tool run -l "ecs-tool" --image_tag '{container_name}-${{ env.VERSION }}' --cluster ${{ env.PROJECT }}-${{ env.STACK }} --task_definition ${{ env.PROJECT }}-${{ env.STACK }}-app --container_name app ./deploy.sh
./ecs-tool deploy --image_tag '{container_name}-${{ env.VERSION }}' --cluster ${{ env.PROJECT }}-${{ env.STACK }} -s app -s scheduler -s events
# Run deploy.sh script before deployments
env "ECS_RUN.SERVICE=${API_SERVICE}" "ECS_RUN.LAUNCH_TYPE=FARGATE" \
./ecs-tool run -l "ecs-tool" \
--image_tag '{container_name}-${{ env.VERSION }}' \
--cluster "${CLUSTER}" \
--task_definition "${TASK_DEF}" \
--container_name "${CONTAINER_NAME}" \
./deploy.sh
# Deploy services
./ecs-tool deploy \
--image_tag '{container_name}-${{ env.VERSION }}' \
--cluster "${CLUSTER}" \
-s "${API_SERVICE}" -s "${SCHEDULER_SERVICE}" -s "${EVENTS_SERVICE}"
build_frontend:
name: Build and Deploy the Console
@@ -175,6 +224,11 @@ jobs:
set -u
DEPLOY_BUCKET=${STATIC_DEPLOY_BUCKET:-${{ env.PROJECT }}-${{ env.STACK }}}
NEW_BUCKET="${PROJECT}-${STACK}-console"
if aws s3api head-bucket --bucket "$NEW_BUCKET" 2>/dev/null; then
DEPLOY_BUCKET="$NEW_BUCKET"
fi
# this value will come from the dotenv above
echo "Deploying to $DEPLOY_BUCKET"
wget -O- https://github.com/bep/s3deploy/releases/download/v2.11.0/s3deploy_2.11.0_linux-amd64.tar.gz | tar xzv -f - s3deploy

11
.gitignore vendored
View File

@@ -3,6 +3,7 @@
.env.backup
.phpunit.result.cache
.pnpm-store
.tool-versions
docker-compose.override.yml
npm-debug.log
yarn-error.log
@@ -16,6 +17,8 @@ api/composer.dev.json
api/composer-install-dev.sh
api/auth.json
api/crontab
api/go-crond
api/.fleetbase-id
act.sh
composer-auth.json
docker/database/*
@@ -31,8 +34,14 @@ packages/loconav
packages/internals
packages/projectargus-engine
packages/customer-portal
# wip
packages/solid
packages/aws-marketplace
packages/countries
packages/fliit
packages/samsara
packages/solid*
packages/valhalla
packages/vroom
solid
verdaccio
# asdf

View File

@@ -7,11 +7,11 @@
<p align="center" dir="auto">
Modular logistics and supply chain operating system
<br>
<a href="https://docs.fleetbase.io/" rel="nofollow">Documentation</a>
<a href="https://docs.fleetbase.io/" rel="nofollow" target="_fleetbase_docs">Documentation</a>
·
<a href="https://console.fleetbase.io" rel="nofollow">Cloud Version</a>
<a href="https://console.fleetbase.io" rel="nofollow" target="_fleetbase_console">Cloud Version</a>
·
<a href="https://fleetbase.apichecker.com" target="_api_status" rel="nofollow">API Status</a>
<a href="https://console.fleetbase.io/aws-marketplace" rel="nofollow" target="_aws_marketplace">Deploy on AWS</a>
·
<a href="https://tally.so/r/3NBpAW" rel="nofollow">Book a Demo</a>
·
@@ -25,7 +25,34 @@
Fleetbase is a modular logistics and supply chain operating system designed to streamline management, planning, optimization, and operational control across various sectors of the supply chain industry.
<p align="center" dir="auto">
<img src="https://github.com/fleetbase/fleetbase/assets/816371/125348c9-c88a-49fe-b098-9abec9d7dff8" alt="Fleetbase Console" width="1200" style="max-width: 100%;" />
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/fleetbase_overview.png" alt="Fleetbase Console" width="1200" style="max-width: 100%;" />
</p>
## Visual Feature Showcase
<p align="center" dir="auto">
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/order-board-kanban.png" alt="Fleetbase Order Board" width="1200" style="max-width: 100%;" />
<em>Visualize and manage your orders with a dynamic Kanban board.</em>
</p>
<p align="center" dir="auto">
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/order-workflow-config.png" alt="Fleetbase Order Workflow Configuration" width="1200" style="max-width: 100%;" />
<em>Create custom order flows and automation with the intuitive workflow builder.</em>
</p>
<p align="center" dir="auto">
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/order-map-view.png" alt="Fleetbase Order Map View" width="1200" style="max-width: 100%;" />
<em>Track individual orders in real-time on an interactive map.</em>
</p>
<p align="center" dir="auto">
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/live-map-tracking.png" alt="Fleetbase Live Map Tracking" width="1200" style="max-width: 100%;" />
<em>Get a complete overview of your fleet and active orders on a live map.</em>
</p>
<p align="center" dir="auto">
<img src="https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/fleet-map-zones.png" alt="Fleetbase Fleet Map with Zones" width="1200" style="max-width: 100%;" />
<em>Define and manage service areas and zones for your fleet.</em>
</p>
**Quickstart**
@@ -39,6 +66,7 @@ cd fleetbase && ./scripts/docker-install.sh
- [Features](#-features)
- [Install](#-install)
- [Deploy on AWS](#-deploy-on-aws-in-one-click)
- [Extensions](#-extensions)
- [Apps](#-apps)
- [Roadmap](#-roadmap)
@@ -117,6 +145,36 @@ services:
You can learn more about full installation, and configuration in the [official documentation](https://docs.fleetbase.io/getting-started/install).
## 🚀 Deploy on AWS in One Click
Deploy your complete Fleetbase logistics platform on AWS with enterprise-grade security, scalability, and reliability. No DevOps expertise required!
[![Deploy to AWS](https://img.shields.io/badge/Deploy%20to%20AWS-FF9900?style=for-the-badge&logo=amazon-aws&logoColor=white)](https://console.fleetbase.io/aws-marketplace)
### ✨ What You Get
- **Complete AWS Infrastructure**: ECS Fargate, RDS MySQL, ElastiCache Redis, S3, CloudFront, and more
- **25-Minute Setup**: From zero to production-ready logistics platform
- **Enterprise Security**: VPC isolation, encrypted storage, secrets management
- **Auto-Scaling**: Handle traffic spikes with ECS Fargate auto-scaling
- **High Availability**: Multi-AZ deployment with 99.9% uptime SLA
- **Cost Optimized**: Pay-as-you-use with optimized resource allocation
### 🏗️ Infrastructure Included
Your AWS deployment includes a complete, production-ready infrastructure stack:
- **Compute**: ECS Fargate cluster with auto-scaling services
- **Database**: RDS MySQL 8.0 with automated backups and Multi-AZ support
- **Cache**: ElastiCache Redis for high-performance caching
- **Storage**: S3 object storage with CloudFront CDN for global distribution
- **Networking**: VPC with private subnets, NAT gateways, and security groups
- **Load Balancing**: Application Load Balancer with SSL certificates
- **Monitoring**: CloudWatch logs, container insights, and health monitoring
- **Messaging**: SQS message queues for background job processing
[**🚀 Deploy Now**](https://console.fleetbase.io/aws-marketplace) | [**📖 Learn More**](https://docs.fleetbase.io/category/deploying/aws)
# 🧩 Extensions
Extensions are modular components that enhance the functionality of your Fleetbase instance. They allow you to add new features, customize existing behavior, or integrate with external systems.
@@ -149,8 +207,8 @@ Fleetbase offers a few open sourced apps which are built on Fleetbase which can
## 🛣️ Roadmap
1. **Inventory and Warehouse Management** ~ Pallet will be Fleetbases first official extension for WMS & Inventory.
2. **Accounting and Invoicing** ~ Ledger will be Fleetbases first official extension accounting and invoicing.
3. **Fleetbase for Desktop** ~ Desktop builds for OSX and Windows.
4. **Custom Maps and Routing Engines** ~ Feature to enable easy integrations with custom maps and routing engines like Google Maps or Mapbox etc…
3. **AI** ~ AI Agent intrgation for system and workflows.
4. **Dynamic Rules System** ~ Trigger events, tasks jobs from a rule builder on resources.
## 🪲 Bugs and 💡 Feature Requests
@@ -186,3 +244,4 @@ Get updates on Fleetbase's development and chat with the project maintainers and
# License & Copyright
Fleetbase is made available under the terms of the <a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank">GNU Affero General Public License 3.0 (AGPL 3.0)</a>. For other licenses <a href="mailto:hello@fleetbase.io" target="_blank">contact us</a>.

View File

@@ -1,17 +1,19 @@
# 🚀 Fleetbase v0.7.8 — 2025-08-12
# 🚀 Fleetbase v0.7.18 — 2025-11-10
> “Improved system maintenance”
> "Hotfix IAM user validation, make online/offline toggle silent"
---
## ✨ Highlights
- Improved and optimizes maintenance scripts
- Patched OSX binary build
- Hotfix validateRequest implementation to not rewrite request params
- Hotfix user validation password optional for creation
- Made online/offline endpoint for drivers silent
- Hotfix QPay payment gateway on Storefront + ebarimt reciept fix
---
## ⚠️ Breaking Changes
- None 🙂
- None
---

View File

@@ -7,32 +7,42 @@
"laravel"
],
"license": "AGPL-3.0-or-later",
"authors": [
{
"name": "Fleetbase Pte Ltd.",
"email": "hello@fleetbase.io"
},
{
"name": "Ronald A. Richardson",
"email": "ron@fleetbase.io"
}
],
"require": {
"php": "^8.0",
"appstract/laravel-opcache": "^4.0",
"fleetbase/core-api": "^1.6.14",
"fleetbase/fleetops-api": "^0.6.16",
"fleetbase/registry-bridge": "^0.0.19",
"fleetbase/storefront-api": "^0.4.0",
"fleetbase/core-api": "^1.6.23",
"fleetbase/fleetops-api": "^0.6.24",
"fleetbase/registry-bridge": "^0.1.0",
"fleetbase/storefront-api": "^0.4.5",
"guzzlehttp/guzzle": "^7.0.1",
"laravel/framework": "^10.0",
"laravel/octane": "^2.3",
"laravel/tinker": "^2.9",
"league/flysystem-aws-s3-v3": "^3.0",
"maatwebsite/excel": "^3.1",
"phpoffice/phpspreadsheet": "^1.28",
"maennchen/zipstream-php": "3.1.2",
"phpoffice/phpspreadsheet": "^1.28",
"predis/predis": "^2.1",
"psr/http-factory-implementation": "*",
"resend/resend-php": "^0.14.0",
"s-ichikawa/laravel-sendgrid-driver": "^4.0",
"stripe/stripe-php": "13.13.0",
"symfony/mailgun-mailer": "^7.1",
"symfony/postmark-mailer": "^7.1"
},
"require-dev": {
"spatie/laravel-ignition": "^2.0",
"fakerphp/faker": "^1.9.1",
"kitloong/laravel-migrations-generator": "^6.10",
"laravel/sail": "^1.0.1",
"mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^7.0",
@@ -79,15 +89,6 @@
],
"clean-logs": [
"composer run-script clear-logs"
],
"dock": [
"docker exec -it fleetbase_os_application_1 /usr/bin/tmux -u new"
],
"dock-server": [
"docker exec -it fleetbase_os_httpd_1 /bin/sh"
],
"tunnel": [
"ngrok http --region=ap --hostname=fleetbase.ap.ngrok.io 8000"
]
},
"extra": {

1651
api/composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,7 @@ return [
|
*/
'paths' => ['/*', 'sanctum/csrf-cookie'],
'paths' => ['*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],

View File

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

View File

@@ -1,4 +1,5 @@
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
# FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
FROM --platform=linux/amd64 docker.io/dunglas/frankenphp:static-builder@sha256:821526b776a26502735d83890cc0a0d579348c510ba6c777df0762cb1c50d967
WORKDIR /go/src/app

View File

@@ -5,6 +5,7 @@ import config from '@fleetbase/console/config/environment';
import loadExtensions from '@fleetbase/ember-core/utils/load-extensions';
import mapEngines from '@fleetbase/ember-core/utils/map-engines';
import loadRuntimeConfig from '@fleetbase/console/utils/runtime-config';
import applyRouterFix from './utils/router-refresh-patch';
export default class App extends Application {
modulePrefix = config.modulePrefix;
@@ -14,6 +15,7 @@ export default class App extends Application {
engines = {};
async ready() {
applyRouterFix(this);
const extensions = await loadExtensions();
this.extensions = extensions;

View File

@@ -1,4 +1,4 @@
<ContentPanel @title="Filesystem" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Filesystem" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Driver" @helpText="Select the default filesystem driver for Fleetbase to use.">
<Select @options={{this.disks}} @value={{this.driver}} @onSelect={{this.setDriver}} @placeholder="Select filesystem driver" class="w-full" disabled={{this.isLoading}} />
</InputGroup>

View File

@@ -1,4 +1,4 @@
<ContentPanel @title="Mail" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Mail" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Mailer" @helpText="Select the default mailer for Fleetbase to use.">
<Select @options={{this.mailers}} @value={{this.mailer}} @onSelect={{this.setMailer}} @placeholder="Select mailer" class="w-full" />
</InputGroup>
@@ -13,6 +13,14 @@
<InputGroup @name="SMTP Timeout" @value={{this.smtpTimeout}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="SMTP Auth Mode" @value={{this.smtpAuth_mode}} disabled={{this.loadConfigValues.isRunning}} />
{{/if}}
{{#if (eq this.mailer "microsoft-graph")}}
<InputGroup @name="Client ID" @value={{this.microsoftGraphClient_id}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="Client Secret" @value={{this.microsoftGraphClient_secret}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="Tenant ID" @value={{this.microsoftGraphTenant_id}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup>
<Toggle @isToggled={{this.microsoftGraphSave_to_sent_items}} @onToggle={{fn (mut this.microsoftGraphSave_to_sent_items)}} @label="Save to sent items" />
</InputGroup>
{{/if}}
{{#if (eq this.mailer "mailgun")}}
<InputGroup @name="Mailgun Domain" @value={{this.mailgunDomain}} disabled={{this.loadConfigValues.isRunning}} />
<InputGroup @name="Mailgun Endpoint" @value={{this.mailgunEndpoint}} disabled={{this.loadConfigValues.isRunning}} />

View File

@@ -26,6 +26,10 @@ export default class ConfigureMailComponent extends Component {
@tracked postmarkToken = null;
@tracked sendgridApi_key = null;
@tracked resendKey = null;
@tracked microsoftGraphClient_id = null;
@tracked microsoftGraphClient_secret = null;
@tracked microsoftGraphTenant_id = null;
@tracked microsoftGraphSave_to_sent_items = false;
/**
* Creates an instance of ConfigureFilesystemComponent.
@@ -64,6 +68,19 @@ export default class ConfigureMailComponent extends Component {
};
}
@action serializeMicrosoftGraphConfig() {
return {
client_id: this.microsoftGraphClient_id,
client_secret: this.microsoftGraphClient_secret,
tenant_id: this.microsoftGraphTenant_id,
save_to_sent_items: this.microsoftGraphSave_to_sent_items,
from: {
address: this.fromAddress,
name: this.fromName,
},
};
}
@action serializeMailgunConfig() {
return {
domain: this.mailgunDomain,
@@ -112,6 +129,7 @@ export default class ConfigureMailComponent extends Component {
postmark: this.serializePostmarkConfig(),
sendgrid: this.serializeSendgridConfig(),
resend: this.serializeResendConfig(),
microsoftGraph: this.serializeMicrosoftGraphConfig(),
});
} catch (error) {
this.notifications.serverError(error);
@@ -131,6 +149,7 @@ export default class ConfigureMailComponent extends Component {
postmark: this.serializePostmarkConfig(),
sendgrid: this.serializeSendgridConfig(),
resend: this.serializeResendConfig(),
microsoftGraph: this.serializeMicrosoftGraphConfig(),
});
this.notifications.success('Mail configuration saved.');
} catch (error) {

View File

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

View File

@@ -1,4 +1,4 @@
<ContentPanel @title="Queue" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Queue" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Driver" @helpText="Select the default queue driver for Fleetbase to use.">
<Select @options={{this.connections}} @value={{this.driver}} @onSelect={{this.setDriver}} @placeholder="Select queue driver" disabled={{this.isLoading}} class="w-full" />
</InputGroup>

View File

@@ -1,15 +1,15 @@
<ContentPanel @title="AWS" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="AWS" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="AWS Access Key" @value={{this.awsKey}} disabled={{this.isLoading}} />
<InputGroup @name="AWS Access Secret" @value={{this.awsSecret}} disabled={{this.isLoading}} />
<InputGroup @name="AWS Region" @value={{this.awsRegion}} disabled={{this.isLoading}} />
</ContentPanel>
<ContentPanel @title="Google Maps" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Google Maps" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Google Maps API Key" @value={{this.googleMapsApiKey}} disabled={{this.isLoading}} />
<InputGroup @name="Google Maps Locale" @value={{this.googleMapsLocale}} disabled={{this.isLoading}} />
</ContentPanel>
<ContentPanel @title="Twilio" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Twilio" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Twilio SID" @value={{this.twilioSid}} disabled={{this.isLoading}} />
<InputGroup @name="Twilio Token" @value={{this.twilioToken}} disabled={{this.isLoading}} />
<InputGroup @name="Twilio From" @value={{this.twilioFrom}} disabled={{this.isLoading}} />
@@ -25,7 +25,7 @@
</div>
</ContentPanel>
<ContentPanel @title="Sentry" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Sentry" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="Sentry DSN" @value={{this.sentryDsn}} disabled={{this.isLoading}} />
{{#if this.sentryTestResponse}}
<div class="flex flex-row items-center rounded-lg border {{if (eq this.sentryTestResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
@@ -36,7 +36,7 @@
<Button @wrapperClass="mt-3" @icon="plug" @text="Test Sentry Config" @onClick={{perform this.testSentry}} @isLoading={{this.testSentry.isRunning}} @disabled={{not this.sentryDsn}} />
</ContentPanel>
<ContentPanel @title="IP Info" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="IP Info" @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name="IP Info API Key" @value={{this.ipinfoApiKey}} disabled={{this.isLoading}} />
</ContentPanel>

View File

@@ -1,4 +1,4 @@
<ContentPanel @title="SocketCluster Connection" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="SocketCluster Connection" @open={{true}} @wrapperClass="bordered-classic">
<p class="mb-4">The SocketCluster configuration cannot be changed at this time.</p>
<div id="output" class="font-mono rounded-lg max-h-full px-6 py-4 overflow-y-scroll bg-black shadow-inner dark:shadow-none">
<div class="flex items-center justify-between mb-4">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,7 @@ import { inject as service } from '@ember/service';
import { later } from '@ember/runloop';
import { action } from '@ember/object';
import { isArray } from '@ember/array';
import { dasherize } from '@ember/string';
import first from '@fleetbase/ember-core/utils/first';
export default class ConsoleController extends Controller {
@@ -16,67 +17,19 @@ export default class ConsoleController extends Controller {
@service intl;
@service universe;
@service abilities;
/**
* Authenticated user organizations.
*
* @var {Array}
*/
@service sidebar;
@tracked organizations = [];
/**
* Sidebar Context Controls
*
* @var {SidebarContext}
*/
@tracked sidebarContext;
/**
* State of sidebar toggle icon
*
* @var {SidebarContext}
*/
@tracked sidebarToggleEnabled = true;
/**
* The sidebar toggle state.
*
* @var {SidebarContext}
*/
@tracked sidebarToggleState = {};
/**
* Routes which should hide the sidebar menu.
*
* @var {Array}
*/
@tracked hiddenSidebarRoutes = ['console.home', 'console.notifications', 'console.virtual'];
/**
* Menu items to be added to the main header navigation bar.
*
* @memberof ConsoleController
*/
@tracked menuItems = [];
/**
* Menu items to be added to the user dropdown menu located in the header.
*
* @memberof ConsoleController
*/
@tracked userMenuItems = [];
/**
* Menu items to be added to the organization dropdown menu located in the header.
*
* @memberof ConsoleController
*/
@tracked organizationMenuItems = [];
/**
* Creates an instance of ConsoleController.
* @memberof ConsoleController
*/
get currentRouteClass() {
return dasherize(this.router.currentRouteName.replace(/\./g, ' '));
}
constructor() {
super(...arguments);
this.router.on('routeDidChange', (transition) => {
@@ -89,17 +42,17 @@ export default class ConsoleController extends Controller {
// Hide the sidebar if the current route is in hiddenSidebarRoutes
if (shouldHideSidebar) {
this.sidebarContext.hideNow();
this.sidebar.hideNow();
this.sidebarToggleEnabled = false;
return; // Exit early as no further action is required
}
// If the sidebar was manually closed and not on a hidden route, keep it closed
if (isSidebarManuallyClosed) {
this.sidebarContext.hideNow();
this.sidebar.hideNow();
} else {
// Otherwise, show the sidebar
this.sidebarContext.show();
this.sidebar.show();
}
// Ensure toggle is enabled unless on a hidden route
@@ -134,7 +87,7 @@ export default class ConsoleController extends Controller {
this.universe.trigger('sidebarContext.available', sidebarContext);
if (this.hiddenSidebarRoutes.includes(this.router.currentRouteName)) {
this.sidebarContext.hideNow();
this.sidebar.hideNow();
this.sidebarToggleEnabled = false;
}
}

View File

@@ -1,151 +1,8 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action, getProperties } from '@ember/object';
import OnboardValidations from '../../validations/onboard';
import lookupValidator from 'ember-changeset-validations';
import Changeset from 'ember-changeset';
export default class OnboardIndexController extends Controller {
/**
* Inject the `fetch` service
*
* @memberof OnboardIndexController
*/
@service fetch;
/**
* Inject the `session` service
*
* @memberof OnboardIndexController
*/
@service session;
/**
* Inject the `router` service
*
* @memberof OnboardIndexController
*/
@service router;
/**
* Inject the `notifications` service
*
* @memberof OnboardIndexController
*/
@service notifications;
/**
* The name input field.
*
* @memberof OnboardIndexController
*/
@tracked name;
/**
* The email input field.
*
* @memberof OnboardIndexController
*/
@tracked email;
/**
* The phone input field.
*
* @memberof OnboardIndexController
*/
@tracked phone;
/**
* The organization_name input field.
*
* @memberof OnboardIndexController
*/
@tracked organization_name;
/**
* The password input field.
*
* @memberof OnboardIndexController
*/
@tracked password;
/**
* The name password confirmation field.
*
* @memberof OnboardIndexController
*/
@tracked password_confirmation;
/**
* The property for error message.
*
* @memberof OnboardIndexController
*/
@tracked error;
/**
* The loading state of the onboard request.
*
* @memberof OnboardIndexController
*/
@tracked isLoading = false;
/**
* The ready state for the form.
*
* @memberof OnboardIndexController
*/
@tracked readyToSubmit = false;
/**
* Start the onboard process.
*
* @return {Promise}
* @memberof OnboardIndexController
*/
@action async startOnboard(event) {
event.preventDefault();
// eslint-disable-next-line ember/no-get
const input = getProperties(this, 'name', 'email', 'phone', 'organization_name', 'password', 'password_confirmation');
const changeset = new Changeset(input, lookupValidator(OnboardValidations), OnboardValidations);
await changeset.validate();
if (changeset.get('isInvalid')) {
const errorMessage = changeset.errors.firstObject.validation.firstObject;
this.notifications.error(errorMessage);
return;
}
// Set user timezone
input.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
this.isLoading = true;
return this.fetch
.post('onboard/create-account', input)
.then(({ status, skipVerification, token, session }) => {
if (status === 'success') {
if (skipVerification === true && token) {
// only manually authenticate if skip verification
this.session.isOnboarding().manuallyAuthenticate(token);
return this.router.transitionTo('console').then(() => {
this.notifications.success('Welcome to Fleetbase!');
});
}
return this.router.transitionTo('onboard.verify-email', { queryParams: { hello: session } });
}
})
.catch((error) => {
this.notifications.serverError(error);
})
.finally(() => {
this.isLoading = false;
});
}
@tracked step;
@tracked session;
@tracked code;
}

View File

@@ -0,0 +1,41 @@
import translations from 'ember-intl/translations';
import { all } from 'rsvp';
const isBrowser = typeof window !== 'undefined';
function langOf(tag = 'en') {
return String(tag).toLowerCase().split('-')[0];
}
async function loadBasePolyfills() {
await import('@formatjs/intl-numberformat/polyfill-force');
await import('@formatjs/intl-pluralrules/polyfill-force');
await import('@formatjs/intl-datetimeformat/polyfill-force');
await import('@formatjs/intl-relativetimeformat/polyfill-force');
}
async function loadLocaleData(lang) {
return all([
import(`@formatjs/intl-numberformat/locale-data/${lang}.js`),
import(`@formatjs/intl-pluralrules/locale-data/${lang}.js`),
import(`@formatjs/intl-datetimeformat/locale-data/${lang}.js`),
import(`@formatjs/intl-relativetimeformat/locale-data/${lang}.js`),
]);
}
export function initialize(application) {
if (!isBrowser) return;
// Build-time list of locales from the generated module
const locales = translations.map(([locale]) => String(locale));
const langs = [...new Set(locales.map(langOf))];
application.deferReadiness();
(async () => {
await loadBasePolyfills();
await all(langs.map(loadLocaleData));
application.advanceReadiness();
})();
}
export default { initialize };

View File

@@ -0,0 +1,19 @@
export function initialize(owner) {
const registry = owner.lookup('service:onboarding-registry');
if (registry) {
const defaultFlow = {
id: 'default@v1',
entry: 'signup',
steps: [
{ id: 'signup', component: 'onboarding/form', next: 'verify-email' },
{ id: 'verify-email', component: 'onboarding/verify-email' },
],
};
registry.registerFlow(defaultFlow);
}
}
export default {
initialize,
};

View File

@@ -0,0 +1,20 @@
import Model, { attr } from '@ember-data/model';
export default class ActivityModel extends Model {
@attr('string') uuid;
@attr('string') log_name;
@attr('string') description;
@attr('string') company_id;
@attr('string') subject_id;
@attr('string') subject_type;
@attr('string') humanized_subject_type;
@attr('string') event;
@attr('string') causer_id;
@attr('string') causer_type;
@attr('string') humanized_causer_type;
@attr('object') properties;
@attr('object') causer;
@attr('object') subject;
@attr('date') created_at;
@attr('date') updated_at;
}

311
console/app/models/alert.js Normal file
View File

@@ -0,0 +1,311 @@
import Model, { attr, belongsTo } from '@ember-data/model';
import { computed } from '@ember/object';
import { format, formatDistanceToNow, differenceInMinutes } from 'date-fns';
export default class AlertModel extends Model {
/** @attributes */
@attr('string') type;
@attr('string') severity;
@attr('string') status;
@attr('string') subject_type;
@attr('string') subject_uuid;
@attr('string') message;
/** @json attributes */
@attr() rule;
@attr() context;
@attr() meta;
/** @dates */
@attr('date') triggered_at;
@attr('date') acknowledged_at;
@attr('date') resolved_at;
@attr('date') created_at;
@attr('date') updated_at;
@attr('date') deleted_at;
/** @relationships */
@belongsTo('company') company;
@belongsTo('user', { inverse: null }) acknowledgedBy;
@belongsTo('user', { inverse: null }) resolvedBy;
/** @computed - Date formatting */
@computed('triggered_at') get triggeredAgo() {
if (!this.triggered_at) return 'Unknown';
return formatDistanceToNow(this.triggered_at) + ' ago';
}
@computed('triggered_at') get triggeredAt() {
if (!this.triggered_at) return 'Unknown';
return format(this.triggered_at, 'yyyy-MM-dd HH:mm');
}
@computed('acknowledged_at') get acknowledgedAgo() {
if (!this.acknowledged_at) return null;
return formatDistanceToNow(this.acknowledged_at) + ' ago';
}
@computed('acknowledged_at') get acknowledgedAt() {
if (!this.acknowledged_at) return 'Not acknowledged';
return format(this.acknowledged_at, 'yyyy-MM-dd HH:mm');
}
@computed('resolved_at') get resolvedAgo() {
if (!this.resolved_at) return null;
return formatDistanceToNow(this.resolved_at) + ' ago';
}
@computed('resolved_at') get resolvedAt() {
if (!this.resolved_at) return 'Not resolved';
return format(this.resolved_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAgo() {
return formatDistanceToNow(this.updated_at) + ' ago';
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAgo() {
return formatDistanceToNow(this.created_at) + ' ago';
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
/** @computed - Status checks */
@computed('acknowledged_at') get isAcknowledged() {
return !!this.acknowledged_at;
}
@computed('resolved_at') get isResolved() {
return !!this.resolved_at;
}
@computed('isAcknowledged', 'isResolved') get isPending() {
return !this.isAcknowledged && !this.isResolved;
}
@computed('isAcknowledged', 'isResolved') get isActive() {
return this.isAcknowledged && !this.isResolved;
}
/** @computed - Duration calculations */
@computed('triggered_at', 'acknowledged_at') get acknowledgmentDurationMinutes() {
if (!this.triggered_at || !this.acknowledged_at) return null;
return differenceInMinutes(new Date(this.acknowledged_at), new Date(this.triggered_at));
}
@computed('triggered_at', 'resolved_at') get resolutionDurationMinutes() {
if (!this.triggered_at || !this.resolved_at) return null;
return differenceInMinutes(new Date(this.resolved_at), new Date(this.triggered_at));
}
@computed('triggered_at') get ageMinutes() {
if (!this.triggered_at) return 0;
return differenceInMinutes(new Date(), new Date(this.triggered_at));
}
@computed('acknowledgmentDurationMinutes') get acknowledgmentDurationFormatted() {
if (!this.acknowledgmentDurationMinutes) return null;
const minutes = this.acknowledgmentDurationMinutes;
if (minutes < 60) return `${minutes}m`;
if (minutes < 1440) return `${Math.floor(minutes / 60)}h ${minutes % 60}m`;
return `${Math.floor(minutes / 1440)}d ${Math.floor((minutes % 1440) / 60)}h`;
}
@computed('resolutionDurationMinutes') get resolutionDurationFormatted() {
if (!this.resolutionDurationMinutes) return null;
const minutes = this.resolutionDurationMinutes;
if (minutes < 60) return `${minutes}m`;
if (minutes < 1440) return `${Math.floor(minutes / 60)}h ${minutes % 60}m`;
return `${Math.floor(minutes / 1440)}d ${Math.floor((minutes % 1440) / 60)}h`;
}
@computed('ageMinutes') get ageFormatted() {
const minutes = this.ageMinutes;
if (minutes < 60) return `${minutes}m`;
if (minutes < 1440) return `${Math.floor(minutes / 60)}h ${minutes % 60}m`;
return `${Math.floor(minutes / 1440)}d ${Math.floor((minutes % 1440) / 60)}h`;
}
/** @computed - Severity styling */
@computed('severity') get severityBadgeClass() {
const severityClasses = {
critical: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300',
high: 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-300',
medium: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300',
low: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300',
info: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300',
};
return severityClasses[this.severity] || severityClasses['info'];
}
@computed('severity') get severityIcon() {
const severityIcons = {
critical: 'fas fa-exclamation-circle',
high: 'fas fa-exclamation-triangle',
medium: 'fas fa-exclamation',
low: 'fas fa-info-circle',
info: 'fas fa-info',
};
return severityIcons[this.severity] || severityIcons['info'];
}
@computed('severity') get severityColor() {
const severityColors = {
critical: 'text-red-600 dark:text-red-400',
high: 'text-orange-600 dark:text-orange-400',
medium: 'text-yellow-600 dark:text-yellow-400',
low: 'text-blue-600 dark:text-blue-400',
info: 'text-gray-600 dark:text-gray-400',
};
return severityColors[this.severity] || severityColors['info'];
}
/** @computed - Status styling */
@computed('status', 'isAcknowledged', 'isResolved') get statusBadgeClass() {
if (this.isResolved) {
return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300';
}
if (this.isAcknowledged) {
return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300';
}
return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300';
}
@computed('status', 'isAcknowledged', 'isResolved') get statusText() {
if (this.isResolved) return 'Resolved';
if (this.isAcknowledged) return 'Acknowledged';
return 'Pending';
}
@computed('status', 'isAcknowledged', 'isResolved') get statusIcon() {
if (this.isResolved) return 'fas fa-check-circle';
if (this.isAcknowledged) return 'fas fa-eye';
return 'fas fa-bell';
}
/** @computed - Type styling */
@computed('type') get typeIcon() {
const typeIcons = {
maintenance: 'fas fa-wrench',
temperature: 'fas fa-thermometer-half',
fuel: 'fas fa-gas-pump',
speed: 'fas fa-tachometer-alt',
location: 'fas fa-map-marker-alt',
system: 'fas fa-cog',
security: 'fas fa-shield-alt',
performance: 'fas fa-chart-line',
compliance: 'fas fa-clipboard-check',
};
return typeIcons[this.type] || 'fas fa-bell';
}
@computed('type') get typeBadgeClass() {
const typeClasses = {
maintenance: 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-300',
temperature: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300',
fuel: 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300',
speed: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300',
location: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300',
system: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300',
security: 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300',
performance: 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-300',
compliance: 'bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-300',
};
return typeClasses[this.type] || 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300';
}
/** @computed - Subject information */
@computed('subject_type') get subjectTypeFormatted() {
if (!this.subject_type) return 'Unknown';
// Convert from model class name to human readable
const typeMap = {
vehicle: 'Vehicle',
driver: 'Driver',
order: 'Order',
device: 'Device',
asset: 'Asset',
maintenance: 'Maintenance',
fuel_report: 'Fuel Report',
};
return typeMap[this.subject_type] || this.subject_type.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
}
/** @computed - Priority and urgency */
@computed('severity', 'ageMinutes') get urgencyLevel() {
const severityWeight = {
critical: 4,
high: 3,
medium: 2,
low: 1,
info: 0,
};
const weight = severityWeight[this.severity] || 0;
const ageHours = this.ageMinutes / 60;
// Calculate urgency based on severity and age
if (weight >= 3 && ageHours > 1) return 'urgent';
if (weight >= 2 && ageHours > 4) return 'urgent';
if (weight >= 3) return 'high';
if (weight >= 2) return 'medium';
return 'low';
}
@computed('urgencyLevel') get urgencyBadgeClass() {
const urgencyClasses = {
urgent: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300 animate-pulse',
high: 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-300',
medium: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300',
low: 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300',
};
return urgencyClasses[this.urgencyLevel] || urgencyClasses['low'];
}
/** @computed - Context information */
@computed('context') get hasContext() {
return !!(this.context && Object.keys(this.context).length > 0);
}
@computed('rule') get hasRule() {
return !!(this.rule && Object.keys(this.rule).length > 0);
}
@computed('context.location') get hasLocation() {
return !!this.context?.location;
}
@computed('context.value', 'rule.{operator,threshold}') get thresholdExceeded() {
if (!this.context?.value || !this.rule?.threshold) return null;
const value = parseFloat(this.context.value);
const threshold = parseFloat(this.rule.threshold);
const operator = this.rule.operator || '>';
switch (operator) {
case '>':
return value > threshold;
case '<':
return value < threshold;
case '>=':
return value >= threshold;
case '<=':
return value <= threshold;
case '==':
return value === threshold;
case '!=':
return value !== threshold;
default:
return null;
}
}
}

View File

@@ -18,6 +18,10 @@ export default class CategoryModel extends Model {
@hasMany('category', { inverse: 'parent' }) subcategories;
@tracked parent_category;
/** Array<CustomFieldModel> attached at runtime for rendering */
@tracked customFields = [];
@tracked isEditing = false;
/** @attributes */
@attr('string') owner_type;
@attr('string') name;
@@ -46,7 +50,7 @@ export default class CategoryModel extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAtShort() {
@@ -58,7 +62,7 @@ export default class CategoryModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAtShort() {

View File

@@ -31,7 +31,7 @@ export default class CommentModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAgo() {
@@ -39,6 +39,6 @@ export default class CommentModel extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
}

View File

@@ -50,7 +50,7 @@ export default class Company extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAtShort() {
@@ -62,7 +62,7 @@ export default class Company extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAtShort() {

View File

@@ -41,7 +41,7 @@ export default class CustomFieldValueModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAgo() {
@@ -49,6 +49,6 @@ export default class CustomFieldValueModel extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
}

View File

@@ -12,6 +12,7 @@ export default class CustomFieldModel extends Model {
/** @attributes */
@attr('string') name;
@attr('string') description;
@attr('string') for;
@attr('string') help_text;
@attr('string') label;
@attr('string') type;
@@ -30,12 +31,20 @@ export default class CustomFieldModel extends Model {
@attr('date') deleted_at;
/** @computed */
@computed('type') get valueType() {
if (this.type === 'file-upload') return 'file';
if (this.type === 'date-time-input') return 'date';
if (this.type === 'model-select') return 'model';
return 'text';
}
@computed('created_at') get createdAgo() {
return formatDistanceToNow(this.created_at);
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAgo() {
@@ -43,6 +52,6 @@ export default class CustomFieldModel extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
}

View File

@@ -25,7 +25,7 @@ export default class DashboardWidgetModel extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAtShort() {
@@ -37,7 +37,7 @@ export default class DashboardWidgetModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAtShort() {

View File

@@ -13,7 +13,11 @@ export default class DashboardModel extends Model {
/** @attributes */
@attr('string') name;
@attr('string') extension;
@attr('boolean') is_default;
@attr('array') tags;
@attr('object') options;
@attr('object') meta;
/** @dates */
@attr('date') created_at;
@@ -25,7 +29,7 @@ export default class DashboardModel extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAtShort() {
@@ -37,7 +41,7 @@ export default class DashboardModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAtShort() {

View File

@@ -111,7 +111,7 @@ export default class ExtensionModel extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAtShort() {
@@ -123,7 +123,7 @@ export default class ExtensionModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAtShort() {

View File

@@ -48,7 +48,7 @@ export default class FileModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('content_type') get isVideo() {

View File

@@ -26,7 +26,7 @@ export default class GroupModel extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAgo() {
@@ -34,6 +34,6 @@ export default class GroupModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
}

View File

@@ -21,11 +21,11 @@ export default class NotificationModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('read_at') get readAt() {
return format(this.read_at, 'PPP p');
return format(this.read_at, 'yyyy-MM-dd HH:mm');
}
@computed('read_at') get isRead() {

View File

@@ -132,6 +132,6 @@ export default class PermissionModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
}

View File

@@ -37,7 +37,7 @@ export default class PolicyModel extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAgo() {
@@ -45,6 +45,6 @@ export default class PolicyModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
}

View File

@@ -0,0 +1,519 @@
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
import { computed } from '@ember/object';
import { isArray } from '@ember/array';
import { getOwner } from '@ember/application';
import { isPresent, isEmpty } from '@ember/utils';
import { format, formatDistanceToNow } from 'date-fns';
export default class ReportModel extends Model {
/** @ids */
@attr('string') public_id;
@attr('string') company_uuid;
@attr('string') created_by_uuid;
@attr('string') category_uuid;
@attr('string') subject_uuid;
/** @attributes */
@attr('string') subject_type;
@attr('string') title;
@attr('string') description;
@attr('date') period_start;
@attr('date') period_end;
@attr('date') last_executed_at;
@attr('number') execution_time;
@attr('number') row_count;
@attr('boolean') is_scheduled;
@attr('boolean') is_generated;
@attr('string') status;
@attr('string') type;
@attr('raw') export_formats;
@attr('raw') schedule_config;
@attr('raw') data;
@attr('raw') result_columns;
@attr('raw') query_config;
@attr('raw') tags;
@attr('raw') options;
@attr('raw') meta;
@attr('string') status;
/** @dates */
@attr('date') created_at;
@attr('date') updated_at;
/** @relationships */
// @belongsTo('company') company;
// @belongsTo('user') createdBy;
// @hasMany('report-execution') executions;
// @hasMany('report-audit-log') auditLogs;
fillResult(result = {}) {
this.setProperties({
result_columns: result?.columns ?? [],
data: result?.data ?? [],
meta: result?.meta ?? {},
row_count: result?.meta?.total_rows ?? 0,
execution_time: result?.meta?.execution_time_ms ?? -1,
last_executed_at: new Date(),
is_generated: true,
});
}
/** @computed */
@computed('updated_at') get updatedAgo() {
return formatDistanceToNow(this.updated_at);
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAgo() {
return formatDistanceToNow(this.created_at);
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('query_config.columns.length', 'query_config.table.name') get hasValidConfig() {
return (
isPresent(this.query_config) &&
isPresent(this.query_config.table) &&
isPresent(this.query_config.table.name) &&
isArray(this.query_config.columns) &&
this.query_config.columns.length > 0
);
}
@computed('query_config.table.name') get tableName() {
return this.query_config?.table?.name || '';
}
@computed('query_config.table.label', 'tableName') get tableLabel() {
return this.query_config?.table?.label || this.tableName;
}
@computed('query_config.columns.[]') get selectedColumns() {
return this.query_config?.columns || [];
}
@computed('selectedColumns.[]', 'query_config.joins.[]') get totalSelectedColumns() {
let count = this.selectedColumns.length;
// Add columns from joins
if (isArray(this.query_config?.joins)) {
this.query_config.joins.forEach((join) => {
if (isArray(join.selectedColumns)) {
count += join.selectedColumns.length;
}
});
}
return count;
}
@computed('query_config.joins.[]') get hasJoins() {
return isArray(this.query_config?.joins) && this.query_config.joins.length > 0;
}
@computed('hasJoins', 'query_config.joins.[]') get joinedTables() {
if (!this.hasJoins) {
return [];
}
return this.query_config.joins.map((join) => ({
table: join.table,
label: join.label || join.table,
type: join.type,
columnsCount: join.selectedColumns?.length || 0,
}));
}
@computed('query_config.conditions.[]') get hasConditions() {
return isArray(this.query_config?.conditions) && this.query_config.conditions.length > 0;
}
@computed('hasConditions', 'query_config.conditions.[]') get conditionsCount() {
if (!this.hasConditions) {
return 0;
}
return this.countConditionsRecursively(this.query_config.conditions);
}
@computed('query_config.groupBy.[]') get hasGrouping() {
return isArray(this.query_config?.groupBy) && this.query_config.groupBy.length > 0;
}
@computed('query_config.sortBy.[]') get hasSorting() {
return isArray(this.query_config?.sortBy) && this.query_config.sortBy.length > 0;
}
@computed('query_config.limit') get hasLimit() {
return isPresent(this.query_config?.limit) && this.query_config.limit > 0;
}
@computed('conditionsCount', 'hasGrouping', 'hasJoins', 'joinedTables.length', 'totalSelectedColumns') get complexity() {
let score = 0;
score += this.totalSelectedColumns;
score += this.hasJoins ? this.joinedTables.length * 3 : 0;
score += this.conditionsCount * 2;
score += this.hasGrouping ? 5 : 0;
if (score < 10) {
return 'simple';
} else if (score < 25) {
return 'moderate';
} else {
return 'complex';
}
}
@computed('complexity', 'totalSelectedColumns', 'joinedTables.length') get estimatedPerformance() {
if (this.complexity === 'simple' && this.totalSelectedColumns <= 10) {
return 'fast';
} else if (this.complexity === 'moderate' && this.joinedTables.length <= 2) {
return 'moderate';
} else {
return 'slow';
}
}
@computed('last_executed_at') get lastExecutedDisplay() {
if (!this.last_executed_at) {
return 'Never executed';
}
return this.last_executed_at.toLocaleDateString() + ' ' + this.last_executed_at.toLocaleTimeString();
}
@computed('average_execution_time') get averageExecutionTimeDisplay() {
if (!this.average_execution_time) {
return 'N/A';
}
if (this.average_execution_time < 1000) {
return `${Math.round(this.average_execution_time)}ms`;
} else {
return `${(this.average_execution_time / 1000).toFixed(2)}s`;
}
}
@computed('execution_count') get executionCountDisplay() {
return this.execution_count || 0;
}
@computed('last_result_count') get lastResultCountDisplay() {
if (this.last_result_count === null || this.last_result_count === undefined) {
return 'N/A';
}
return this.last_result_count.toLocaleString();
}
@computed('export_formats.[]') get availableExportFormats() {
return this.export_formats || ['csv', 'excel', 'json'];
}
@computed('tags.[]') get tagsList() {
return this.tags || [];
}
@computed('shared_with.[]') get sharedWithList() {
return this.shared_with || [];
}
@computed('is_scheduled', 'next_scheduled_run', 'schedule_frequency', 'schedule_timezone') get scheduleInfo() {
if (!this.is_scheduled) {
return null;
}
return {
frequency: this.schedule_frequency,
nextRun: this.next_scheduled_run,
timezone: this.schedule_timezone || 'UTC',
};
}
@computed('hasConditions', 'query_config.conditions.[]') get conditionsSummary() {
if (!this.hasConditions) {
return [];
}
return this.extractConditionsSummary(this.query_config.conditions);
}
@computed('status') get statusDisplay() {
const statusMap = {
draft: 'Draft',
active: 'Active',
archived: 'Archived',
error: 'Error',
};
return statusMap[this.status] || this.status;
}
@computed('status') get statusClass() {
const statusClasses = {
draft: 'status-draft',
active: 'status-active',
archived: 'status-archived',
error: 'status-error',
};
return statusClasses[this.status] || 'status-unknown';
}
// Helper methods
countConditionsRecursively(conditions) {
let count = 0;
if (!isArray(conditions)) {
return count;
}
conditions.forEach((condition) => {
if (condition.conditions) {
count += this.countConditionsRecursively(condition.conditions);
} else {
count++;
}
});
return count;
}
extractConditionsSummary(conditions, summary = []) {
if (!isArray(conditions)) {
return summary;
}
conditions.forEach((condition) => {
if (condition.conditions) {
this.extractConditionsSummary(condition.conditions, summary);
} else if (condition.field && condition.operator) {
summary.push({
field: condition.field.label || condition.field.name,
operator: condition.operator.label || condition.operator.value,
value: condition.value,
table: condition.field.table || this.tableName,
});
}
});
return summary;
}
// API methods for interacting with the new backend
async execute() {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const response = await fetch.post(this.id ? `reports/${this.id}/execute` : 'reports/execute-query', { query_config: this.query_config });
return response;
} catch (error) {
throw error;
}
}
// API methods for interacting with the new backend
async executeQuery() {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const response = await fetch.post('reports/execute-query', { query_config: this.query_config });
return response;
} catch (error) {
throw error;
}
}
async export(format = 'csv', options = {}) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const response = await fetch.post(`reports/${this.id}/export`, {
format,
options,
});
return response;
} catch (error) {
throw error;
}
}
async validate() {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const response = await fetch.post('reports/validate-query', {
query_config: this.query_config,
});
return response;
} catch (error) {
throw error;
}
}
async analyze() {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const response = await fetch.post('reports/analyze-query', {
query_config: this.query_config,
});
return response;
} catch (error) {
throw error;
}
}
// Static methods for direct query operations
static async executeQuery(queryConfig) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const response = await fetch.post('reports/execute-query', {
query_config: queryConfig,
});
return response;
} catch (error) {
throw error;
}
}
static async exportQuery(queryConfig, format = 'csv', options = {}) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const response = await fetch('reports/export-query', {
query_config: queryConfig,
format,
options,
});
return response;
} catch (error) {
throw error;
}
}
static async validateQuery(queryConfig) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const response = await fetch.post('reports/validate-query', { query_config: queryConfig });
return response;
} catch (error) {
throw error;
}
}
static async analyzeQuery(queryConfig) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const response = await fetch.post('reports/analyze-query', { query_config: queryConfig });
return response;
} catch (error) {
throw error;
}
}
static async getTables() {
try {
const { tables } = await fetch.get('reports/tables');
return tables;
} catch (error) {
throw error;
}
}
static async getTableSchema(tableName) {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const { schema } = await fetch.get(`reports/tables/${tableName}/schema`);
return schema;
} catch (error) {
throw error;
}
}
static async getExportFormats() {
const owner = getOwner(this);
const fetch = owner.lookup('service:fetch');
try {
const { formats } = await fetch.get('reports/export-formats');
return formats;
} catch (error) {
throw error;
}
}
// Utility methods for frontend display
getComplexityBadgeClass() {
const complexityClasses = {
simple: 'badge-success',
moderate: 'badge-warning',
complex: 'badge-danger',
};
return complexityClasses[this.complexity] || 'badge-secondary';
}
getPerformanceBadgeClass() {
const performanceClasses = {
fast: 'badge-success',
moderate: 'badge-warning',
slow: 'badge-danger',
};
return performanceClasses[this.estimatedPerformance] || 'badge-secondary';
}
getQuerySummary() {
const parts = [];
parts.push(`${this.totalSelectedColumns} columns from ${this.tableLabel}`);
if (this.hasJoins) {
parts.push(`${this.joinedTables.length} joins`);
}
if (this.hasConditions) {
parts.push(`${this.conditionsCount} conditions`);
}
if (this.hasGrouping) {
parts.push('grouped');
}
if (this.hasSorting) {
parts.push('sorted');
}
if (this.hasLimit) {
parts.push(`limited to ${this.query_config.limit} rows`);
}
return parts.join(', ');
}
}

View File

@@ -38,7 +38,7 @@ export default class RoleModel extends Model {
}
@computed('updated_at') get updatedAt() {
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAtShort() {
@@ -50,7 +50,7 @@ export default class RoleModel extends Model {
}
@computed('created_at') get createdAt() {
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAtShort() {

View File

@@ -186,7 +186,7 @@ export default class UserModel extends Model {
if (!isValid(this.updated_at)) {
return '-';
}
return format(this.updated_at, 'PPP p');
return format(this.updated_at, 'yyyy-MM-dd HH:mm');
}
@computed('updated_at') get updatedAtShort() {
@@ -207,7 +207,7 @@ export default class UserModel extends Model {
if (!isValid(this.created_at)) {
return '-';
}
return format(this.created_at, 'PPP p');
return format(this.created_at, 'yyyy-MM-dd HH:mm');
}
@computed('created_at') get createdAtShort() {

View File

@@ -3,6 +3,17 @@ import { inject as service } from '@ember/service';
export default class OnboardIndexRoute extends Route {
@service store;
@service('onboarding-orchestrator') orchestrator;
queryParams = {
step: { refreshModel: false },
session: { refreshModel: false },
code: { refreshModel: false },
};
beforeModel() {
this.orchestrator.start();
}
model() {
return this.store.findRecord('brand', 1);

View File

@@ -0,0 +1,13 @@
import ApplicationSerializer from '@fleetbase/ember-core/serializers/application';
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
export default class CategorySerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {
/**
* Embedded relationship attributes
*
* @var {Object}
*/
get attrs() {
return {};
}
}

View File

@@ -0,0 +1,4 @@
import ApplicationSerializer from '@fleetbase/ember-core/serializers/application';
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
export default class AlertSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {}

View File

@@ -0,0 +1,4 @@
import ApplicationSerializer from '@fleetbase/ember-core/serializers/application';
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
export default class ReportSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {}

View File

@@ -0,0 +1,39 @@
import Service, { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class OnboardingContextService extends Service {
@service appCache;
@tracked data = {};
get(key) {
return this.data[key] ?? this.appCache.get(`onboarding:context:${key}`);
}
getFromCache(key) {
return this.appCache.get(`onboarding:context:${key}`);
}
set(key, value, options = {}) {
this.data = { ...this.data, [key]: value };
if (options?.persist === true) {
this.appCache.set(`onboarding:context:${key}`, value);
}
}
persist(key, value) {
this.set(key, value, { persist: true });
}
del(key) {
const { [key]: _drop, ...rest } = this.data; // eslint-disable-line no-unused-vars
this.data = rest;
this.appCache.set(`onboarding:context:${key}`, undefined);
}
reset() {
for (let key in this.data) {
this.appCache.set(`onboarding:context:${key}`, undefined);
}
this.data = {};
}
}

View File

@@ -0,0 +1,71 @@
import Service from '@ember/service';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class OnboardingOrchestratorService extends Service {
@service onboardingRegistry;
@service onboardingContext;
@tracked flow = null;
@tracked current = null;
@tracked history = [];
@tracked sessionId = null;
start(flowId = null, opts = {}) {
const flow = this.onboardingRegistry.getFlow(flowId ?? this.onboardingRegistry.defaultFlow);
if (!flow) throw new Error(`Onboarding flow '${flowId}' not found`);
this.flow = flow;
this.sessionId = opts.sessionId || null;
this.history = [];
this.goto(flow.entry);
}
async goto(stepId) {
if (!this.flow) throw new Error('No active onboarding flow');
const step = this.flow.steps.find((s) => s.id === stepId);
if (!step) throw new Error(`Step '${stepId}' not found`);
if (typeof step.guard === 'function' && !step.guard(this.onboardingContext)) {
return this.next();
}
if (typeof step.beforeEnter === 'function') {
await step.beforeEnter(this.onboardingContext);
}
this.current = step;
}
async next() {
if (!this.flow || !this.current) return;
const leaving = this.current;
if (typeof leaving.afterLeave === 'function') {
await leaving.afterLeave(this.onboardingContext);
}
if (!this.history.includes(leaving)) this.history.push(leaving);
let nextId;
if (typeof leaving.next === 'function') {
nextId = leaving.next(this.onboardingContext);
} else {
nextId = leaving.next;
}
if (!nextId) {
this.current = null; // finished
return;
}
return this.goto(nextId);
}
async back() {
if (!this.flow || this.history.length === 0) return;
const prev = this.history[this.history.length - 1];
if (prev && prev.allowBack === false) return;
this.history = this.history.slice(0, -1);
await this.goto(prev.id);
}
}

View File

@@ -0,0 +1,31 @@
import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class OnboardingRegistryService extends Service {
flows = new Map();
@tracked defaultFlow = 'default@v1';
useFlow(flowId) {
this.defaultFlow = flowId;
}
registerFlow(flow) {
if (!flow || !flow.id || !flow.entry || !Array.isArray(flow.steps)) {
throw new Error('Invalid FlowDef: id, entry, steps are required');
}
const ids = new Set(flow.steps.map((s) => s.id));
if (!ids.has(flow.entry)) {
throw new Error(`Flow '${flow.id}' entry '${flow.entry}' not found in steps`);
}
for (const s of flow.steps) {
if (typeof s.next === 'string' && s.next && !ids.has(s.next)) {
throw new Error(`Flow '${flow.id}' step '${s.id}' has unknown next '${s.next}'`);
}
}
this.flows.set(flow.id, flow);
}
getFlow(id) {
return this.flows.get(id);
}
}

View File

@@ -0,0 +1,114 @@
import Service, { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { later } from '@ember/runloop';
import { task } from 'ember-concurrency';
export default class UserVerificationService extends Service {
@service fetch;
@service notifications;
@service modalsManager;
@service currentUser;
@service router;
@service session;
@service intl;
@tracked token;
@tracked code;
@tracked ready;
@tracked waiting = false;
@action start(options = {}) {
this.#wait(options?.timeout ?? 75000);
}
@action didntReceiveCode() {
this.waiting = true;
}
@action validateInput(event) {
const value = event instanceof HTMLElement ? event.value : (event?.target?.value ?? '');
this.ready = value?.length > 5;
}
@action resendBySms() {
this.modalsManager.show('modals/verify-by-sms', {
title: 'Verify Account by Phone',
acceptButtonText: 'Send',
phone: this.currentUser.phone,
confirm: async (modal) => {
modal.startLoading();
const phone = modal.getOption('phone');
if (!phone) {
this.notifications.error('No phone number provided.');
}
try {
await this.fetch.post('onboard/send-verification-sms', { phone, session: this.hello });
this.notifications.success('Verification code SMS sent!');
modal.done();
} catch (error) {
this.notifications.serverError(error);
modal.stopLoading();
}
},
});
}
@action resendEmail() {
this.modalsManager.show('modals/resend-verification-email', {
title: 'Resend Verification Code',
acceptButtonText: 'Send',
email: this.currentUser.email,
confirm: async (modal) => {
modal.startLoading();
const email = modal.getOption('email');
if (!email) {
this.notifications.error('No email number provided.');
}
try {
await this.fetch.post('onboard/send-verification-email', { email, session: this.hello });
this.notifications.success('Verification code email sent!');
modal.done();
} catch (error) {
this.notifications.serverError(error);
modal.stopLoading();
}
},
});
}
@task *verifyCode() {
try {
const { status, token } = yield this.fetch.post('auth/verify-email', { token: this.token, code: this.code, email: this.email, authenticate: true });
if (status === 'ok') {
this.notifications.success('Email successfully verified!');
if (token) {
this.notifications.info(`Welcome to ${this.intl.t('app.name')}`);
this.session.manuallyAuthenticate(token);
return this.router.transitionTo('console');
}
return this.router.transitionTo('auth.login');
}
} catch (error) {
this.notifications.serverError(error);
}
}
setToken(token) {
this.token = token;
}
setCode(code) {
this.code = code;
}
#wait(timeout = 75000) {
return later(this, () => {
this.waiting = true;
}, timeout);
}
}

View File

@@ -67,11 +67,3 @@ body.console-admin-organizations-index-index .next-table-wrapper > table {
body[data-theme='dark'] #boot-loader > .loader-container > .loading-message {
color: #fff;
}
/** hotfix: ember-power-select-trigger broken padding after upgrade - @todo move to ember-ui */
body.fleetbase-console .ember-power-select-trigger {
padding-top: 0.5rem;
padding-right: 2.5rem;
padding-bottom: 0.5rem;
padding-left: 0.75rem;
}

View File

@@ -1,7 +1,16 @@
{{page-title (t "app.name")}}
<Layout::Container>
<Layout::Header @brand={{@model}} @menuItems={{this.menuItems}} @organizationMenuItems={{this.organizationMenuItems}} @userMenuItems={{this.userMenuItems}} @onAction={{this.onAction}} @showSidebarToggle={{true}} @sidebarToggleEnabled={{this.sidebarToggleEnabled}} @onSidebarToggle={{this.onSidebarToggle}} />
<Layout::Main>
<Layout::Header
@brand={{@model}}
@menuItems={{this.menuItems}}
@organizationMenuItems={{this.organizationMenuItems}}
@userMenuItems={{this.userMenuItems}}
@onAction={{this.onAction}}
@showSidebarToggle={{true}}
@sidebarToggleEnabled={{true}}
@onSidebarToggle={{this.onSidebarToggle}}
/>
<Layout::Main class={{this.currentRouteClass}}>
<Layout::Sidebar @onSetup={{this.setSidebarContext}}>
<div class="next-sidebar-content-inner">
<div role="menu" id="sidebar-menu-items">
@@ -11,13 +20,21 @@
<Layout::Section>
{{outlet}}
</Layout::Section>
<ResourceContextPanel />
</Layout::Main>
<Layout::MobileNavbar @brand={{@model}} @user={{this.user}} @organizations={{this.organizations}} @menuItems={{this.menuItems}} @extensions={{this.extensions}} @onAction={{this.onAction}} />
<Layout::MobileNavbar
@brand={{@model}}
@user={{this.user}}
@organizations={{this.organizations}}
@menuItems={{this.menuItems}}
@extensions={{this.extensions}}
@onAction={{this.onAction}}
/>
</Layout::Container>
<ChatContainer />
<ConsoleWormhole />
<ImpersonatorTray />
{{!-- template-lint-disable no-potential-path-strings --}}
{{! template-lint-disable no-potential-path-strings }}
<RegistryYield @registry="@fleetbase/console" as |RegistryComponent|>
<RegistryComponent @controller={{this}} />
</RegistryYield>
</RegistryYield>

View File

@@ -4,7 +4,7 @@
<Layout::Section::Body class="overflow-y-scroll h-full">
<div class="container mx-auto h-screen">
<div class="max-w-3xl my-10 mx-auto space-y-6">
<ContentPanel @title="Change Password" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Change Password" @open={{true}} @wrapperClass="bordered-classic">
<form id="change-password-form" aria-label="change-password" {{on "submit" (perform this.changePassword)}}>
<legend class="mb-3">Change Password</legend>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
@@ -16,7 +16,7 @@
</ContentPanel>
{{#if this.isSystemTwoFaEnabled}}
<ContentPanel @title="2FA Settings" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="2FA Settings" @open={{true}} @wrapperClass="bordered-classic">
<div class="mb-3">
{{#if this.loadUserTwoFaSettings.isIdle}}
<TwoFaSettings @twoFaMethods={{this.methods}} @twoFaSettings={{this.twoFaSettings}} @onTwoFaToggled={{this.onTwoFaToggled}} @onTwoFaMethodSelected={{this.onTwoFaMethodSelected}} />

View File

@@ -3,7 +3,7 @@
<Layout::Section::Body class="overflow-y-scroll h-full">
<div class="container mx-auto h-screen">
<div class="max-w-3xl my-10 mx-auto">
<ContentPanel @title={{t "common.your-profile"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title={{t "common.your-profile"}} @open={{true}} @wrapperClass="bordered-classic">
<form class="flex flex-col md:flex-row" {{on "submit" (perform this.saveProfile)}}>
<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" />
@@ -38,7 +38,7 @@
</InputGroup>
</div>
<div class="mt-3 flex items-center justify-end">
<Button @buttonType="submit" @type="primary" @size="lg" @icon="save" @text={{t "common.save-button-text"}} @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>
</form>

View File

@@ -7,7 +7,7 @@
<div class="flex flex-row justify-end">
<Button @type="primary" @icon="plus" @text="Create Organization" @onClick={{this.createOrganization}} />
</div>
<ContentPanel @title="Your Organizations" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="Your Organizations" @open={{true}} @wrapperClass="bordered-classic">
<div class="space-y-2">
{{#each @model as |organization|}}
<div class="grid grid-cols-3 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 rounded-lg px-3 py-2 items-center">

View File

@@ -1,10 +1,10 @@
{{page-title "Admin"}}
<EmberWormhole @to="sidebar-menu-items">
<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.branding" @icon="palette">{{t "common.branding"}}</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.index" @icon="rectangle-list">{{t "console.admin.menu.overview"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.organizations" @icon="building">{{t "console.admin.menu.organizations"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.branding" @icon="palette">{{t "console.admin.menu.branding"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.two-fa-settings" @icon="shield-halved">{{t "console.admin.menu.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>
{{#each this.universe.adminMenuItems as |menuItem|}}
<Layout::Sidebar::Item
@@ -25,12 +25,12 @@
</Layout::Sidebar::Panel>
{{/each}}
<Layout::Sidebar::Panel @open={{true}} @title="System Config">
<Layout::Sidebar::Item @route="console.admin.config.services" @icon="bell-concierge">{{t "common.services"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.mail" @icon="envelope">{{t "common.mail"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.filesystem" @icon="hard-drive">{{t "common.filesystem"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.queue" @icon="layer-group">{{t "common.queue"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.socket" @icon="plug">{{t "common.socket"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.notification-channels" @icon="tower-broadcast">{{t "common.push-notifications"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.services" @icon="bell-concierge">{{t "console.admin.menu.services"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.mail" @icon="envelope">{{t "console.admin.menu.mail"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.filesystem" @icon="hard-drive">{{t "console.admin.menu.filesystem"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.queue" @icon="layer-group">{{t "console.admin.menu.queue"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.socket" @icon="plug">{{t "console.admin.menu.socket"}}</Layout::Sidebar::Item>
<Layout::Sidebar::Item @route="console.admin.config.notification-channels" @icon="tower-broadcast">{{t "console.admin.menu.push-notifications"}}</Layout::Sidebar::Item>
</Layout::Sidebar::Panel>
</EmberWormhole>

View File

@@ -1,12 +1,12 @@
{{page-title (t "console.admin.branding.title")}}
<Layout::Section::Header @title={{t "console.admin.branding.title"}}>
<Button @type="primary" @size="sm" @icon="save" @text={{t "common.save-button-text"}} @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
<Button @type="primary" @size="sm" @icon="save" @text={{t "common.save-changes"}} @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
</Layout::Section::Header>
<Layout::Section::Body class="overflow-y-scroll h-full">
<div class="container mx-auto h-screen">
<div class="max-w-3xl my-10 mx-auto space-y-6">
<ContentPanel @title={{t "console.admin.branding.title"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title={{t "console.admin.branding.title"}} @open={{true}} @wrapperClass="bordered-classic">
<form class="flex flex-col" {{on "submit" this.save}}>
<div class="input-group">
<label>{{t "console.admin.branding.icon-text"}}</label>

View File

@@ -1,13 +1,15 @@
{{page-title (concat (t "console.admin.schedule-monitor.schedule-monitor") " - " @model.name)}}
<Overlay @isOpen={{true}} @onLoad={{this.setOverlayContext}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width="600px" @isResizable={{true}}>
<Overlay::Header @title={{concat (t "console.admin.schedule-monitor.task-logs-for") @model.name}} @titleClass="max-w-400px truncate" @hideStatusDot={{true}} @titleWrapperClass="leading-5">
<div class="flex flex-1 justify-end">
<Button @type="default" @icon="times" @helpText={{t "common.close-and-save"}} @onClick={{this.onPressClose}} />
</div>
<:actions>
<div class="flex flex-1 justify-end">
<Button @type="default" @icon="times" @helpText={{t "common.close"}} @onClick={{this.onPressClose}} />
</div>
</:actions>
</Overlay::Header>
<Overlay::Body>
<div class="p-4">
<div class="px-3 py-2">
<div class="flex items-center justify-between mb-4">
<div class="text-sm">{{t "console.admin.schedule-monitor.showing-last-count" count=20}}</div>
<Button @size="xs" @icon="arrows-rotate" @onClick={{perform this.reload @model}} @isLoading={{not this.reload.isIdle}} />

View File

@@ -1,12 +1,12 @@
{{page-title "2FA Config"}}
<Layout::Section::Header @title="2FA Config">
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.saveSettings}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
<Button @type="primary" @size="sm" @icon="save" @text={{t "common.save-changes"}} @onClick={{this.saveSettings}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
</Layout::Section::Header>
<Layout::Section::Body class="overflow-y-scroll h-full">
<div class="container mx-auto h-screen">
<div class="max-w-3xl my-10 mx-auto space-y-4">
<ContentPanel @title="2FA Config" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="2FA Config" @open={{true}} @wrapperClass="bordered-classic">
{{#if this.loadSystemTwoFaConfig.isIdle}}
<TwoFaSettings
@showEnforceOption={{true}}

View File

@@ -1,7 +1,7 @@
{{page-title "Dashboard"}}
<Layout::Section::Body class="overflow-y-scroll h-full">
<TwoFaEnforcementAlert />
<Dashboard @sidebar={{this.sidebarContext}} class="flex items-center justify-between mb-4 mt-6 px-14" />
<Dashboard @extension="core" @createWrapperClass="px-10" class="flex items-center justify-between mb-4 mt-6 px-14" />
<Spacer @height="300px" />
</Layout::Section::Body>
<div id="console-home-wormhole" />

View File

@@ -3,7 +3,7 @@
<Layout::Section::Body class="overflow-y-scroll h-full">
<div class="container mx-auto h-screen">
<div class="max-w-3xl my-10 mx-auto space-y-6">
<ContentPanel @title={{t "console.settings.index.title"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title={{t "console.settings.index.title"}} @open={{true}} @wrapperClass="bordered-classic">
<form {{on "submit" (perform this.saveSettings)}}>
<InputGroup @name={{t "console.settings.index.organization-name"}} @value={{@model.name}} />
<InputGroup @name={{t "console.settings.index.organization-description"}} @value={{@model.description}} />
@@ -18,12 +18,12 @@
</InputGroup>
<InputGroup @name={{t "console.settings.index.organization-id"}} @value={{@model.public_id}} @disabled={{true}} />
<div class="mt-3 flex items-center justify-end">
<Button @buttonType="submit" @type="primary" @size="lg" @icon="save" @text="{{t "common.save-button-text"}}" @isLoading={{this.saveSettings.isRunning}} />
<Button @buttonType="submit" @type="primary" @size="lg" @icon="save" @text="{{t "common.save-changes"}}" @isLoading={{this.saveSettings.isRunning}} />
</div>
</form>
</ContentPanel>
<ContentPanel @title={{t "console.settings.index.organization-branding"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title={{t "console.settings.index.organization-branding"}} @open={{true}} @wrapperClass="bordered-classic">
<InputGroup @name={{t "console.settings.index.logo"}} @helpText={{t "console.settings.index.logo-help-text"}}>
<div class="flex flex-row items-center">
<Image src={{@model.logo_url}} @fallbackSrc={{config "defaultValues.placeholderImage"}} alt={{concat @model.name " logo"}} class="h-20 w-64 border dark:border-gray-900 rounded-md mr-4" />

View File

@@ -1,13 +1,13 @@
{{page-title "Notifications"}}
<Layout::Section::Header @title={{t "common.notifications"}}>
<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}} />
<Button @type="primary" @size="sm" @icon="save" @text={{t "common.save-changes"}} @onClick={{perform this.saveSettings}} @disabled={{this.saveSettings.isRunning}} @isLoading={{or this.saveSettings.isRunning this.getSettings.isRunning}} />
</Layout::Section::Header>
<Layout::Section::Body class="overflow-y-scroll h-full">
<div class="container mx-auto h-screen">
<div class="max-w-3xl my-10 mx-auto space-y-4">
{{#each-in this.groupedNotifications as |groupName notifications|}}
<ContentPanel @title={{concat (smart-humanize groupName) " " (t "console.admin.notifications.notification-settings") }} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title={{concat (smart-humanize groupName) " " (t "console.admin.notifications.notification-settings") }} @open={{true}} @wrapperClass="bordered-classic">
{{#each notifications as |notification|}}
<InputGroup @name={{titleize notification.name}} @helpText={{notification.description}}>
<div class="fleetbase-model-select fleetbase-power-select ember-model-select">

View File

@@ -4,7 +4,7 @@
<Layout::Section::Body class="overflow-y-scroll h-full">
<div class="container mx-auto h-screen">
<div class="max-w-3xl my-10 mx-auto space-y-6">
<ContentPanel @title="2FA Settings" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<ContentPanel @title="2FA Settings" @open={{true}} @wrapperClass="bordered-classic">
<div class="mb-3">
{{#if this.loadCompanyTwoFaSettings.isIdle}}
<TwoFaSettings

View File

@@ -1,42 +1 @@
<div class="bg-white dark:bg-gray-800 py-5 px-4 shadow rounded-lg w-full">
<div class="mb-4">
<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">
{{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" this.startOnboard}}>
{{#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 @icon="check" @iconPrefix="fas" @type="primary" @size="lg" @text={{t "onboard.index.continue-button-text"}} @isLoading={{this.isLoading}} @disabled={{this.readyToSubmit}} @onClick={{this.startOnboard}} />
</div>
</form>
<RegistryYield @registry="onboard" as |YieldedComponent ctx|>
<YieldedComponent @context={{ctx}} />
</RegistryYield>
</div>
<Onboarding::Yield @step={{this.step}} @session={{this.session}} @code={{this.code}} @brand={{@model}} />

View File

@@ -0,0 +1,46 @@
import Transform from '@ember-data/serializer/transform';
import { isArray } from '@ember/array';
export default class ArrayTransform extends Transform {
deserialize(serialized) {
if (serialized === null || serialized === undefined) {
return [];
}
if (isArray(serialized)) {
return serialized;
}
if (typeof serialized !== 'string') {
return Array.from(serialized);
}
try {
return JSON.parse(serialized);
} catch (e) {
// Fallback: return empty array if parsing fails
return [];
}
}
serialize(deserialized) {
if (deserialized === null || deserialized === undefined) {
return [];
}
if (isArray(deserialized)) {
return deserialized;
}
if (typeof deserialized !== 'string') {
return Array.from(deserialized);
}
// Fallback: attempt to parse if its a string
try {
return JSON.parse(deserialized);
} catch (e) {
return [];
}
}
}

View File

@@ -0,0 +1,36 @@
import Transform from '@ember-data/serializer/transform';
import isObject from '@fleetbase/ember-core/utils/is-object';
export default class ObjectTransform extends Transform {
deserialize(serialized) {
if (!serialized) {
return {};
}
if (isObject(serialized)) {
return serialized;
}
try {
return JSON.parse(serialized);
} catch {
return {};
}
}
serialize(deserialized) {
if (!deserialized) {
return {};
}
if (isObject(deserialized)) {
return deserialized;
}
try {
return JSON.parse(deserialized);
} catch {
return {};
}
}
}

View File

@@ -0,0 +1,160 @@
import { debug } from '@ember/debug';
/**
* Fleetbase Router Refresh Bug Fix Utility
*
* This utility patches the Ember.js router refresh bug that causes
* "missing params" errors when transitioning to nested routes with
* dynamic segments while query parameters with refreshModel: true
* are present.
*
* Bug: https://github.com/emberjs/ember.js/issues/19260
*
* @author Fleetbase Pte Ltd <hello@fleetbase.io>
* @version 1.0.0
*/
/**
* Applies the router refresh bug fix patch
* @param {Application} application - The Ember application instance
*/
export function patchRouterRefresh(application) {
if (!application || typeof application.lookup !== 'function') {
debug('[Fleetbase Router Patch] Invalid application instance provided');
return;
}
try {
const router = application.lookup('router:main');
if (!router || !router._routerMicrolib) {
debug('[Fleetbase Router Patch] Router not found or invalid');
return;
}
// Check if already patched
if (router._routerMicrolib._fleetbaseRefreshPatched) {
debug('[Fleetbase Router Patch] Already applied, skipping');
return;
}
const originalRefresh = router._routerMicrolib.refresh.bind(router._routerMicrolib);
router._routerMicrolib.refresh = function (pivotRoute) {
const previousTransition = this.activeTransition;
const state = previousTransition ? previousTransition[this.constructor.STATE_SYMBOL] : this.state;
const routeInfos = state.routeInfos;
if (pivotRoute === undefined) {
pivotRoute = routeInfos[0].route;
}
const name = routeInfos[routeInfos.length - 1].name;
const currentRouteInfo = routeInfos[routeInfos.length - 1];
// Extract current dynamic segment parameters
const contexts = [];
if (currentRouteInfo && currentRouteInfo.params) {
const handlers = this.recognizer.handlersFor(name);
const targetHandler = handlers[handlers.length - 1];
if (targetHandler && targetHandler.names && targetHandler.names.length > 0) {
targetHandler.names.forEach((paramName) => {
if (currentRouteInfo.params[paramName] !== undefined) {
contexts.push(currentRouteInfo.params[paramName]);
}
});
}
}
const NamedTransitionIntent = this.constructor.NamedTransitionIntent;
const intent = new NamedTransitionIntent(
this,
name,
pivotRoute,
contexts, // Preserve dynamic segments instead of empty array
this._changedQueryParams || state.queryParams
);
const newTransition = this.transitionByIntent(intent, false);
if (previousTransition && previousTransition.urlMethod === 'replace') {
newTransition.method(previousTransition.urlMethod);
}
return newTransition;
};
// Mark as patched
router._routerMicrolib._fleetbaseRefreshPatched = true;
debug('[Fleetbase Router Patch] Successfully applied router refresh bug fix');
} catch (error) {
debug('[Fleetbase Router Patch] Failed to apply patch: ' + error.message);
}
}
/**
* Alternative error suppression approach for cases where patching fails
* @param {Application} application - The Ember application instance
*/
export function suppressRouterRefreshErrors(application) {
if (!application) {
debug('[Fleetbase Router Patch] Invalid application instance for error suppression');
return;
}
try {
// Global error handler for unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
const error = event.reason;
if (error?.message?.includes("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments")) {
debug('[Fleetbase Router Patch] Suppressed known Ember route refresh bug:', error.message);
event.preventDefault(); // Prevent the error from being logged
}
});
// Ember.js error handler
if (window.Ember) {
const originalEmberError = window.Ember.onerror;
window.Ember.onerror = function (error) {
if (error?.message?.includes("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments")) {
debug('[Fleetbase Router Patch] Suppressed known Ember route refresh bug:', error.message);
return; // Suppress the error
}
// Let other errors through
if (originalEmberError) {
return originalEmberError(error);
}
throw error;
};
}
debug('[Fleetbase Router Patch] Error suppression handlers installed');
} catch (error) {
debug('[Fleetbase Router Patch] Failed to install error suppression: ' + error.message);
}
}
/**
* Main function to apply the complete router fix
* @param {Application} application - The Ember application instance
* @param {Object} options - Configuration options
* @param {boolean} options.suppressErrors - Whether to also install error suppression (default: true)
*/
export default function applyRouterFix(application, options = {}) {
const { suppressErrors = true } = options;
debug('[Fleetbase Router Patch] Applying Ember router refresh bug fix...');
// Apply the main patch
patchRouterRefresh(application);
// Optionally install error suppression as fallback
if (suppressErrors) {
suppressRouterRefreshErrors(application);
}
debug('[Fleetbase Router Patch] Router fix application complete');
}

View File

@@ -23,7 +23,7 @@ module.exports = function (environment) {
APP: {
autoboot: false,
extensions: asArray(getenv('EXTENSIONS')),
disableRuntimeConfig: toBoolean(getenv('DISABLE_RUNTIME_CONFIG'))
disableRuntimeConfig: toBoolean(getenv('DISABLE_RUNTIME_CONFIG')),
},
API: {
@@ -49,7 +49,8 @@ module.exports = function (environment) {
defaultValues: {
categoryImage: getenv('DEFAULT_CATEGORY_IMAGE', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/images/fallback-placeholder-1.png'),
placeholderImage: getenv('DEFAULT_PLACEHOLDER_IMAGE', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/images/fallback-placeholder-2.png'),
placeholderImage: getenv('DEFAULT_PLACEHOLDER_IMAGE', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/image-file-icon.png'),
placeholderImageOld: getenv('DEFAULT_PLACEHOLDER_IMAGE_OLD', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/images/fallback-placeholder-2.png'),
driverImage: getenv('DEFAULT_DRIVER_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png'),
userImage: getenv('DEFAULT_USER_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png'),
contactImage: getenv('DEFAULT_CONTACT_IMAGE', 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png'),

View File

@@ -1,6 +1,6 @@
{
"name": "@fleetbase/console",
"version": "0.7.8",
"version": "0.7.18",
"private": true,
"description": "Modular logistics and supply chain operating system (LSOS)",
"repository": "https://github.com/fleetbase/fleetbase",
@@ -29,15 +29,19 @@
},
"dependencies": {
"@ember/legacy-built-in-components": "^0.4.2",
"@fleetbase/dev-engine": "^0.2.9",
"@fleetbase/dev-engine": "^0.2.10",
"@fleetbase/ember-core": "latest",
"@fleetbase/ember-ui": "latest",
"@fleetbase/fleetops-data": "latest",
"@fleetbase/fleetops-engine": "^0.6.16",
"@fleetbase/iam-engine": "^0.1.3",
"@fleetbase/fleetops-engine": "^0.6.25",
"@fleetbase/iam-engine": "^0.1.4",
"@fleetbase/leaflet-routing-machine": "^3.2.17",
"@fleetbase/registry-bridge-engine": "^0.0.19",
"@fleetbase/storefront-engine": "^0.4.0",
"@fleetbase/registry-bridge-engine": "^0.1.0",
"@fleetbase/storefront-engine": "^0.4.6",
"@formatjs/intl-datetimeformat": "^6.18.2",
"@formatjs/intl-numberformat": "^8.15.6",
"@formatjs/intl-pluralrules": "^5.4.6",
"@formatjs/intl-relativetimeformat": "^11.4.13",
"@fortawesome/ember-fontawesome": "^2.0.0",
"ember-changeset": "4.1.2",
"ember-changeset-validations": "4.1.2",
@@ -46,6 +50,7 @@
"ember-concurrency-decorators": "^2.0.3",
"ember-intl": "6.3.2",
"ember-math-helpers": "^2.18.2",
"ember-maybe-in-element": "^2.1.0",
"ember-prism": "^0.13.0",
"ember-radio-button": "3.0.0-beta.1",
"ember-tag-input": "^3.1.0",

3427
console/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,9 +8,8 @@ export default class Router extends EmberRouter {
Router.map(function () {
this.route('virtual', { path: '/:slug' });
this.route('install');
this.route('onboard', function () {
this.route('verify-email');
this.route('index', { path: '/' });
});
this.route('auth', function () {
this.route('login', { path: '/' });

View File

@@ -9,7 +9,7 @@ module.exports = {
'./node_modules/@fleetbase+*/addon/**/*.{hbs,js}',
'./node_modules/@fleetbase/ember-ui/addon/templates/**/*.{hbs,js}',
'./node_modules/@fleetbase/ember-ui/addon/components/**/*.{hbs,js}',
'./node_modules/**/*-engine/addon/**/*.{hbs,js}'
'./node_modules/**/*-engine/addon/**/*.{hbs,js}',
],
},
safelist: [

View File

@@ -0,0 +1,26 @@
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 | Component | onboarding/form', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<Onboarding::Form />`);
assert.dom().hasText('');
// Template block usage:
await render(hbs`
<Onboarding::Form>
template block text
</Onboarding::Form>
`);
assert.dom().hasText('template block text');
});
});

View File

@@ -0,0 +1,26 @@
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 | Component | onboarding/verify-email', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<Onboarding::VerifyEmail />`);
assert.dom().hasText('');
// Template block usage:
await render(hbs`
<Onboarding::VerifyEmail>
template block text
</Onboarding::VerifyEmail>
`);
assert.dom().hasText('template block text');
});
});

View File

@@ -0,0 +1,26 @@
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 | Component | onboarding/yield', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<Onboarding::Yield />`);
assert.dom().hasText('');
// Template block usage:
await render(hbs`
<Onboarding::Yield>
template block text
</Onboarding::Yield>
`);
assert.dom().hasText('template block text');
});
});

View File

@@ -0,0 +1,37 @@
import Application from '@ember/application';
import config from '@fleetbase/console/config/environment';
import { initialize } from '@fleetbase/console/initializers/load-intl-polyfills';
import { module, test } from 'qunit';
import Resolver from 'ember-resolver';
import { run } from '@ember/runloop';
module('Unit | Initializer | load-intl-polyfills', function (hooks) {
hooks.beforeEach(function () {
this.TestApplication = class TestApplication extends Application {
modulePrefix = config.modulePrefix;
podModulePrefix = config.podModulePrefix;
Resolver = Resolver;
};
this.TestApplication.initializer({
name: 'initializer under test',
initialize,
});
this.application = this.TestApplication.create({
autoboot: false,
});
});
hooks.afterEach(function () {
run(this.application, 'destroy');
});
// TODO: Replace this with your real tests.
test('it works', async function (assert) {
await this.application.boot();
assert.ok(true);
});
});

View File

@@ -0,0 +1,39 @@
import Application from '@ember/application';
import config from '@fleetbase/console/config/environment';
import { initialize } from '@fleetbase/console/instance-initializers/register-default-onboarding-flow';
import { module, test } from 'qunit';
import Resolver from 'ember-resolver';
import { run } from '@ember/runloop';
module('Unit | Instance Initializer | register-default-onboarding-flow', function (hooks) {
hooks.beforeEach(function () {
this.TestApplication = class TestApplication extends Application {
modulePrefix = config.modulePrefix;
podModulePrefix = config.podModulePrefix;
Resolver = Resolver;
};
this.TestApplication.instanceInitializer({
name: 'initializer under test',
initialize,
});
this.application = this.TestApplication.create({
autoboot: false,
});
this.instance = this.application.buildInstance();
});
hooks.afterEach(function () {
run(this.instance, 'destroy');
run(this.application, 'destroy');
});
// TODO: Replace this with your real tests.
test('it works', async function (assert) {
await this.instance.boot();
assert.ok(true);
});
});

View File

@@ -0,0 +1,14 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Model | activity', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord('activity', {});
assert.ok(model);
});
});

View File

@@ -0,0 +1,14 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Model | alert', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord('alert', {});
assert.ok(model);
});
});

View File

@@ -0,0 +1,14 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Model | report', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let model = store.createRecord('report', {});
assert.ok(model);
});
});

View File

@@ -0,0 +1,24 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Serializer | activity', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let serializer = store.serializerFor('activity');
assert.ok(serializer);
});
test('it serializes records', function (assert) {
let store = this.owner.lookup('service:store');
let record = store.createRecord('activity', {});
let serializedRecord = record.serialize();
assert.ok(serializedRecord);
});
});

View File

@@ -0,0 +1,24 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Serializer | alert', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let serializer = store.serializerFor('alert');
assert.ok(serializer);
});
test('it serializes records', function (assert) {
let store = this.owner.lookup('service:store');
let record = store.createRecord('alert', {});
let serializedRecord = record.serialize();
assert.ok(serializedRecord);
});
});

View File

@@ -0,0 +1,24 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Serializer | report', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let store = this.owner.lookup('service:store');
let serializer = store.serializerFor('report');
assert.ok(serializer);
});
test('it serializes records', function (assert) {
let store = this.owner.lookup('service:store');
let record = store.createRecord('report', {});
let serializedRecord = record.serialize();
assert.ok(serializedRecord);
});
});

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,13 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Transform | array', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let transform = this.owner.lookup('transform:array');
assert.ok(transform);
});
});

View File

@@ -0,0 +1,13 @@
import { module, test } from 'qunit';
import { setupTest } from '@fleetbase/console/tests/helpers';
module('Unit | Transform | object', function (hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function (assert) {
let transform = this.owner.lookup('transform:object');
assert.ok(transform);
});
});

View File

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

View File

@@ -0,0 +1,754 @@
app:
name: Fleetbase
common:
new: جديد
create: إنشاء
add: إضافة
edit: تعديل
update: تحديث
save: حفظ
save-changes: حفظ التغييرات
delete: حذف
delete-selected: حذف المحدد
delete-selected-count: حذف {count} المحدد
remove: إزالة
cancel: إلغاء
confirm: تأكيد
close: إغلاق
open: فتح
view: عرض
preview: معاينة
upload: رفع
download: تنزيل
import: استيراد
export: تصدير
print: طباعة
duplicate: تكرار
copy: نسخ
paste: لصق
share: مشاركة
refresh: تحديث
reset: إعادة تعيين
retry: إعادة المحاولة
back: عودة
next: التالي
previous: السابق
submit: إرسال
apply: تطبيق
continue: متابعة
proceed: المتابعة
select: تحديد
deselect: إلغاء التحديد
search: بحث
filter: تصفية
sort: فرز
view-all: عرض الكل
clear: مسح
done: تم
finish: إنهاء
skip: تخطي
method: طريقة
bulk-delete: حذف جماعي
bulk-delete-resource: حذف جماعي {resource}
bulk-cancel: إلغاء جماعي
bulk-cancel-resource: إلغاء جماعي {resource}
bulk-actions: إجراءات جماعية
column: عمود
row: صف
table: جدول
list: قائمة
grid: شبكة
form: نموذج
field: حقل
section: قسم
panel: لوحة
card: بطاقة
tab: تبويب
modal: نافذة منبثقة
dialog: حوار
menu: قائمة
dropdown: قائمة منسدلة
tooltip: تلميح
sidebar: الشريط الجانبي
toolbar: شريط الأدوات
footer: تذييل
header: رأس الصفحة
title: عنوان
subtitle: عنوان فرعي
description: وصف
placeholder: عنصر نائب
label: تسمية
button: زر
icon: أيقونة
avatar: صورة رمزية
link: رابط
badge: شارة
tag: وسم
banner: لافتة
step: خطوة
progress: تقدم
map: خريطة
board: لوحة
loading: جارٍ التحميل
loading-resource: جارٍ تحميل {resource}
saving: جارٍ الحفظ
processing: جارٍ المعالجة
fetching: جارٍ الجلب
updating: جارٍ التحديث
uploading: جارٍ الرفع
completed: مكتمل
success: نجاح
failed: فشل
error: خطأ
warning: تحذير
info: معلومات
ready: جاهز
active: نشط
inactive: غير نشط
enabled: مفعل
disabled: معطل
online: متصل
offline: غير متصل
pending: قيد الانتظار
archived: مؤرشف
hidden: مخفي
visible: مرئي
empty: فارغ
not-found: غير موجود
no-results: لا توجد نتائج
try-again: حاول مرة أخرى
are-you-sure: هل أنت متأكد؟
changes-saved: تم حفظ التغييرات بنجاح.
saved-successfully: تم حفظ التغييرات بنجاح.
field-saved: '{field} تم حفظه بنجاح.'
changes-discarded: تم تجاهل التغييرات.
delete-confirm: هل أنت متأكد أنك تريد حذف هذا العنصر؟
action-successful: تم تنفيذ الإجراء بنجاح.
action-failed: فشل الإجراء. يرجى المحاولة مرة أخرى.
something-went-wrong: حدث خطأ ما.
please-wait: يرجى الانتظار...
sign-in: تسجيل الدخول
sign-out: تسجيل الخروج
sign-up: إنشاء حساب
log-in: تسجيل الدخول
log-out: تسجيل الخروج
register: تسجيل
forgot-password: نسيت كلمة المرور
reset-password: إعادة تعيين كلمة المرور
change-password: تغيير كلمة المرور
password: كلمة المرور
confirm-password: تأكيد كلمة المرور
email: البريد الإلكتروني
username: اسم المستخدم
remember-me: تذكرني
welcome: مرحباً
welcome-back: مرحباً بعودتك
profile: الملف الشخصي
account: الحساب
settings: الإعدادات
preferences: التفضيلات
record: سجل
records: سجلات
item: عنصر
items: عناصر
entry: إدخال
entries: إدخالات
id: المعرف
name: الاسم
type: النوع
category: الفئة
overview: نظرة عامة
value: القيمة
amount: المبلغ
price: السعر
quantity: الكمية
status: الحالة
date: التاريخ
date-created: تاريخ الإنشاء
date-updated: تاريخ التحديث
time: الوقت
created-at: تم الإنشاء في
updated-at: تم التحديث في
expired-at: انتهت صلاحيتها في
last-seen-at: آخر ظهور في
last-modified: آخر تعديل
last-modified-data: 'آخر تعديل: {date}'
actions: الإجراءات
details: تفاصيل
notes: ملاحظات
reference: مرجع
filter-by: تصفية حسب
sort-by: ترتيب حسب
ascending: تصاعدي
descending: تنازلي
all: الكل
none: لا شيء
select-all: تحديد الكل
deselect-all: إلغاء تحديد الكل
show-more: عرض المزيد
show-less: عرض أقل
page: صفحة
of: من
total: الإجمالي
items-per-page: العناصر في كل صفحة
showing: عرض
to: إلى
results: النتائج
load-more: تحميل المزيد
no-more-results: لا مزيد من النتائج
today: اليوم
yesterday: أمس
tomorrow: غدًا
day: يوم
week: أسبوع
month: شهر
year: سنة
date-range: نطاق التاريخ
start-date: تاريخ البدء
end-date: تاريخ الانتهاء
time-zone: المنطقة الزمنية
system: النظام
dashboard: لوحة التحكم
home: الرئيسية
analytics: التحليلات
reports: التقارير
logs: السجلات
help: مساعدة
support: الدعم
contact: اتصال
documentation: التوثيق
language: اللغة
version: الإصدار
theme: الثيم
light-mode: الوضع الفاتح
dark-mode: الوضع الداكن
update-available: تحديث متوفر
install-update: تثبيت التحديث
maintenance-mode: وضع الصيانة
notification: إشعار
notifications: الإشعارات
mark-as-read: وضع كمقروء
mark-all-as-read: وضع الكل كمقروء
clear-notifications: مسح الإشعارات
company: شركة
companies: شركات
user: مستخدم
users: مستخدمون
role: دور
roles: أدوار
permission: إذن
permissions: أذونات
group: مجموعة
groups: مجموعات
unauthorized: غير مصرح
forbidden: ممنوع
resource-not-found: المورد غير موجود
server-error: خطأ في الخادم
validation-error: خطأ في التحقق
timeout-error: انتهت مهلة الطلب
network-error: خطأ في الشبكة
unknown-error: خطأ غير معروف
file: ملف
files: ملفات
folder: مجلد
folders: مجلدات
upload-file: رفع ملف
upload-files: رفع ملفات
upload-image: رفع صورة
upload-image-supported: يدعم PNG و JPEG و GIF
choose-file: اختر ملف
choose-files: اختر ملفات
drag-and-drop: اسحب وأفلت
download-file: تحميل ملف
file-size: حجم الملف
file-type: نوع الملف
confirm-delete: تأكيد الحذف
confirm-action: تأكيد الإجراء
confirm-exit: تأكيد الخروج
confirm-and-save-changes: تأكيد وحفظ التغييرات
are-you-sure-exit: هل أنت متأكد أنك تريد الخروج؟
unsaved-changes-warning: لديك تغييرات غير محفوظة.
connected: متصل
disconnected: غير متصل
reconnecting: إعادة الاتصال
connection-lost: انقطع الاتصال
connection-restored: تم استعادة الاتصال
show: عرض
hide: إخفاء
expand: توسيع
collapse: طي
enable: تمكين
disable: تعطيل
minimize: تصغير
maximize: تكبير
restore: استعادة
zoom-in: تكبير
zoom-out: تصغير
fullscreen: شاشة كاملة
exit-fullscreen: خروج من الشاشة الكاملة
true: 'true'
false: 'false'
ok: موافق
none-available: لا يوجد
default: افتراضي
custom: مخصص
general: عام
advanced: متقدم
placeholder-text: أدخل النص هنا...
learn-more: تعرف على المزيد
view-resource: عرض {resource}
view-resource-details: عرض تفاصيل {resource}
create-a-new-resource: إنشاء {resource} جديد
create-new-resource: إنشاء {resource} جديد
search-resource: بحث في {resource}
new-resource: '{resource} جديد'
update-resource: تحديث {resource}
save-resource-changes: حفظ تغييرات {resource}
creating-resource: إنشاء {resource}
cancel-resource: إلغاء {resource}
delete-resource: حذف {resource}
delete-resource-name: 'حذف: {resourceName}'
delete-resource-named: حذف {resource} ({resourceName})
delete-resource-prompt: لا يمكن التراجع عن هذا الإجراء. بمجرد الحذف، سيتم إزالة
السجل نهائيًا.
delete-cannot-be-undone: لا يمكن التراجع عن هذا الإجراء. بمجرد الحذف، سيتم إزالة
السجل نهائيًا.
create-resource: إنشاء {resource}
edit-resource: تعديل {resource}
edit-resource-details: تعديل تفاصيل {resource}
edit-resource-type-name: 'تعديل {resource}: {resourceName}'
edit-resource-name: 'تعديل: {resourceName}'
config: الإعدادات
select-field: اختر {field}
columns: الأعمدة
metadata: البيانات الوصفية
meta: ميتا
resource-created-success: تم إنشاء {resource} جديد بنجاح.
resource-created-success-name: تم إنشاء {resource} جديد ({resourceName}) بنجاح.
resource-updated-success: تم تحديث {resource} ({resourceName}) بنجاح.
resource-action-success: تم {action} {resource} ({resourceName}) بنجاح.
resource-deleted-success: تم حذف {resource} ({resourceName}) بنجاح.
resource-deleted: تم حذف {resource} ({resourceName}).
continue-without-saving: المتابعة بدون حفظ؟
continue-without-saving-prompt: لديك تغييرات غير محفوظة على هذا {resource}. المتابعة
ستتجاهلها. انقر متابعة للمتابعة.
resource:
alert: تنبيه
alerts: تنبيهات
brand: علامة تجارية
brands: علامات تجارية
category: فئة
categories: فئات
chat-attachment: مرفق المحادثة
chat-attachments: مرفقات المحادثة
chat-channel: قناة المحادثة
chat-channels: قنوات المحادثة
chat-log: سجل المحادثة
chat-logs: سجلات المحادثة
chat-message: رسالة المحادثة
chat-messages: رسائل المحادثة
chat-participant: مشارك المحادثة
chat-participants: مشاركو المحادثة
chat-receipt: إيصال المحادثة
chat-receipts: إيصالات المحادثة
comment: تعليق
comments: تعليقات
company: شركة
companies: شركات
custom-field-value: قيمة الحقل المخصص
custom-field-values: قيم الحقول المخصصة
custom-field: حقل مخصص
custom-fields: حقول مخصصة
dashboard-widget: أداة لوحة التحكم
dashboard-widgets: أدوات لوحة التحكم
dashboard: لوحة التحكم
dashboards: لوحات التحكم
extension: امتداد
extensions: امتدادات
file: ملف
files: ملفات
group: مجموعة
groups: مجموعات
notification: إشعار
notifications: إشعارات
permission: إذن
permissions: أذونات
policy: سياسة
policies: سياسات
report: تقرير
reports: تقارير
role: دور
roles: أدوار
setting: إعداد
settings: إعدادات
transaction: معاملة
transactions: معاملات
user-device: جهاز المستخدم
user-devices: أجهزة المستخدم
user: مستخدم
users: مستخدمون
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: يجب أن يكون التعليق مكونًا من حرفين على الأقل
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: إغلاق وحفظ
filters-picker:
filters: الفلاتر
filter-data: تصفية البيانات
visible-column-picker:
select-viewable-columns: اختر الأعمدة المرئية
customize-columns: تخصيص الأعمدة
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: إرسال عبر الرسائل النصية
two-fa:
verify-code:
verification-code: رمز التحقق
check-title: تحقق من بريدك الإلكتروني أو هاتفك
check-subtitle: لقد أرسلنا لك رمز تحقق. أدخل الرمز أدناه لإكمال عملية تسجيل
الدخول.
expired-help-text: رمز التحقق الخاص بالمصادقة الثنائية قد انتهت صلاحيته. يمكنك
طلب رمز جديد إذا كنت بحاجة إلى مزيد من الوقت.
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: الصور
timezone: اختر منطقتك الزمنية.
admin:
menu:
overview: نظرة عامة
organizations: المنظمات
branding: العلامة التجارية
2fa-config: إعداد التحقق بخطوتين
schedule-monitor: مراقبة الجدول
services: الخدمات
mail: البريد
filesystem: نظام الملفات
queue: الطابور
socket: المقبس
push-notifications: الإشعارات الفورية
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: تكوين الإشعارات الفورية
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: تحميل خلفية جديدة
organization-timezone: اختر المنطقة الزمنية الافتراضية لمنظمتك.
select-timezone: اختر المنطقة الزمنية.
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: الإرسال عبر الرسائل النصية
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

@@ -1,364 +0,0 @@
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: تكوين المصادقة الثنائية
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: إشعارات الدفع
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). قم بتمكين المصادقة الثنائية في إعدادات حسابك للحصول على طبقة إضافية من الحماية.
button-text: إعداد المصادقة الثنائية
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: إرسال عبر الرسائل القصيرة
two-fa:
verify-code:
verification-code: رمز التحقق
check-title: تحقق من بريدك الإلكتروني أو هاتفك
check-subtitle: لقد أرسلنا لك رمز تحقق. أدخل الرمز أدناه لإكمال عملية تسجيل الدخول.
expired-help-text: انتهت صلاحية رمز المصادقة الثنائية الخاص بك. يمكنك طلب رمز آخر إذا كنت بحاجة إلى مزيد من الوقت.
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: تكوين إشعارات الدفع
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: إرسال عبر الرسائل القصيرة
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

@@ -1,240 +1,632 @@
app:
name: Fleetbase
terms:
new: Ново
sort: Сортиране
filter: Филтър
columns: Колони
settings: Настройки
home: Начало
admin: Админ
logout: Изход
dashboard: Табло
search: Търсене
search-input: Поле за търсене
common:
confirm: Потвърждение
edit: Редактиране
save: Запазване
common:
new: Нов
create: Създай
add: Добави
edit: Редактирай
update: Обнови
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: Избери файл
delete-selected: Изтрий избраните
delete-selected-count: Изтрий {count} избрани
remove: Премахни
cancel: Откажи
confirm: Потвърди
close: Затвори
open: Отвори
view: Преглед
preview: Преглед
upload: Качи
download: Изтегли
import: Импортирай
export: Експортирай
print: Принтирай
duplicate: Дублирай
copy: Копирай
paste: Постави
share: Сподели
refresh: Обнови
reset: Нулирай
retry: Опитай отново
back: Назад
next: Напред
previous: Предишен
submit: Изпрати
apply: Приложи
continue: Продължи
proceed: Продължи
select: Избери
deselect: Премахни избора
search: Търси
filter: Филтрирай
sort: Подреди
view-all: Виж всички
clear: Изчисти
done: Готово
export: Експорт
reload: Презареди
reload-data: Презареди данните
unauthorized: Неразрешено
unauthorized-to: Нямате разрешение за
unauthorized-access: Неразрешен достъп
unauthorized-access-message: Неразрешен достъп, трябва да заявите необходимите разрешения.
permissions-required-for-changes: Нямате нужните разрешения, за да направите промени.
push-notifications: Push известия
finish: Завърши
skip: Пропусни
method: Метод
bulk-delete: Масово изтриване
bulk-delete-resource: Масово изтриване на {resource}
bulk-cancel: Масово отказване
bulk-cancel-resource: Масово отказване на {resource}
bulk-actions: Масови действия
column: Колона
row: Ред
table: Таблица
list: Списък
grid: Мрежа
form: Формуляр
field: Поле
section: Секция
panel: Панел
card: Картичка
tab: Раздел
modal: Модален прозорец
dialog: Диалог
menu: Меню
dropdown: Падащо меню
tooltip: Подсказка
sidebar: Странична лента
toolbar: Лента с инструменти
footer: Долен колонтитул
header: Горен колонтитул
title: Заглавие
subtitle: Подзаглавие
description: Описание
placeholder: Запълващ текст
label: Етикет
button: Бутон
icon: Икона
avatar: Аватар
link: Връзка
badge: Отличителен знак
tag: Етикет
banner: Банер
step: Стъпка
progress: Напредък
map: Карта
board: Дъска
loading: Зареждане
loading-resource: Зареждане на {resource}
saving: Записване
processing: Обработка
fetching: Извличане
updating: Актуализиране
uploading: Качване
completed: Завършено
success: Успешно
failed: Неуспешно
error: Грешка
warning: Предупреждение
info: Информация
ready: Готов
active: Активен
inactive: Неактивен
enabled: Активиран
disabled: Деактивиран
online: Онлайн
offline: Офлайн
pending: В очакване
archived: Архивиран
hidden: Скрит
visible: Видим
empty: Празен
not-found: Не е намерено
no-results: Няма резултати
try-again: Опитайте отново
are-you-sure: Сигурни ли сте?
changes-saved: Промените бяха запазени успешно.
saved-successfully: Промените бяха запазени успешно.
field-saved: '{field} беше запазено успешно.'
changes-discarded: Промените бяха отхвърлени.
delete-confirm: Сигурни ли сте, че искате да изтриете този елемент?
action-successful: Действието беше изпълнено успешно.
action-failed: Действието не бе успешно. Моля, опитайте отново.
something-went-wrong: Нещо се обърка.
please-wait: Моля, изчакайте...
sign-in: Вход
sign-out: Изход
sign-up: Регистрация
log-in: Вход
log-out: Изход
register: Регистрирай се
forgot-password: Забравена парола
reset-password: Нулиране на парола
change-password: Смяна на парола
password: Парола
confirm-password: Потвърдете паролата
email: Имейл
username: Потребителско име
remember-me: Запомни ме
welcome: Добре дошли
welcome-back: Добре дошли отново
profile: Профил
account: Акаунт
settings: Настройки
preferences: Предпочитания
record: Запис
records: Записи
item: Елемент
items: Артикули
entry: Запис
entries: Записи
id: ИД
name: Име
type: Тип
category: Категория
overview: Преглед
value: Стойност
amount: Количество
price: Цена
quantity: Количество
status: Статус
date: Дата
date-created: Дата на създаване
date-updated: Дата на актуализация
time: Време
created-at: Създаден на
updated-at: Актуализиран на
expired-at: Изтекъл на
last-seen-at: Последно видян на
last-modified: Последна промяна
last-modified-data: 'Последна промяна: {date}'
actions: Действия
details: Подробности
notes: Бележки
reference: Референция
filter-by: Филтрирай по
sort-by: Сортирай по
ascending: Възходящо
descending: Низходящо
all: Всички
none: Няма
select-all: Избери всички
deselect-all: Премахни избора на всички
show-more: Покажи още
show-less: Покажи по-малко
page: Страница
of: от
total: Общо
items-per-page: Артикули на страница
showing: Показване
to: до
results: Резултати
load-more: Зареди още
no-more-results: Няма повече резултати
today: Днес
yesterday: Вчера
tomorrow: Утре
day: Ден
week: Седмица
month: Месец
year: Година
date-range: Период от дати
start-date: Начална дата
end-date: Крайна дата
time-zone: Часова зона
system: Система
dashboard: Табло
home: Начало
analytics: Анализи
reports: Доклади
logs: Логове
help: Помощ
support: Поддръжка
contact: Контакт
documentation: Документация
language: Език
version: Версия
theme: Тема
light-mode: Светъл режим
dark-mode: Тъмен режим
update-available: Налична актуализация
install-update: Инсталирай актуализация
maintenance-mode: Режим на поддръжка
notification: Известие
notifications: Известия
mark-as-read: Маркирай като прочетено
mark-all-as-read: Маркирай всички като прочетени
clear-notifications: Изчисти известията
company: Компания
companies: Компании
user: Потребител
users: Потребители
role: Роля
roles: Роли
permission: Разрешение
permissions: Разрешения
group: Група
groups: Групи
unauthorized: Неоторизиран
forbidden: Забранено
resource-not-found: Ресурсът не е намерен
server-error: Сървърна грешка
validation-error: Грешка при валидиране
timeout-error: Времето за заявката изтече
network-error: Мрежова грешка
unknown-error: Неизвестна грешка
file: Файл
files: Файлове
folder: Папка
folders: Папки
upload-file: Качи файл
upload-files: Качи файлове
upload-image: Качи изображение
upload-image-supported: Поддържа PNG, JPEG и GIF
choose-file: Избери файл
choose-files: Избери файлове
drag-and-drop: Плъзни и пусни
download-file: Изтегли файл
file-size: Размер на файла
file-type: Тип на файла
confirm-delete: Потвърди изтриване
confirm-action: Потвърди действие
confirm-exit: Потвърди изход
confirm-and-save-changes: Потвърди и запази промените
are-you-sure-exit: Сигурни ли сте, че искате да излезете?
unsaved-changes-warning: Имате незапазени промени.
connected: Свързан
disconnected: Разкачен
reconnecting: Преконектиране
connection-lost: Връзката е изгубена
connection-restored: Връзката е възстановена
show: Покажи
hide: Скрий
expand: Разгъни
collapse: Свий
enable: Активирай
disable: Деактивирай
minimize: Минимизирай
maximize: Максимизирай
restore: Възстанови
zoom-in: Увеличи
zoom-out: Намали
fullscreen: Цял екран
exit-fullscreen: Излез от цял екран
true: 'true'
false: 'false'
ok: ОК
none-available: Няма налични
default: По подразбиране
custom: Персонализиран
general: Общи
advanced: Разширени
placeholder-text: Въведете текст тук...
learn-more: Научете повече
view-resource: Преглед на {resource}
view-resource-details: Преглед на подробности за {resource}
create-a-new-resource: Създаване на нов {resource}
create-new-resource: Създай нов {resource}
search-resource: Търсене на {resource}
new-resource: Нов {resource}
update-resource: Актуализиране на {resource}
save-resource-changes: Запазване на промените в {resource}
creating-resource: Създаване на {resource}
cancel-resource: Отказване на {resource}
delete-resource: Изтриване на {resource}
delete-resource-name: 'Изтриване: {resourceName}'
delete-resource-named: Изтриване на {resource} ({resourceName})
delete-resource-prompt: Това действие не може да бъде отменено. След изтриване,
записът ще бъде окончателно премахнат.
delete-cannot-be-undone: Това действие не може да бъде отменено. След изтриване,
записът ще бъде окончателно премахнат.
create-resource: Създаване на {resource}
edit-resource: Редактиране на {resource}
edit-resource-details: Редактиране на детайлите на {resource}
edit-resource-type-name: 'Редактиране на {resource}: {resourceName}'
edit-resource-name: 'Редактиране: {resourceName}'
config: Конфигурация
select-field: Изберете {field}
columns: Колони
metadata: Метаданни
meta: Мета
resource-created-success: Нов {resource} беше създаден успешно.
resource-created-success-name: Нов {resource} ({resourceName}) беше създаден успешно.
resource-updated-success: '{resource} ({resourceName}) беше актуализиран успешно.'
resource-action-success: '{resource} ({resourceName}) {action} успешно.'
resource-deleted-success: '{resource} ({resourceName}) беше изтрит успешно.'
resource-deleted: '{resource} ({resourceName}) беше изтрит.'
continue-without-saving: Продължите без запазване?
continue-without-saving-prompt: Имате незапазени промени в този {resource}. Продължаването
ще ги отхвърли. Натиснете Продължи, за да продължите.
resource:
alert: Известие
alerts: Известия
brand: Марка
brands: Марки
category: Категория
categories: Категории
chat-attachment: Прикачен файл в чат
chat-attachments: Прикачени файлове в чат
chat-channel: Чат канал
chat-channels: Чат канали
chat-log: Чат лог
chat-logs: Чат логове
chat-message: Чат съобщение
chat-messages: Чат съобщения
chat-participant: Участник в чат
chat-participants: Участници в чат
chat-receipt: Чат разписка
chat-receipts: Чат разписки
comment: Коментар
comments: Коментари
company: Компания
companies: Компании
custom-field-value: Стойност на персонализирано поле
custom-field-values: Стойности на персонализирани полета
custom-field: Персонализирано поле
custom-fields: Персонализирани полета
dashboard-widget: Уиджет на таблото
dashboard-widgets: Уиджети на таблото
dashboard: Табло
dashboards: Табла
extension: Разширение
extensions: Разширения
file: Файл
files: Файлове
group: Група
groups: Групи
notification: Известие
notifications: Известия
permission: Разрешение
permissions: Разрешения
policy: Политика
policies: Политики
report: Доклад
reports: Доклади
role: Роля
roles: Роли
setting: Настройка
settings: Настройки
transaction: Транзакция
transactions: Транзакции
user-device: Потребителско устройство
user-devices: Потребителски устройства
user: Потребител
users: Потребители
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: Затвори и запази
filters-picker:
filters: Филтри
filter-data: Филтриране на данни
visible-column-picker:
select-viewable-columns: Изберете видими колони
customize-columns: Персонализиране на колони
component:
file:
dropdown-label: Действия с файла
import-modal:
loading-message: Обработване на импорта...
drop-upload: Пуснете, за да качите
invalid: Невалидно
ready-upload: готово за качване.
loading-message: Обработка на импорта...
drop-upload: Пуснете за качване
invalid: Невалиден
ready-upload: готов за качване.
upload-spreadsheets: Качване на електронни таблици
drag-drop: Плъзнете и пуснете файлове с електронни таблици върху тази зона
drag-drop: Плъзнете и пуснете файлове с електронни таблици в тази зона
button-text: или изберете електронни таблици за качване
spreadsheets: електронни таблици
upload-queue: Опашка за качване
dropzone:
file: файл
drop-to-upload: Пуснете, за да качите
invalid: Невалидно
files-ready-for-upload: >-
{numOfFiles} готови за качване.
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-images-videos: Плъзнете и пуснете файлове с изображения и видеа
в тази зона
dropzone-supported-avatars: Плъзнете и пуснете SVG или PNG файлове
dropzone-supported-files: Плъзнете и пуснете файлове в тази зона
or-select-button-text: или изберете файлове за качване.
upload-queue: Опашка за качване
uploading: Качване...
two-fa-enforcement-alert:
message: За да подобрите сигурността на акаунта си, организацията ви изисква двуфакторно удостоверяване (2FA). Активирайте 2FA в настройките на акаунта си за допълнителен слой защита.
message: За да подобри сигурността на вашия акаунт, вашата организация изисква
двуфакторна автентикация (2FA). Активирайте 2FA в настройките на акаунта си
за допълнителен слой защита.
button-text: Настройте 2FA
comment-thread:
publish-comment-button-text: Публикувай коментар
publish-reply-button-text: Публикувай отговор
reply-comment-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-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: Редактиране на подредбата
confirm-create-dashboard: Създайте табло!
edit-layout: Редактиране на оформление
add-widgets: Добавяне на джаджи
delete-dashboard: Изтрийте таблото
save-dashboard: Запазете таблото
delete-dashboard: Изтрий таблото
save-dashboard: Запази таблото
you-cannot-delete-this-dashboard: Не можете да изтриете това табло.
are-you-sure-you-want-delete-dashboard: Сигурни ли сте, че искате да изтриете {dashboardName}?
are-you-sure-you-want-delete-dashboard: Сигурни ли сте, че искате да изтриете
{dashboardName}?
dashboard-widget-panel:
widget-name: >-
Джаджа {widgetName}
widget-name: Джаджа {widgetName}
select-widgets: Изберете джаджи
close-and-save: Затвори и запази
services:
dashboard-service:
create-dashboard-success-notification: Ново табло `{dashboardName}` е създадено успешно.
create-dashboard-success-notification: Новото табло `{dashboardName}` беше създадено
успешно.
delete-dashboard-success-notification: Таблото `{dashboardName}` беше изтрито.
auth:
verification:
header-title: Верификация на акаунта
title: Потвърдете своя имейл адрес
message-text: <strong>Почти готово!</strong><br> Проверете имейла си за код за потвърждение.
verification-code-text: Въведете кода за потвърждение, който сте получили по имейл.
header-title: Потвърждение на акаунт
title: Потвърдете вашия имейл адрес
message-text: <strong>Почти сте готови!</strong><br> Проверете имейла си за код
за потвърждение.
verification-code-text: Въведете кода за потвърждение, който получихте по имейл.
verification-input-label: Код за потвърждение
verify-button-text: Потвърдете и продължете
verify-button-text: Потвърди и продължи
didnt-receive-a-code: Все още не сте получили код?
not-sent:
message: Все още не сте получили код?
alternative-choice: Използвайте алтернативните опции по-долу, за да потвърдите акаунта си.
resend-email: Изпратете имейл отново
send-by-sms: Изпратете по SMS
alternative-choice: Използвайте алтернативните опции по-долу, за да потвърдите
акаунта си.
resend-email: Изпрати имейл отново
send-by-sms: Изпрати чрез SMS
two-fa:
verify-code:
verification-code: Код за потвърждение
check-title: Проверете своя имейл или телефон
check-subtitle: Изпратихме ви код за потвърждение. Въведете го по-долу, за да завършите процеса на вход.
expired-help-text: Вашият 2FA код е изтекъл. Можете да заявите нов код, ако ви е нужно още време.
check-title: Проверете имейла или телефона си
check-subtitle: Изпратихме ви код за потвърждение. Въведете кода по-долу, за
да завършите процеса на влизане.
expired-help-text: Вашият 2FA код за удостоверяване е изтекъл. Можете да поискате
нов код, ако имате нужда от повече време.
resend-code: Изпрати кода отново
verify-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: Възникна грешка при повторното изпращане на кода. Моля, опитайте отново.
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:
is-sent:
title: Почти готово!
message: <strong>Проверете имейла си!</strong><br> Изпратихме ви магически линк, който ще ви позволи да нулирате паролата си. Линкът изтича след 15 минути.
message: <strong>Проверете имейла си!</strong><br> Изпратихме ви магически линк
на имейла, който ще ви позволи да нулирате паролата си. Линкът изтича след
15 минути.
not-sent:
title: Забравена парола?
message: <strong>Не се притеснявайте, ние ще помогнем.</strong><br> Въведете имейла, който използвате за вход в {appName}, и ще ви изпратим сигурен линк за нулиране на паролата.
title: Забравили ли сте паролата си?
message: <strong>Не се притеснявайте, ние сме тук за вас.</strong><br> Въведете
имейла, който използвате за вход в {appName} и ще ви изпратим сигурен линк
за нулиране на паролата.
form:
email-label: Вашият имейл адрес
submit-button: Добре, изпратете ми магически линк!
nevermind-button: Отказ
nevermind-button: Няма значение
login:
title: Влезте в акаунта си
no-identity-notification: Пропуснахте ли да въведете своя имейл?
no-password-notification: Пропуснахте ли да въведете своята парола?
unverified-notification: Акаунтът ви трябва да бъде потвърден, за да продължите.
no-identity-notification: Забравихте ли да въведете имейла си?
no-password-notification: Забравихте ли да въведете паролата си?
unverified-notification: Вашият акаунт трябва да бъде потвърден, за да продължите.
password-reset-required: Необходимо е нулиране на паролата, за да продължите.
failed-attempt:
message: <strong>Забравихте паролата си?</strong><br> Кликнете върху бутона по-долу, за да я нулирате.
button-text: Добре, помогнете ми!
message: <strong>Забравили ли сте паролата си?</strong><br> Натиснете бутона
по-долу, за да нулирате паролата си.
button-text: Добре, помогнете ми да нулирам!
form:
email-label: Имейл адрес
password-label: Парола
remember-me-label: Запомни ме
forgot-password-label: Забравена парола?
forgot-password-label: Забравили ли сте паролата си?
sign-in-button: Вход
create-account-button: Създаване на нов акаунт
slow-connection-message: Забавена връзка.
create-account-button: Създайте нов акаунт
slow-connection-message: Имате проблеми с връзката.
reset-password:
success-message: Паролата ви е нулирана! Влезте, за да продължите.
invalid-verification-code: Тази връзка за нулиране на паролата е невалидна или е изтекла.
success-message: Вашата парола беше нулирана! Влезте, за да продължите.
invalid-verification-code: Този линк за нулиране на парола е невалиден или изтекъл.
title: Нулирайте паролата си
form:
code:
label: Вашият код за нулиране
help-text: Кодът за потвърждение, който получихте по имейл.
help-text: Кодът за потвърждение, който получихте на имейла си.
password:
label: Нова парола
help-text: Въведете парола от поне 6 символа, за да продължите.
help-text: Въведете парола с поне 6 символа, за да продължите.
confirm-password:
label: Потвърдете новата парола
help-text: Въведете парола от поне 6 символа, за да продължите.
submit-button: Нулирай паролата
help-text: Въведете парола с поне 6 символа, за да продължите.
submit-button: Нулиране на паролата
back-button: Назад
console:
create-or-join-organization:
modal-title: Създаване или присъединяване към организация
modal-title: Създайте или се присъединете към организация
join-success-notification: Присъединихте се към нова организация!
create-success-notification: Създадохте нова организация!
switch-organization:
modal-title: Сигурни ли сте, че искате да превключите към организацията {organizationName}?
modal-body: При потвърждение акаунтът ви ще остане вписан, но основната ви организация ще бъде сменена.
modal-accept-button-text: Да, искам да превключа
success-notification: Превключихте организацията
modal-title: Сигурни ли сте, че искате да превключите организацията на {organizationName}?
modal-body: С потвърждението вашият акаунт ще остане влязъл, но основната ви организация
ще бъде сменена.
modal-accept-button-text: Да, искам да сменя организацията
success-notification: Сменихте организацията
account:
index:
upload-new: Качете нов
index:
upload-new: Качете ново
phone: Вашият телефонен номер.
photos: снимки
timezone: Изберете вашата часова зона.
admin:
menu:
overview: Преглед
organizations: Организации
branding: Брандиране
2fa-config: Настройка на 2FA
schedule-monitor: Монитор на графика
services: Услуги
mail: Поща
filesystem: Файлова система
queue: Опашка
socket: Сокет
push-notifications: Известия
schedule-monitor:
schedule-monitor: Монитор на графика
task-logs-for: >-
Логове на задачите за:
showing-last-count: Показване на последните {count} записа
task-logs-for: 'Логове на задачата за: '
showing-last-count: Показване на последните {count} логове
name: Име
type: Тип
timezone: Часова зона
@@ -243,9 +635,9 @@ console:
last-failure: Последна грешка
date: Дата
memory: Памет
runtime: Времетраене
output: Резултат
no-output: Няма резултат
runtime: Време на изпълнение
output: Изход
no-output: Няма изход
config:
database:
title: Конфигурация на базата данни
@@ -253,8 +645,8 @@ console:
title: Конфигурация на файловата система
mail:
title: Конфигурация на пощата
notification-channels:
title: Конфигурация на Push известия
notification-channels:
title: Конфигурация на известията
queue:
title: Конфигурация на опашката
services:
@@ -264,17 +656,17 @@ console:
branding:
title: Брандиране
icon-text: Икона
upload-new: Качете нов
reset-default: Възстанови по подразбиране
upload-new: Качване на нов
reset-default: Възстановяване по подразбиране
logo-text: Лого
theme: Основна тема
theme: Тема по подразбиране
index:
total-users: Общо потребители
total-organizations: Общо организации
total-transactions: Общо транзакции
notifications:
title: Известия
notification-settings: Настройки за известия
notification-settings: Настройки на известията
organizations:
index:
title: Организации
@@ -293,34 +685,38 @@ console:
organization-description: Описание на организацията
organization-phone: Телефонен номер на организацията
organization-currency: Валута на организацията
organization-id: Идентификатор на организацията
organization-id: ИД на организацията
organization-branding: Брандиране на организацията
logo: Лого
logo-help-text: Лого на вашата организация.
upload-new-logo: Качете ново лого
logo-help-text: Лого за вашата организация.
upload-new-logo: Качване на ново лого
backdrop: Фон
backdrop-help-text: По желание можете да зададете банер или фонова картинка за организацията.
upload-new-backdrop: Качете нов фон
backdrop-help-text: По избор банер или фонова снимка за вашата организация.
upload-new-backdrop: Качване на нов фон
organization-timezone: Изберете стандартната часова зона за вашата организация.
select-timezone: Изберете часова зона.
extensions:
title: Разширенията идват скоро!
message: Моля, проверете отново в следващите версии, докато подготвяме хранилище и пазар за разширения.
message: Моля, проверявайте отново в следващите версии, докато подготвяме стартирането
на хранилището и пазара за разширения.
notifications:
select-all: Избери всички
mark-as-read: Маркирай като прочетени
received: >-
Получено:
mark-as-read: Маркирай като прочетено
received: 'Получени:'
message: Няма известия за показване.
invite:
for-users:
invitation-message: Поканени сте да се присъедините към {companyName}
invitation-sent-message: Поканени сте да се присъедините към организацията {companyName} в {appName}. За да приемете тази покана, въведете кода за покана, който сте получили по имейл, и натиснете Продължи.
invitation-message: Бяхте поканени да се присъедините към {companyName}
invitation-sent-message: Бяхте поканени да се присъедините към организацията {companyName}
в {appName}. За да приемете тази покана, въведете кода за покана, получен по
имейл, и натиснете продължи.
invitation-code-sent-text: Вашият код за покана
accept-invitation-text: Приемете поканата
accept-invitation-text: Приеми поканата
onboard:
index:
title: Създайте своя акаунт
welcome-title: <strong>Добре дошли в {companyName}!</strong><br />
welcome-text: Попълнете изискваните данни по-долу, за да започнете.
welcome-text: Попълнете необходимите данни по-долу, за да започнете.
full-name: Пълно име
full-name-help-text: Вашето пълно име
your-email: Имейл адрес
@@ -328,38 +724,44 @@ onboard:
phone: Телефонен номер
phone-help-text: Вашият телефонен номер
organization-name: Име на организацията
organization-help-text: Името на вашата организация; всички услуги и ресурси ще се управляват под тази организация. По-късно можете да създавате колкото организации желаете.
organization-help-text: Името на вашата организация, всички ваши услуги и ресурси
ще се управляват под тази организация, по-късно можете да създадете толкова
организации, колкото искате или имате нужда.
password: Въведете парола
password-help-text: Вашата парола; уверете се, че е достатъчно сигурна.
confirm-password: Потвърдете паролата
confirm-password-help-text: Просто за да я потвърдите, въведете я отново.
password-help-text: Вашата парола, уверете се, че е добра.
confirm-password: Потвърдете паролата си
confirm-password-help-text: Просто за да потвърдите паролата, която въведохте
по-горе.
continue-button-text: Продължи
verify-email:
header-title: Верификация на акаунта
header-title: Потвърждение на акаунта
title: Потвърдете своя имейл адрес
message-text: <strong>Почти готово!</strong><br> Проверете имейла си за код за потвърждение.
verification-code-text: Въведете кода за потвърждение, който сте получили по имейл.
message-text: <strong>Почти сте готови!</strong><br> Проверете имейла си за код
за потвърждение.
verification-code-text: Въведете кода за потвърждение, който получихте по имейл.
verification-input-label: Код за потвърждение
verify-button-text: Потвърдете и продължете
verify-button-text: Потвърди и продължи
didnt-receive-a-code: Все още не сте получили код?
not-sent:
message: Все още не сте получили код?
alternative-choice: Използвайте алтернативните опции по-долу, за да потвърдите акаунта си.
resend-email: Изпратете имейл отново
send-by-sms: Изпратете по SMS
alternative-choice: Използвайте алтернативните опции по-долу, за да потвърдите
акаунта си.
resend-email: Изпрати имейл отново
send-by-sms: Изпрати чрез SMS
install:
installer-header: Инсталатор
failed-message-sent: Инсталацията не беше успешна! Кликнете бутона по-долу, за да опитате отново.
retry-install: Опитайте да инсталирате отново
start-install: Стартиране на инсталацията
failed-message-sent: Инсталацията неуспешна! Натиснете бутона по-долу, за да опитате
отново.
retry-install: Опитай отново инсталацията
start-install: Започни инсталацията
layout:
header:
menus:
organization:
settings: Настройки на организацията
create-or-join: Създаване или присъединяване към организации
explore-extensions: Разгледайте разширенията
explore-extensions: Разгледайте разширения
user:
view-profile: Преглед на профила
keyboard-shortcuts: Покажи клавишните комбинации
keyboard-shortcuts: Показване на клавишни комбинации
changelog: Дневник на промените

View File

@@ -1,84 +1,472 @@
app:
name: Fleetbase
terms:
common:
new: New
sort: Sort
filter: Filer
columns: Columns
settings: Settings
home: Home
admin: Admin
logout: Logout
dashboard: Dashboard
search: Search
search-input: Search Input
common:
confirm: Confirm
create: Create
add: Add
edit: Edit
update: Update
save: Save
save-changes: Save Changes
cancel: Cancel
2fa-config: 2FA Config
account: Account
admin: Admin
branding: Branding
columns: Columns
dashboard: Dashboard
date-of-birth: Date of Birth
delete: Delete
email: Email
filesystem: Filesystem
filter: Filer
home: Home
logout: Logout
mail: Mail
name: Name
new: New
notification-channels: Notification Channels
notifications: Notifications
organization: Organization
organizations: Organizations
overview: Overview
phone: Your phone number
profile: Profile
queue: Queue
save-button-text: Save Changes
search-input: Search Input
search: Search
services: Services
settings: Settings
socket: Socket
sort: Sort
two-factor: Two Factor
uploading: Uploading...
delete-selected: Delete Selected
delete-selected-count: Delete {count} Selected
your-profile: Your Profile
created-at: Created At
country: Country
phone-number: Phone
status: Status
close-and-save: Close and Save
users: Users
changelog: Changelog
ok: OK
select-file: Select File
date-of-birth: Date of Birth
organization: Organization
two-factor: Two Factor
remove: Remove
cancel: Cancel
confirm: Confirm
close: Close
open: Open
view: View
preview: Preview
upload: Upload
download: Download
import: Import
export: Export
print: Print
duplicate: Duplicate
copy: Copy
paste: Paste
share: Share
refresh: Refresh
reset: Reset
retry: Retry
back: Back
next: Next
previous: Previous
submit: Submit
apply: Apply
continue: Continue
proceed: Proceed
select: Select
deselect: Deselect
search: Search
filter: Filter
sort: Sort
view-all: View All
clear: Clear
done: Done
export: Export
reload: Reload
reload-data: Reload data
unauthorized: Unauthorized
unauthorized-to: Unauthorized to
unauthorized-access: Unauthorized Access
unauthorized-access-message: Unauthorized Access, you must request permissions to access.
permissions-required-for-changes: You do not have the required permissions to make changes.
push-notifications: Push Notifications
role: Role
finish: Finish
skip: Skip
method: Method
bulk-delete: Bulk Delete
bulk-delete-resource: Bulk Delete {resource}
bulk-cancel: Bulk Cancel
bulk-cancel-resource: Bulk Cancel {resource}
bulk-actions: Bulk Actions
column: Column
row: Row
table: Table
list: List
grid: Grid
form: Form
field: Field
section: Section
panel: Panel
card: Card
tab: Tab
modal: Modal
dialog: Dialog
menu: Menu
dropdown: Dropdown
tooltip: Tooltip
sidebar: Sidebar
toolbar: Toolbar
footer: Footer
header: Header
title: Title
subtitle: Subtitle
description: Description
placeholder: Placeholder
label: Label
button: Button
icon: Icon
avatar: Avatar
link: Link
badge: Badge
tag: Tag
banner: Banner
step: Step
progress: Progress
map: Map
board: Board
loading: Loading
loading-resource: Loading {resource}
saving: Saving
processing: Processing
fetching: Fetching
updating: Updating
uploading: Uploading
completed: Completed
success: Success
failed: Failed
error: Error
warning: Warning
info: Info
ready: Ready
activity: Activity
active: Active
inactive: Inactive
enabled: Enabled
disabled: Disabled
online: Online
offline: Offline
pending: Pending
archived: Archived
hidden: Hidden
visible: Visible
empty: Empty
not-found: Not Found
no-results: No Results
try-again: Try Again
are-you-sure: Are you sure?
changes-saved: Changes saved successfully.
saved-successfully: Changes saved successfully.
field-saved: >-
{field} saved successfully.
changes-discarded: Changes discarded.
delete-confirm: Are you sure you want to delete this item?
action-successful: Action completed successfully.
action-failed: Action failed. Please try again.
something-went-wrong: Something went wrong.
please-wait: Please wait...
sign-in: Sign In
sign-out: Sign Out
sign-up: Sign Up
log-in: Log In
log-out: Log Out
register: Register
forgot-password: Forgot Password
reset-password: Reset Password
change-password: Change Password
password: Password
confirm-password: Confirm Password
email: Email
username: Username
remember-me: Remember Me
welcome: Welcome
welcome-back: Welcome Back
profile: Profile
account: Account
settings: Settings
preferences: Preferences
record: Record
records: Records
item: Item
items: Items
entry: Entry
entries: Entries
id: ID
name: Name
type: Type
category: Category
overview: Overview
value: Value
amount: Amount
price: Price
quantity: Quantity
status: Status
date: Date
date-created: Date Created
date-updated: Date Updated
time: Time
created-at: Created At
updated-at: Updated At
expired-at: Expired at
last-seen-at: Last Seen At
last-modified: Last Modified
last-modified-data: >-
Last Modified: {date}
actions: Actions
details: Details
notes: Notes
reference: Reference
filter-by: Filter By
filter-by-field: Filter By {field}
sort-by: Sort By
ascending: Ascending
descending: Descending
all: All
none: None
select-all: Select All
deselect-all: Deselect All
show-more: Show More
show-less: Show Less
page: Page
of: of
total: Total
items-per-page: Items per page
showing: Showing
to: to
results: Results
load-more: Load More
no-more-results: No More Results
today: Today
yesterday: Yesterday
tomorrow: Tomorrow
day: Day
week: Week
month: Month
year: Year
date-range: Date Range
start-date: Start Date
end-date: End Date
time-zone: Time Zone
system: System
dashboard: Dashboard
home: Home
analytics: Analytics
reports: Reports
logs: Logs
help: Help
support: Support
contact: Contact
documentation: Documentation
language: Language
timezone: Timezone
version: Version
theme: Theme
light-mode: Light Mode
dark-mode: Dark Mode
update-available: Update Available
install-update: Install Update
maintenance-mode: Maintenance Mode
notification: Notification
notifications: Notifications
mark-as-read: Mark as Read
mark-all-as-read: Mark All as Read
clear-notifications: Clear Notifications
company: Company
companies: Companies
user: User
users: Users
role: Role
roles: Roles
permission: Permission
permissions: Permissions
group: Group
groups: Groups
unauthorized: Unauthorized
forbidden: Forbidden
resource-not-found: Resource Not Found
server-error: Server Error
validation-error: Validation Error
timeout-error: Request Timed Out
network-error: Network Error
unknown-error: Unknown Error
file: File
files: Files
folder: Folder
folders: Folder's
upload-file: Upload File
upload-files: Upload Files
upload-image: Upload Image
upload-image-supported: Supports PNGs, JPEGs and GIFs
choose-file: Choose File
choose-files: Choose Files
drag-and-drop: Drag and Drop
download-file: Download File
file-size: File Size
file-type: File Type
confirm-delete: Confirm Delete
confirm-action: Confirm Action
confirm-exit: Confirm Exit
confirm-and-save-changes: Confirm & Save Changes
are-you-sure-exit: Are you sure you want to exit?
unsaved-changes-warning: You have unsaved changes.
connected: Connected
disconnected: Disconnected
reconnecting: Reconnecting
connection-lost: Connection Lost
connection-restored: Connection Restored
show: Show
hide: Hide
expand: Expand
collapse: Collapse
enable: Enable
disable: Disable
minimize: Minimize
maximize: Maximize
restore: Restore
zoom-in: Zoom In
zoom-out: Zoom Out
fullscreen: Fullscreen
exit-fullscreen: Exit Fullscreen
yes: Yes
no: No
ok: OK
none-available: None Available
default: Default
custom: Custom
general: General
advanced: Advanced
placeholder-text: Enter text here...
learn-more: Learn More
view-resource: View {resource}
view-resource-details: View {resource} Details
create-a-new-resource: Create a new {resource}
create-new-resource: Create new {resource}
search-resource: Search {resource}
new-resource: New {resource}
update-resource: Update {resource}
save-resource-changes: Save {resource} Changes
creating-resource: Creating {resource}
cancel-resource: Cancel {resource}
delete-resource: Delete {resource}
delete-resource-name: >-
Delete: {resourceName}
delete-resource-named: Delete {resource} ({resourceName})
delete-resource-prompt: This action cannot be undone. Once deleted, the record will be permanently removed.
delete-cannot-be-undone: This action cannot be undone. Once deleted, the record will be permanently removed.
create-resource: Create {resource}
edit-resource: Edit {resource}
edit-resource-details: Edit {resource} Details
edit-resource-type-name: >-
Edit {resource}: {resourceName}
edit-resource-name: >-
Edit: {resourceName}
config: Config
select-field: Select {field}
columns: Columns
metadata: Metadata
meta: Meta
resource-created-success: New {resource} created successfully.
resource-created-success-name: New {resource} ({resourceName}) created successfully.
resource-updated-success: >-
{resource} ({resourceName}) updated successfully.
resource-action-success: >-
{resource} ({resourceName}) {action} successfully.
resource-deleted-success: >-
{resource} ({resourceName}) deleted successfully.
resource-deleted: >-
{resource} ({resourceName}) deleted.
continue-without-saving: Continue Without Saving?
continue-without-saving-prompt: You have unsaved changes to this {resource}. Continuing will discard them. Click Continue to proceed.
resource:
alert: Alert
alerts: Alerts
brand: Brand
brands: Brands
category: Category
categories: Categories
chat-attachment: Chat Attachment
chat-attachments: Chat Attachments
chat-channel: Chat Channel
chat-channels: Chat Channels
chat-log: Chat Log
chat-logs: Chat Logs
chat-message: Chat Message
chat-messages: Chat Messages
chat-participant: Chat Participant
chat-participants: Chat Participants
chat-receipt: Chat Receipt
chat-receipts: Chat Receipts
comment: Comment
comments: Comments
company: Company
companies: Companies
custom-field-value: Custom Field Value
custom-field-values: Custom Field Values
custom-field: Custom Field
custom-fields: Custom Fields
dashboard-widget: Dashboard Widget
dashboard-widgets: Dashboard Widgets
dashboard: Dashboard
dashboards: Dashboards
extension: Extension
extensions: Extensions
file: File
files: Files
group: Group
groups: Groups
notification: Notification
notifications: Notifications
permission: Permission
permissions: Permissions
policy: Policy
policies: Policies
report: Report
reports: Reports
role: Role
roles: Roles
setting: Setting
settings: Settings
transaction: Transaction
transactions: Transactions
user-device: User Device
user-devices: User Devices
user: User
users: Users
dropzone:
file: file
drop-to-upload: Drop to upload
invalid: Invalid
files-ready-for-upload: >-
{numOfFiles} ready for upload.
upload-images-videos: Upload Images & Videos
upload-documents: Upload Documents
upload-documents-files: Upload Documents & Files
upload-avatar-files: Upload Custom Avatars
dropzone-supported-images-videos: Drag and drop image and video files onto this dropzone
dropzone-supported-avatars: Drag and drop SVG or PNG files
dropzone-supported-files: Drag and drop files onto this dropzone
or-select-button-text: or select files to upload.
upload-queue: Upload Queue
uploading: Uploading...
two-fa-enforcement-alert:
message: To enhance the security of your account, your organization requires Two-Factor Authentication (2FA). Enable 2FA in your account settings for an additional layer of protection.
button-text: Setup 2FA
comment-thread:
publish-comment-button-text: Publish comment
publish-reply-button-text: Publish reply
reply-comment-button-text: Reply
edit-comment-button-text: Edit
delete-comment-button-text: Delete
comment-published-ago: >-
{createdAgo} ago
comment-input-placeholder: Input a new comment...
comment-reply-placeholder: Input your reply...
comment-input-empty-notification: You cannot publish empty comments...
comment-min-length-notification: Comment must be atleast 2 characters
dashboard:
select-dashboard: Select Dashboard
create-new-dashboard: Create new Dashboard
create-a-new-dashboard: Create a new Dashboard
confirm-create-dashboard: Create Dashboard!
edit-layout: Edit layout
add-widgets: Add widgets
delete-dashboard: Delete dashboard
save-dashboard: Save Dashboard
you-cannot-delete-this-dashboard: You cannot delete this dashboard.
are-you-sure-you-want-delete-dashboard: Are you sure to delete this {dashboardName}?
dashboard-widget-panel:
widget-name: >-
{widgetName} Widget
select-widgets: Select Widgets
close-and-save: Close and Save
filters-picker:
filters: Filters
filter-data: Filter Data
visible-column-picker:
select-viewable-columns: Select viewable columns
customize-columns: Customize Columns
component:
file:
dropdown-label: File actions
import-modal:
loading-message: Processing import...
drop-upload: Drop to upload
@@ -89,6 +477,7 @@ component:
button-text: or select spreadsheets to upload
spreadsheets: spreadsheets
upload-queue: Upload Queue
dropzone:
file: file
drop-to-upload: Drop to upload
@@ -105,9 +494,11 @@ component:
or-select-button-text: or select files to upload.
upload-queue: Upload Queue
uploading: Uploading...
two-fa-enforcement-alert:
message: To enhance the security of your account, your organization requires Two-Factor Authentication (2FA). Enable 2FA in your account settings for an additional layer of protection.
button-text: Setup 2FA
comment-thread:
publish-comment-button-text: Publish comment
publish-reply-button-text: Publish reply
@@ -120,6 +511,7 @@ component:
comment-reply-placeholder: Input your reply...
comment-input-empty-notification: You cannot publish empty comments...
comment-min-length-notification: Comment must be atleast 2 characters
dashboard:
select-dashboard: Select Dashboard
create-new-dashboard: Create new Dashboard
@@ -131,15 +523,18 @@ component:
save-dashboard: Save Dashboard
you-cannot-delete-this-dashboard: You cannot delete this dashboard.
are-you-sure-you-want-delete-dashboard: Are you sure to delete this {dashboardName}?
dashboard-widget-panel:
widget-name: >-
{widgetName} Widget
select-widgets: Select Widgets
close-and-save: Close and Save
services:
dashboard-service:
create-dashboard-success-notification: New dashboard `{dashboardName}` created succesfully.
delete-dashboard-success-notification: Dashboard `{dashboardName}` was deleted.
auth:
verification:
header-title: Account Verification
@@ -154,6 +549,7 @@ auth:
alternative-choice: Use alternaitve options below to verify your account.
resend-email: Resend Email
send-by-sms: Send by SMS
two-fa:
verify-code:
verification-code: Verification Code
@@ -167,9 +563,11 @@ auth:
verification-successful-notification: Verification successful!
verification-code-expired-notification: Verification code has expired. Please request a new one.
verification-code-failed-notification: Verification failed. Please try again.
resend-code:
verification-code-resent-notification: New verification code sent.
verification-code-resent-error-notification: Error resending verification code. Please try again.
forgot-password:
success-message: Check your email to continue!
is-sent:
@@ -182,6 +580,7 @@ auth:
email-label: Your email address
submit-button: OK, Send me a magic link!
nevermind-button: Nevermind
login:
title: Sign in to your account
no-identity-notification: Did you forget to enter your email?
@@ -191,6 +590,7 @@ auth:
failed-attempt:
message: <strong>Forgot your password?</strong><br> Click the button below to reset your password.
button-text: Ok, help me reset!
form:
email-label: Email address
password-label: Password
@@ -199,6 +599,7 @@ auth:
sign-in-button: Sign in
create-account-button: Create a new Account
slow-connection-message: Experiencing connectivity issues.
reset-password:
success-message: Your password has been reset! Login to continue.
invalid-verification-code: This reset password link is invalid or expired.
@@ -215,23 +616,39 @@ auth:
help-text: Enter a password at-least 6 characters to continue.
submit-button: Reset Password
back-button: Back
console:
create-or-join-organization:
modal-title: Create or join a organization
join-success-notification: You have joined a new organization!
create-success-notification: You have created a new organization!
switch-organization:
modal-title: Are you sure you want to switch organization to {organizationName}?
modal-body: By confirming your account will remain logged in, but your primary organization will be switched.
modal-accept-button-text: Yes, I want to switch organization
success-notification: You have switched organizations
account:
index:
upload-new: Upload new
phone: Your phone number.
photos: photos
timezone: Select your timezone.
admin:
menu:
overview: Overview
organizations: Organizations
branding: Branding
2fa-config: 2FA Config
schedule-monitor: Schedule Monitor
services: Services
mail: Mail
filesystem: Filesystem
queue: Queue
socket: Socket
push-notifications: Push Notifications
schedule-monitor:
schedule-monitor: Schedule Monitor
task-logs-for: >-
@@ -288,6 +705,7 @@ console:
email-column: Email
users:
title: Users
settings:
index:
title: Organization Settings
@@ -305,21 +723,25 @@ console:
upload-new-backdrop: Upload new backdrop
organization-timezone: Select the default timezone for your organization.
select-timezone: Select timezone.
extensions:
title: Extensions are coming soon!
message: Please check back in the upcoming versions as we prepare to launch the Extensions repository and marketplace.
notifications:
select-all: Select All
mark-as-read: Mark as Read
received: >-
Received:
message: No notifications to display.
invite:
for-users:
invitation-message: You've been invited to join {companyName}
invitation-sent-message: You've been invited to join the {companyName} organization on {appName}. To accept this invitation, input your invitation code received by email and click continue.
invitation-code-sent-text: Your invitiation code
accept-invitation-text: Accept Invitation
onboard:
index:
title: Create your account
@@ -351,11 +773,13 @@ onboard:
alternative-choice: Use alternaitve options below to verify your account.
resend-email: Resend Email
send-by-sms: Send by SMS
install:
installer-header: Installer
failed-message-sent: The install failed! Click the button below to retry the install.
retry-install: Retry Install
start-install: Start Install
layout:
header:
menus:

View File

@@ -0,0 +1,771 @@
app:
name: Fleetbase
common:
new: Nuevo
create: Crear
add: Añadir
edit: Editar
update: Actualizar
save: Guardar
save-changes: Guardar Cambios
delete: Eliminar
delete-selected: Eliminar Seleccionados
delete-selected-count: Eliminar {count} Seleccionados
remove: Quitar
cancel: Cancelar
confirm: Confirmar
close: Cerrar
open: Abrir
view: Ver
preview: Vista previa
upload: Subir
download: Descargar
import: Importar
export: Exportar
print: Imprimir
duplicate: Duplicar
copy: Copiar
paste: Pegar
share: Compartir
refresh: Actualizar
reset: Restablecer
retry: Reintentar
back: Atrás
next: Siguiente
previous: Anterior
submit: Enviar
apply: Aplicar
continue: Continuar
proceed: Proceder
select: Seleccionar
deselect: Deseleccionar
search: Buscar
filter: Filtrar
sort: Ordenar
view-all: Ver Todo
clear: Limpiar
done: Hecho
finish: Finalizar
skip: Omitir
method: Método
bulk-delete: Eliminación Masiva
bulk-delete-resource: Eliminación Masiva de {resource}
bulk-cancel: Cancelación masiva
bulk-cancel-resource: Cancelación masiva de {resource}
bulk-actions: Acciones masivas
column: Columna
row: Fila
table: Tabla
list: Lista
grid: Cuadrícula
form: Formulario
field: Campo
section: Sección
panel: Panel
card: Tarjeta
tab: Pestaña
modal: Modal
dialog: Diálogo
menu: Menú
dropdown: Desplegable
tooltip: Información sobre herramientas
sidebar: Barra lateral
toolbar: Barra de herramientas
footer: Pie de página
header: Encabezado
title: Título
subtitle: Subtítulo
description: Descripción
placeholder: Marcador de posición
label: Etiqueta
button: Botón
icon: Icono
avatar: Avatar
link: Enlace
badge: Distintivo
tag: Etiqueta
banner: Banner
step: Paso
progress: Progreso
map: Mapa
board: Tablero
loading: Cargando
loading-resource: Cargando {resource}
saving: Guardando
processing: Procesando
fetching: Obteniendo
updating: Actualizando
uploading: Subiendo
completed: Completado
success: Éxito
failed: Fallido
error: Error
warning: Advertencia
info: Información
ready: Listo
active: Activo
inactive: Inactivo
enabled: Habilitado
disabled: Deshabilitado
online: En línea
offline: Desconectado
pending: Pendiente
archived: Archivado
hidden: Oculto
visible: Visible
empty: Vacío
not-found: No encontrado
no-results: Sin resultados
try-again: Intentar de nuevo
are-you-sure: ¿Estás seguro?
changes-saved: Cambios guardados correctamente.
saved-successfully: Cambios guardados correctamente.
field-saved: '{field} guardado correctamente.'
changes-discarded: Cambios descartados.
delete-confirm: ¿Estás seguro de que quieres eliminar este elemento?
action-successful: Acción completada con éxito.
action-failed: La acción ha fallado. Por favor, inténtalo de nuevo.
something-went-wrong: Algo salió mal.
please-wait: Por favor espera...
sign-in: Iniciar sesión
sign-out: Cerrar sesión
sign-up: Registrarse
log-in: Iniciar sesión
log-out: Cerrar sesión
register: Registrar
forgot-password: ¿Olvidaste tu contraseña?
reset-password: Restablecer contraseña
change-password: Cambiar contraseña
password: Contraseña
confirm-password: Confirmar contraseña
email: Correo electrónico
username: Nombre de usuario
remember-me: Recuérdame
welcome: Bienvenido
welcome-back: Bienvenido de nuevo
profile: Perfil
account: Cuenta
settings: Configuración
preferences: Preferencias
record: Registro
records: Registros
item: Elemento
items: Artículos
entry: Entrada
entries: Entradas
id: ID
name: Nombre
type: Tipo
category: Categoría
overview: Resumen
value: Valor
amount: Cantidad
price: Precio
quantity: Cantidad
status: Estado
date: Fecha
date-created: Fecha de creación
date-updated: Fecha de actualización
time: Hora
created-at: Creado en
updated-at: Actualizado en
expired-at: Expirado en
last-seen-at: Última vez visto en
last-modified: Última modificación
last-modified-data: 'Última modificación: {date}'
actions: Acciones
details: Detalles
notes: Notas
reference: Referencia
filter-by: Filtrar por
sort-by: Ordenar por
ascending: Ascendente
descending: Descendente
all: Todos
none: Ninguno
select-all: Seleccionar todo
deselect-all: Deseleccionar todo
show-more: Mostrar más
show-less: Mostrar menos
page: Página
of: de
total: Total
items-per-page: Artículos por página
showing: Mostrando
to: a
results: Resultados
load-more: Cargar más
no-more-results: No hay más resultados
today: Hoy
yesterday: Ayer
tomorrow: Mañana
day: Día
week: Semana
month: Mes
year: Año
date-range: Rango de fechas
start-date: Fecha de inicio
end-date: Fecha de fin
time-zone: Zona horaria
system: Sistema
dashboard: Panel
home: Inicio
analytics: Analíticas
reports: Informes
logs: Registros
help: Ayuda
support: Soporte
contact: Contacto
documentation: Documentación
language: Idioma
version: Versión
theme: Tema
light-mode: Modo claro
dark-mode: Modo oscuro
update-available: Actualización disponible
install-update: Instalar actualización
maintenance-mode: Modo mantenimiento
notification: Notificación
notifications: Notificaciones
mark-as-read: Marcar como leído
mark-all-as-read: Marcar todo como leído
clear-notifications: Borrar notificaciones
company: Empresa
companies: Empresas
user: Usuario
users: Usuarios
role: Rol
roles: Roles
permission: Permiso
permissions: Permisos
group: Grupo
groups: Grupos
unauthorized: No autorizado
forbidden: Prohibido
resource-not-found: Recurso no encontrado
server-error: Error del servidor
validation-error: Error de validación
timeout-error: Tiempo de espera agotado
network-error: Error de red
unknown-error: Error desconocido
file: Archivo
files: Archivos
folder: Carpeta
folders: Carpetas
upload-file: Subir archivo
upload-files: Subir archivos
upload-image: Subir imagen
upload-image-supported: Soporta PNG, JPEG y GIF
choose-file: Elegir archivo
choose-files: Elegir archivos
drag-and-drop: Arrastrar y soltar
download-file: Descargar archivo
file-size: Tamaño del archivo
file-type: Tipo de archivo
confirm-delete: Confirmar eliminación
confirm-action: Confirmar acción
confirm-exit: Confirmar salida
confirm-and-save-changes: Confirmar y guardar cambios
are-you-sure-exit: ¿Estás seguro de que quieres salir?
unsaved-changes-warning: Tienes cambios sin guardar.
connected: Conectado
disconnected: Desconectado
reconnecting: Reconectando
connection-lost: Conexión perdida
connection-restored: Conexión restaurada
show: Mostrar
hide: Ocultar
expand: Expandir
collapse: Colapsar
enable: Habilitar
disable: Deshabilitar
minimize: Minimizar
maximize: Maximizar
restore: Restaurar
zoom-in: Acercar
zoom-out: Alejar
fullscreen: Pantalla completa
exit-fullscreen: Salir de pantalla completa
true: 'true'
false: 'false'
ok: Aceptar
none-available: Ninguno disponible
default: Predeterminado
custom: Personalizado
general: General
advanced: Avanzado
placeholder-text: Introduce texto aquí...
learn-more: Aprender más
view-resource: Ver {resource}
view-resource-details: Ver detalles de {resource}
create-a-new-resource: Crear un nuevo {resource}
create-new-resource: Crear nuevo {resource}
search-resource: Buscar {resource}
new-resource: Nuevo {resource}
update-resource: Actualizar {resource}
save-resource-changes: Guardar cambios de {resource}
creating-resource: Creando {resource}
cancel-resource: Cancelar {resource}
delete-resource: Eliminar {resource}
delete-resource-name: 'Eliminar: {resourceName}'
delete-resource-named: Eliminar {resource} ({resourceName})
delete-resource-prompt: Esta acción no se puede deshacer. Una vez eliminado, el
registro será eliminado permanentemente.
delete-cannot-be-undone: Esta acción no se puede deshacer. Una vez eliminado, el
registro será eliminado permanentemente.
create-resource: Crear {resource}
edit-resource: Editar {resource}
edit-resource-details: Editar detalles de {resource}
edit-resource-type-name: 'Editar {resource}: {resourceName}'
edit-resource-name: 'Editar: {resourceName}'
config: Configuración
select-field: Seleccionar {field}
columns: Columnas
metadata: Metadatos
meta: Meta
resource-created-success: Nuevo {resource} creado con éxito.
resource-created-success-name: Nuevo {resource} ({resourceName}) creado con éxito.
resource-updated-success: '{resource} ({resourceName}) actualizado con éxito.'
resource-action-success: '{resource} ({resourceName}) {action} con éxito.'
resource-deleted-success: '{resource} ({resourceName}) eliminado con éxito.'
resource-deleted: '{resource} ({resourceName}) eliminado.'
continue-without-saving: ¿Continuar sin guardar?
continue-without-saving-prompt: Tienes cambios sin guardar en este {resource}. Continuar
descartará esos cambios. Haz clic en Continuar para proceder.
resource:
alert: Alerta
alerts: Alertas
brand: Marca
brands: Marcas
category: Categoría
categories: Categorías
chat-attachment: Archivo adjunto de chat
chat-attachments: Archivos adjuntos de chat
chat-channel: Canal de chat
chat-channels: Canales de chat
chat-log: Registro de chat
chat-logs: Registros de chat
chat-message: Mensaje de chat
chat-messages: Mensajes de chat
chat-participant: Participante del chat
chat-participants: Participantes del chat
chat-receipt: Recibo de chat
chat-receipts: Recibos de chat
comment: Comentario
comments: Comentarios
company: Empresa
companies: Empresas
custom-field-value: Valor de campo personalizado
custom-field-values: Valores de campo personalizado
custom-field: Campo personalizado
custom-fields: Campos personalizados
dashboard-widget: Widget del panel
dashboard-widgets: Widgets del panel
dashboard: Panel
dashboards: Paneles
extension: Extensión
extensions: Extensiones
file: Archivo
files: Archivos
group: Grupo
groups: Grupos
notification: Notificación
notifications: Notificaciones
permission: Permiso
permissions: Permisos
policy: Política
policies: Políticas
report: Informe
reports: Informes
role: Rol
roles: Roles
setting: Configuración
settings: Configuraciones
transaction: Transacción
transactions: Transacciones
user-device: Dispositivo del usuario
user-devices: Dispositivos del usuario
user: Usuario
users: Usuarios
dropzone:
file: archivo
drop-to-upload: Suelta para subir
invalid: Inválido
files-ready-for-upload: '{numOfFiles} listo(s) para subir.'
upload-images-videos: Subir imágenes y vídeos
upload-documents: Subir documentos
upload-documents-files: Subir documentos y archivos
upload-avatar-files: Subir avatares personalizados
dropzone-supported-images-videos: Arrastra y suelta archivos de imagen y vídeo en
esta zona
dropzone-supported-avatars: Arrastra y suelta archivos SVG o PNG
dropzone-supported-files: Arrastra y suelta archivos en esta zona
or-select-button-text: o selecciona archivos para subir.
upload-queue: Cola de subida
uploading: Subiendo...
two-fa-enforcement-alert:
message: Para mejorar la seguridad de su cuenta, su organización requiere Autenticación
de Dos Factores (2FA). Active 2FA en la configuración de su cuenta para una capa
adicional de protección.
button-text: Configurar 2FA
comment-thread:
publish-comment-button-text: Publicar comentario
publish-reply-button-text: Publicar respuesta
reply-comment-button-text: Responder
edit-comment-button-text: Editar
delete-comment-button-text: Eliminar
comment-published-ago: hace {createdAgo}
comment-input-placeholder: Escribe un nuevo comentario...
comment-reply-placeholder: Escribe tu respuesta...
comment-input-empty-notification: No puedes publicar comentarios vacíos...
comment-min-length-notification: El comentario debe tener al menos 2 caracteres
dashboard:
select-dashboard: Seleccionar Panel
create-new-dashboard: Crear nuevo Panel
create-a-new-dashboard: Crear un nuevo Panel
confirm-create-dashboard: ¡Crear Panel!
edit-layout: Editar diseño
add-widgets: Añadir widgets
delete-dashboard: Eliminar panel
save-dashboard: Guardar Panel
you-cannot-delete-this-dashboard: No puedes eliminar este panel.
are-you-sure-you-want-delete-dashboard: ¿Estás seguro de que quieres eliminar este
{dashboardName}?
dashboard-widget-panel:
widget-name: Widget {widgetName}
select-widgets: Seleccionar Widgets
close-and-save: Cerrar y Guardar
filters-picker:
filters: Filtros
filter-data: Filtrar Datos
visible-column-picker:
select-viewable-columns: Seleccionar columnas visibles
customize-columns: Personalizar Columnas
component:
file:
dropdown-label: Acciones de archivo
import-modal:
loading-message: Procesando importación...
drop-upload: Suelta para subir
invalid: Inválido
ready-upload: listo para subir.
upload-spreadsheets: Subir Hojas de Cálculo
drag-drop: Arrastra y suelta archivos de hojas de cálculo en esta zona
button-text: o selecciona hojas de cálculo para subir
spreadsheets: hojas de cálculo
upload-queue: Cola de Subida
dropzone:
file: archivo
drop-to-upload: Suelta para subir
invalid: Inválido
files-ready-for-upload: '{numOfFiles} listo(s) para subir.'
upload-images-videos: Subir Imágenes y Videos
upload-documents: Subir Documentos
upload-documents-files: Subir Documentos y Archivos
upload-avatar-files: Subir Avatares Personalizados
dropzone-supported-images-videos: Arrastra y suelta archivos de imagen y video
en esta zona
dropzone-supported-avatars: Arrastra y suelta archivos SVG o PNG
dropzone-supported-files: Arrastra y suelta archivos en esta zona
or-select-button-text: o selecciona archivos para subir.
upload-queue: Cola de Subida
uploading: Subiendo...
two-fa-enforcement-alert:
message: Para mejorar la seguridad de tu cuenta, tu organización requiere Autenticación
de Dos Factores (2FA). Activa 2FA en la configuración de tu cuenta para una
capa adicional de protección.
button-text: Configurar 2FA
comment-thread:
publish-comment-button-text: Publicar comentario
publish-reply-button-text: Publicar respuesta
reply-comment-button-text: Responder
edit-comment-button-text: Editar
delete-comment-button-text: Eliminar
comment-published-ago: hace {createdAgo}
comment-input-placeholder: Escribe un nuevo comentario...
comment-reply-placeholder: Escribe tu respuesta...
comment-input-empty-notification: No puedes publicar comentarios vacíos...
comment-min-length-notification: El comentario debe tener al menos 2 caracteres
dashboard:
select-dashboard: Seleccionar panel
create-new-dashboard: Crear nuevo panel
create-a-new-dashboard: Crear un nuevo panel
confirm-create-dashboard: ¡Crear panel!
edit-layout: Editar diseño
add-widgets: Agregar widgets
delete-dashboard: Eliminar panel
save-dashboard: Guardar panel
you-cannot-delete-this-dashboard: No puedes eliminar este panel.
are-you-sure-you-want-delete-dashboard: ¿Estás seguro de que quieres eliminar
{dashboardName}?
dashboard-widget-panel:
widget-name: Widget {widgetName}
select-widgets: Seleccionar widgets
close-and-save: Cerrar y guardar
services:
dashboard-service:
create-dashboard-success-notification: Nuevo panel `{dashboardName}` creado con
éxito.
delete-dashboard-success-notification: El panel `{dashboardName}` fue eliminado.
auth:
verification:
header-title: Verificación de cuenta
title: Verifica tu dirección de correo electrónico
message-text: <strong>¡Casi terminado!</strong><br> Revisa tu correo para un código
de verificación.
verification-code-text: Introduce el código de verificación que recibiste por
correo.
verification-input-label: Código de verificación
verify-button-text: Verificar y continuar
didnt-receive-a-code: ¿No has recibido un código?
not-sent:
message: ¿No has recibido un código?
alternative-choice: Usa las opciones alternativas abajo para verificar tu cuenta.
resend-email: Reenviar correo
send-by-sms: Enviar por SMS
two-fa:
verify-code:
verification-code: Código de verificación
check-title: Revisa tu correo o teléfono
check-subtitle: Te hemos enviado un código de verificación. Introduce el código
abajo para completar el proceso de inicio de sesión.
expired-help-text: Tu código de autenticación 2FA ha expirado. Puedes solicitar
otro código si necesitas más tiempo.
resend-code: Reenviar código
verify-code: Verificar código
cancel-two-factor: Cancelar autenticación de dos factores
invalid-session-error-notification: Sesión inválida. Por favor, inténtalo de
nuevo.
verification-successful-notification: ¡Verificación exitosa!
verification-code-expired-notification: El código de verificación ha expirado.
Por favor, solicita uno nuevo.
verification-code-failed-notification: La verificación falló. Por favor, inténtalo
de nuevo.
resend-code:
verification-code-resent-notification: Nuevo código de verificación enviado.
verification-code-resent-error-notification: Error al reenviar el código de
verificación. Por favor, inténtalo de nuevo.
forgot-password:
success-message: ¡Revisa tu correo para continuar!
is-sent:
title: ¡Casi listo!
message: <strong>¡Revisa tu correo electrónico!</strong><br> Te hemos enviado
un enlace mágico a tu correo que te permitirá restablecer tu contraseña. El
enlace expira en 15 minutos.
not-sent:
title: ¿Olvidaste tu contraseña?
message: <strong>No te preocupes, te respaldamos.</strong><br> Introduce el
correo electrónico que usas para iniciar sesión en {appName} y te enviaremos
un enlace seguro para restablecer tu contraseña.
form:
email-label: Tu dirección de correo electrónico
submit-button: ¡OK, envíame un enlace mágico!
nevermind-button: No importa
login:
title: Inicia sesión en tu cuenta
no-identity-notification: ¿Olvidaste ingresar tu correo electrónico?
no-password-notification: ¿Olvidaste ingresar tu contraseña?
unverified-notification: Tu cuenta necesita ser verificada para continuar.
password-reset-required: Se requiere un restablecimiento de contraseña para continuar.
failed-attempt:
message: <strong>¿Olvidaste tu contraseña?</strong><br> Haz clic en el botón
de abajo para restablecer tu contraseña.
button-text: ¡Ok, ayúdame a restablecerla!
form:
email-label: Correo electrónico
password-label: Contraseña
remember-me-label: Recuérdame
forgot-password-label: ¿Olvidaste tu contraseña?
sign-in-button: Iniciar sesión
create-account-button: Crear una nueva cuenta
slow-connection-message: Experimentando problemas de conectividad.
reset-password:
success-message: ¡Tu contraseña ha sido restablecida! Inicia sesión para continuar.
invalid-verification-code: Este enlace para restablecer la contraseña es inválido
o ha expirado.
title: Restablece tu contraseña
form:
code:
label: Tu código de restablecimiento
help-text: El código de verificación que recibiste en tu correo electrónico.
password:
label: Nueva contraseña
help-text: Introduce una contraseña de al menos 6 caracteres para continuar.
confirm-password:
label: Confirma la nueva contraseña
help-text: Introduce una contraseña de al menos 6 caracteres para continuar.
submit-button: Restablecer contraseña
back-button: Volver
console:
create-or-join-organization:
modal-title: Crear o unirse a una organización
join-success-notification: ¡Te has unido a una nueva organización!
create-success-notification: ¡Has creado una nueva organización!
switch-organization:
modal-title: ¿Estás seguro de que quieres cambiar la organización a {organizationName}?
modal-body: Al confirmar, tu cuenta permanecerá iniciada, pero tu organización
principal será cambiada.
modal-accept-button-text: Sí, quiero cambiar de organización
success-notification: Has cambiado de organización
account:
index:
upload-new: Subir nuevo
phone: Tu número de teléfono.
photos: fotos
timezone: Selecciona tu zona horaria.
admin:
menu:
overview: Resumen
organizations: Organizaciones
branding: Imagen de marca
2fa-config: Configuración 2FA
schedule-monitor: Monitor de programación
services: Servicios
mail: Correo
filesystem: Sistema de archivos
queue: Cola
socket: Socket
push-notifications: Notificaciones push
schedule-monitor:
schedule-monitor: Monitor de programación
task-logs-for: 'Registros de tareas para: '
showing-last-count: Mostrando los últimos {count} registros
name: Nombre
type: Tipo
timezone: Zona horaria
last-started: Último inicio
last-finished: Última finalización
last-failure: Último fallo
date: Fecha
memory: Memoria
runtime: Tiempo de ejecución
output: Salida
no-output: Sin salida
config:
database:
title: Configuración de la base de datos
filesystem:
title: Configuración del sistema de archivos
mail:
title: Configuración de correo
notification-channels:
title: Configuración de notificaciones push
queue:
title: Configuración de la cola
services:
title: Configuración de servicios
socket:
title: Configuración de socket
branding:
title: Identidad corporativa
icon-text: Icono
upload-new: Subir nuevo
reset-default: Restablecer a predeterminado
logo-text: Logo
theme: Tema predeterminado
index:
total-users: Total de usuarios
total-organizations: Total de organizaciones
total-transactions: Total de transacciones
notifications:
title: Notificaciones
notification-settings: Configuración de notificaciones
organizations:
index:
title: Organizaciones
owner-name-column: Propietario
owner-phone-column: Teléfono del propietario
owner-email-column: Correo electrónico del propietario
users-count-column: Usuarios
phone-column: Teléfono
email-column: Correo electrónico
users:
title: Usuarios
settings:
index:
title: Configuración de la organización
organization-name: Nombre de la organización
organization-description: Descripción de la organización
organization-phone: Número de teléfono de la organización
organization-currency: Moneda de la organización
organization-id: ID de la organización
organization-branding: Marca de la organización
logo: Logo
logo-help-text: Logo para su organización.
upload-new-logo: Subir nuevo logo
backdrop: Fondo
backdrop-help-text: Banner o imagen de fondo opcional para su organización.
upload-new-backdrop: Subir nuevo fondo
organization-timezone: Seleccione la zona horaria predeterminada para su organización.
select-timezone: Seleccione zona horaria.
extensions:
title: ¡Las extensiones llegarán pronto!
message: Por favor, vuelva a consultar en las próximas versiones mientras preparamos
el lanzamiento del repositorio y mercado de Extensiones.
notifications:
select-all: Seleccionar todo
mark-as-read: Marcar como leído
received: 'Recibido:'
message: No hay notificaciones para mostrar.
invite:
for-users:
invitation-message: Has sido invitado a unirte a {companyName}
invitation-sent-message: Has sido invitado a unirte a la organización {companyName}
en {appName}. Para aceptar esta invitación, introduce tu código de invitación
recibido por correo electrónico y haz clic en continuar.
invitation-code-sent-text: Tu código de invitación
accept-invitation-text: Aceptar invitación
onboard:
index:
title: Crea tu cuenta
welcome-title: <strong>¡Bienvenido a {companyName}!</strong><br />
welcome-text: Completa los detalles requeridos a continuación para comenzar.
full-name: Nombre completo
full-name-help-text: Tu nombre completo
your-email: Dirección de correo electrónico
your-email-help-text: Tu dirección de correo electrónico
phone: Número de teléfono
phone-help-text: Tu número de teléfono
organization-name: Nombre de la organización
organization-help-text: El nombre de tu organización, todos tus servicios y recursos
serán gestionados bajo esta organización, más adelante podrás crear tantas organizaciones
como quieras o necesites.
password: Introduce una contraseña
password-help-text: Tu contraseña, asegúrate de que sea buena.
confirm-password: Confirma tu contraseña
confirm-password-help-text: Solo para confirmar la contraseña que introdujiste
arriba.
continue-button-text: Continuar
verify-email:
header-title: Verificación de cuenta
title: Verifica tu dirección de correo electrónico
message-text: <strong>¡Casi terminado!</strong><br> Revisa tu correo electrónico
para un código de verificación.
verification-code-text: Introduce el código de verificación que recibiste por
correo electrónico.
verification-input-label: Código de verificación
verify-button-text: Verificar y continuar
didnt-receive-a-code: ¿No has recibido un código todavía?
not-sent:
message: ¿No has recibido un código todavía?
alternative-choice: Usa las opciones alternativas a continuación para verificar
tu cuenta.
resend-email: Reenviar correo electrónico
send-by-sms: Enviar por SMS
install:
installer-header: Instalador
failed-message-sent: ¡La instalación falló! Haz clic en el botón de abajo para reintentar
la instalación.
retry-install: Reintentar instalación
start-install: Iniciar instalación
layout:
header:
menus:
organization:
settings: Configuración de la organización
create-or-join: Crear o unirse a organizaciones
explore-extensions: Explorar extensiones
user:
view-profile: Ver perfil
keyboard-shortcuts: Mostrar atajos de teclado
changelog: Registro de cambios

View File

@@ -0,0 +1,774 @@
app:
name: Fleetbase
common:
new: Nouveau
create: Créer
add: Ajouter
edit: Modifier
update: Mettre à jour
save: Enregistrer
save-changes: Enregistrer les modifications
delete: Supprimer
delete-selected: Supprimer la sélection
delete-selected-count: Supprimer {count} sélectionné(s)
remove: Retirer
cancel: Annuler
confirm: Confirmer
close: Fermer
open: Ouvrir
view: Voir
preview: Aperçu
upload: Téléverser
download: Télécharger
import: Importer
export: Exporter
print: Imprimer
duplicate: Dupliquer
copy: Copier
paste: Coller
share: Partager
refresh: Actualiser
reset: Réinitialiser
retry: Réessayer
back: Retour
next: Suivant
previous: Précédent
submit: Soumettre
apply: Appliquer
continue: Continuer
proceed: Procéder
select: Sélectionner
deselect: Désélectionner
search: Rechercher
filter: Filtrer
sort: Trier
view-all: Voir tout
clear: Effacer
done: Terminé
finish: Terminer
skip: Passer
method: Méthode
bulk-delete: Suppression en masse
bulk-delete-resource: Suppression en masse de {resource}
bulk-cancel: Annulation en masse
bulk-cancel-resource: Annulation en masse de {resource}
bulk-actions: Actions en masse
column: Colonne
row: Ligne
table: Table
list: Liste
grid: Grille
form: Formulaire
field: Champ
section: Section
panel: Panneau
card: Carte
tab: Onglet
modal: Fenêtre modale
dialog: Dialogue
menu: Menu
dropdown: Menu déroulant
tooltip: Info-bulle
sidebar: Barre latérale
toolbar: Barre d'outils
footer: Pied de page
header: En-tête
title: Titre
subtitle: Sous-titre
description: Description
placeholder: Espace réservé
label: Étiquette
button: Bouton
icon: Icône
avatar: Avatar
link: Lien
badge: Badge
tag: Étiquette
banner: Bannière
step: Étape
progress: Progression
map: Carte
board: Tableau
loading: Chargement
loading-resource: Chargement de {resource}
saving: Enregistrement
processing: Traitement
fetching: Récupération
updating: Mise à jour
uploading: Téléversement
completed: Terminé
success: Succès
failed: Échec
error: Erreur
warning: Avertissement
info: Info
ready: Prêt
active: Actif
inactive: Inactif
enabled: Activé
disabled: Désactivé
online: En ligne
offline: Hors ligne
pending: En attente
archived: Archivé
hidden: Caché
visible: Visible
empty: Vide
not-found: Non trouvé
no-results: Aucun résultat
try-again: Réessayer
are-you-sure: Êtes-vous sûr ?
changes-saved: Modifications enregistrées avec succès.
saved-successfully: Modifications enregistrées avec succès.
field-saved: '{field} enregistré avec succès.'
changes-discarded: Modifications annulées.
delete-confirm: Êtes-vous sûr de vouloir supprimer cet élément ?
action-successful: Action réalisée avec succès.
action-failed: Échec de l'action. Veuillez réessayer.
something-went-wrong: Une erreur est survenue.
please-wait: Veuillez patienter...
sign-in: Se connecter
sign-out: Se déconnecter
sign-up: S'inscrire
log-in: Connexion
log-out: Déconnexion
register: S'enregistrer
forgot-password: Mot de passe oublié
reset-password: Réinitialiser le mot de passe
change-password: Changer le mot de passe
password: Mot de passe
confirm-password: Confirmer le mot de passe
email: Email
username: Nom d'utilisateur
remember-me: Se souvenir de moi
welcome: Bienvenue
welcome-back: Bon retour
profile: Profil
account: Compte
settings: Paramètres
preferences: Préférences
record: Enregistrement
records: Enregistrements
item: Élément
items: Articles
entry: Entrée
entries: Entrées
id: ID
name: Nom
type: Type
category: Catégorie
overview: Aperçu
value: Valeur
amount: Montant
price: Prix
quantity: Quantité
status: Statut
date: Date
date-created: Date de création
date-updated: Date de mise à jour
time: Heure
created-at: Créé le
updated-at: Mis à jour le
expired-at: Expiré le
last-seen-at: Dernière vue le
last-modified: Dernière modification
last-modified-data: 'Dernière modification : {date}'
actions: Actions
details: Détails
notes: Notes
reference: Référence
filter-by: Filtrer par
sort-by: Trier par
ascending: Ascendant
descending: Descendant
all: Tous
none: Aucun
select-all: Tout sélectionner
deselect-all: Tout désélectionner
show-more: Afficher plus
show-less: Afficher moins
page: Page
of: de
total: Total
items-per-page: Articles par page
showing: Affichage
to: à
results: Résultats
load-more: Charger plus
no-more-results: Plus de résultats
today: Aujourd'hui
yesterday: Hier
tomorrow: Demain
day: Jour
week: Semaine
month: Mois
year: Année
date-range: Plage de dates
start-date: Date de début
end-date: Date de fin
time-zone: Fuseau horaire
system: Système
dashboard: Tableau de bord
home: Accueil
analytics: Analytique
reports: Rapports
logs: Journaux
help: Aide
support: Support
contact: Contact
documentation: Documentation
language: Langue
version: Version
theme: Thème
light-mode: Mode clair
dark-mode: Mode sombre
update-available: Mise à jour disponible
install-update: Installer la mise à jour
maintenance-mode: Mode maintenance
notification: Notification
notifications: Notifications
mark-as-read: Marquer comme lu
mark-all-as-read: Tout marquer comme lu
clear-notifications: Effacer les notifications
company: Entreprise
companies: Entreprises
user: Utilisateur
users: Utilisateurs
role: Rôle
roles: Rôles
permission: Permission
permissions: Permissions
group: Groupe
groups: Groupes
unauthorized: Non autorisé
forbidden: Interdit
resource-not-found: Ressource non trouvée
server-error: Erreur serveur
validation-error: Erreur de validation
timeout-error: Délai de la requête dépassé
network-error: Erreur réseau
unknown-error: Erreur inconnue
file: Fichier
files: Fichiers
folder: Dossier
folders: Dossiers
upload-file: Téléverser un fichier
upload-files: Téléverser des fichiers
upload-image: Téléverser une image
upload-image-supported: Prend en charge les PNG, JPEG et GIF
choose-file: Choisir un fichier
choose-files: Choisir des fichiers
drag-and-drop: Glisser-déposer
download-file: Télécharger le fichier
file-size: Taille du fichier
file-type: Type de fichier
confirm-delete: Confirmer la suppression
confirm-action: Confirmer l'action
confirm-exit: Confirmer la sortie
confirm-and-save-changes: Confirmer et enregistrer les modifications
are-you-sure-exit: Êtes-vous sûr de vouloir quitter ?
unsaved-changes-warning: Vous avez des modifications non enregistrées.
connected: Connecté
disconnected: Déconnecté
reconnecting: Reconnexion
connection-lost: Connexion perdue
connection-restored: Connexion rétablie
show: Afficher
hide: Cacher
expand: Développer
collapse: Réduire
enable: Activer
disable: Désactiver
minimize: Minimiser
maximize: Maximiser
restore: Restaurer
zoom-in: Zoom avant
zoom-out: Zoom arrière
fullscreen: Plein écran
exit-fullscreen: Quitter le plein écran
true: 'true'
false: 'false'
ok: OK
none-available: Aucun disponible
default: Par défaut
custom: Personnalisé
general: Général
advanced: Avancé
placeholder-text: Entrez le texte ici...
learn-more: En savoir plus
view-resource: Voir {resource}
view-resource-details: Voir les détails de {resource}
create-a-new-resource: Créer un nouveau {resource}
create-new-resource: Créer un nouveau {resource}
search-resource: Rechercher {resource}
new-resource: Nouveau {resource}
update-resource: Mettre à jour {resource}
save-resource-changes: Enregistrer les modifications de {resource}
creating-resource: Création de {resource}
cancel-resource: Annuler {resource}
delete-resource: Supprimer {resource}
delete-resource-name: 'Supprimer : {resourceName}'
delete-resource-named: Supprimer {resource} ({resourceName})
delete-resource-prompt: Cette action est irréversible. Une fois supprimé, l'enregistrement
sera définitivement supprimé.
delete-cannot-be-undone: Cette action est irréversible. Une fois supprimé, l'enregistrement
sera définitivement supprimé.
create-resource: Créer {resource}
edit-resource: Modifier {resource}
edit-resource-details: Modifier les détails de {resource}
edit-resource-type-name: 'Modifier {resource} : {resourceName}'
edit-resource-name: 'Modifier : {resourceName}'
config: Configuration
select-field: Sélectionner {field}
columns: Colonnes
metadata: Métadonnées
meta: Meta
resource-created-success: Nouveau {resource} créé avec succès.
resource-created-success-name: Nouveau {resource} ({resourceName}) créé avec succès.
resource-updated-success: '{resource} ({resourceName}) mis à jour avec succès.'
resource-action-success: '{resource} ({resourceName}) {action} avec succès.'
resource-deleted-success: '{resource} ({resourceName}) supprimé avec succès.'
resource-deleted: '{resource} ({resourceName}) supprimé.'
continue-without-saving: Continuer sans enregistrer ?
continue-without-saving-prompt: Vous avez des modifications non enregistrées sur
ce {resource}. Continuer les supprimera. Cliquez sur Continuer pour poursuivre.
resource:
alert: Alerte
alerts: Alertes
brand: Marque
brands: Marques
category: Catégorie
categories: Catégories
chat-attachment: Pièce jointe de chat
chat-attachments: Pièces jointes de chat
chat-channel: Canal de chat
chat-channels: Canaux de chat
chat-log: Journal de chat
chat-logs: Journaux de chat
chat-message: Message de chat
chat-messages: Messages de chat
chat-participant: Participant au chat
chat-participants: Participants au chat
chat-receipt: Reçu de chat
chat-receipts: Reçus de chat
comment: Commentaire
comments: Commentaires
company: Entreprise
companies: Entreprises
custom-field-value: Valeur de champ personnalisé
custom-field-values: Valeurs de champ personnalisé
custom-field: Champ personnalisé
custom-fields: Champs personnalisés
dashboard-widget: Widget de tableau de bord
dashboard-widgets: Widgets de tableau de bord
dashboard: Tableau de bord
dashboards: Tableaux de bord
extension: Extension
extensions: Extensions
file: Fichier
files: Fichiers
group: Groupe
groups: Groupes
notification: Notification
notifications: Notifications
permission: Permission
permissions: Permissions
policy: Politique
policies: Politiques
report: Rapport
reports: Rapports
role: Rôle
roles: Rôles
setting: Paramètre
settings: Paramètres
transaction: Transaction
transactions: Transactions
user-device: Appareil utilisateur
user-devices: Appareils utilisateur
user: Utilisateur
users: Utilisateurs
dropzone:
file: fichier
drop-to-upload: Déposez pour télécharger
invalid: Invalide
files-ready-for-upload: '{numOfFiles} prêt(s) à être téléchargé(s).'
upload-images-videos: Télécharger des images et vidéos
upload-documents: Télécharger des documents
upload-documents-files: Télécharger des documents et fichiers
upload-avatar-files: Télécharger des avatars personnalisés
dropzone-supported-images-videos: Glissez-déposez des fichiers image et vidéo dans
cette zone
dropzone-supported-avatars: Glissez-déposez des fichiers SVG ou PNG
dropzone-supported-files: Glissez-déposez des fichiers dans cette zone
or-select-button-text: ou sélectionnez des fichiers à télécharger.
upload-queue: File d'attente de téléchargement
uploading: Téléchargement en cours...
two-fa-enforcement-alert:
message: Pour renforcer la sécurité de votre compte, votre organisation exige l'authentification
à deux facteurs (2FA). Activez la 2FA dans les paramètres de votre compte pour
une couche de protection supplémentaire.
button-text: Configurer la 2FA
comment-thread:
publish-comment-button-text: Publier le commentaire
publish-reply-button-text: Publier la réponse
reply-comment-button-text: Répondre
edit-comment-button-text: Modifier
delete-comment-button-text: Supprimer
comment-published-ago: il y a {createdAgo}
comment-input-placeholder: Saisissez un nouveau commentaire...
comment-reply-placeholder: Saisissez votre réponse...
comment-input-empty-notification: Vous ne pouvez pas publier de commentaires vides...
comment-min-length-notification: Le commentaire doit contenir au moins 2 caractères
dashboard:
select-dashboard: Sélectionner un tableau de bord
create-new-dashboard: Créer un nouveau tableau de bord
create-a-new-dashboard: Créer un nouveau tableau de bord
confirm-create-dashboard: Créer le tableau de bord !
edit-layout: Modifier la disposition
add-widgets: Ajouter des widgets
delete-dashboard: Supprimer le tableau de bord
save-dashboard: Enregistrer le tableau de bord
you-cannot-delete-this-dashboard: Vous ne pouvez pas supprimer ce tableau de bord.
are-you-sure-you-want-delete-dashboard: Êtes-vous sûr de vouloir supprimer ce {dashboardName}
?
dashboard-widget-panel:
widget-name: Widget {widgetName}
select-widgets: Sélectionner des widgets
close-and-save: Fermer et enregistrer
filters-picker:
filters: Filtres
filter-data: Filtrer les données
visible-column-picker:
select-viewable-columns: Sélectionner les colonnes visibles
customize-columns: Personnaliser les colonnes
component:
file:
dropdown-label: Actions sur le fichier
import-modal:
loading-message: Traitement de l'importation...
drop-upload: Déposez pour télécharger
invalid: Invalide
ready-upload: prêt à être téléchargé.
upload-spreadsheets: Télécharger des feuilles de calcul
drag-drop: Glissez et déposez les fichiers de feuilles de calcul sur cette zone
button-text: ou sélectionnez des feuilles de calcul à télécharger
spreadsheets: feuilles de calcul
upload-queue: File d'attente de téléchargement
dropzone:
file: fichier
drop-to-upload: Déposez pour télécharger
invalid: Invalide
files-ready-for-upload: '{numOfFiles} prêts à être téléchargés.'
upload-images-videos: Télécharger des images et vidéos
upload-documents: Télécharger des documents
upload-documents-files: Télécharger des documents et fichiers
upload-avatar-files: Télécharger des avatars personnalisés
dropzone-supported-images-videos: Glissez et déposez des fichiers image et vidéo
sur cette zone
dropzone-supported-avatars: Glissez et déposez des fichiers SVG ou PNG
dropzone-supported-files: Glissez et déposez des fichiers sur cette zone
or-select-button-text: ou sélectionnez des fichiers à télécharger.
upload-queue: File d'attente de téléchargement
uploading: Téléchargement en cours...
two-fa-enforcement-alert:
message: Pour renforcer la sécurité de votre compte, votre organisation exige
l'authentification à deux facteurs (2FA). Activez la 2FA dans les paramètres
de votre compte pour une couche de protection supplémentaire.
button-text: Configurer la 2FA
comment-thread:
publish-comment-button-text: Publier le commentaire
publish-reply-button-text: Publier la réponse
reply-comment-button-text: Répondre
edit-comment-button-text: Modifier
delete-comment-button-text: Supprimer
comment-published-ago: Il y a {createdAgo}
comment-input-placeholder: Saisissez un nouveau commentaire...
comment-reply-placeholder: Saisissez votre réponse...
comment-input-empty-notification: Vous ne pouvez pas publier de commentaires vides...
comment-min-length-notification: Le commentaire doit contenir au moins 2 caractères
dashboard:
select-dashboard: Sélectionner un tableau de bord
create-new-dashboard: Créer un nouveau tableau de bord
create-a-new-dashboard: Créer un nouveau tableau de bord
confirm-create-dashboard: Créer le tableau de bord !
edit-layout: Modifier la mise en page
add-widgets: Ajouter des widgets
delete-dashboard: Supprimer le tableau de bord
save-dashboard: Enregistrer le tableau de bord
you-cannot-delete-this-dashboard: Vous ne pouvez pas supprimer ce tableau de bord.
are-you-sure-you-want-delete-dashboard: Êtes-vous sûr de vouloir supprimer ce
{dashboardName} ?
dashboard-widget-panel:
widget-name: Widget {widgetName}
select-widgets: Sélectionner des widgets
close-and-save: Fermer et enregistrer
services:
dashboard-service:
create-dashboard-success-notification: Nouveau tableau de bord `{dashboardName}`
créé avec succès.
delete-dashboard-success-notification: Le tableau de bord `{dashboardName}` a
été supprimé.
auth:
verification:
header-title: Vérification du compte
title: Vérifiez votre adresse e-mail
message-text: <strong>Presque terminé !</strong><br> Vérifiez votre e-mail pour
un code de vérification.
verification-code-text: Entrez le code de vérification que vous avez reçu par
e-mail.
verification-input-label: Code de vérification
verify-button-text: Vérifier et continuer
didnt-receive-a-code: Vous n'avez pas encore reçu de code ?
not-sent:
message: Vous n'avez pas encore reçu de code ?
alternative-choice: Utilisez les options alternatives ci-dessous pour vérifier
votre compte.
resend-email: Renvoyer l'e-mail
send-by-sms: Envoyer par SMS
two-fa:
verify-code:
verification-code: Code de vérification
check-title: Vérifiez votre e-mail ou téléphone
check-subtitle: Nous vous avons envoyé un code de vérification. Entrez le code
ci-dessous pour terminer le processus de connexion.
expired-help-text: Votre code d'authentification 2FA a expiré. Vous pouvez demander
un autre code si vous avez besoin de plus de temps.
resend-code: Renvoyer le code
verify-code: Vérifier le code
cancel-two-factor: Annuler l'authentification à deux facteurs
invalid-session-error-notification: Session invalide. Veuillez réessayer.
verification-successful-notification: Vérification réussie !
verification-code-expired-notification: Le code de vérification a expiré. Veuillez
en demander un nouveau.
verification-code-failed-notification: Échec de la vérification. Veuillez réessayer.
resend-code:
verification-code-resent-notification: Nouveau code de vérification envoyé.
verification-code-resent-error-notification: Erreur lors de la réexpédition
du code de vérification. Veuillez réessayer.
forgot-password:
success-message: Vérifiez votre e-mail pour continuer !
is-sent:
title: Presque terminé !
message: <strong>Vérifiez votre email !</strong><br> Nous vous avons envoyé
un lien magique par email qui vous permettra de réinitialiser votre mot de
passe. Le lien expire dans 15 minutes.
not-sent:
title: Mot de passe oublié ?
message: <strong>Ne vous inquiétez pas, nous sommes là pour vous aider.</strong><br>
Entrez l'email que vous utilisez pour vous connecter à {appName} et nous vous
enverrons un lien sécurisé pour réinitialiser votre mot de passe.
form:
email-label: Votre adresse email
submit-button: OK, envoyez-moi un lien magique !
nevermind-button: Peu importe
login:
title: Connectez-vous à votre compte
no-identity-notification: Avez-vous oublié de saisir votre email ?
no-password-notification: Avez-vous oublié de saisir votre mot de passe ?
unverified-notification: Votre compte doit être vérifié pour continuer.
password-reset-required: Une réinitialisation du mot de passe est requise pour
continuer.
failed-attempt:
message: <strong>Mot de passe oublié ?</strong><br> Cliquez sur le bouton ci-dessous
pour réinitialiser votre mot de passe.
button-text: D'accord, aidez-moi à réinitialiser !
form:
email-label: Adresse email
password-label: Mot de passe
remember-me-label: Se souvenir de moi
forgot-password-label: Mot de passe oublié ?
sign-in-button: Se connecter
create-account-button: Créer un nouveau compte
slow-connection-message: Problèmes de connexion en cours.
reset-password:
success-message: Votre mot de passe a été réinitialisé ! Connectez-vous pour continuer.
invalid-verification-code: Ce lien de réinitialisation de mot de passe est invalide
ou expiré.
title: Réinitialisez votre mot de passe
form:
code:
label: Votre code de réinitialisation
help-text: Le code de vérification que vous avez reçu par email.
password:
label: Nouveau mot de passe
help-text: Entrez un mot de passe d'au moins 6 caractères pour continuer.
confirm-password:
label: Confirmez le nouveau mot de passe
help-text: Entrez un mot de passe d'au moins 6 caractères pour continuer.
submit-button: Réinitialiser le mot de passe
back-button: Retour
console:
create-or-join-organization:
modal-title: Créer ou rejoindre une organisation
join-success-notification: Vous avez rejoint une nouvelle organisation !
create-success-notification: Vous avez créé une nouvelle organisation !
switch-organization:
modal-title: Êtes-vous sûr de vouloir changer d'organisation pour {organizationName}
?
modal-body: En confirmant, votre compte restera connecté, mais votre organisation
principale sera changée.
modal-accept-button-text: Oui, je veux changer d'organisation
success-notification: Vous avez changé d'organisation
account:
index:
upload-new: Télécharger nouveau
phone: Votre numéro de téléphone.
photos: photos
timezone: Sélectionnez votre fuseau horaire.
admin:
menu:
overview: Vue d'ensemble
organizations: Organisations
branding: Image de marque
2fa-config: Configuration 2FA
schedule-monitor: Surveillance du planning
services: Services
mail: Courrier
filesystem: Système de fichiers
queue: File d'attente
socket: Socket
push-notifications: Notifications Push
schedule-monitor:
schedule-monitor: Moniteur de planification
task-logs-for: 'Journaux des tâches pour : '
showing-last-count: Affichage des {count} derniers journaux
name: Nom
type: Type
timezone: Fuseau horaire
last-started: Dernier démarrage
last-finished: Dernière fin
last-failure: Dernier échec
date: Date
memory: Mémoire
runtime: Durée d'exécution
output: Sortie
no-output: Pas de sortie
config:
database:
title: Configuration de la base de données
filesystem:
title: Configuration du système de fichiers
mail:
title: Configuration du courrier
notification-channels:
title: Configuration des notifications push
queue:
title: Configuration de la file d'attente
services:
title: Configuration des services
socket:
title: Configuration du socket
branding:
title: Image de marque
icon-text: Icône
upload-new: Télécharger nouveau
reset-default: Réinitialiser par défaut
logo-text: Logo
theme: Thème par défaut
index:
total-users: Nombre total d'utilisateurs
total-organizations: Nombre total d'organisations
total-transactions: Nombre total de transactions
notifications:
title: Notifications
notification-settings: Paramètres des notifications
organizations:
index:
title: Organisations
owner-name-column: Propriétaire
owner-phone-column: Téléphone du propriétaire
owner-email-column: Téléphone du propriétaire
users-count-column: Utilisateurs
phone-column: Téléphone
email-column: Email
users:
title: Utilisateurs
settings:
index:
title: Paramètres de l'organisation
organization-name: Nom de l'organisation
organization-description: Description de l'organisation
organization-phone: Numéro de téléphone de l'organisation
organization-currency: Devise de l'organisation
organization-id: ID de l'organisation
organization-branding: Image de marque de l'organisation
logo: Logo
logo-help-text: Logo de votre organisation.
upload-new-logo: Télécharger un nouveau logo
backdrop: Fond
backdrop-help-text: Bannière ou image de fond optionnelle pour votre organisation.
upload-new-backdrop: Télécharger un nouveau fond
organization-timezone: Sélectionnez le fuseau horaire par défaut pour votre
organisation.
select-timezone: Sélectionnez le fuseau horaire.
extensions:
title: Les extensions arrivent bientôt !
message: Veuillez revenir dans les prochaines versions pendant que nous préparons
le lancement du dépôt et du marché des extensions.
notifications:
select-all: Tout sélectionner
mark-as-read: Marquer comme lu
received: 'Reçu :'
message: Aucune notification à afficher.
invite:
for-users:
invitation-message: Vous avez été invité à rejoindre {companyName}
invitation-sent-message: Vous avez été invité à rejoindre l'organisation {companyName}
sur {appName}. Pour accepter cette invitation, saisissez votre code d'invitation
reçu par email et cliquez sur continuer.
invitation-code-sent-text: Votre code d'invitation
accept-invitation-text: Accepter l'invitation
onboard:
index:
title: Créez votre compte
welcome-title: <strong>Bienvenue chez {companyName} !</strong><br />
welcome-text: Complétez les informations requises ci-dessous pour commencer.
full-name: Nom complet
full-name-help-text: Votre nom complet
your-email: Adresse e-mail
your-email-help-text: Votre adresse e-mail
phone: Numéro de téléphone
phone-help-text: Votre numéro de téléphone
organization-name: Nom de l'organisation
organization-help-text: Le nom de votre organisation, tous vos services et ressources
seront gérés sous cette organisation, vous pourrez ensuite créer autant d'organisations
que vous le souhaitez ou en avez besoin.
password: Entrez un mot de passe
password-help-text: Votre mot de passe, assurez-vous qu'il soit solide.
confirm-password: Confirmez votre mot de passe
confirm-password-help-text: Juste pour confirmer le mot de passe que vous avez
saisi ci-dessus.
continue-button-text: Continuer
verify-email:
header-title: Vérification du compte
title: Vérifiez votre adresse e-mail
message-text: <strong>Presque terminé !</strong><br> Vérifiez votre e-mail pour
un code de vérification.
verification-code-text: Entrez le code de vérification que vous avez reçu par
e-mail.
verification-input-label: Code de vérification
verify-button-text: Vérifier & Continuer
didnt-receive-a-code: Vous n'avez pas encore reçu de code ?
not-sent:
message: Vous n'avez pas encore reçu de code ?
alternative-choice: Utilisez les options alternatives ci-dessous pour vérifier
votre compte.
resend-email: Renvoyer l'e-mail
send-by-sms: Envoyer par SMS
install:
installer-header: Installateur
failed-message-sent: L'installation a échoué ! Cliquez sur le bouton ci-dessous
pour réessayer l'installation.
retry-install: Réessayer l'installation
start-install: Démarrer l'installation
layout:
header:
menus:
organization:
settings: Paramètres de l'organisation
create-or-join: Créer ou rejoindre des organisations
explore-extensions: Explorer les extensions
user:
view-profile: Voir le profil
keyboard-shortcuts: Afficher les raccourcis clavier
changelog: Journal des modifications

View File

@@ -0,0 +1,770 @@
app:
name: Fleetbase
common:
new: Шинэ
create: Үүсгэх
add: Нэмэх
edit: Засах
update: Шинэчлэх
save: Хадгалах
save-changes: Өөрчлөлтийг хадгалах
delete: Устгах
delete-selected: Сонгосон устгах
delete-selected-count: '{count} ширхэгийг устгах'
remove: Хасах
cancel: Цуцлах
confirm: Батлах
close: Хаах
open: Нээх
view: Харах
preview: Урьдчилсан харалт
upload: Ачаалах
download: Татаж авах
import: Импортлох
export: Экспортлох
print: Хэвлэх
duplicate: Хуулбарлах
copy: Хуулах
paste: Наах
share: Хуваалцах
refresh: Шинэчлэх
reset: Дахин тохируулах
retry: Дахин оролдох
back: Буцах
next: Дараах
previous: Өмнөх
submit: Илгээх
apply: Хэрэглэх
continue: Үргэлжлүүлэх
proceed: Үргэлжлүүлэх
select: Сонгох
deselect: Сонголтыг цуцлах
search: Хайх
filter: Шүүлтүүр
sort: Эрэмбэлэх
view-all: Бүгдийг харах
clear: Цэвэрлэх
done: Болсон
finish: Дуусгах
skip: Алгасах
method: Арга
bulk-delete: Бөөнөөр устгах
bulk-delete-resource: Бөөнөөр устгах {resource}
bulk-cancel: Бөөн цуцлах
bulk-cancel-resource: Бөөн цуцлах {resource}
bulk-actions: Бөөн үйлдлүүд
column: Багана
row: Мөр
table: Хүснэгт
list: Жагсаалт
grid: Сүлжээ
form: Форм
field: Талбар
section: Хэсэг
panel: Самбар
card: Карт
tab: Хуудас
modal: Модал
dialog: Диалог
menu: Цэс
dropdown: Унждаг цэс
tooltip: Тайлбар
sidebar: Хажуугийн самбар
toolbar: Хэрэгслийн самбар
footer: Доод хэсэг
header: Дээд хэсэг
title: Гарчиг
subtitle: Дэд гарчиг
description: Тодорхойлолт
placeholder: Түгээмэл орлуулах текст
label: Шошго
button: Товч
icon: Тэмдэг
avatar: Профайл зураг
link: Холбоос
badge: Шагнал
tag: Таг
banner: Туг
step: Алхам
progress: Ахиц
map: Газрын зураг
board: Самбар
loading: Ачааллаж байна
loading-resource: '{resource} ачааллаж байна'
saving: Хадгалж байна
processing: Боловсруулж байна
fetching: Угсарч байна
updating: Шинэчилж байна
uploading: Ачааллаж байна
completed: Дууссан
success: Амжилттай
failed: Амжилтгүй
error: Алдаа
warning: Анхааруулга
info: Мэдээлэл
ready: Бэлэн
active: Идэвхтэй
inactive: Идэвхгүй
enabled: Идэвхжсэн
disabled: Идэвхгүй болгосон
online: Онлайн
offline: Оффлайн
pending: Хүлээгдэж буй
archived: Архивлагдсан
hidden: Нуугдсан
visible: Ил харагдах
empty: Хоосон
not-found: Олдсонгүй
no-results: Үр дүн олдсонгүй
try-again: Дахин оролдоно уу
are-you-sure: Та итгэлтэй байна уу?
changes-saved: Өөрчлөлтүүд амжилттай хадгалагдлаа.
saved-successfully: Өөрчлөлтүүд амжилттай хадгалагдлаа.
field-saved: '{field} амжилттай хадгалагдлаа.'
changes-discarded: Өөрчлөлтүүд устгагдлаа.
delete-confirm: Та энэ зүйл устгахдаа итгэлтэй байна уу?
action-successful: Үйлдэл амжилттай боллоо.
action-failed: Үйлдэл амжилтгүй боллоо. Дахин оролдоно уу.
something-went-wrong: Ямар нэг зүйл буруу боллоо.
please-wait: Түр хүлээнэ үү...
sign-in: Нэвтрэх
sign-out: Гарах
sign-up: Бүртгүүлэх
log-in: Нэвтрэх
log-out: Гарах
register: Бүртгүүлэх
forgot-password: Нууц үгээ мартсан
reset-password: Нууц үг сэргээх
change-password: Нууц үг солих
password: Нууц үг
confirm-password: Нууц үгээ баталгаажуулах
email: И-мэйл
username: Хэрэглэгчийн нэр
remember-me: Намайг сана
welcome: Тавтай морил
welcome-back: Дахин тавтай морил
profile: Профайл
account: Данс
settings: Тохиргоо
preferences: Тохиргоо
record: Бичлэг
records: Бичлэгүүд
item: Зүйл
items: Бараа
entry: Оролт
entries: Оролтууд
id: ID
name: Нэр
type: Төрөл
category: Ангилал
overview: Тойм
value: Үнэлгээ
amount: Тоо хэмжээ
price: Үнэ
quantity: Тоо ширхэг
status: Төлөв
date: Огноо
date-created: Үүсгэсэн огноо
date-updated: Шинэчилсэн огноо
time: Цаг
created-at: Үүсгэсэн газар
updated-at: Шинэчилсэн газар
expired-at: Хугацаа дууссан
last-seen-at: Сүүлд харагдсан
last-modified: Сүүлд өөрчлөгдсөн
last-modified-data: 'Сүүлд өөрчлөгдсөн: {date}'
actions: Үйлдлүүд
details: Дэлгэрэнгүй
notes: Тэмдэглэл
reference: Лавлагаа
filter-by: Шүүлтүүрээр
sort-by: Эрэмбэлэх
ascending: Өсөх дарааллаар
descending: Буурах дарааллаар
all: Бүгд
none: Ямар ч
select-all: Бүгдийг сонгох
deselect-all: Бүгдийг цуцлах
show-more: Илүүг үзүүлэх
show-less: Багаг үзүүлэх
page: Хуудас
of: нийт
total: Нийт
items-per-page: Хуудас бүрийн бараа
showing: Үзүүлж байна
to: хүртэл
results: Үр дүн
load-more: Илүү ачааллах
no-more-results: Илүү үр дүн алга
today: Өнөөдөр
yesterday: Өчигдөр
tomorrow: Маргааш
day: Өдөр
week: Долоо хоног
month: Сар
year: Жил
date-range: Огнооны хүрээ
start-date: Эхлэх огноо
end-date: Дуусах огноо
time-zone: Цагийн бүс
system: Систем
dashboard: Хяналтын самбар
home: Нүүр
analytics: Аналитик
reports: Тайлангууд
logs: Тэмдэглэлүүд
help: Тусламж
support: Дэмжлэг
contact: Холбоо барих
documentation: Баримт бичиг
language: Хэл
version: Хувилбар
theme: Сэдэв
light-mode: Гэрэлтэй горим
dark-mode: Харанхуй горим
update-available: Шинэчлэлт бэлэн байна
install-update: Шинэчлэл суулгах
maintenance-mode: Үйлчилгээний горим
notification: Мэдэгдэл
notifications: Мэдэгдлүүд
mark-as-read: Уншсан гэж тэмдэглэх
mark-all-as-read: Бүгдийг уншсан гэж тэмдэглэх
clear-notifications: Мэдэгдлийг цэвэрлэх
company: Компани
companies: Компаниуд
user: Хэрэглэгч
users: Хэрэглэгчид
role: Үүрэг
roles: Үүргүүд
permission: Зөвшөөрөл
permissions: Зөвшөөрлүүд
group: Бүлэг
groups: Бүлгүүд
unauthorized: Зөвшөөрөлгүй
forbidden: Хориглосон
resource-not-found: Ресурс олдсонгүй
server-error: Серверийн алдаа
validation-error: Баталгаажуулалтын алдаа
timeout-error: Хүсэлт хугацаа дууссан
network-error: Сүлжээний алдаа
unknown-error: Тодорхойгүй алдаа
file: Файл
files: Файлууд
folder: Фолдер
folders: Фолдерууд
upload-file: Файл оруулах
upload-files: Файлууд оруулах
upload-image: Зураг оруулах
upload-image-supported: PNG, JPEG болон GIF дэмжигддэг
choose-file: Файл сонгох
choose-files: Файлууд сонгох
drag-and-drop: Чирж тавих
download-file: Файл татаж авах
file-size: Файлын хэмжээ
file-type: Файлын төрөл
confirm-delete: Устгахыг баталгаажуулах
confirm-action: Үйлдлийг баталгаажуулах
confirm-exit: Гарахыг баталгаажуулах
confirm-and-save-changes: Баталгаажуулж, өөрчлөлтийг хадгалах
are-you-sure-exit: Гарахдаа итгэлтэй байна уу?
unsaved-changes-warning: Танд хадгалаагүй өөрчлөлтүүд байна.
connected: Холбогдсон
disconnected: Тасарсан
reconnecting: Дахин холбогдож байна
connection-lost: Холболт тасарсан
connection-restored: Холболт сэргээгдсэн
show: Үзүүлэх
hide: Нуух
expand: Тэлэх
collapse: Агших
enable: Идэвхжүүлэх
disable: Идэвхгүй болгох
minimize: Богиносгох
maximize: Дээд зэргээр томруулах
restore: Сэргээх
zoom-in: Ойртуулах
zoom-out: Холдуулах
fullscreen: Дэлгэц дүүрэн
exit-fullscreen: Дэлгэц дүүрэн горимоос гарах
true: "true"
false: "false"
ok: Зөвшөөрөх
none-available: Боломжгүй
default: Анхдагч
custom: Захиалгат
general: Ерөнхий
advanced: Ахисан түвшин
placeholder-text: Энд текст оруулна уу...
learn-more: Илүү ихийг мэдэх
view-resource: '{resource} харах'
view-resource-details: '{resource} дэлгэрэнгүй харах'
create-a-new-resource: Шинэ {resource} үүсгэх
create-new-resource: Шинэ {resource} үүсгэх
search-resource: '{resource} хайх'
new-resource: Шинэ {resource}
update-resource: '{resource}-ийг шинэчлэх'
save-resource-changes: '{resource}-ийн өөрчлөлтүүдийг хадгалах'
creating-resource: '{resource} үүсгэж байна'
cancel-resource: '{resource}-ийг цуцлах'
delete-resource: '{resource}-ийг устгах'
delete-resource-name: 'Устгах: {resourceName}'
delete-resource-named: '{resource} ({resourceName}) устгах'
delete-resource-prompt: Энэ үйлдлийг буцаах боломжгүй. Устгасны дараа бүртгэл бүрмөсөн
устгагдана.
delete-cannot-be-undone: Энэ үйлдлийг буцаах боломжгүй. Устгасны дараа бүртгэл бүрмөсөн
устгагдана.
create-resource: '{resource} үүсгэх'
edit-resource: '{resource}-ийг засах'
edit-resource-details: '{resource}-ийн дэлгэрэнгүй мэдээллийг засах'
edit-resource-type-name: '{resource}: {resourceName} засах'
edit-resource-name: 'Засах: {resourceName}'
config: Тохиргоо
select-field: '{field}-ийг сонгох'
columns: Баганууд
metadata: Метадата
meta: Мета
resource-created-success: Шинэ {resource} амжилттай үүслээ.
resource-created-success-name: Шинэ {resource} ({resourceName}) амжилттай үүслээ.
resource-updated-success: '{resource} ({resourceName}) амжилттай шинэчлэгдлээ.'
resource-action-success: '{resource} ({resourceName}) {action} амжилттай боллоо.'
resource-deleted-success: '{resource} ({resourceName}) амжилттай устгагдлаа.'
resource-deleted: '{resource} ({resourceName}) устгагдсан.'
continue-without-saving: Хадгалалгүй үргэлжлүүлэх үү?
continue-without-saving-prompt: Танд энэ {resource}-ийн хадгалагдаагүй өөрчлөлтүүд
байна. Үргэлжлүүлэхэд эдгээр өөрчлөлтүүд устах болно. Үргэлжлүүлэхийг дарна уу.
resource:
alert: Анхааруулга
alerts: Анхааруулгууд
brand: Брэнд
brands: Брэндүүд
category: Ангилал
categories: Ангилалууд
chat-attachment: Чатын хавсралт
chat-attachments: Чатын хавсралтууд
chat-channel: Чатын суваг
chat-channels: Чатын сувгууд
chat-log: Чатын бүртгэл
chat-logs: Чатын бүртгэлүүд
chat-message: Чатын мессеж
chat-messages: Чатын мессежүүд
chat-participant: Чатын оролцогч
chat-participants: Чатын оролцогчид
chat-receipt: Чатын баримт
chat-receipts: Чатын баримтууд
comment: Сэтгэгдэл
comments: Сэтгэгдлүүд
company: Компанийн
companies: Компаниуд
custom-field-value: Захиалгат талбарын утга
custom-field-values: Захиалгат талбарын утгууд
custom-field: Захиалгат талбар
custom-fields: Захиалгат талбарууд
dashboard-widget: Хянах самбарын виджет
dashboard-widgets: Хянах самбарын виджетүүд
dashboard: Хянах самбар
dashboards: Хянах самбарууд
extension: Өргөтгөл
extensions: Өргөтгөлүүд
file: Файл
files: Файлууд
group: Бүлэг
groups: Бүлгүүд
notification: Мэдэгдэл
notifications: Мэдэгдлүүд
permission: Зөвшөөрөл
permissions: Зөвшөөрлүүд
policy: Бодлого
policies: Бодлогууд
report: Тайлан
reports: Тайлангууд
role: Үүрэг
roles: Үүргүүд
setting: Тохиргоо
settings: Тохиргоонууд
transaction: Гүйлгээ
transactions: Гүйлгээүүд
user-device: Хэрэглэгчийн төхөөрөмж
user-devices: Хэрэглэгчийн төхөөрөмжүүд
user: Хэрэглэгч
users: Хэрэглэгчид
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: Хаах ба хадгалах
filters-picker:
filters: Шүүлтүүрүүд
filter-data: Өгөгдлийг шүүх
visible-column-picker:
select-viewable-columns: Үзэгдэх багануудыг сонгох
customize-columns: Багануудыг тохируулах
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: зурагнууд
timezone: Цагийн бүсээ сонгоно уу.
admin:
menu:
overview: Тойм
organizations: Байгууллагууд
branding: Брэндинг
2fa-config: 2FA тохиргоо
schedule-monitor: Хуваарь хянах
services: Үйлчилгээ
mail: И-мэйл
filesystem: Файлын систем
queue: Эрэмбэлсэн жагсаалт
socket: Сокет
push-notifications: Түлхэх мэдэгдэл
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: Түлхэх мэдэгдлийн тохиргоо
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: Байгууллагын ID
organization-branding: Байгууллагын брэнд
logo: Лого
logo-help-text: Таны байгууллагын лого.
upload-new-logo: Шинэ лого оруулах
backdrop: Дэвсгэр зураг
backdrop-help-text: Таны байгууллагад зориулсан нэмэлт баннер эсвэл дэвсгэр
зураг.
upload-new-backdrop: Шинэ дэвсгэр зураг оруулах
organization-timezone: Таны байгууллагын үндсэн цагийн бүсийг сонгоно уу.
select-timezone: Цагийн бүс сонгох.
extensions:
title: Өргөтгөлүүд удахгүй ирнэ!
message: Өргөтгөлүүдийн сан болон зах зээлийг нээхэд бэлдэж байгаа тул дараагийн
хувилбаруудаа шалгаарай.
notifications:
select-all: Бүгдийг Сонгох
mark-as-read: Уншсан гэж тэмдэглэх
received: 'Хүлээн авсан:'
message: Үзүүлэх мэдэгдэл алга.
invite:
for-users:
invitation-message: Танд {companyName} нэгдэх урилга ирлээ
invitation-sent-message: '{appName} дээрх {companyName} байгууллагад нэгдэх урилгыг
танд илгээсэн. Урилгыг хүлээн авахын тулд имэйлээр авсан урилгын кодоо оруулж
үргэлжлүүлнэ үү.'
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: Өөрчлөлтийн түүх

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