mirror of
https://github.com/fleetbase/fleetbase.git
synced 2026-01-07 06:50:14 +00:00
Compare commits
2 Commits
v0.4.21
...
feature/bi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff59941947 | ||
|
|
013e19f39e |
@@ -9,8 +9,8 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"fleetbase/core-api": "^1.4.22",
|
||||
"fleetbase/fleetops-api": "^0.4.27",
|
||||
"fleetbase/core-api": "^1.4.16",
|
||||
"fleetbase/fleetops-api": "^0.4.24",
|
||||
"fleetbase/storefront-api": "^0.3.7",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"laravel/framework": "^10.0",
|
||||
@@ -32,12 +32,6 @@
|
||||
"nunomaduro/collision": "^7.0",
|
||||
"phpunit/phpunit": "^10.0"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/fleetbase/laravel-model-caching"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
@@ -98,6 +92,6 @@
|
||||
"php-http/discovery": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
|
||||
1167
api/composer.lock
generated
1167
api/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'url' => env('APP_URL', 'http://localhost:8000'),
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
|
||||
'asset_url' => env('ASSET_URL', null),
|
||||
|
||||
|
||||
@@ -20,6 +20,3 @@ php artisan queue:restart
|
||||
|
||||
# Sync scheduler
|
||||
php artisan schedule-monitor:sync
|
||||
|
||||
# Clear cache
|
||||
php artisan cache:clear
|
||||
|
||||
30
console/app/components/locale-selector.hbs
Normal file
30
console/app/components/locale-selector.hbs
Normal file
@@ -0,0 +1,30 @@
|
||||
<div class="next-user-button" ...attributes>
|
||||
<BasicDropdown @defaultClass={{@wrapperClass}} @onOpen={{@onOpen}} @onClose={{@onClose}} @verticalPosition={{@verticalPosition}} @horizontalPosition={{@horizontalPosition}} @renderInPlace={{or @renderInPlace true}} @initiallyOpened={{@initiallyOpened}} as |dd|>
|
||||
<dd.Trigger class={{@triggerClass}}>
|
||||
<div class="next-org-button-trigger flex-shrink-0 {{if dd.isOpen 'is-open'}}">
|
||||
<FaIcon @icon="globe" @size="sm" />
|
||||
</div>
|
||||
</dd.Trigger>
|
||||
<dd.Content class={{@contentClass}}>
|
||||
<div class="next-dd-menu {{@dropdownMenuClass}} {{if dd.isOpen 'is-open'}}">
|
||||
{{#each-in this.availableLocales as |key country|}}
|
||||
<div class="px-1">
|
||||
<a href="javascript:;" class="next-dd-item" {{on "click" (fn this.changeLocale key)}}>
|
||||
<div class="flex flex-row items-center justify-between w-full">
|
||||
<div class="flex-1">
|
||||
<span class="mr-1">{{country.emoji}}</span>
|
||||
<span>{{country.language}}</span>
|
||||
</div>
|
||||
{{#if (eq this.currentLocale key)}}
|
||||
<div>
|
||||
<FaIcon @icon="check" class="text-green-400" />
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{{/each-in}}
|
||||
</div>
|
||||
</dd.Content>
|
||||
</BasicDropdown>
|
||||
</div>
|
||||
144
console/app/components/locale-selector.js
Normal file
144
console/app/components/locale-selector.js
Normal file
@@ -0,0 +1,144 @@
|
||||
import Component from '@glimmer/component';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { task } from 'ember-concurrency-decorators';
|
||||
|
||||
export default class LocaleSelectorComponent extends Component {
|
||||
/**
|
||||
* Inject the intl service.
|
||||
*
|
||||
* @memberof LocaleSelectorComponent
|
||||
*/
|
||||
@service intl;
|
||||
|
||||
/**
|
||||
* Inject the intl service.
|
||||
*
|
||||
* @memberof LocaleSelectorComponent
|
||||
*/
|
||||
@service fetch;
|
||||
|
||||
/**
|
||||
* Tracks all the available locales.
|
||||
*
|
||||
* @memberof LocaleSelectorComponent
|
||||
*/
|
||||
@tracked locales = [];
|
||||
|
||||
/**
|
||||
* All available countries data.
|
||||
*
|
||||
* @memberof LocaleSelectorComponent
|
||||
*/
|
||||
@tracked countries = [];
|
||||
|
||||
/**
|
||||
* The current locale in use.
|
||||
*
|
||||
* @memberof LocaleSelectorComponent
|
||||
*/
|
||||
@tracked currentLocale;
|
||||
|
||||
/**
|
||||
* Creates an instance of LocaleSelectorComponent.
|
||||
* @memberof LocaleSelectorComponent
|
||||
*/
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
this.locales = this.intl.locales;
|
||||
this.currentLocale = this.intl.primaryLocale;
|
||||
this.loadAvailableCountries.perform();
|
||||
|
||||
// Check for locale change
|
||||
this.intl.onLocaleChanged(() => {
|
||||
this.currentLocale = this.intl.primaryLocale;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the change of locale.
|
||||
* @param {string} selectedLocale - The selected locale.
|
||||
* @returns {void}
|
||||
* @memberof LocaleSelectorComponent
|
||||
* @method changeLocale
|
||||
* @instance
|
||||
* @action
|
||||
*/
|
||||
@action changeLocale(selectedLocale) {
|
||||
this.currentLocale = selectedLocale;
|
||||
this.intl.setLocale(selectedLocale);
|
||||
// Persist to server
|
||||
this.saveUserLocale.perform(selectedLocale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads available countries asynchronously.
|
||||
* @returns {void}
|
||||
* @memberof LocaleSelectorComponent
|
||||
* @method loadAvailableCountries
|
||||
* @instance
|
||||
* @task
|
||||
* @generator
|
||||
*/
|
||||
@task *loadAvailableCountries() {
|
||||
this.countries = yield this.fetch.get('lookup/countries', { columns: ['name', 'cca2', 'flag', 'emoji', 'languages'] });
|
||||
this.availableLocales = this._createAvailableLocaleMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the user's selected locale to the server.
|
||||
* @param {string} locale - The user's selected locale.
|
||||
* @returns {void}
|
||||
* @memberof LocaleSelectorComponent
|
||||
* @method saveUserLocale
|
||||
* @instance
|
||||
* @task
|
||||
* @generator
|
||||
*/
|
||||
@task *saveUserLocale(locale) {
|
||||
yield this.fetch.post('users/locale', { locale });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a map of available locales.
|
||||
* @private
|
||||
* @returns {Object} - The map of available locales.
|
||||
* @memberof LocaleSelectorComponent
|
||||
* @method _createAvailableLocaleMap
|
||||
* @instance
|
||||
*/
|
||||
_createAvailableLocaleMap() {
|
||||
const localeMap = {};
|
||||
|
||||
for (let i = 0; i < this.locales.length; i++) {
|
||||
const locale = this.locales.objectAt(i);
|
||||
|
||||
localeMap[locale] = this._findCountryDataForLocale(locale);
|
||||
}
|
||||
|
||||
return localeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds country data for a given locale.
|
||||
* @private
|
||||
* @param {string} locale - The locale to find country data for.
|
||||
* @returns {Object|null} - The country data or null if not found.
|
||||
* @memberof LocaleSelectorComponent
|
||||
* @method _findCountryDataForLocale
|
||||
* @instance
|
||||
*/
|
||||
_findCountryDataForLocale(locale) {
|
||||
const localeCountry = locale.split('-')[1];
|
||||
const country = this.countries.find((country) => country.cca2.toLowerCase() === localeCountry);
|
||||
|
||||
if (country) {
|
||||
// get the language
|
||||
country.language = Object.values(country.languages)[0];
|
||||
}
|
||||
|
||||
return country;
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,6 @@ export default class ConsoleController extends Controller {
|
||||
@action setSidebarContext(sidebarContext) {
|
||||
this.sidebarContext = sidebarContext;
|
||||
this.universe.sidebarContext = sidebarContext;
|
||||
this.universe.trigger('sidebarContext.available', sidebarContext);
|
||||
|
||||
if (this.hiddenSidebarRoutes.includes(this.router.currentRouteName)) {
|
||||
this.sidebarContext.hideNow();
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import Model, { attr, belongsTo } from '@ember-data/model';
|
||||
import { getOwner } from '@ember/application';
|
||||
import { computed } from '@ember/object';
|
||||
import { format, formatDistanceToNow, isValid as isValidDate } from 'date-fns';
|
||||
import isVideoFile from '@fleetbase/ember-core/utils/is-video-file';
|
||||
import isImageFile from '@fleetbase/ember-core/utils/is-image-file';
|
||||
|
||||
export default class ChatAttachment extends Model {
|
||||
/** @ids */
|
||||
@attr('string') chat_channel_uuid;
|
||||
@attr('string') sender_uuid;
|
||||
@attr('string') file_uuid;
|
||||
@attr('string') chat_message_uuid;
|
||||
|
||||
/** @relationships */
|
||||
@belongsTo('user', { async: true }) sender;
|
||||
@belongsTo('chat-channel', { async: true }) chatChannel;
|
||||
@belongsTo('file', { async: true }) file;
|
||||
|
||||
/** @attributes */
|
||||
@attr('string') chat_channel_uuid;
|
||||
@attr('string') sender_uuid;
|
||||
@attr('string') file_uuid;
|
||||
@attr('string') url;
|
||||
@attr('string') filename;
|
||||
@attr('string') content_type;
|
||||
|
||||
/** @dates */
|
||||
@attr('date') created_at;
|
||||
@attr('date') updated_at;
|
||||
|
||||
/** @computed */
|
||||
@computed('updated_at') get updatedAgo() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.updated_at);
|
||||
}
|
||||
|
||||
@computed('updated_at') get updatedAt() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.updated_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAgo() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.created_at);
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAt() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.created_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
@computed('content_type') get isVideo() {
|
||||
return isVideoFile(this.content_type);
|
||||
}
|
||||
|
||||
@computed('content_type') get isImage() {
|
||||
return isImageFile(this.content_type);
|
||||
}
|
||||
|
||||
/** @methods */
|
||||
downloadFromApi() {
|
||||
window.open(ENV.api.host + '/' + ENV.api.namespace + '/files/download?file=' + this.file_uuid, '_self');
|
||||
}
|
||||
|
||||
download() {
|
||||
const owner = getOwner(this);
|
||||
const fetch = owner.lookup('service:fetch');
|
||||
|
||||
return fetch.download('files/download', { file: this.file_uuid }, { fileName: this.filename, mimeType: this.content_type });
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import Model, { attr, hasMany, belongsTo } from '@ember-data/model';
|
||||
import { computed } from '@ember/object';
|
||||
import { getOwner } from '@ember/application';
|
||||
import { format, formatDistanceToNow, isValid as isValidDate } from 'date-fns';
|
||||
|
||||
export default class ChatChannelModel extends Model {
|
||||
/** @ids */
|
||||
@attr('string') public_id;
|
||||
@attr('string') company_uuid;
|
||||
@attr('string') created_by_uuid;
|
||||
|
||||
/** @attributes */
|
||||
@attr('string') name;
|
||||
@attr('string') title;
|
||||
@attr('number') unread_count;
|
||||
@attr('string') slug;
|
||||
@attr('array') feed;
|
||||
@attr('array') meta;
|
||||
|
||||
/** @relationships */
|
||||
@hasMany('chat-participant', { async: false }) participants;
|
||||
@belongsTo('chat-message', { async: false }) last_message;
|
||||
|
||||
/** @dates */
|
||||
@attr('date') created_at;
|
||||
@attr('date') updated_at;
|
||||
|
||||
/** @computed */
|
||||
@computed('updated_at') get updatedAgo() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.updated_at);
|
||||
}
|
||||
|
||||
@computed('updated_at') get updatedAt() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.updated_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAgo() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.created_at);
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAt() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.created_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
/** @methods */
|
||||
toJSON() {
|
||||
return {
|
||||
company_uuid: this.company_uuid,
|
||||
name: this.name,
|
||||
meta: this.meta,
|
||||
};
|
||||
}
|
||||
|
||||
reloadParticipants() {
|
||||
const owner = getOwner(this);
|
||||
const store = owner.lookup('service:store');
|
||||
|
||||
return store.query('chat-participant', { chat_channel_uuid: this.id }).then((participants) => {
|
||||
this.set('participants', participants);
|
||||
return participants;
|
||||
});
|
||||
}
|
||||
|
||||
existsInFeed(type, record) {
|
||||
return this.feed.find((_) => _.type === type && _.record.id === record.id) !== undefined;
|
||||
}
|
||||
|
||||
doesntExistsInFeed(type, record) {
|
||||
return this.feed.find((_) => _.type === type && _.record.id === record.id) === undefined;
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import Model, { attr, belongsTo } from '@ember-data/model';
|
||||
import { computed } from '@ember/object';
|
||||
import { format, formatDistanceToNow, isValid as isValidDate } from 'date-fns';
|
||||
|
||||
export default class ChatLogModel extends Model {
|
||||
/** @ids */
|
||||
@attr('string') company_uuid;
|
||||
@attr('string') chat_channel_uuid;
|
||||
@attr('string') initiator_uuid;
|
||||
|
||||
/** @attributes */
|
||||
@attr('string') content;
|
||||
@attr('string') resolved_content;
|
||||
@attr('string') event_type;
|
||||
@attr('string') status;
|
||||
@attr('array') meta;
|
||||
|
||||
/** @dates */
|
||||
@attr('date') created_at;
|
||||
@attr('date') updated_at;
|
||||
|
||||
/** @computed */
|
||||
@computed('updated_at') get updatedAgo() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.updated_at, { addSuffix: true });
|
||||
}
|
||||
|
||||
@computed('updated_at') get updatedAt() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.updated_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAgo() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.created_at, { addSuffix: true });
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAt() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.created_at, 'PP HH:mm');
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import Model, { attr, belongsTo, hasMany } from '@ember-data/model';
|
||||
import { computed } from '@ember/object';
|
||||
import { format, formatDistanceToNow, isValid as isValidDate } from 'date-fns';
|
||||
|
||||
export default class ChatMessage extends Model {
|
||||
/** @ids */
|
||||
@attr('string') chat_channel_uuid;
|
||||
@attr('string') sender_uuid;
|
||||
|
||||
/** @attributes */
|
||||
@attr('string') content;
|
||||
@attr('array') attachment_files;
|
||||
|
||||
/** @relationships */
|
||||
@belongsTo('chat-participant', { async: false }) sender;
|
||||
@hasMany('chat-attachment', { async: false }) attachments;
|
||||
@hasMany('chat-receipt', { async: false }) receipts;
|
||||
|
||||
/** @dates */
|
||||
@attr('date') created_at;
|
||||
@attr('date') updated_at;
|
||||
|
||||
/** @computed */
|
||||
@computed('updated_at') get updatedAgo() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.updated_at, { addSuffix: true });
|
||||
}
|
||||
|
||||
@computed('updated_at') get updatedAt() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.updated_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAgo() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.created_at, { addSuffix: true });
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAt() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.created_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
/** @methods */
|
||||
hasReadReceipt(chatParticipant) {
|
||||
return chatParticipant && this.receipts.find((receipt) => chatParticipant.id === receipt.participant_uuid) !== undefined;
|
||||
}
|
||||
|
||||
doesntHaveReadReceipt(chatParticipant) {
|
||||
return !this.hasReadReceipt(chatParticipant);
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import Model, { attr, belongsTo } from '@ember-data/model';
|
||||
import { computed } from '@ember/object';
|
||||
import { format, formatDistanceToNow, isValid as isValidDate } from 'date-fns';
|
||||
|
||||
export default class ChatParticipant extends Model {
|
||||
/** @ids */
|
||||
@attr('string') user_uuid;
|
||||
@attr('string') chat_channel_uuid;
|
||||
|
||||
/** @attributes */
|
||||
@attr('string') name;
|
||||
@attr('string') username;
|
||||
@attr('string') phone;
|
||||
@attr('string') email;
|
||||
@attr('string') avatar_url;
|
||||
@attr('boolean') is_online;
|
||||
|
||||
/** @relationships */
|
||||
@belongsTo('user', { async: true }) user;
|
||||
@belongsTo('chat-channel', { async: true }) chatChannel;
|
||||
|
||||
/** @dates */
|
||||
@attr('date') last_seen_at;
|
||||
@attr('date') created_at;
|
||||
@attr('date') updated_at;
|
||||
|
||||
/** @computed */
|
||||
@computed('updated_at') get updatedAgo() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.updated_at);
|
||||
}
|
||||
|
||||
@computed('updated_at') get updatedAt() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.updated_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAgo() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.created_at);
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAt() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.created_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
@computed('last_seen_at') get lastSeenAgo() {
|
||||
if (!isValidDate(this.last_seen_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.last_seen_at);
|
||||
}
|
||||
|
||||
@computed('last_seen_at') get lastSeenAt() {
|
||||
if (!isValidDate(this.last_seen_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.last_seen_at, 'PP HH:mm');
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import Model, { attr, belongsTo } from '@ember-data/model';
|
||||
import { computed } from '@ember/object';
|
||||
import { format as formatDate, formatDistanceToNow, isValid as isValidDate } from 'date-fns';
|
||||
|
||||
export default class ChatReceipt extends Model {
|
||||
/** @ids */
|
||||
@attr('string') participant_uuid;
|
||||
@attr('string') chat_message_uuid;
|
||||
|
||||
/** @relationships */
|
||||
@belongsTo('chat-participant', { async: true }) participant;
|
||||
@belongsTo('chat-message', { async: true }) chatMessage;
|
||||
|
||||
/** @attributes */
|
||||
@attr('string') participant_name;
|
||||
|
||||
/** @dates */
|
||||
@attr('date') created_at;
|
||||
@attr('date') updated_at;
|
||||
@attr('date') read_at;
|
||||
|
||||
/** @computed */
|
||||
@computed('updated_at') get updatedAgo() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.updated_at, { addSuffix: true });
|
||||
}
|
||||
|
||||
@computed('updated_at') get updatedAt() {
|
||||
if (!isValidDate(this.updated_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.updated_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAgo() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.created_at, { addSuffix: true });
|
||||
}
|
||||
|
||||
@computed('created_at') get createdAt() {
|
||||
if (!isValidDate(this.created_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.created_at, 'PP HH:mm');
|
||||
}
|
||||
|
||||
@computed('read_at') get readAgo() {
|
||||
if (!isValidDate(this.read_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDistanceToNow(this.read_at, { addSuffix: true });
|
||||
}
|
||||
|
||||
@computed('read_at') get readAt() {
|
||||
if (!isValidDate(this.read_at)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return formatDate(this.read_at, 'PP HH:mm');
|
||||
}
|
||||
}
|
||||
@@ -69,8 +69,8 @@ export default class FileModel extends Model {
|
||||
|
||||
download() {
|
||||
const owner = getOwner(this);
|
||||
const fetch = owner.lookup('service:fetch');
|
||||
const fetch = owner.lookup(`service:store`);
|
||||
|
||||
return fetch.download('files/download', { file: this.id }, { fileName: this.original_filename, mimeType: this.content_type });
|
||||
return fetch.download('files/download', { file: this.id });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,13 +26,11 @@ export default class UserModel extends Model {
|
||||
@attr('string') type;
|
||||
@attr('string') session_status;
|
||||
@attr('string') status;
|
||||
@attr('boolean') is_online;
|
||||
@attr('boolean') is_admin;
|
||||
@attr('raw') types;
|
||||
@attr('raw') meta;
|
||||
|
||||
/** @dates */
|
||||
@attr('date') last_seen_at;
|
||||
@attr('date') phone_verified_at;
|
||||
@attr('date') email_verified_at;
|
||||
@attr('date') last_login;
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import ApplicationSerializer from '@fleetbase/ember-core/serializers/application';
|
||||
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
|
||||
import { getOwner } from '@ember/application';
|
||||
import { underscore } from '@ember/string';
|
||||
import { isArray } from '@ember/array';
|
||||
|
||||
export default class ChatChannelSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {
|
||||
/**
|
||||
* Embedded relationship attributes
|
||||
*
|
||||
* @var {Object}
|
||||
*/
|
||||
get attrs() {
|
||||
return {
|
||||
participants: { embedded: 'always' },
|
||||
last_message: { embedded: 'always' },
|
||||
};
|
||||
}
|
||||
|
||||
serialize(snapshot) {
|
||||
let json = {
|
||||
name: snapshot.attr('name'),
|
||||
meta: snapshot.attr('meta'),
|
||||
};
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
normalize(typeClass, hash) {
|
||||
if (isArray(hash.feed)) {
|
||||
hash.feed = this.serializeFeed(hash.feed);
|
||||
}
|
||||
|
||||
return super.normalize(...arguments);
|
||||
}
|
||||
|
||||
serializeFeed(feed = []) {
|
||||
return feed.map((item) => this.serializeItem(item)).sortBy('created_at');
|
||||
}
|
||||
|
||||
serializeItem(item) {
|
||||
switch (item.type) {
|
||||
case 'message':
|
||||
return { ...item, record: this.serializeItemType('chat-message', item.data) };
|
||||
case 'log':
|
||||
return { ...item, record: this.serializeItemType('chat-log', item.data) };
|
||||
case 'attachment':
|
||||
return { ...item, record: this.serializeItemType('chat-attachment', item.data) };
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
serializeItemType(modelType, data) {
|
||||
const owner = getOwner(this);
|
||||
const store = owner.lookup('service:store');
|
||||
const normalized = store.normalize(modelType, data);
|
||||
return store.push(normalized);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import ApplicationSerializer from '@fleetbase/ember-core/serializers/application';
|
||||
import { EmbeddedRecordsMixin } from '@ember-data/serializer/rest';
|
||||
|
||||
export default class ChatMessageSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {
|
||||
/**
|
||||
* Embedded relationship attributes
|
||||
*
|
||||
* @var {Object}
|
||||
*/
|
||||
get attrs() {
|
||||
return {
|
||||
sender: { embedded: 'always' },
|
||||
attachments: { embedded: 'always' },
|
||||
receipts: { embedded: 'always' },
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import ApplicationSerializer from '@fleetbase/ember-core/serializers/application';
|
||||
|
||||
export default class ChatParticipantSerializer extends ApplicationSerializer {}
|
||||
@@ -14,5 +14,9 @@
|
||||
</Layout::Main>
|
||||
<Layout::MobileNavbar @brand={{@model}} @user={{this.user}} @organizations={{this.organizations}} @menuItems={{this.universe.headerMenuItems}} @extensions={{this.extensions}} @onAction={{this.onAction}} />
|
||||
</Layout::Container>
|
||||
<ChatContainer />
|
||||
<ConsoleWormhole />
|
||||
|
||||
{{!-- Add Locale Selector to Header --}}
|
||||
<EmberWormhole @to="view-header-actions">
|
||||
<LocaleSelector class="mr-0.5" />
|
||||
</EmberWormhole>
|
||||
<ConsoleWormhole />
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fleetbase/console",
|
||||
"version": "0.4.21",
|
||||
"version": "0.4.16",
|
||||
"private": true,
|
||||
"description": "Fleetbase Console",
|
||||
"repository": "https://github.com/fleetbase/fleetbase",
|
||||
@@ -29,9 +29,9 @@
|
||||
"test:ember": "ember test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fleetbase/ember-core": "^0.2.9",
|
||||
"@fleetbase/ember-ui": "^0.2.13",
|
||||
"@fleetbase/fleetops-engine": "^0.4.27",
|
||||
"@fleetbase/ember-core": "^0.2.8",
|
||||
"@fleetbase/ember-ui": "^0.2.12",
|
||||
"@fleetbase/fleetops-engine": "^0.4.24",
|
||||
"@fleetbase/fleetops-data": "^0.1.14",
|
||||
"@fleetbase/storefront-engine": "^0.3.7",
|
||||
"@fleetbase/dev-engine": "^0.2.2",
|
||||
@@ -142,8 +142,8 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"@fleetbase/ember-core": "^0.2.9",
|
||||
"@fleetbase/ember-ui": "^0.2.13",
|
||||
"@fleetbase/ember-core": "^0.2.8",
|
||||
"@fleetbase/ember-ui": "^0.2.12",
|
||||
"@fleetbase/fleetops-data": "^0.1.14"
|
||||
}
|
||||
},
|
||||
|
||||
1496
console/pnpm-lock.yaml
generated
1496
console/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
26
console/tests/integration/components/locale-selector-test.js
Normal file
26
console/tests/integration/components/locale-selector-test.js
Normal 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 | locale-selector', 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`<LocaleSelector />`);
|
||||
|
||||
assert.dom().hasText('');
|
||||
|
||||
// Template block usage:
|
||||
await render(hbs`
|
||||
<LocaleSelector>
|
||||
template block text
|
||||
</LocaleSelector>
|
||||
`);
|
||||
|
||||
assert.dom().hasText('template block text');
|
||||
});
|
||||
});
|
||||
@@ -1,14 +0,0 @@
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Model | chat log', 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('chat-log', {});
|
||||
assert.ok(model);
|
||||
});
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Serializer | chat channel', 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('chat-channel');
|
||||
|
||||
assert.ok(serializer);
|
||||
});
|
||||
|
||||
test('it serializes records', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let record = store.createRecord('chat-channel', {});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
|
||||
assert.ok(serializedRecord);
|
||||
});
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Serializer | chat message', 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('chat-message');
|
||||
|
||||
assert.ok(serializer);
|
||||
});
|
||||
|
||||
test('it serializes records', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let record = store.createRecord('chat-message', {});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
|
||||
assert.ok(serializedRecord);
|
||||
});
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
import { setupTest } from '@fleetbase/console/tests/helpers';
|
||||
|
||||
module('Unit | Serializer | chat participant', 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('chat-participant');
|
||||
|
||||
assert.ok(serializer);
|
||||
});
|
||||
|
||||
test('it serializes records', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let record = store.createRecord('chat-participant', {});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
|
||||
assert.ok(serializedRecord);
|
||||
});
|
||||
});
|
||||
1283
database.mmd
1283
database.mmd
File diff suppressed because it is too large
Load Diff
@@ -69,9 +69,6 @@ services:
|
||||
MAIL_FROM_NAME: Fleetbase
|
||||
APP_NAME: Fleetbase
|
||||
LOG_CHANNEL: daily
|
||||
MODEL_CACHE_ENABLED: true
|
||||
RESPONSE_CACHE_ENABLED: true
|
||||
RESPONSE_CACHE_DRIVER: redis
|
||||
depends_on:
|
||||
- database
|
||||
- cache
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 2.3 MiB After Width: | Height: | Size: 1.4 MiB |
17568
erd.svg
17568
erd.svg
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 794 KiB |
Submodule packages/core-api updated: 96c766bb19...20b33106eb
Submodule packages/ember-core updated: a068790fa5...f01867c219
Submodule packages/ember-ui updated: 9899510caa...700a229449
Submodule packages/fleetops updated: 46a2fa7231...ece7edf086
47
static-build.Dockerfile
Normal file
47
static-build.Dockerfile
Normal file
@@ -0,0 +1,47 @@
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
|
||||
# # Install packages
|
||||
# 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
|
||||
|
||||
# Set some build ENV variables
|
||||
ENV LOG_CHANNEL=stdout
|
||||
ENV CACHE_DRIVER=null
|
||||
ENV BROADCAST_DRIVER=socketcluster
|
||||
ENV QUEUE_CONNECTION=redis
|
||||
ENV CADDYFILE_PATH=/fleetbase/Caddyfile
|
||||
ENV OCTANE_SERVER=frankenphp
|
||||
|
||||
# Set environment
|
||||
ARG ENVIRONMENT=production
|
||||
ENV APP_ENV=$ENVIRONMENT
|
||||
|
||||
# Copy Caddyfile
|
||||
COPY ./Caddyfile $CADDYFILE_PATH
|
||||
|
||||
# Create /fleetbase directory and set correct permissions
|
||||
RUN mkdir -p /fleetbase && mkdir -p /fleetbase/api && mkdir -p /fleetbase/console
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /fleetbase/api
|
||||
|
||||
# Setup api
|
||||
COPY ./api /fleetbase/api
|
||||
|
||||
# Setup console
|
||||
COPY ./console /fleetbase/console
|
||||
|
||||
# Set permissions for deploy script
|
||||
RUN chmod +x /fleetbase/api/deploy.sh
|
||||
|
||||
# Pre-install Composer dependencies
|
||||
# RUN /bin/sh -c "composer install --no-scripts --optimize-autoloader --no-dev"
|
||||
|
||||
# Dump autoload
|
||||
# RUN /bin/sh -c "composer dumpautoload"
|
||||
|
||||
# Build binary
|
||||
RUN EMBED=/ \
|
||||
PHP_EXTENSIONS=pdo_mysql,gd,bcmath,redis,intl,zip,gmp,apcu,opcache,memcached,imagick,geos,sockets,pcntl \
|
||||
./build-static.sh
|
||||
Reference in New Issue
Block a user