mirror of
https://github.com/fleetbase/fleetbase.git
synced 2026-01-03 12:57:05 +00:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62c396b789 | ||
|
|
295da5f331 | ||
|
|
e775ccc2c8 | ||
|
|
bd0759881f | ||
|
|
830ae69b1d | ||
|
|
3b9a80866f | ||
|
|
76badbf949 | ||
|
|
f968556585 | ||
|
|
6d01eab305 | ||
|
|
9406446db1 | ||
|
|
565db7bbce | ||
|
|
003cb467e8 | ||
|
|
8e1b281e77 | ||
|
|
af4507cc87 | ||
|
|
2a2c7d8426 | ||
|
|
077a4298b9 | ||
|
|
af840d30d0 | ||
|
|
a253c0c6f7 | ||
|
|
0fc1d6068d | ||
|
|
6993510d08 | ||
|
|
4fcf09c1b8 | ||
|
|
f89596a74b | ||
|
|
d89e93f248 | ||
|
|
2f0c15bc93 | ||
|
|
ae6c07006b | ||
|
|
d754641493 | ||
|
|
bb0d706006 | ||
|
|
652bc363e1 | ||
|
|
363309af61 | ||
|
|
83791ea91c |
2
.github/workflows/cd.yml
vendored
2
.github/workflows/cd.yml
vendored
@@ -147,7 +147,7 @@ jobs:
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
pnpm build
|
||||
pnpm build --environment production
|
||||
working-directory: ./console
|
||||
|
||||
- name: Deploy Console 🚀
|
||||
|
||||
2
.github/workflows/gcp-cd.yml
vendored
2
.github/workflows/gcp-cd.yml
vendored
@@ -173,7 +173,7 @@ jobs:
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
pnpm build
|
||||
pnpm build --environment production
|
||||
working-directory: ./console
|
||||
|
||||
- name: Deploy Console 🚀
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^7.3|^8.0",
|
||||
"fleetbase/core-api": "^1.4.0",
|
||||
"fleetbase/fleetops-api": "^0.4.7",
|
||||
"fleetbase/storefront-api": "^0.2.11",
|
||||
"php": "^8.0",
|
||||
"fleetbase/core-api": "^1.4.7",
|
||||
"fleetbase/fleetops-api": "^0.4.13",
|
||||
"fleetbase/storefront-api": "^0.3.1",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/octane": "^2.3",
|
||||
@@ -20,7 +20,8 @@
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"phpoffice/phpspreadsheet": "^1.28",
|
||||
"predis/predis": "^2.1",
|
||||
"psr/http-factory-implementation": "*"
|
||||
"psr/http-factory-implementation": "*",
|
||||
"s-ichikawa/laravel-sendgrid-driver": "^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"spatie/laravel-ignition": "^2.0",
|
||||
|
||||
1152
api/composer.lock
generated
1152
api/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ return [
|
||||
|
||||
'allowed_methods' => ['*'],
|
||||
|
||||
'allowed_origins' => array_filter(['http://localhost:4200', env('CONSOLE_HOST'), Utils::addWwwToUrl(env('CONSOLE_URL'))]),
|
||||
'allowed_origins' => array_filter(['http://localhost:4200', env('CONSOLE_HOST'), Utils::addWwwToUrl(env('CONSOLE_HOST'))]),
|
||||
|
||||
'allowed_origins_patterns' => [],
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ WORKDIR /app
|
||||
RUN mkdir -p ~/.pnpm
|
||||
ENV PNPM_HOME /root/.pnpm
|
||||
|
||||
# Set environment
|
||||
ARG ENVIRONMENT=production
|
||||
|
||||
# Add the pnpm global bin to the PATH
|
||||
ENV PATH /root/.pnpm/bin:$PATH
|
||||
|
||||
@@ -33,7 +36,7 @@ RUN pnpm install
|
||||
COPY console .
|
||||
|
||||
# Build the application
|
||||
RUN pnpm build
|
||||
RUN pnpm build --environment $ENVIRONMENT
|
||||
|
||||
# ---- Serve Stage ----
|
||||
FROM nginx:alpine
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<Textarea class="form-input w-full" @value={{this.apn.private_key_content}} placeholder="APN Private Key" rows="10" disabled={{this.isLoading}} />
|
||||
</InputGroup> --}}
|
||||
<InputGroup @wrapperClass="flex flex-row items-center">
|
||||
<UploadButton @name="apn-key" @accept="text/plain,application/x-pem-file,application/x-pkcs12,application/x-x509-ca-cert,.p12,.pem,.p8" @onFileAdded={{this.uploadApnKey}} @buttonText="Upload P8 Key File" @uploadIcon="upload" class="w-auto m-0i mt-0i" />
|
||||
<UploadButton @name="apn-key" @accept="text/plain,application/x-pem-file,application/x-pkcs12,application/x-x509-ca-cert,.p12,.pem,.p8" @onFileAdded={{this.uploadApnKey}} @buttonText="Upload P8 Key File" @icon="upload" class="w-auto m-0i mt-0i" />
|
||||
{{#if this.apn.private_key_file}}
|
||||
<div class="ml-2.5 text-sm dark:text-white text-black flex flex-row items-center border border-blue-500 rounded-lg px-2 py-0.5 -mt-1">
|
||||
<FaIcon @icon="file-text" @size="sm" class="mr-2 dark:text-white text-black" />
|
||||
@@ -15,16 +15,32 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroup @wrapperClass="mb-0i">
|
||||
<Checkbox @label="APN Production" @value={{this.apn.production}} @onToggle={{fn (mut this.apn.production)}} @disabled={{this.isLoading}} />
|
||||
</InputGroup>
|
||||
</ContentPanel>
|
||||
|
||||
<ContentPanel @title="Firebase Configutation" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
|
||||
<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}}
|
||||
<div class="ml-2.5 text-sm dark:text-white text-black flex flex-row items-center border border-blue-500 rounded-lg px-2 py-0.5 -mt-1">
|
||||
<FaIcon @icon="file-text" @size="sm" class="mr-2 dark:text-white text-black" />
|
||||
<span>{{this.firebase.credentials_file.original_filename}}</span>
|
||||
<a href="javascript:;" class="text-red-500 ml-2" {{on "click" this.removeFirebaseCredentialsFile}}><FaIcon @icon="times" class="text-red-500" /></a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</InputGroup>
|
||||
</ContentPanel>
|
||||
|
||||
<ContentPanel @title="Test Push Notification" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-900">
|
||||
{{#if this.testResponse}}
|
||||
<div class="animate-pulse flex flex-row items-center rounded-lg border {{if (eq this.testResponse.status 'error') 'border-red-900 bg-red-800 text-red-100' 'border-green-900 bg-green-800 text-green-100'}} shadow-sm my-2 px-4 py-2">
|
||||
<FaIcon @icon={{if (eq this.testResponse.status 'error') 'triangle-exclamation' 'circle-check'}} class="mr-1.5 {{if (eq this.testResponse.status 'error') 'text-red-200' 'text-green-200'}}" />
|
||||
<span class="text-xs">{{this.this.testResponse.message}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="mt-3 rounded-lg bg-gray-900 shadow-inner p-3">
|
||||
<div class="">
|
||||
<div class="flex flex-col space-y-2">
|
||||
<div class="flex flex-row items-center">
|
||||
<div class="text-sm w-40">Title:</div>
|
||||
@@ -47,6 +63,8 @@
|
||||
</div>
|
||||
</ContentPanel>
|
||||
|
||||
<Spacer @height="300px" />
|
||||
|
||||
<EmberWormhole @to="next-view-section-subheader-actions">
|
||||
<Button @type="primary" @size="sm" @icon="save" @text="Save Changes" @onClick={{this.save}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
|
||||
</EmberWormhole>
|
||||
@@ -18,14 +18,13 @@ export default class ConfigureNotificationChannelsComponent extends Component {
|
||||
team_id: '',
|
||||
app_bundle_id: '',
|
||||
private_key_path: '',
|
||||
_private_key_path: '',
|
||||
private_key_file_id: '',
|
||||
private_key_file: null,
|
||||
production: true,
|
||||
};
|
||||
@tracked fcm = {
|
||||
firebase_credentials_json: '',
|
||||
firebase_database_url: '',
|
||||
firebase_project_name: '',
|
||||
@tracked firebase = {
|
||||
credentials: ''
|
||||
};
|
||||
|
||||
constructor() {
|
||||
@@ -38,26 +37,37 @@ export default class ConfigureNotificationChannelsComponent extends Component {
|
||||
apnConfig.private_key_file = null;
|
||||
apnConfig.private_key_file_id = '';
|
||||
apnConfig.private_key_path = '';
|
||||
apnConfig._private_key_path = '';
|
||||
|
||||
this.apn = apnConfig;
|
||||
}
|
||||
|
||||
@action removeFirebaseCredentialsFile() {
|
||||
const firebaseConfig = this.firebase;
|
||||
firebaseConfig.credentials_file = null;
|
||||
firebaseConfig.credentials_file_id = '';
|
||||
firebaseConfig.credentials = '';
|
||||
|
||||
this.firebase = firebaseConfig;
|
||||
}
|
||||
|
||||
@action uploadApnKey(file) {
|
||||
try {
|
||||
this.fetch.uploadFile.perform(
|
||||
file,
|
||||
{
|
||||
disk: 'local',
|
||||
path: `apn`,
|
||||
path: 'apn',
|
||||
subject_uuid: this.currentUser.companyId,
|
||||
subject_type: `company`,
|
||||
type: `apn_key`,
|
||||
subject_type: 'company',
|
||||
type: 'apn_key',
|
||||
},
|
||||
(uploadedFile) => {
|
||||
const apnConfig = this.apn;
|
||||
apnConfig.private_key_file = uploadedFile;
|
||||
apnConfig.private_key_file_id = uploadedFile.id;
|
||||
apnConfig.private_key_path = uploadedFile.path;
|
||||
apnConfig._private_key_path = uploadedFile.path;
|
||||
|
||||
this.apn = apnConfig;
|
||||
}
|
||||
@@ -67,6 +77,31 @@ export default class ConfigureNotificationChannelsComponent extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
@action uploadFirebaseCredentials(file) {
|
||||
try {
|
||||
this.fetch.uploadFile.perform(
|
||||
file,
|
||||
{
|
||||
disk: 'local',
|
||||
path: 'firebase',
|
||||
subject_uuid: this.currentUser.companyId,
|
||||
subject_type: 'company',
|
||||
type: 'firebase_credentials',
|
||||
},
|
||||
(uploadedFile) => {
|
||||
const firebaseConfig = this.firebase;
|
||||
firebaseConfig.credentials_file = uploadedFile;
|
||||
firebaseConfig.credentials_file_id = uploadedFile.id;
|
||||
firebaseConfig.credentials_file_path = uploadedFile.path;
|
||||
|
||||
this.firebase = firebaseConfig;
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
this.notifications.serverError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@action setConfigValues(config) {
|
||||
for (const key in config) {
|
||||
if (this[key] !== undefined) {
|
||||
@@ -94,9 +129,13 @@ export default class ConfigureNotificationChannelsComponent extends Component {
|
||||
const apnConfig = this.apn;
|
||||
delete apnConfig.private_key_file;
|
||||
|
||||
const firebaseConfig = this.firebase;
|
||||
delete firebaseConfig.credentials_file;
|
||||
|
||||
this.fetch
|
||||
.post('settings/notification-channels-config', {
|
||||
apn: apnConfig,
|
||||
firebase: firebaseConfig,
|
||||
})
|
||||
.then(() => {
|
||||
this.notifications.success("Notification channel's configuration saved.");
|
||||
@@ -112,6 +151,7 @@ export default class ConfigureNotificationChannelsComponent extends Component {
|
||||
this.fetch
|
||||
.post('settings/test-notification-channels-config', {
|
||||
apn: this.apn,
|
||||
firebase: this.firebase,
|
||||
title: this.testTitle,
|
||||
message: this.testMessage,
|
||||
apnToken: this.apnToken,
|
||||
|
||||
@@ -2,6 +2,7 @@ import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
/**
|
||||
* Controller responsible for handling two-factor authentication.
|
||||
* @class AuthTwoFaController
|
||||
@@ -53,6 +54,8 @@ export default class AuthTwoFaController extends Controller {
|
||||
|
||||
/**
|
||||
* The current 2FA identity in memory
|
||||
* @property {string} identity
|
||||
* @tracked
|
||||
*/
|
||||
@tracked identity;
|
||||
|
||||
|
||||
@@ -51,6 +51,13 @@ export default class ConsoleController extends Controller {
|
||||
*/
|
||||
@service router;
|
||||
|
||||
/**
|
||||
* Inject the `intl` service.
|
||||
*
|
||||
* @var {Service}
|
||||
*/
|
||||
@service intl;
|
||||
|
||||
/**
|
||||
* Inject the `universe` service.
|
||||
*
|
||||
@@ -205,8 +212,8 @@ export default class ConsoleController extends Controller {
|
||||
const country = this.currentUser.country;
|
||||
|
||||
this.modalsManager.show('modals/create-or-join-org', {
|
||||
title: 'Create or join a organization',
|
||||
acceptButtonText: 'Confirm',
|
||||
title: this.intl.t('console.create-or-join-organization.modal-title'),
|
||||
acceptButtonText: this.intl.t('common.confirm'),
|
||||
acceptButtonIcon: 'check',
|
||||
acceptButtonIconPrefix: 'fas',
|
||||
action: 'join',
|
||||
@@ -226,13 +233,22 @@ export default class ConsoleController extends Controller {
|
||||
const { action, next, name, description, phone, currency, country, timezone } = modal.getOptions();
|
||||
|
||||
if (action === 'join') {
|
||||
return this.fetch.post('auth/join-organization', { next }).then(() => {
|
||||
this.fetch.flushRequestCache('auth/organizations');
|
||||
this.notifications.success('You have joined a new organization!');
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 900);
|
||||
});
|
||||
return this.fetch
|
||||
.post('auth/join-organization', { next })
|
||||
.then(() => {
|
||||
this.fetch.flushRequestCache('auth/organizations');
|
||||
this.notifications.success(this.intl.t('console.create-or-join-organization.join-success-notification'));
|
||||
later(
|
||||
this,
|
||||
() => {
|
||||
window.location.reload();
|
||||
},
|
||||
900
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.notifications.serverError(error);
|
||||
});
|
||||
}
|
||||
|
||||
return this.fetch
|
||||
@@ -246,7 +262,7 @@ export default class ConsoleController extends Controller {
|
||||
})
|
||||
.then(() => {
|
||||
this.fetch.flushRequestCache('auth/organizations');
|
||||
this.notifications.success('You have created a new organization!');
|
||||
this.notifications.success(this.intl.t('console.create-or-join-organization.create-success-notification'));
|
||||
later(
|
||||
this,
|
||||
() => {
|
||||
@@ -254,6 +270,9 @@ export default class ConsoleController extends Controller {
|
||||
},
|
||||
900
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.notifications.serverError(error);
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -270,9 +289,9 @@ export default class ConsoleController extends Controller {
|
||||
}
|
||||
|
||||
this.modalsManager.confirm({
|
||||
title: `Are you sure you want to switch organization to ${organization.name}?`,
|
||||
body: `By confirming your account will remain logged in, but your primary organization will be switched.`,
|
||||
acceptButtonText: `Yes, I want to switch organization`,
|
||||
title: this.intl.t('console.switch-organization.modal-title', { organizationName: organization.name }),
|
||||
body: this.intl.t('console.switch-organization.modal-body'),
|
||||
acceptButtonText: this.intl.t('console.switch-organization.modal-accept-button-text'),
|
||||
acceptButtonScheme: 'primary',
|
||||
confirm: (modal) => {
|
||||
modal.startLoading();
|
||||
@@ -281,10 +300,14 @@ export default class ConsoleController extends Controller {
|
||||
.post('auth/switch-organization', { next: organization.uuid })
|
||||
.then(() => {
|
||||
this.fetch.flushRequestCache('auth/organizations');
|
||||
this.notifications.success('You have switched organizations');
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 900);
|
||||
this.notifications.success(this.intl.t('console.switch-organization.success-notification'));
|
||||
later(
|
||||
this,
|
||||
() => {
|
||||
window.location.reload();
|
||||
},
|
||||
900
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.notifications.serverError(error);
|
||||
@@ -295,8 +318,8 @@ export default class ConsoleController extends Controller {
|
||||
|
||||
@action viewChangelog() {
|
||||
this.modalsManager.show('modals/changelog', {
|
||||
title: 'Changelog',
|
||||
acceptButtonText: 'OK',
|
||||
title: this.intl.t('common.changelog'),
|
||||
acceptButtonText: this.intl.t('common.ok'),
|
||||
hideDeclineButton: true,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { task } from 'ember-concurrency';
|
||||
|
||||
/**
|
||||
* Controller for managing organizations in the admin console.
|
||||
@@ -41,6 +40,13 @@ export default class ConsoleAdminOrganizationsController extends Controller {
|
||||
*/
|
||||
@service filters;
|
||||
|
||||
/**
|
||||
* The search query param value.
|
||||
*
|
||||
* @var {String|null}
|
||||
*/
|
||||
@tracked query;
|
||||
|
||||
/**
|
||||
* The current page of data being viewed
|
||||
*
|
||||
@@ -104,14 +110,36 @@ export default class ConsoleAdminOrganizationsController extends Controller {
|
||||
filterable: true,
|
||||
filterComponent: 'filter/string',
|
||||
},
|
||||
{
|
||||
label: this.intl.t('console.admin.organizations.index.owner-name-column'),
|
||||
valuePath: 'owner.name',
|
||||
width: '200px',
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.intl.t('console.admin.organizations.index.owner-email-column'),
|
||||
valuePath: 'owner.email',
|
||||
width: '200px',
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
},
|
||||
{
|
||||
label: this.intl.t('console.admin.organizations.index.phone-column'),
|
||||
valuePath: 'phone',
|
||||
valuePath: 'owner.phone',
|
||||
width: '200px',
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
filterComponent: 'filter/string',
|
||||
},
|
||||
{
|
||||
label: this.intl.t('console.admin.organizations.index.users-count-column'),
|
||||
valuePath: 'users_count',
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.intl.t('common.created-at'),
|
||||
valuePath: 'createdAt',
|
||||
@@ -119,15 +147,14 @@ export default class ConsoleAdminOrganizationsController extends Controller {
|
||||
];
|
||||
|
||||
/**
|
||||
* `search` is a task that performs a search query on the 'company' model in the store.
|
||||
* Update search query param and reset page to 1
|
||||
*
|
||||
* @method search
|
||||
* @param {string} query - The search query.
|
||||
* @returns {Promise} A promise that resolves with the search results.
|
||||
* @public
|
||||
* @param {Event} event
|
||||
* @memberof ConsoleAdminOrganizationsController
|
||||
*/
|
||||
@task({ restartable: true }) *search(event) {
|
||||
this.companies = yield this.store.query('company', { query: event.target.value });
|
||||
@action search(event) {
|
||||
this.query = event.target.value ?? '';
|
||||
this.page = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,9 +2,6 @@ import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { isBlank } from '@ember/utils';
|
||||
import { task } from 'ember-concurrency-decorators';
|
||||
import { timeout } from 'ember-concurrency';
|
||||
|
||||
export default class ConsoleAdminOrganizationsIndexUsersController extends Controller {
|
||||
/**
|
||||
@@ -95,6 +92,17 @@ export default class ConsoleAdminOrganizationsIndexUsersController extends Contr
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Update search query param and reset page to 1
|
||||
*
|
||||
* @param {Event} event
|
||||
* @memberof ConsoleAdminOrganizationsController
|
||||
*/
|
||||
@action search(event) {
|
||||
this.nestedQuery = event.target.value ?? '';
|
||||
this.nestedPage = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the overlay component context object.
|
||||
*
|
||||
@@ -118,22 +126,4 @@ export default class ConsoleAdminOrganizationsIndexUsersController extends Contr
|
||||
|
||||
return this.router.transitionTo('console.admin.organizations.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* `search` is a task that performs a search query on the 'company' model in the store.
|
||||
*
|
||||
* @method search
|
||||
* @param {string} query - The search query.
|
||||
* @returns {Promise} A promise that resolves with the search results.
|
||||
* @public
|
||||
*/
|
||||
@task({ restartable: true }) *search(event) {
|
||||
const searchQuery = event.target.value ?? '';
|
||||
if (isBlank(searchQuery)) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield timeout(600);
|
||||
this.nestedQuery = searchQuery;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export default class Company extends Model {
|
||||
@attr('string') place_uuid;
|
||||
|
||||
/** @relationships */
|
||||
@belongsTo('user') owner;
|
||||
@belongsTo('file') logo;
|
||||
@belongsTo('file') backdrop;
|
||||
|
||||
@@ -23,6 +24,7 @@ export default class Company extends Model {
|
||||
@attr('string') backdrop_url;
|
||||
@attr('string') description;
|
||||
@attr('raw') options;
|
||||
@attr('number') users_count;
|
||||
@attr('string') type;
|
||||
@attr('string') currency;
|
||||
@attr('string') country;
|
||||
|
||||
@@ -14,11 +14,6 @@ export default class ConsoleAdminOrganizationsRoute extends Route {
|
||||
};
|
||||
|
||||
model(params) {
|
||||
return this.store.query('company', params);
|
||||
}
|
||||
|
||||
setupController(controller, model) {
|
||||
super.setupController(controller, model);
|
||||
controller.companies = model;
|
||||
return this.store.query('company', { view: 'admin', ...params });
|
||||
}
|
||||
}
|
||||
|
||||
15
console/app/serializers/company.js
Normal file
15
console/app/serializers/company.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import ApplicationSerializer from '@fleetbase/ember-core/serializers/application';
|
||||
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
|
||||
|
||||
export default class CompanySerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {
|
||||
/**
|
||||
* Embedded relationship attributes
|
||||
*
|
||||
* @var {Object}
|
||||
*/
|
||||
get attrs() {
|
||||
return {
|
||||
owner: { embedded: 'always' },
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -44,3 +44,7 @@ body[data-theme='dark'] .two-fa-enforcement-alert button#two-fa-setup-button.btn
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
body.console-admin-organizations-index-index .next-table-wrapper > table {
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
<FaIcon @icon="check-circle" @size="lg" class="text-green-900 mr-4" />
|
||||
</div>
|
||||
<p class="flex-1 text-sm text-green-900 dark:text-green-900">
|
||||
<strong>Check your {{this.selectedMethod}}</strong><br />
|
||||
We've sent you a verification code. Enter the code below to complete the login process.
|
||||
<strong>{{t "auth.two-fa.verify-code.check-title"}}</strong><br />
|
||||
{{t "auth.two-fa.verify-code.check-subtitle"}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -26,22 +26,22 @@
|
||||
{{/if}}
|
||||
{{#if this.isCodeExpired}}
|
||||
<InfoBlock>
|
||||
<div>Your 2FA authentication code has expired. You can request another code if you need more time.</div>
|
||||
<Button @type="primary" @wrapperClass="mt-2" @text="Resend Code" @icon="arrow-rotate-right" @onClick={{this.resendCode}} />
|
||||
<div>{{t "auth.two-fa.verify-code.expired-help-text"}}</div>
|
||||
<Button @type="primary" @wrapperClass="mt-2" @text={{t "auth.two-fa.verify-code.resend-code"}} @icon="arrow-rotate-right" @onClick={{this.resendCode}} />
|
||||
</InfoBlock>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<Button @buttonType="submit" @type="primary" @text="Verify Code" @icon="check-circle" @wrapperClass="btn-block" @isLoading={{this.isLoading}} />
|
||||
<Button @buttonType="submit" @type="primary" @text={{t "auth.two-fa.verify-code.verify-code"}} @icon="check-circle" @wrapperClass="btn-block" @isLoading={{this.isLoading}} />
|
||||
</div>
|
||||
|
||||
<div class="text-center flex flex-row items-center justify-center space-x-4 mt-3.5">
|
||||
<a href="#" class="text-sm text-blue-500 hover:underline inline-block" {{on "click" this.resendCode}}>
|
||||
Resend Code
|
||||
{{t "auth.two-fa.verify-code.resend-code"}}
|
||||
</a>
|
||||
<a href="#" class="text-sm text-danger hover:underline inline-block" {{on "click" this.cancelTwoFactor}}>
|
||||
Cancel Two-Factor
|
||||
{{t "auth.two-fa.verify-code.cancel-two-factor"}}
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,15 +1,16 @@
|
||||
{{page-title (t "console.admin.organizations.index.title")}}
|
||||
<Layout::Section::Header @title={{t "console.admin.organizations.index.title"}} @searchQuery={{this.query}} @onSearch={{perform this.search}} />
|
||||
{{!-- template-lint-disable no-unbound --}}
|
||||
<Layout::Section::Header @title={{t "console.admin.organizations.index.title"}} @searchQuery={{unbound this.query}} @onSearch={{this.search}} />
|
||||
|
||||
<Layout::Section::Body>
|
||||
<Table
|
||||
@rows={{this.companies}}
|
||||
@rows={{@model}}
|
||||
@columns={{this.columns}}
|
||||
@selectable={{true}}
|
||||
@canSelectAll={{true}}
|
||||
@selectable={{false}}
|
||||
@canSelectAll={{false}}
|
||||
@onSetup={{fn (mut this.table)}}
|
||||
@pagination={{true}}
|
||||
@paginationMeta={{this.companies}}
|
||||
@paginationMeta={{@model.meta}}
|
||||
@page={{this.page}}
|
||||
@onPageChange={{fn (mut this.page)}}
|
||||
@tfootVerticalOffset="53"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{{page-title (t "common.users")}}
|
||||
<Overlay @isOpen={{@isOpen}} @onLoad={{this.setOverlayContext}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width={{or this.width @width "600px"}}>
|
||||
<Overlay @isOpen={{@isOpen}} @onLoad={{this.setOverlayContext}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width="600px" @isResizable={{true}}>
|
||||
<Overlay::Header @title={{concat this.company.name " - " (t "common.users")}} @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}} />
|
||||
@@ -7,12 +7,13 @@
|
||||
</Overlay::Header>
|
||||
|
||||
<Overlay::Body class="without-padding">
|
||||
<Layout::Section::Header @title={{t "console.admin.organizations.users.title"}} @searchQuery={{this.nestedQuery}} @onSearch={{perform this.search}}>
|
||||
{{!-- template-lint-disable no-unbound --}}
|
||||
<Layout::Section::Header @title={{t "console.admin.organizations.users.title"}} @searchQuery={{unbound this.nestedQuery}} @onSearch={{this.search}}>
|
||||
<Pagination @meta={{@model.meta}} @page={{this.nestedPage}} @onPageChange={{fn (mut this.nestedPage)}} @metaInfoClass="hidden" @metaInfoWrapperClass="within-layout-section-header" />
|
||||
</Layout::Section::Header>
|
||||
|
||||
<Layout::Section::Body>
|
||||
<Table @rows={{@model}} @columns={{this.columns}} @selectable={{true}} @canSelectAll={{true}} @onSetup={{fn (mut this.table)}} />
|
||||
<Table @rows={{@model}} @columns={{this.columns}} @selectable={{false}} @canSelectAll={{false}} @onSetup={{fn (mut this.table)}} />
|
||||
</Layout::Section::Body>
|
||||
</Overlay::Body>
|
||||
</Overlay>
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fleetbase/console",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.6",
|
||||
"private": true,
|
||||
"description": "Fleetbase Console",
|
||||
"repository": "https://github.com/fleetbase/fleetbase",
|
||||
@@ -12,7 +12,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "node prebuild.js",
|
||||
"build": "pnpm run prebuild && ember build --environment=production",
|
||||
"build": "pnpm run prebuild && ember build",
|
||||
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
|
||||
"lint:css": "stylelint \"**/*.css\"",
|
||||
"lint:css:fix": "concurrently \"npm:lint:css -- --fix\"",
|
||||
@@ -24,15 +24,16 @@
|
||||
"postinstall": "patch-package",
|
||||
"lint:intl": "fleetbase-intl-lint",
|
||||
"start": "pnpm run prebuild && ember serve",
|
||||
"start:dev": "pnpm run prebuild && ember serve --environment development",
|
||||
"test": "concurrently \"npm:lint\" \"npm:test:*\" --names \"lint,test:\"",
|
||||
"test:ember": "ember test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fleetbase/ember-core": "^0.2.4",
|
||||
"@fleetbase/ember-ui": "^0.2.10",
|
||||
"@fleetbase/storefront-engine": "^0.2.11",
|
||||
"@fleetbase/fleetops-engine": "^0.4.7",
|
||||
"@fleetbase/fleetops-data": "^0.1.8",
|
||||
"@fleetbase/ember-ui": "^0.2.11",
|
||||
"@fleetbase/fleetops-engine": "^0.4.13",
|
||||
"@fleetbase/fleetops-data": "^0.1.9",
|
||||
"@fleetbase/storefront-engine": "^0.3.1",
|
||||
"@fleetbase/dev-engine": "^0.2.1",
|
||||
"@fleetbase/iam-engine": "^0.0.9",
|
||||
"@fleetbase/leaflet-routing-machine": "^3.2.16",
|
||||
@@ -142,8 +143,8 @@
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"@fleetbase/ember-core": "^0.2.4",
|
||||
"@fleetbase/ember-ui": "^0.2.10",
|
||||
"@fleetbase/fleetops-data": "^0.1.8"
|
||||
"@fleetbase/ember-ui": "^0.2.11",
|
||||
"@fleetbase/fleetops-data": "^0.1.9"
|
||||
}
|
||||
},
|
||||
"prettier": {
|
||||
|
||||
1401
console/pnpm-lock.yaml
generated
1401
console/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
24
console/tests/unit/serializers/company-test.js
Normal file
24
console/tests/unit/serializers/company-test.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Serializer | company', 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('company');
|
||||
|
||||
assert.ok(serializer);
|
||||
});
|
||||
|
||||
test('it serializes records', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let record = store.createRecord('company', {});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
|
||||
assert.ok(serializedRecord);
|
||||
});
|
||||
});
|
||||
@@ -13,6 +13,7 @@ terms:
|
||||
search: Search
|
||||
search-input: Search Input
|
||||
common:
|
||||
confirm: Confirm
|
||||
edit: Edit
|
||||
save: Save
|
||||
cancel: Cancel
|
||||
@@ -56,6 +57,8 @@ common:
|
||||
status: Status
|
||||
close-and-save: Close and Save
|
||||
users: Users
|
||||
changelog: Changelog
|
||||
ok: OK
|
||||
component:
|
||||
file:
|
||||
dropdown-label: File actions
|
||||
@@ -68,7 +71,9 @@ component:
|
||||
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
|
||||
@@ -124,6 +129,13 @@ auth:
|
||||
send-by-sms: Send by SMS
|
||||
two-fa:
|
||||
verify-code:
|
||||
verification-code: Verification Code
|
||||
check-title: Check your email or phone
|
||||
check-subtitle: We've sent you a verification code. Enter the code below to complete the login process.
|
||||
expired-help-text: Your 2FA authentication code has expired. You can request another code if you need more time.
|
||||
resend-code: Resend Code
|
||||
verify-code: Verify Code
|
||||
cancel-two-factor: Cancel Two-Factor
|
||||
invalid-session-error-notification: Invalid session. Please try again.
|
||||
verification-successful-notification: Verification successful!
|
||||
verification-code-expired-notification: Verification code has expired. Please request a new one.
|
||||
@@ -175,6 +187,15 @@ auth:
|
||||
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
|
||||
@@ -213,6 +234,10 @@ console:
|
||||
organizations:
|
||||
index:
|
||||
title: Organizations
|
||||
owner-name-column: Owner
|
||||
owner-phone-column: Owner Phone
|
||||
owner-email-column: Owner Phone
|
||||
users-count-column: Users
|
||||
phone-column: Phone
|
||||
email-column: Email
|
||||
users:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# syntax = docker/dockerfile:1.2
|
||||
# Base stage
|
||||
FROM dunglas/frankenphp:sha-7454826-php8.2-alpine as base
|
||||
FROM dunglas/frankenphp:1.1.0-php8.2-bookworm as base
|
||||
|
||||
# Install packages
|
||||
RUN apk update && apk add git openssh bind-tools mycli nodejs npm \
|
||||
RUN apt-get update && apt-get install -y git bind9-utils mycli nodejs npm \
|
||||
&& mkdir -p /root/.ssh \
|
||||
&& ssh-keyscan github.com >> /root/.ssh/known_hosts
|
||||
|
||||
@@ -98,12 +98,12 @@ RUN chmod 0600 ./crontab
|
||||
# Scheduler dev stage
|
||||
FROM scheduler-base as scheduler-dev
|
||||
ENTRYPOINT []
|
||||
CMD ["go-crond", "--verbose", "--no-auto", "root:./crontab"]
|
||||
CMD ["go-crond", "--verbose", "root:./crontab"]
|
||||
|
||||
# Scheduler stage
|
||||
FROM scheduler-base as scheduler
|
||||
ENTRYPOINT ["/sbin/ssm-parent", "-c", ".ssm-parent.yaml", "run", "--"]
|
||||
CMD ["go-crond", "--verbose", "--no-auto", "root:./crontab"]
|
||||
CMD ["go-crond", "--verbose", "root:./crontab"]
|
||||
|
||||
# Events stage
|
||||
FROM base as events
|
||||
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
{{- include "helm.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
replicas: 1
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
@@ -66,7 +66,7 @@ metadata:
|
||||
{{- include "helm.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
replicas: 1
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
replicaCount: 1
|
||||
replicaCount: 2
|
||||
|
||||
image:
|
||||
repository: OVERRIDE
|
||||
@@ -25,10 +25,12 @@ serviceAccount:
|
||||
|
||||
podAnnotations: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
podSecurityContext:
|
||||
{}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
securityContext:
|
||||
{}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
@@ -54,7 +56,8 @@ ingress:
|
||||
# hosts:
|
||||
# - chart-example.local
|
||||
|
||||
resources: {}
|
||||
resources:
|
||||
{}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
|
||||
Submodule packages/core-api updated: c98e08a257...9c21c006c2
Submodule packages/ember-ui updated: e532986a5b...813241f0c3
Submodule packages/fleetops updated: 9ce45d0402...bdcadd7618
Submodule packages/storefront updated: 9096a19131...c356f467c0
@@ -62,7 +62,7 @@ deploy:
|
||||
|
||||
# build the builder
|
||||
- docker buildx build -t frontend-${STACK}-${VERSION} --load --target builder -f console/Dockerfile .
|
||||
- docker run -i --rm --env-file /tmp/dotenv.file -v "$(pwd)/console_dist:/app/dist" frontend-${STACK}-${VERSION} pnpm build
|
||||
- docker run -i --rm --env-file /tmp/dotenv.file -v "$(pwd)/console_dist:/app/dist" frontend-${STACK}-${VERSION} pnpm build --environment production
|
||||
- |-
|
||||
DEPLOY_BUCKET=${PROJECT}-${STACK}
|
||||
wget -O- https://github.com/bep/s3deploy/releases/download/v2.11.0/s3deploy_2.11.0_linux-amd64.tar.gz | tar xzv -f - s3deploy
|
||||
|
||||
Reference in New Issue
Block a user