diff --git a/.eslintrc.js b/.eslintrc.js
index d483054..6ce7d20 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -16,6 +16,10 @@ module.exports = {
env: {
browser: true,
},
+ globals: {
+ socketClusterClient: 'readonly',
+ L: 'readonly',
+ },
rules: {
'ember/no-array-prototype-extensions': 'off',
'ember/no-computed-properties-in-native-classes': 'off',
@@ -27,7 +31,7 @@ module.exports = {
'n/no-unpublished-require': [
'error',
{
- allowModules: ['resolve', 'broccoli-funnel'],
+ allowModules: ['resolve'],
},
],
},
diff --git a/.stylelintignore b/.stylelintignore
index a0cf71c..29348e2 100644
--- a/.stylelintignore
+++ b/.stylelintignore
@@ -6,3 +6,7 @@
# addons
/.node_modules.ember-try/
+
+# server
+/server/
+/server_vendor/
diff --git a/.stylelintrc.js b/.stylelintrc.js
index 62d4554..f1804fe 100644
--- a/.stylelintrc.js
+++ b/.stylelintrc.js
@@ -2,4 +2,9 @@
module.exports = {
extends: ['stylelint-config-standard', 'stylelint-prettier/recommended'],
+ rules: {
+ 'selector-class-pattern': null,
+ 'no-descending-specificity': null,
+ 'color-function-notation': null,
+ },
};
diff --git a/addon/components/explorer-header.hbs b/addon/components/explorer-header.hbs
new file mode 100644
index 0000000..a7cc128
--- /dev/null
+++ b/addon/components/explorer-header.hbs
@@ -0,0 +1,18 @@
+
\ No newline at end of file
diff --git a/addon/components/explorer-header.js b/addon/components/explorer-header.js
new file mode 100644
index 0000000..2c26ee9
--- /dev/null
+++ b/addon/components/explorer-header.js
@@ -0,0 +1,25 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+
+export default class ExplorerHeaderComponent extends Component {
+ @service explorerState;
+ @tracked state = [];
+
+ constructor(owner, { pod }) {
+ super(...arguments);
+ this.state = this.explorerState.get(pod);
+ this.explorerState.on('change', (id, state) => {
+ if (id === pod) {
+ this.state = state;
+ }
+ });
+ }
+
+ @action onStateClicked(content) {
+ if (typeof this.args.onStateClicked === 'function') {
+ this.args.onStateClicked(content);
+ }
+ }
+}
diff --git a/addon/components/modals/backup-pod.hbs b/addon/components/modals/backup-pod.hbs
new file mode 100644
index 0000000..464bfc7
--- /dev/null
+++ b/addon/components/modals/backup-pod.hbs
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/addon/components/modals/create-pod.hbs b/addon/components/modals/create-pod.hbs
new file mode 100644
index 0000000..e57cead
--- /dev/null
+++ b/addon/components/modals/create-pod.hbs
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/addon/components/modals/resync-pod.hbs b/addon/components/modals/resync-pod.hbs
new file mode 100644
index 0000000..464bfc7
--- /dev/null
+++ b/addon/components/modals/resync-pod.hbs
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/addon/components/table/cell/pod-content-actions.hbs b/addon/components/table/cell/pod-content-actions.hbs
new file mode 100644
index 0000000..ab01dce
--- /dev/null
+++ b/addon/components/table/cell/pod-content-actions.hbs
@@ -0,0 +1,32 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/addon/components/table/cell/pod-content-actions.js b/addon/components/table/cell/pod-content-actions.js
new file mode 100644
index 0000000..3c69eae
--- /dev/null
+++ b/addon/components/table/cell/pod-content-actions.js
@@ -0,0 +1,73 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { action, computed } from '@ember/object';
+import { isArray } from '@ember/array';
+
+export default class TableCellPodContentActionsComponent extends Component {
+ constructor(owner, { column, row }) {
+ super(...arguments);
+ if (isArray(column.actions)) {
+ this.actions = column.actions;
+ }
+
+ if (typeof column.actions === 'function') {
+ this.actions = column.actions(row);
+ }
+ }
+
+ @tracked actions = [];
+ @tracked defaultButtonText = 'Actions';
+
+ @computed('args.column.ddButtonText', 'defaultButtonText') get buttonText() {
+ const { ddButtonText } = this.args.column;
+
+ if (ddButtonText === undefined) {
+ return this.defaultButtonText;
+ }
+
+ if (ddButtonText === false) {
+ return null;
+ }
+
+ return ddButtonText;
+ }
+
+ @action setupComponent(dropdownWrapperNode) {
+ const tableCellNode = this.getOwnerTableCell(dropdownWrapperNode);
+ tableCellNode.style.overflow = 'visible';
+ }
+
+ @action getOwnerTableCell(dropdownWrapperNode) {
+ while (dropdownWrapperNode) {
+ dropdownWrapperNode = dropdownWrapperNode.parentNode;
+
+ if (dropdownWrapperNode.tagName.toLowerCase() === 'td') {
+ return dropdownWrapperNode;
+ }
+ }
+
+ return undefined;
+ }
+
+ @action onDropdownItemClick(columnAction, row, dd) {
+ if (typeof dd?.actions?.close === 'function') {
+ dd.actions.close();
+ }
+
+ if (typeof columnAction?.fn === 'function') {
+ columnAction.fn(row);
+ }
+ }
+
+ @action calculatePosition(trigger) {
+ let { width } = trigger.getBoundingClientRect();
+
+ let style = {
+ marginTop: '0px',
+ right: width + 3,
+ top: 0,
+ };
+
+ return { style };
+ }
+}
diff --git a/addon/components/table/cell/pod-content-name.hbs b/addon/components/table/cell/pod-content-name.hbs
new file mode 100644
index 0000000..bad8160
--- /dev/null
+++ b/addon/components/table/cell/pod-content-name.hbs
@@ -0,0 +1,8 @@
+
+ {{#if (has-block)}}
+ {{yield}}
+ {{else}}
+
+ {{or @value @column.anchorText "-"}}
+ {{/if}}
+
\ No newline at end of file
diff --git a/addon/components/table/cell/pod-content-name.js b/addon/components/table/cell/pod-content-name.js
new file mode 100644
index 0000000..5ebc866
--- /dev/null
+++ b/addon/components/table/cell/pod-content-name.js
@@ -0,0 +1,16 @@
+import Component from '@glimmer/component';
+import { action } from '@ember/object';
+
+export default class TableCellPodContentNameComponent extends Component {
+ @action onClick() {
+ const { column, row } = this.args;
+
+ if (typeof column?.action === 'function') {
+ column.action(row);
+ }
+
+ if (typeof column?.onClick === 'function') {
+ column.onClick(row, ...arguments);
+ }
+ }
+}
diff --git a/addon/controllers/account.js b/addon/controllers/account.js
new file mode 100644
index 0000000..7bfbc31
--- /dev/null
+++ b/addon/controllers/account.js
@@ -0,0 +1,130 @@
+import Controller from '@ember/controller';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+import { alias } from '@ember/object/computed';
+import { task } from 'ember-concurrency';
+
+export default class AccountController extends Controller {
+ /**
+ * Inject the `currentUser` service.
+ *
+ * @memberof ConsoleAccountIndexController
+ */
+ @service currentUser;
+
+ /**
+ * Inject the `fetch` service.
+ *
+ * @memberof ConsoleAccountIndexController
+ */
+ @service fetch;
+
+ /**
+ * Inject the `notifications` service.
+ *
+ * @memberof ConsoleAccountIndexController
+ */
+ @service notifications;
+
+ /**
+ * Inject the `modalsManager` service.
+ *
+ * @memberof ConsoleAccountIndexController
+ */
+ @service modalsManager;
+
+ /**
+ * Alias to the currentUser service user record.
+ *
+ * @memberof ConsoleAccountIndexController
+ */
+ @alias('currentUser.user') user;
+
+ /**
+ * Handle upload of new photo
+ *
+ * @param {UploadFile} file
+ * @memberof ConsoleAccountIndexController
+ */
+ @action uploadNewPhoto(file) {
+ return this.fetch.uploadFile.perform(
+ file,
+ {
+ path: `uploads/${this.user.company_uuid}/users/${this.user.slug}`,
+ subject_uuid: this.user.id,
+ subject_type: 'user',
+ type: 'user_avatar',
+ },
+ (uploadedFile) => {
+ this.user.setProperties({
+ avatar_uuid: uploadedFile.id,
+ avatar_url: uploadedFile.url,
+ });
+
+ return this.user.save();
+ }
+ );
+ }
+
+ /**
+ * Starts the task to change password
+ *
+ * @param {Event} event
+ * @memberof ConsoleAccountIndexController
+ */
+ @task *saveProfile(event) {
+ // If from event fired
+ if (event instanceof Event) {
+ event.preventDefault();
+ }
+
+ let canUpdateProfile = true;
+ // If email has been changed prompt for password validation
+ if (this.changedUserAttribute('email')) {
+ canUpdateProfile = yield this.validatePassword.perform();
+ }
+
+ if (canUpdateProfile === true) {
+ try {
+ const user = yield this.user.save();
+ this.notifications.success('Profile changes saved.');
+ this.currentUser.set('user', user);
+ } catch (error) {
+ this.notifications.serverError(error);
+ }
+ } else {
+ this.user.rollbackAttributes();
+ }
+ }
+
+ /**
+ * Task to validate current password
+ *
+ * @return {boolean}
+ * @memberof ConsoleAccountIndexController
+ */
+ @task *validatePassword() {
+ let isPasswordValid = false;
+
+ yield this.modalsManager.show('modals/validate-password', {
+ body: 'You must validate your password to update the account email address.',
+ onValidated: (isValid) => {
+ isPasswordValid = isValid;
+ },
+ });
+
+ return isPasswordValid;
+ }
+
+ /**
+ * Checks if any user attribute has been changed
+ *
+ * @param {string} attributeKey
+ * @return {boolean}
+ * @memberof ConsoleAccountIndexController
+ */
+ changedUserAttribute(attributeKey) {
+ const changedAttributes = this.user.changedAttributes();
+ return changedAttributes[attributeKey] !== undefined;
+ }
+}
diff --git a/addon/controllers/application.js b/addon/controllers/application.js
index a87cc82..8a0d04c 100644
--- a/addon/controllers/application.js
+++ b/addon/controllers/application.js
@@ -1,27 +1,30 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
-import { task } from 'ember-concurrency';
+import { tracked } from '@glimmer/tracking';
+import { task, timeout } from 'ember-concurrency';
export default class ApplicationController extends Controller {
- @service universe;
@service fetch;
+ @service appCache;
+ @tracked pods = [];
constructor() {
super(...arguments);
- this.universe.on('sidebarContext.available', (sidebarContext) => {
- sidebarContext.hideNow();
- });
+ this.getPods.perform();
}
- @task *authenticate() {
- const { authenticationUrl, identifier } = yield this.fetch.get('request-authentication', {}, { namespace: 'solid/int/v1' });
- if (authenticationUrl) {
- window.location.href = `${authenticationUrl}/${identifier}`;
+ @task *getPods() {
+ yield timeout(600);
+
+ if (this.appCache.has('solid:pods')) {
+ this.pods = this.appCache.get('solid:pods', []);
+ return;
}
- }
- @task *getAccountIndex() {
- const response = yield this.fetch.get('account', {}, { namespace: 'solid/int/v1' });
- console.log('[response]', response);
+ try {
+ this.pods = yield this.fetch.get('pods', {}, { namespace: 'solid/int/v1' });
+ } catch (error) {
+ // silence
+ }
}
}
diff --git a/addon/controllers/home.js b/addon/controllers/home.js
new file mode 100644
index 0000000..033a1bd
--- /dev/null
+++ b/addon/controllers/home.js
@@ -0,0 +1,23 @@
+import Controller from '@ember/controller';
+import { inject as service } from '@ember/service';
+import { task } from 'ember-concurrency';
+
+export default class HomeController extends Controller {
+ @service fetch;
+ @service notifications;
+
+ @task *authenticate() {
+ try {
+ const { authenticationUrl, identifier } = yield this.fetch.get('request-authentication', {}, { namespace: 'solid/int/v1' });
+ if (authenticationUrl) {
+ window.location.href = `${authenticationUrl}/${identifier}`;
+ }
+ } catch (error) {
+ this.notifications.serverError(error);
+ }
+ }
+
+ @task *getAccountIndex() {
+ yield this.fetch.get('account', {}, { namespace: 'solid/int/v1' });
+ }
+}
diff --git a/addon/controllers/pods/explorer.js b/addon/controllers/pods/explorer.js
new file mode 100644
index 0000000..6d08210
--- /dev/null
+++ b/addon/controllers/pods/explorer.js
@@ -0,0 +1,149 @@
+import Controller from '@ember/controller';
+import { action } from '@ember/object';
+import { inject as service } from '@ember/service';
+import { tracked } from '@glimmer/tracking';
+import { task, timeout } from 'ember-concurrency';
+
+export default class PodsExplorerController extends Controller {
+ @service hostRouter;
+ @service fetch;
+ @service notifications;
+ @service explorerState;
+ @service modalsManager;
+ @service crud;
+ @tracked cursor = '';
+ @tracked pod = '';
+ @tracked query = '';
+ queryParams = ['cursor', 'pod', 'query'];
+ columns = [
+ {
+ label: 'Name',
+ valuePath: 'name',
+ width: '75%',
+ cellComponent: 'table/cell/pod-content-name',
+ onClick: this.viewContents,
+ },
+ {
+ label: 'Type',
+ valuePath: 'type',
+ cellClassNames: 'capitalize',
+ width: '5%',
+ },
+ {
+ label: 'Size',
+ valuePath: 'size',
+ width: '5%',
+ },
+ {
+ label: 'Created At',
+ valuePath: 'created_at',
+ width: '15%',
+ },
+ {
+ label: '',
+ cellComponent: 'table/cell/pod-content-actions',
+ ddButtonText: false,
+ ddButtonIcon: 'ellipsis-h',
+ ddButtonIconPrefix: 'fas',
+ ddMenuLabel: 'Actions',
+ cellClassNames: 'overflow-visible',
+ wrapperClass: 'flex items-center justify-end mx-2',
+ width: '10%',
+ actions: (content) => {
+ return [
+ {
+ label: content.type === 'folder' ? 'Browse Folder' : 'View Contents',
+ fn: this.viewContents,
+ },
+ {
+ separator: true,
+ },
+ {
+ label: 'Delete',
+ fn: this.deleteSomething,
+ },
+ ];
+ },
+ sortable: false,
+ filterable: false,
+ resizable: false,
+ searchable: false,
+ },
+ ];
+
+ @action reload() {
+ this.hostRouter.refresh();
+ }
+
+ @action back() {
+ if (typeof this.cursor === 'string' && this.cursor.length && this.cursor !== this.model.id) {
+ const current = this.reverseCursor();
+ return this.hostRouter.transitionTo('console.solid-protocol.pods.explorer', current, { queryParams: { cursor: this.cursor, pod: this.pod } });
+ }
+
+ this.hostRouter.transitionTo('console.solid-protocol.pods.index');
+ }
+
+ @action viewContents(content) {
+ if (content.type === 'folder') {
+ return this.hostRouter.transitionTo('console.solid-protocol.pods.explorer', content, { queryParams: { cursor: this.trackCursor(content), pod: this.pod } });
+ }
+
+ if (content.type === 'file') {
+ return this.hostRouter.transitionTo('console.solid-protocol.pods.explorer.content', content);
+ }
+
+ return this.hostRouter.transitionTo('console.solid-protocol.pods.explorer', this.pod, { queryParams: { cursor: this.trackCursor(content), pod: this.pod } });
+ }
+
+ @action deleteSomething() {
+ this.modalsManager.confirm({
+ title: 'Are you sure you want to delete this content?',
+ body: 'Deleting this Content will remove this content from this pod. This is irreversible!',
+ acceptButtonText: 'Delete Forever',
+ confirm: () => {},
+ });
+ }
+
+ @action deleteSelected() {
+ const selected = this.table.selectedRows;
+
+ this.crud.bulkDelete(selected, {
+ modelNamePath: 'name',
+ acceptButtonText: 'Delete All',
+ onSuccess: () => {
+ return this.hostRouter.refresh();
+ },
+ });
+ }
+
+ trackCursor(content) {
+ if (typeof this.cursor === 'string' && this.cursor.includes(content.id)) {
+ const segments = this.cursor.split(':');
+ const currentIndex = segments.findIndex((segment) => segment === content.id);
+
+ if (currentIndex > -1) {
+ const retainedSegments = segments.slice(0, currentIndex + 1);
+ this.cursor = retainedSegments.join(':');
+ return this.cursor;
+ }
+ }
+
+ this.cursor = this.cursor ? `${this.cursor}:${content.id}` : content.id;
+ return this.cursor;
+ }
+
+ reverseCursor() {
+ const segments = this.cursor.split(':');
+ segments.pop();
+ const current = segments[segments.length - 1];
+ this.cursor = segments.join(':');
+ return current;
+ }
+
+ @task({ restartable: true }) *search(event) {
+ yield timeout(300);
+ const query = typeof event.target.value === 'string' ? event.target.value : '';
+ this.hostRouter.transitionTo('console.solid-protocol.pods.explorer', this.model.id, { queryParams: { cursor: this.cursor, query } });
+ }
+}
diff --git a/addon/controllers/pods/explorer/content.js b/addon/controllers/pods/explorer/content.js
new file mode 100644
index 0000000..b6a540e
--- /dev/null
+++ b/addon/controllers/pods/explorer/content.js
@@ -0,0 +1,12 @@
+import Controller from '@ember/controller';
+import { action } from '@ember/object';
+
+export default class PodsExplorerContentController extends Controller {
+ @action setOverlayContext(overlayContextApi) {
+ this.overlayContextApi = overlayContextApi;
+ }
+
+ @action onPressClose() {
+ window.history.back();
+ }
+}
diff --git a/addon/controllers/pods/index.js b/addon/controllers/pods/index.js
new file mode 100644
index 0000000..a0a63e7
--- /dev/null
+++ b/addon/controllers/pods/index.js
@@ -0,0 +1,137 @@
+import Controller from '@ember/controller';
+import { action } from '@ember/object';
+import { inject as service } from '@ember/service';
+import { tracked } from '@glimmer/tracking';
+import { task, timeout } from 'ember-concurrency';
+
+export default class PodsIndexController extends Controller {
+ @service hostRouter;
+ @service notifications;
+ @service filters;
+ @service modalsManager;
+ @service crud;
+ @tracked query = '';
+
+ columns = [
+ {
+ label: 'Pod',
+ valuePath: 'name',
+ width: '80%',
+ cellComponent: 'table/cell/anchor',
+ onClick: this.explorePod,
+ },
+ {
+ label: 'Size',
+ valuePath: 'size',
+ width: '5%',
+ },
+ {
+ label: 'Created At',
+ valuePath: 'created_at',
+ width: '15%',
+ },
+ {
+ label: '',
+ cellComponent: 'table/cell/dropdown',
+ ddButtonText: false,
+ ddButtonIcon: 'ellipsis-h',
+ ddButtonIconPrefix: 'fas',
+ ddMenuLabel: 'Pod Actions',
+ cellClassNames: 'overflow-visible',
+ wrapperClass: 'flex items-center justify-end mx-2',
+ width: '10%',
+ actions: [
+ {
+ label: 'Browse',
+ fn: this.openPod,
+ },
+ {
+ label: 'Backup',
+ fn: this.backupPod,
+ },
+ {
+ label: 'Re-sync',
+ fn: this.resyncPod,
+ },
+ {
+ separator: true,
+ },
+ {
+ label: 'Delete',
+ fn: this.deletePod,
+ },
+ ],
+ sortable: false,
+ filterable: false,
+ resizable: false,
+ searchable: false,
+ },
+ ];
+
+ @action reload() {
+ this.hostRouter.refresh();
+ }
+
+ @action openPod(pod) {
+ this.hostRouter.transitionTo('console.solid-protocol.pods.index.pod', pod);
+ }
+
+ @action explorePod(pod) {
+ this.hostRouter.transitionTo('console.solid-protocol.pods.explorer', pod, { queryParams: { cursor: pod.id, pod: pod.id } });
+ }
+
+ @action createPod() {
+ this.modalsManager.show('modals/create-pod', {
+ title: 'Create a new Pod',
+ acceptButtonText: 'Create Pod',
+ pod: {
+ name: null,
+ },
+ confirm: () => {},
+ });
+ }
+
+ @action backupPod() {
+ this.modalsManager.confirm({
+ title: 'Are you sure you want to create a backup?',
+ body: 'Running a backup will create a duplicate Pod with the same contents.',
+ acceptButtonText: 'Start Backup',
+ confirm: () => {},
+ });
+ }
+
+ @action resyncPod() {
+ this.modalsManager.confirm({
+ title: 'Are you sure you want to re-sync?',
+ body: 'Running a re-sync will update all data from Fleetbase to this pod, overwriting the current contents with the latest.',
+ acceptButtonText: 'Start Sync',
+ confirm: () => {},
+ });
+ }
+
+ @action deletePod() {
+ this.modalsManager.confirm({
+ title: 'Are you sure you want to delete this Pod?',
+ body: "Deleting this Pod will destroy this pod and all it's contents. This is irreversible!",
+ acceptButtonText: 'Delete Forever',
+ confirm: () => {},
+ });
+ }
+
+ @action deleteSelectedPods() {
+ const selected = this.table.selectedRows;
+
+ this.crud.bulkDelete(selected, {
+ modelNamePath: 'name',
+ acceptButtonText: 'Delete All',
+ onSuccess: () => {
+ return this.hostRouter.refresh();
+ },
+ });
+ }
+
+ @task({ restartable: true }) *search(event) {
+ yield timeout(300);
+ this.query = typeof event.target.value === 'string' ? event.target.value : '';
+ }
+}
diff --git a/addon/controllers/pods/index/pod.js b/addon/controllers/pods/index/pod.js
new file mode 100644
index 0000000..57ee654
--- /dev/null
+++ b/addon/controllers/pods/index/pod.js
@@ -0,0 +1,12 @@
+import Controller from '@ember/controller';
+import { action } from '@ember/object';
+
+export default class PodsIndexPodController extends Controller {
+ @action setOverlayContext(overlayContextApi) {
+ this.overlayContextApi = overlayContextApi;
+ }
+
+ @action onPressClose() {
+ window.history.back();
+ }
+}
diff --git a/addon/routes.js b/addon/routes.js
index fbe9f1b..edcdee1 100644
--- a/addon/routes.js
+++ b/addon/routes.js
@@ -1,3 +1,14 @@
import buildRoutes from 'ember-engines/routes';
-export default buildRoutes(function () {});
+export default buildRoutes(function () {
+ this.route('home', { path: '/' });
+ this.route('account');
+ this.route('pods', function () {
+ this.route('explorer', { path: '/explorer/:id' }, function () {
+ this.route('content', { path: '/~/:slug' });
+ });
+ this.route('index', { path: '/' }, function () {
+ this.route('pod', { path: '/pod/:slug' });
+ });
+ });
+});
diff --git a/addon/routes/account.js b/addon/routes/account.js
new file mode 100644
index 0000000..17e9a38
--- /dev/null
+++ b/addon/routes/account.js
@@ -0,0 +1,3 @@
+import Route from '@ember/routing/route';
+
+export default class AccountRoute extends Route {}
diff --git a/addon/routes/home.js b/addon/routes/home.js
new file mode 100644
index 0000000..f9ee296
--- /dev/null
+++ b/addon/routes/home.js
@@ -0,0 +1,3 @@
+import Route from '@ember/routing/route';
+
+export default class HomeRoute extends Route {}
diff --git a/addon/routes/pods/explorer.js b/addon/routes/pods/explorer.js
new file mode 100644
index 0000000..cded656
--- /dev/null
+++ b/addon/routes/pods/explorer.js
@@ -0,0 +1,44 @@
+import Route from '@ember/routing/route';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+
+export default class PodsExplorerRoute extends Route {
+ @service fetch;
+ @service explorerState;
+
+ queryParmas = {
+ query: {
+ refreshModel: true,
+ },
+ pod: {
+ refreshModel: false,
+ },
+ cursor: {
+ refreshModel: false,
+ },
+ };
+
+ @action willTransition(transition) {
+ const pod = transition.to.queryParams.pod;
+ const cursor = transition.to.queryParams.cursor;
+ if (pod && cursor) {
+ this.explorerState.trackWithCursor(pod, cursor);
+ }
+ }
+
+ beforeModel(transition) {
+ const pod = transition.to.queryParams.pod;
+ const cursor = transition.to.queryParams.cursor;
+ if (pod && cursor) {
+ this.explorerState.trackWithCursor(pod, cursor);
+ }
+ }
+
+ model({ id, query }) {
+ return this.fetch.get('pods', { id, query }, { namespace: 'solid/int/v1' });
+ }
+
+ afterModel(model, transition) {
+ this.explorerState.track(transition.to.queryParams.pod, model);
+ }
+}
diff --git a/addon/routes/pods/explorer/content.js b/addon/routes/pods/explorer/content.js
new file mode 100644
index 0000000..88b97fb
--- /dev/null
+++ b/addon/routes/pods/explorer/content.js
@@ -0,0 +1,10 @@
+import Route from '@ember/routing/route';
+import { inject as service } from '@ember/service';
+
+export default class PodsExplorerContentRoute extends Route {
+ @service fetch;
+
+ model({ slug }) {
+ return this.fetch.get('pods', { slug }, { namespace: 'solid/int/v1' });
+ }
+}
diff --git a/addon/routes/pods/index.js b/addon/routes/pods/index.js
new file mode 100644
index 0000000..96345c5
--- /dev/null
+++ b/addon/routes/pods/index.js
@@ -0,0 +1,21 @@
+import Route from '@ember/routing/route';
+import { inject as service } from '@ember/service';
+
+export default class PodsIndexRoute extends Route {
+ @service fetch;
+ @service appCache;
+
+ queryParams = {
+ query: {
+ refreshModel: true,
+ },
+ };
+
+ model(params) {
+ return this.fetch.get('pods', params, { namespace: 'solid/int/v1' });
+ }
+
+ afterModel(model) {
+ this.appCache.set('solid:pods', model);
+ }
+}
diff --git a/addon/routes/pods/index/pod.js b/addon/routes/pods/index/pod.js
new file mode 100644
index 0000000..a4339fc
--- /dev/null
+++ b/addon/routes/pods/index/pod.js
@@ -0,0 +1,3 @@
+import Route from '@ember/routing/route';
+
+export default class PodsIndexPodRoute extends Route {}
diff --git a/addon/services/explorer-state.js b/addon/services/explorer-state.js
new file mode 100644
index 0000000..dc34089
--- /dev/null
+++ b/addon/services/explorer-state.js
@@ -0,0 +1,101 @@
+import Service from '@ember/service';
+import Evented from '@ember/object/evented';
+import { inject as service } from '@ember/service';
+import { isArray } from '@ember/array';
+
+export default class ExplorerStateService extends Service.extend(Evented) {
+ @service appCache;
+
+ trackWithCursor(id, cursor) {
+ const segments = typeof cursor === 'string' ? cursor.split(':') : [];
+ const state = this.get(id);
+ this.update(
+ id,
+ state.filter((content) => {
+ return segments.includes(content.id);
+ })
+ );
+ this.clean(id);
+ return this;
+ }
+
+ track(id, content) {
+ if (id === content.id) {
+ this.initialize(id, content);
+ } else {
+ this.push(id, content);
+ }
+
+ this.clean(id);
+ return this;
+ }
+
+ initialize(id, content) {
+ const state = this.get(id);
+ if (isArray(state) && state.length === 0) {
+ state.pushObject(content);
+ this.update(id, state);
+ }
+
+ return this;
+ }
+
+ push(id, content) {
+ const state = this.get(id);
+ if (isArray(state) && this.doesntHave(id, content)) {
+ state.pushObject(content);
+ this.update(id, state);
+ }
+
+ return this;
+ }
+
+ pop(id) {
+ const state = this.get(id);
+ if (isArray(state)) {
+ state.pop();
+ this.update(id, state);
+ }
+
+ return this;
+ }
+
+ has(id, content) {
+ const state = this.get(id);
+ return state.findIndex((_) => _.id === content.id) >= 0;
+ }
+
+ doesntHave(id, content) {
+ return !this.has(id, content);
+ }
+
+ get(id) {
+ return this.appCache.get(`${id}:explorer:state`, []);
+ }
+
+ update(id, state = []) {
+ this.appCache.set(`${id}:explorer:state`, state);
+ this.trigger('change', id, state);
+ return this;
+ }
+
+ clean(id) {
+ const state = this.get(id);
+ if (isArray(state)) {
+ const seenIds = new Set();
+ this.update(
+ id,
+ state.filter((_) => {
+ if (seenIds.has(_.id)) {
+ return false;
+ }
+
+ seenIds.add(_.id);
+ return true;
+ })
+ );
+ }
+
+ return this;
+ }
+}
diff --git a/addon/styles/solid-engine.css b/addon/styles/solid-engine.css
index 9681a09..34b3003 100644
--- a/addon/styles/solid-engine.css
+++ b/addon/styles/solid-engine.css
@@ -27,3 +27,49 @@ body[data-theme='dark'] .solid-fleetbase-home-container a:not([class*='text-']),
.solid-fleetbase-home-container a:hover {
opacity: 0.5;
}
+
+.pod-explorer-breadcrumb-container {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.pod-explorer-breadcrumb-container > .pod-explorer-breadcrumb:first-child {
+ border-top-left-radius: 0.75rem;
+ border-bottom-left-radius: 0.75rem;
+}
+
+.pod-explorer-breadcrumb-container > .pod-explorer-breadcrumb:last-child {
+ border-top-right-radius: 0.75rem;
+ border-bottom-right-radius: 0.75rem;
+}
+
+.pod-explorer-breadcrumb {
+ font-size: 0.85rem;
+ border: 1px #111827 solid;
+ padding: 0 0.75rem;
+ line-height: 1.75rem;
+ background-color: #1f2937;
+ color: #fff;
+}
+
+.pod-explorer-breadcrumb:hover {
+ opacity: 0.75;
+}
+
+.pod-explorer-breadcrumb.active-breadcrumb {
+ background-color: #2563eb;
+ color: #eff6ff;
+}
+
+body[data-theme='light'] .pod-explorer-breadcrumb {
+ border: 1px #e5e7eb solid;
+ background-color: #e5e7eb;
+ color: #1f2937;
+}
+
+body[data-theme='light'] .pod-explorer-breadcrumb.active-breadcrumb {
+ background-color: #3b82f6;
+ color: #eff6ff;
+ border-color: #2563eb;
+}
diff --git a/addon/templates/account.hbs b/addon/templates/account.hbs
new file mode 100644
index 0000000..a614e2c
--- /dev/null
+++ b/addon/templates/account.hbs
@@ -0,0 +1,42 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/addon/templates/application.hbs b/addon/templates/application.hbs
index 6b8d727..ccfcc25 100644
--- a/addon/templates/application.hbs
+++ b/addon/templates/application.hbs
@@ -1,15 +1,20 @@
-
-
+
+ Home
+ Pods
+ {{!--
+ All
+ {{#each this.pods as |pod|}}
+
+
+
+
+ {{pod.name}}
+
+ {{/each}}
+ --}}
+ Account
+
-
- Welcome to Solid for Fleetbase
- Getting Started
-
-
- Sign up for an account to get started with your own Pod and WebID. Once you are logged in you can begin to manage your pods and sync data directly from Fleetbase to your Pods.
-
-
- {{!-- --}}
-
+
{{outlet}}
\ No newline at end of file
diff --git a/addon/templates/home.hbs b/addon/templates/home.hbs
new file mode 100644
index 0000000..101af59
--- /dev/null
+++ b/addon/templates/home.hbs
@@ -0,0 +1,11 @@
+
+
+ Welcome to Solid for Fleetbase
+ Getting Started
+
+
+ Sign up for an account to get started with your own Pod and WebID. Once you are logged in you can begin to manage your pods and sync data directly from Fleetbase to your Pods.
+
+
+ {{!-- --}}
+
\ No newline at end of file
diff --git a/addon/templates/pods/explorer.hbs b/addon/templates/pods/explorer.hbs
new file mode 100644
index 0000000..0dac5e7
--- /dev/null
+++ b/addon/templates/pods/explorer.hbs
@@ -0,0 +1,20 @@
+
+
+
+ {{#if (safe-has this.table "selectedRows")}}
+
+
+
+ {{/if}}
+
+
+
+
+
+{{outlet}}
\ No newline at end of file
diff --git a/addon/templates/pods/explorer/content.hbs b/addon/templates/pods/explorer/content.hbs
new file mode 100644
index 0000000..376c29a
--- /dev/null
+++ b/addon/templates/pods/explorer/content.hbs
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
ID: {{@model.id}}
+
Name: {{@model.name}}
+
Size: {{@model.size}}
+
+
+
+
\ No newline at end of file
diff --git a/addon/templates/pods/index.hbs b/addon/templates/pods/index.hbs
new file mode 100644
index 0000000..45212ed
--- /dev/null
+++ b/addon/templates/pods/index.hbs
@@ -0,0 +1,19 @@
+
+
+ {{#if (safe-has this.table "selectedRows")}}
+
+
+
+ {{/if}}
+
+
+
+
+
+{{outlet}}
\ No newline at end of file
diff --git a/addon/templates/pods/index/pod.hbs b/addon/templates/pods/index/pod.hbs
new file mode 100644
index 0000000..c432f19
--- /dev/null
+++ b/addon/templates/pods/index/pod.hbs
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/components/explorer-header.js b/app/components/explorer-header.js
new file mode 100644
index 0000000..4de1d90
--- /dev/null
+++ b/app/components/explorer-header.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/components/explorer-header';
diff --git a/app/components/modals/backup-pod.js b/app/components/modals/backup-pod.js
new file mode 100644
index 0000000..f5857f0
--- /dev/null
+++ b/app/components/modals/backup-pod.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/components/modals/backup-pod';
diff --git a/app/components/modals/create-pod.js b/app/components/modals/create-pod.js
new file mode 100644
index 0000000..bf62513
--- /dev/null
+++ b/app/components/modals/create-pod.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/components/modals/create-pod';
diff --git a/app/components/modals/resync-pod.js b/app/components/modals/resync-pod.js
new file mode 100644
index 0000000..2509e4d
--- /dev/null
+++ b/app/components/modals/resync-pod.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/components/modals/resync-pod';
diff --git a/app/components/table/cell/pod-content-actions.js b/app/components/table/cell/pod-content-actions.js
new file mode 100644
index 0000000..995164e
--- /dev/null
+++ b/app/components/table/cell/pod-content-actions.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/components/table/cell/pod-content-actions';
diff --git a/app/components/table/cell/pod-content-name.js b/app/components/table/cell/pod-content-name.js
new file mode 100644
index 0000000..db872a3
--- /dev/null
+++ b/app/components/table/cell/pod-content-name.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/components/table/cell/pod-content-name';
diff --git a/app/controllers/account.js b/app/controllers/account.js
new file mode 100644
index 0000000..c262c60
--- /dev/null
+++ b/app/controllers/account.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/controllers/account';
diff --git a/app/controllers/home.js b/app/controllers/home.js
new file mode 100644
index 0000000..5331cb3
--- /dev/null
+++ b/app/controllers/home.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/controllers/home';
diff --git a/app/controllers/pods/explorer.js b/app/controllers/pods/explorer.js
new file mode 100644
index 0000000..2f59204
--- /dev/null
+++ b/app/controllers/pods/explorer.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/controllers/pods/explorer';
diff --git a/app/controllers/pods/explorer/content.js b/app/controllers/pods/explorer/content.js
new file mode 100644
index 0000000..457ddf5
--- /dev/null
+++ b/app/controllers/pods/explorer/content.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/controllers/pods/explorer/content';
diff --git a/app/controllers/pods/index.js b/app/controllers/pods/index.js
new file mode 100644
index 0000000..135e730
--- /dev/null
+++ b/app/controllers/pods/index.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/controllers/pods/index';
diff --git a/app/controllers/pods/index/pod.js b/app/controllers/pods/index/pod.js
new file mode 100644
index 0000000..e8310f2
--- /dev/null
+++ b/app/controllers/pods/index/pod.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/controllers/pods/index/pod';
diff --git a/app/routes/account.js b/app/routes/account.js
new file mode 100644
index 0000000..9421510
--- /dev/null
+++ b/app/routes/account.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/routes/account';
diff --git a/app/routes/home.js b/app/routes/home.js
new file mode 100644
index 0000000..e1f7576
--- /dev/null
+++ b/app/routes/home.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/routes/home';
diff --git a/app/routes/pods/explorer.js b/app/routes/pods/explorer.js
new file mode 100644
index 0000000..caa9316
--- /dev/null
+++ b/app/routes/pods/explorer.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/routes/pods/explorer';
diff --git a/app/routes/pods/explorer/content.js b/app/routes/pods/explorer/content.js
new file mode 100644
index 0000000..01b498a
--- /dev/null
+++ b/app/routes/pods/explorer/content.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/routes/pods/explorer/content';
diff --git a/app/routes/pods/index.js b/app/routes/pods/index.js
new file mode 100644
index 0000000..9ba4189
--- /dev/null
+++ b/app/routes/pods/index.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/routes/pods/index';
diff --git a/app/routes/pods/index/pod.js b/app/routes/pods/index/pod.js
new file mode 100644
index 0000000..6982688
--- /dev/null
+++ b/app/routes/pods/index/pod.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/routes/pods/index/pod';
diff --git a/app/services/explorer-state.js b/app/services/explorer-state.js
new file mode 100644
index 0000000..3be8754
--- /dev/null
+++ b/app/services/explorer-state.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/services/explorer-state';
diff --git a/app/templates/account.js b/app/templates/account.js
new file mode 100644
index 0000000..85e6c60
--- /dev/null
+++ b/app/templates/account.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/templates/account';
diff --git a/app/templates/home.js b/app/templates/home.js
new file mode 100644
index 0000000..20cd7d2
--- /dev/null
+++ b/app/templates/home.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/templates/home';
diff --git a/app/templates/pods/explorer.js b/app/templates/pods/explorer.js
new file mode 100644
index 0000000..585adf4
--- /dev/null
+++ b/app/templates/pods/explorer.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/templates/pods/explorer';
diff --git a/app/templates/pods/explorer/content.js b/app/templates/pods/explorer/content.js
new file mode 100644
index 0000000..f6f4ddb
--- /dev/null
+++ b/app/templates/pods/explorer/content.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/templates/pods/explorer/content';
diff --git a/app/templates/pods/index.js b/app/templates/pods/index.js
new file mode 100644
index 0000000..05f0844
--- /dev/null
+++ b/app/templates/pods/index.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/templates/pods/index';
diff --git a/app/templates/pods/index/pod.js b/app/templates/pods/index/pod.js
new file mode 100644
index 0000000..940d9d7
--- /dev/null
+++ b/app/templates/pods/index/pod.js
@@ -0,0 +1 @@
+export { default } from '@fleetbase/solid-engine/templates/pods/index/pod';
diff --git a/composer.json b/composer.json
index e4141e1..45b0d32 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"name": "fleetbase/solid-api",
- "version": "0.0.2",
+ "version": "0.0.3",
"description": "Solid Protocol Extension to Store and Share Data with Fleetbase",
"keywords": [
"fleetbase-extension",
@@ -28,8 +28,8 @@
],
"require": {
"php": "^8.0",
- "fleetbase/core-api": "^1.4.16",
- "fleetbase/fleetops-api": "^0.4.25",
+ "fleetbase/core-api": "^1.4.22",
+ "fleetbase/fleetops-api": "^0.4.27",
"php-http/guzzle7-adapter": "^1.0",
"psr/http-factory-implementation": "*",
"jumbojett/openid-connect-php": "^0.9.10",
@@ -50,6 +50,12 @@
"phpstan/phpstan": "^1.10.38",
"symfony/var-dumper": "^5.4.29"
},
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "https://github.com/fleetbase/laravel-model-caching"
+ }
+ ],
"autoload": {
"psr-4": {
"Fleetbase\\Solid\\": "server/src/",
diff --git a/extension.json b/extension.json
index d1d9a18..e29cfdc 100644
--- a/extension.json
+++ b/extension.json
@@ -1,6 +1,6 @@
{
"name": "Solid",
- "version": "0.0.1",
+ "version": "0.0.3",
"description": "Solid Protocol Extension to Store and Share Data with Fleetbase",
"repository": "https://github.com/fleetbase/solid",
"license": "MIT",
diff --git a/package.json b/package.json
index 685d03e..4b5497d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@fleetbase/solid-engine",
- "version": "0.0.2",
+ "version": "0.0.3",
"description": "Solid Protocol Extension to Store and Share Data with Fleetbase",
"fleetbase": {
"route": "solid-protocol"
@@ -45,8 +45,8 @@
},
"dependencies": {
"@babel/core": "^7.23.2",
- "@fleetbase/ember-core": "^0.2.8",
- "@fleetbase/ember-ui": "^0.2.12",
+ "@fleetbase/ember-core": "^0.2.9",
+ "@fleetbase/ember-ui": "^0.2.13",
"@fleetbase/fleetops-data": "^0.1.14",
"@fortawesome/ember-fontawesome": "^0.4.1",
"@fortawesome/fontawesome-svg-core": "^6.4.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 06d354d..90b0225 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,15 +1,19 @@
lockfileVersion: '6.0'
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
dependencies:
'@babel/core':
specifier: ^7.23.2
version: 7.23.2
'@fleetbase/ember-core':
- specifier: ^0.2.8
- version: 0.2.8(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(webpack@5.89.0)
+ specifier: ^0.2.9
+ version: 0.2.9(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(webpack@5.89.0)
'@fleetbase/ember-ui':
- specifier: ^0.2.12
- version: 0.2.12(@ember/test-helpers@3.2.0)(@glimmer/component@1.1.2)(@glimmer/tracking@1.1.2)(ember-source@5.4.0)(postcss@8.4.35)(rollup@4.12.0)(tracked-built-ins@3.3.0)(webpack@5.89.0)
+ specifier: ^0.2.13
+ version: 0.2.13(@ember/test-helpers@3.2.0)(@glimmer/component@1.1.2)(@glimmer/tracking@1.1.2)(ember-source@5.4.0)(postcss@8.4.35)(rollup@4.12.0)(tracked-built-ins@3.3.0)(webpack@5.89.0)
'@fleetbase/fleetops-data':
specifier: ^0.1.14
version: 0.1.14
@@ -727,6 +731,19 @@ packages:
'@babel/core': 7.23.2
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.2)
+ dev: true
+
+ /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.24.4):
+ resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==}
+ engines: {node: '>=6.9.0'}
+ deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.24.4
+ '@babel/helper-plugin-utils': 7.22.5
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.4)
+ dev: false
/@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.23.2):
resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==}
@@ -739,6 +756,20 @@ packages:
'@babel/helper-plugin-utils': 7.22.5
'@babel/helper-skip-transparent-expression-wrappers': 7.22.5
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.2)
+ dev: true
+
+ /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.24.4):
+ resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==}
+ engines: {node: '>=6.9.0'}
+ deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.24.4
+ '@babel/helper-plugin-utils': 7.22.5
+ '@babel/helper-skip-transparent-expression-wrappers': 7.22.5
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.4)
+ dev: false
/@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.23.2):
resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==}
@@ -2177,6 +2208,17 @@ packages:
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.2)
+ /@babel/plugin-transform-typescript@7.5.5(@babel/core@7.24.4):
+ resolution: {integrity: sha512-pehKf4m640myZu5B2ZviLaiBlxMCjSZ1qTEO459AXKX5GnPueyulJeCqZFs1nz/Ya2dDzXQ1NxZ/kKNWyD4h6w==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.24.4
+ '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.24.4)
+ '@babel/helper-plugin-utils': 7.22.5
+ '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.4)
+ dev: false
+
/@babel/plugin-transform-typescript@7.8.7(@babel/core@7.23.2):
resolution: {integrity: sha512-7O0UsPQVNKqpHeHLpfvOG4uXmlw+MOxYvUv6Otc9uH5SYMIxvF6eBdjkWvC3f9G+VXe0RsNExyAQBeTRug/wqQ==}
peerDependencies:
@@ -2186,6 +2228,18 @@ packages:
'@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.23.2)
'@babel/helper-plugin-utils': 7.22.5
'@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.2)
+ dev: true
+
+ /@babel/plugin-transform-typescript@7.8.7(@babel/core@7.24.4):
+ resolution: {integrity: sha512-7O0UsPQVNKqpHeHLpfvOG4uXmlw+MOxYvUv6Otc9uH5SYMIxvF6eBdjkWvC3f9G+VXe0RsNExyAQBeTRug/wqQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ dependencies:
+ '@babel/core': 7.24.4
+ '@babel/helper-create-class-features-plugin': 7.23.10(@babel/core@7.24.4)
+ '@babel/helper-plugin-utils': 7.22.5
+ '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.4)
+ dev: false
/@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.23.2):
resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==}
@@ -3347,7 +3401,7 @@ packages:
- supports-color
dev: true
- /@ember/render-modifiers@2.1.0(@babel/core@7.23.2)(ember-source@5.4.0):
+ /@ember/render-modifiers@2.1.0(@babel/core@7.24.4)(ember-source@5.4.0):
resolution: {integrity: sha512-LruhfoDv2itpk0fA0IC76Sxjcnq/7BC6txpQo40hOko8Dn6OxwQfxkPIbZGV0Cz7df+iX+VJrcYzNIvlc3w2EQ==}
engines: {node: 12.* || 14.* || >= 16}
peerDependencies:
@@ -3357,9 +3411,9 @@ packages:
'@glint/template':
optional: true
dependencies:
- '@embroider/macros': 1.13.5
+ '@embroider/macros': 1.15.0
ember-cli-babel: 7.26.11
- ember-modifier-manager-polyfill: 1.2.0(@babel/core@7.23.2)
+ ember-modifier-manager-polyfill: 1.2.0(@babel/core@7.24.4)
ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0)
transitivePeerDependencies:
- '@babel/core'
@@ -3580,33 +3634,33 @@ packages:
peerDependencies:
ember-source: '>= 4.0.0'
dependencies:
- '@babel/core': 7.23.2
- ember-cli-babel: 8.2.0(@babel/core@7.23.2)
+ '@babel/core': 7.24.4
+ ember-cli-babel: 8.2.0(@babel/core@7.24.4)
ember-cli-htmlbars: 6.3.0
ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0)
transitivePeerDependencies:
- supports-color
dev: false
- /@fleetbase/ember-core@0.2.8(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(webpack@5.89.0):
- resolution: {integrity: sha512-9GGwjkp038UuMX4IHjw4NUqSinCOQWMisFG6XhQT8iyGlcOfSXJX8CxMyNutKpdwQ21VPbRoylVw0q4CmwjaNw==}
+ /@fleetbase/ember-core@0.2.9(@ember/test-helpers@3.2.0)(ember-source@5.4.0)(webpack@5.89.0):
+ resolution: {integrity: sha512-Z4XU5QydqP4dqzyncYW1vKxsUn9VjPiJ/R7l/L+jHuJTMr2AbbkZV5LtoQ0nP+Ib2euhlLMgLuxwlVRWUv/C+g==}
engines: {node: '>= 18'}
dependencies:
- '@babel/core': 7.23.2
+ '@babel/core': 7.24.4
compress-json: 3.0.3
date-fns: 2.30.0
ember-auto-import: 2.7.2(webpack@5.89.0)
- ember-cli-babel: 8.2.0(@babel/core@7.23.2)
+ ember-cli-babel: 8.2.0(@babel/core@7.24.4)
ember-cli-htmlbars: 6.3.0
ember-cli-notifications: 9.0.0
- ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0)
- ember-concurrency-decorators: 2.0.3(@babel/core@7.23.2)
+ ember-concurrency: 3.1.1(@babel/core@7.24.4)(ember-source@5.4.0)
+ ember-concurrency-decorators: 2.0.3(@babel/core@7.24.4)
ember-decorators: 6.1.1
ember-get-config: 2.1.1
ember-inflector: 4.0.2
- ember-intl: 6.3.2(@babel/core@7.23.2)(webpack@5.89.0)
- ember-loading: 2.0.0(@babel/core@7.23.2)
- ember-local-storage: 2.0.7(@babel/core@7.23.2)
+ ember-intl: 6.3.2(@babel/core@7.24.4)(webpack@5.89.0)
+ ember-loading: 2.0.0(@babel/core@7.24.4)
+ ember-local-storage: 2.0.7(@babel/core@7.24.4)
ember-simple-auth: 6.0.0(@ember/test-helpers@3.2.0)
ember-wormhole: 0.6.0
socketcluster-client: 17.2.2
@@ -3621,15 +3675,15 @@ packages:
- webpack
dev: false
- /@fleetbase/ember-ui@0.2.12(@ember/test-helpers@3.2.0)(@glimmer/component@1.1.2)(@glimmer/tracking@1.1.2)(ember-source@5.4.0)(postcss@8.4.35)(rollup@4.12.0)(tracked-built-ins@3.3.0)(webpack@5.89.0):
- resolution: {integrity: sha512-F1jqOAH8ACEW5QWyFgQrVvZB/jTMtK8pJG8MghSpLqo0zh+NKFs70PNGg18fKAljfL50Ld2wuP5c4rxhGxgX8A==}
+ /@fleetbase/ember-ui@0.2.13(@ember/test-helpers@3.2.0)(@glimmer/component@1.1.2)(@glimmer/tracking@1.1.2)(ember-source@5.4.0)(postcss@8.4.35)(rollup@4.12.0)(tracked-built-ins@3.3.0)(webpack@5.89.0):
+ resolution: {integrity: sha512-H+6H/+Uefif1kaxxGyLqfp40Krr7dhOXXi+AOCi00mhbfTyM2pVWFVLMj3TXoDB9GIYKGreQMuIx1XDc/yM4Nw==}
engines: {node: '>= 18'}
dependencies:
- '@babel/core': 7.23.2
- '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0)
+ '@babel/core': 7.24.4
+ '@ember/render-modifiers': 2.1.0(@babel/core@7.24.4)(ember-source@5.4.0)
'@ember/string': 3.1.1
'@embroider/addon': 0.30.0
- '@embroider/macros': 1.13.5
+ '@embroider/macros': 1.15.0
'@fleetbase/ember-accounting': 0.0.1(ember-source@5.4.0)
'@floating-ui/dom': 1.6.3
'@fortawesome/ember-fontawesome': 1.0.3(rollup@4.12.0)(webpack@5.89.0)
@@ -3651,26 +3705,26 @@ packages:
date-fns: 2.30.0
ember-animated: 1.1.4(@ember/test-helpers@3.2.0)(ember-source@5.4.0)
ember-auto-import: 2.7.2(webpack@5.89.0)
- ember-basic-dropdown: 7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0)
- ember-cli-babel: 8.2.0(@babel/core@7.23.2)
+ ember-basic-dropdown: 7.3.0(@babel/core@7.24.4)(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0)
+ ember-cli-babel: 8.2.0(@babel/core@7.24.4)
ember-cli-htmlbars: 6.3.0
ember-cli-postcss: 8.2.0
ember-cli-string-helpers: 6.1.0
ember-composable-helpers: 5.0.0
- ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0)
- ember-concurrency-decorators: 2.0.3(@babel/core@7.23.2)
+ ember-concurrency: 3.1.1(@babel/core@7.24.4)(ember-source@5.4.0)
+ ember-concurrency-decorators: 2.0.3(@babel/core@7.24.4)
ember-concurrency-test-waiter: 0.4.0(ember-concurrency@3.1.1)
ember-file-upload: 8.4.0(@ember/test-helpers@3.2.0)(@glimmer/component@1.1.2)(@glimmer/tracking@1.1.2)(ember-modifier@4.1.0)(tracked-built-ins@3.3.0)(webpack@5.89.0)
ember-focus-trap: 1.1.0(ember-source@5.4.0)
ember-get-config: 2.1.1
ember-inflector: 4.0.2
- ember-loading: 2.0.0(@babel/core@7.23.2)
+ ember-loading: 2.0.0(@babel/core@7.24.4)
ember-math-helpers: 4.0.0(ember-source@5.4.0)
ember-modifier: 4.1.0(ember-source@5.4.0)
ember-on-helper: 0.1.0
- ember-power-calendar: 0.18.0(@babel/core@7.23.2)(ember-source@5.4.0)
- ember-power-select: 7.2.0(@babel/core@7.23.2)(ember-source@5.4.0)(webpack@5.89.0)
- ember-ref-bucket: 4.1.0(@babel/core@7.23.2)
+ ember-power-calendar: 0.18.0(@babel/core@7.24.4)(ember-source@5.4.0)
+ ember-power-select: 7.2.0(@babel/core@7.24.4)(ember-source@5.4.0)(webpack@5.89.0)
+ ember-ref-bucket: 4.1.0(@babel/core@7.24.4)
ember-responsive: 5.0.0
ember-style-modifier: 3.1.1(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0)
ember-truth-helpers: 4.0.3(ember-source@5.4.0)
@@ -3949,6 +4003,29 @@ packages:
- '@babel/core'
- supports-color
+ /@glimmer/component@1.1.2(@babel/core@7.24.4):
+ resolution: {integrity: sha512-XyAsEEa4kWOPy+gIdMjJ8XlzA3qrGH55ZDv6nA16ibalCR17k74BI0CztxuRds+Rm6CtbUVgheCVlcCULuqD7A==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+ dependencies:
+ '@glimmer/di': 0.1.11
+ '@glimmer/env': 0.1.7
+ '@glimmer/util': 0.44.0
+ broccoli-file-creator: 2.1.1
+ broccoli-merge-trees: 3.0.2
+ ember-cli-babel: 7.26.11
+ ember-cli-get-component-path-option: 1.0.0
+ ember-cli-is-package-missing: 1.0.0
+ ember-cli-normalize-entity-name: 1.0.0
+ ember-cli-path-utils: 1.0.0
+ ember-cli-string-utils: 1.1.0
+ ember-cli-typescript: 3.0.0(@babel/core@7.24.4)
+ ember-cli-version-checker: 3.1.3
+ ember-compatibility-helpers: 1.2.7(@babel/core@7.24.4)
+ transitivePeerDependencies:
+ - '@babel/core'
+ - supports-color
+ dev: false
+
/@glimmer/destroyable@0.84.3:
resolution: {integrity: sha512-4tUw5UR4ntuySPvbcWyCMRjqxMJMV1GewjU3zGq22XvuBVFfq2K9WmuYV9H9FHg8X0MgDwcus+LjxrVSel39Sw==}
dependencies:
@@ -5304,6 +5381,7 @@ packages:
/async-each@1.0.6:
resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==}
+ requiresBuild: true
dev: false
optional: true
@@ -5432,7 +5510,7 @@ packages:
resolution: {integrity: sha512-N1ZfNprtf/37x0R05J0QCW/9pCAcuI+bjZIK9tlu0JEkwEST7ssdD++gxHRbD58AiG5QE5OuNYhRoEFsc1wESw==}
engines: {node: '>= 12.*'}
- /babel-loader@8.3.0(@babel/core@7.23.2)(webpack@4.47.0):
+ /babel-loader@8.3.0(@babel/core@7.23.2)(webpack@5.89.0):
resolution: {integrity: sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==}
engines: {node: '>= 8.9'}
peerDependencies:
@@ -5444,22 +5522,22 @@ packages:
loader-utils: 2.0.4
make-dir: 3.1.0
schema-utils: 2.7.1
- webpack: 4.47.0
- dev: false
+ webpack: 5.89.0
- /babel-loader@8.3.0(@babel/core@7.23.2)(webpack@5.89.0):
+ /babel-loader@8.3.0(@babel/core@7.24.4)(webpack@4.47.0):
resolution: {integrity: sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==}
engines: {node: '>= 8.9'}
peerDependencies:
'@babel/core': ^7.0.0
webpack: '>=2'
dependencies:
- '@babel/core': 7.23.2
+ '@babel/core': 7.24.4
find-cache-dir: 3.3.2
loader-utils: 2.0.4
make-dir: 3.1.0
schema-utils: 2.7.1
- webpack: 5.89.0
+ webpack: 4.47.0
+ dev: false
/babel-messages@6.23.0:
resolution: {integrity: sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==}
@@ -5480,6 +5558,16 @@ packages:
'@babel/core': 7.23.2
semver: 5.7.2
+ /babel-plugin-debug-macros@0.2.0(@babel/core@7.24.4):
+ resolution: {integrity: sha512-Wpmw4TbhR3Eq2t3W51eBAQSdKlr+uAyF0GI4GtPfMCD12Y4cIdpKC9l0RjNTH/P9isFypSqqewMPm7//fnZlNA==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-beta.42
+ dependencies:
+ '@babel/core': 7.24.4
+ semver: 5.7.2
+ dev: false
+
/babel-plugin-debug-macros@0.3.4(@babel/core@7.23.2):
resolution: {integrity: sha512-wfel/vb3pXfwIDZUrkoDrn5FHmlWI96PCJ3UCDv2a86poJ3EQrnArNW5KfHSVJ9IOgxHbo748cQt7sDU+0KCEw==}
engines: {node: '>=6'}
@@ -5747,6 +5835,7 @@ packages:
/binary-extensions@1.13.1:
resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==}
engines: {node: '>=0.10.0'}
+ requiresBuild: true
dev: false
optional: true
@@ -5761,6 +5850,7 @@ packages:
/bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
+ requiresBuild: true
dependencies:
file-uri-to-path: 1.0.0
dev: false
@@ -6854,6 +6944,7 @@ packages:
/chokidar@2.1.8:
resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==}
deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
+ requiresBuild: true
dependencies:
anymatch: 2.0.0
async-each: 1.0.6
@@ -7948,7 +8039,7 @@ packages:
dependencies:
'@ember/test-helpers': 3.2.0(ember-source@5.4.0)(webpack@5.89.0)
'@embroider/addon-shim': 1.8.7
- '@embroider/macros': 1.13.5
+ '@embroider/macros': 1.15.0
'@embroider/util': 1.13.0(ember-source@5.4.0)
assert-never: 1.2.1
ember-element-helper: 0.8.6(ember-source@5.4.0)
@@ -7995,13 +8086,13 @@ packages:
resolution: {integrity: sha512-gLqML2k77AuUiXxWNon1FSzuG1DV7PEPpCLCU5aJvf6fdL6rmFfElsZRh+8ELEB/qP9dT+LHjNEunVzd2dYc8A==}
engines: {node: '>= 10.*'}
dependencies:
- '@babel/core': 7.23.2
- '@babel/preset-env': 7.23.9(@babel/core@7.23.2)
- '@babel/traverse': 7.23.9
- '@babel/types': 7.23.9
+ '@babel/core': 7.24.4
+ '@babel/preset-env': 7.23.9(@babel/core@7.24.4)
+ '@babel/traverse': 7.24.1
+ '@babel/types': 7.24.0
'@embroider/shared-internals': 1.8.3
babel-core: 6.26.3
- babel-loader: 8.3.0(@babel/core@7.23.2)(webpack@4.47.0)
+ babel-loader: 8.3.0(@babel/core@7.24.4)(webpack@4.47.0)
babel-plugin-syntax-dynamic-import: 6.18.0
babylon: 6.18.0
broccoli-debug: 0.6.5
@@ -8114,15 +8205,15 @@ packages:
- webpack
dev: false
- /ember-basic-dropdown@7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0):
+ /ember-basic-dropdown@7.3.0(@babel/core@7.24.4)(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0):
resolution: {integrity: sha512-XzLd1noCrHjG7O35HpZ+ljj7VwPPqon7svbvNJ2U7421e00eXBUVcCioGJFo1NnnPkjc14FTDc5UwktbGSbJdQ==}
engines: {node: 16.* || >= 18}
peerDependencies:
ember-source: ^3.28.0 || ^4.0.0 || >=5.0.0
dependencies:
- '@embroider/macros': 1.13.5
+ '@embroider/macros': 1.15.0
'@embroider/util': 1.13.0(ember-source@5.4.0)
- '@glimmer/component': 1.1.2(@babel/core@7.23.2)
+ '@glimmer/component': 1.1.2(@babel/core@7.24.4)
'@glimmer/tracking': 1.1.2
ember-auto-import: 2.7.2(webpack@5.89.0)
ember-cli-babel: 7.26.11
@@ -8481,7 +8572,7 @@ packages:
resolution: {integrity: sha512-Lw8B6MJx2n8CNF2TSIKs+hWLw0FqSYjr2/NRPyquyYA05qsl137WJSYW3ZqTsLgoinHat0DGF2qaCXocLhLmyA==}
engines: {node: 10.* || >=12.*}
dependencies:
- '@babel/core': 7.23.2
+ '@babel/core': 7.24.4
broccoli-funnel: 3.0.8
ember-cli-babel: 7.26.11
resolve: 1.22.8
@@ -8564,6 +8655,26 @@ packages:
- '@babel/core'
- supports-color
+ /ember-cli-typescript@3.0.0(@babel/core@7.24.4):
+ resolution: {integrity: sha512-lo5YArbJzJi5ssvaGqTt6+FnhTALnSvYVuxM7lfyL1UCMudyNJ94ovH5C7n5il7ATd6WsNiAPRUO/v+s5Jq/aA==}
+ engines: {node: 8.* || >= 10.*}
+ dependencies:
+ '@babel/plugin-transform-typescript': 7.5.5(@babel/core@7.24.4)
+ ansi-to-html: 0.6.15
+ debug: 4.3.4
+ ember-cli-babel-plugin-helpers: 1.1.1
+ execa: 2.1.0
+ fs-extra: 8.1.0
+ resolve: 1.22.8
+ rsvp: 4.8.5
+ semver: 6.3.1
+ stagehand: 1.0.1
+ walk-sync: 2.2.0
+ transitivePeerDependencies:
+ - '@babel/core'
+ - supports-color
+ dev: false
+
/ember-cli-typescript@3.1.4(@babel/core@7.23.2):
resolution: {integrity: sha512-HJ73kL45OGRmIkPhBNFt31I1SGUvdZND+LCH21+qpq3pPlFpJG8GORyXpP+2ze8PbnITNLzwe5AwUrpyuRswdQ==}
engines: {node: 8.* || >= 10.*}
@@ -8585,6 +8696,30 @@ packages:
transitivePeerDependencies:
- '@babel/core'
- supports-color
+ dev: true
+
+ /ember-cli-typescript@3.1.4(@babel/core@7.24.4):
+ resolution: {integrity: sha512-HJ73kL45OGRmIkPhBNFt31I1SGUvdZND+LCH21+qpq3pPlFpJG8GORyXpP+2ze8PbnITNLzwe5AwUrpyuRswdQ==}
+ engines: {node: 8.* || >= 10.*}
+ dependencies:
+ '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.24.4)
+ '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.24.4)
+ '@babel/plugin-transform-typescript': 7.8.7(@babel/core@7.24.4)
+ ansi-to-html: 0.6.15
+ broccoli-stew: 3.0.0
+ debug: 4.3.4
+ ember-cli-babel-plugin-helpers: 1.1.1
+ execa: 3.4.0
+ fs-extra: 8.1.0
+ resolve: 1.22.8
+ rsvp: 4.8.5
+ semver: 6.3.1
+ stagehand: 1.0.1
+ walk-sync: 2.2.0
+ transitivePeerDependencies:
+ - '@babel/core'
+ - supports-color
+ dev: false
/ember-cli-typescript@4.2.1:
resolution: {integrity: sha512-0iKTZ+/wH6UB/VTWKvGuXlmwiE8HSIGcxHamwNhEC5x1mN3z8RfvsFZdQWYUzIWFN2Tek0gmepGRPTwWdBYl/A==}
@@ -8817,6 +8952,20 @@ packages:
- '@babel/core'
- supports-color
+ /ember-compatibility-helpers@1.2.7(@babel/core@7.24.4):
+ resolution: {integrity: sha512-BtkjulweiXo9c3yVWrtexw2dTmBrvavD/xixNC6TKOBdrixUwU+6nuOO9dufDWsMxoid7MvtmDpzc9+mE8PdaA==}
+ engines: {node: 10.* || >= 12.*}
+ dependencies:
+ babel-plugin-debug-macros: 0.2.0(@babel/core@7.24.4)
+ ember-cli-version-checker: 5.1.2
+ find-up: 5.0.0
+ fs-extra: 9.1.0
+ semver: 5.7.2
+ transitivePeerDependencies:
+ - '@babel/core'
+ - supports-color
+ dev: false
+
/ember-composable-helpers@5.0.0:
resolution: {integrity: sha512-gyUrjiSju4QwNrsCLbBpP0FL6VDFZaELNW7Kbcp60xXhjvNjncYgzm4zzYXhT+i1lLA6WEgRZ3lOGgyBORYD0w==}
engines: {node: 12.* || 14.* || >= 16}
@@ -8835,11 +8984,11 @@ packages:
ember-concurrency: ^2.0.0-rc.1
dependencies:
'@babel/helper-plugin-utils': 7.22.5
- '@babel/types': 7.23.9
+ '@babel/types': 7.24.0
ember-cli-babel: 7.26.11
ember-cli-babel-plugin-helpers: 1.1.1
ember-cli-htmlbars: 4.5.0
- ember-concurrency: 2.3.7(@babel/core@7.23.2)
+ ember-concurrency: 2.3.7(@babel/core@7.24.4)
transitivePeerDependencies:
- supports-color
dev: false
@@ -8855,6 +9004,20 @@ packages:
transitivePeerDependencies:
- '@babel/core'
- supports-color
+ dev: true
+
+ /ember-concurrency-decorators@2.0.3(@babel/core@7.24.4):
+ resolution: {integrity: sha512-r6O34YKI/slyYapVsuOPnmaKC4AsmBSwvgcadbdy+jHNj+mnryXPkm+3hhhRnFdlsKUKdEuXvl43lhjhYRLhhA==}
+ engines: {node: 10.* || >= 12}
+ dependencies:
+ '@ember-decorators/utils': 6.1.1
+ ember-cli-babel: 7.26.11
+ ember-cli-htmlbars: 4.5.0
+ ember-cli-typescript: 3.1.4(@babel/core@7.24.4)
+ transitivePeerDependencies:
+ - '@babel/core'
+ - supports-color
+ dev: false
/ember-concurrency-test-waiter@0.4.0(ember-concurrency@3.1.1):
resolution: {integrity: sha512-Yx3rDu9C1oDzWOFk9C4G9VQvnALZXsNvTGgRhM4J4Uzk1/tlRfZ0eLEJHWJqO3P3nyHdGlNAWYLq6Ozi0iFhQA==}
@@ -8863,7 +9026,7 @@ packages:
ember-concurrency: '>=0.7.19'
dependencies:
ember-cli-babel: 7.26.11
- ember-concurrency: 3.1.1(@babel/core@7.23.2)(ember-source@5.4.0)
+ ember-concurrency: 3.1.1(@babel/core@7.24.4)(ember-source@5.4.0)
transitivePeerDependencies:
- supports-color
dev: false
@@ -8876,7 +9039,7 @@ packages:
dependencies:
ember-cli-babel: 7.26.11
ember-cli-htmlbars: 4.5.0
- ember-concurrency: 2.3.7(@babel/core@7.23.2)
+ ember-concurrency: 2.3.7(@babel/core@7.24.4)
transitivePeerDependencies:
- supports-color
dev: false
@@ -8896,20 +9059,38 @@ packages:
transitivePeerDependencies:
- '@babel/core'
- supports-color
+ dev: true
+
+ /ember-concurrency@2.3.7(@babel/core@7.24.4):
+ resolution: {integrity: sha512-sz6sTIXN/CuLb5wdpauFa+rWXuvXXSnSHS4kuNzU5GSMDX1pLBWSuovoUk61FUe6CYRqBmT1/UushObwBGickQ==}
+ engines: {node: 10.* || 12.* || 14.* || >= 16}
+ dependencies:
+ '@babel/helper-plugin-utils': 7.22.5
+ '@babel/types': 7.23.9
+ '@glimmer/tracking': 1.1.2
+ ember-cli-babel: 7.26.11
+ ember-cli-babel-plugin-helpers: 1.1.1
+ ember-cli-htmlbars: 5.7.2
+ ember-compatibility-helpers: 1.2.7(@babel/core@7.24.4)
+ ember-destroyable-polyfill: 2.0.3(@babel/core@7.24.4)
+ transitivePeerDependencies:
+ - '@babel/core'
+ - supports-color
+ dev: false
- /ember-concurrency@3.1.1(@babel/core@7.23.2)(ember-source@5.4.0):
+ /ember-concurrency@3.1.1(@babel/core@7.24.4)(ember-source@5.4.0):
resolution: {integrity: sha512-doXFYYfy1C7jez+jDDlfahTp03QdjXeSY/W3Zbnx/q3UNJ9g10Shf2d7M/HvWo/TC22eU+6dPLIpqd/6q4pR+Q==}
engines: {node: 16.* || >= 18}
peerDependencies:
ember-source: ^3.28.0 || ^4.0.0 || >=5.0.0
dependencies:
'@babel/helper-plugin-utils': 7.22.5
- '@babel/types': 7.23.9
+ '@babel/types': 7.24.0
'@glimmer/tracking': 1.1.2
ember-cli-babel: 7.26.11
ember-cli-babel-plugin-helpers: 1.1.1
ember-cli-htmlbars: 6.3.0
- ember-compatibility-helpers: 1.2.7(@babel/core@7.23.2)
+ ember-compatibility-helpers: 1.2.7(@babel/core@7.24.4)
ember-source: 5.4.0(@babel/core@7.23.2)(@glimmer/component@1.1.2)(rsvp@4.8.5)(webpack@5.89.0)
transitivePeerDependencies:
- '@babel/core'
@@ -8993,6 +9174,19 @@ packages:
transitivePeerDependencies:
- '@babel/core'
- supports-color
+ dev: true
+
+ /ember-destroyable-polyfill@2.0.3(@babel/core@7.24.4):
+ resolution: {integrity: sha512-TovtNqCumzyAiW0/OisSkkVK93xnVF4NRU6+FN0ubpfwEOpRrmM2RqDwXI6YAChCgSHON1cz0DfQStpA1Gjuuw==}
+ engines: {node: 10.* || >= 12}
+ dependencies:
+ ember-cli-babel: 7.26.11
+ ember-cli-version-checker: 5.1.2
+ ember-compatibility-helpers: 1.2.7(@babel/core@7.24.4)
+ transitivePeerDependencies:
+ - '@babel/core'
+ - supports-color
+ dev: false
/ember-element-helper@0.6.1(ember-source@5.4.0):
resolution: {integrity: sha512-YiOdAMlzYul4ulkIoNp8z7iHDfbT1fbut/9xGFRfxDwU/FmF8HtAUB2f1veu/w50HTeZNopa1OV2PCloZ76XlQ==}
@@ -9078,7 +9272,7 @@ packages:
'@ember/test-helpers': 3.2.0(ember-source@5.4.0)(webpack@5.89.0)
'@ember/test-waiters': 3.1.0
'@embroider/addon-shim': 1.8.7
- '@embroider/macros': 1.13.5
+ '@embroider/macros': 1.15.0
'@glimmer/component': 1.1.2(@babel/core@7.23.2)
'@glimmer/tracking': 1.1.2
ember-auto-import: 2.7.2(webpack@5.89.0)
@@ -9121,7 +9315,7 @@ packages:
resolution: {integrity: sha512-uNmv1cPG/4qsac8oIf5txJ2FZ8p88LEpG4P3dNcjsJS98Y8hd0GPMFwVqpnzI78Lz7VYRGQWY4jnE4qm5R3j4g==}
engines: {node: 12.* || 14.* || >= 16}
dependencies:
- '@embroider/macros': 1.13.5
+ '@embroider/macros': 1.15.0
ember-cli-babel: 7.26.11
transitivePeerDependencies:
- '@glint/template'
@@ -9172,6 +9366,42 @@ packages:
- webpack
dev: false
+ /ember-intl@6.3.2(@babel/core@7.24.4)(webpack@5.89.0):
+ resolution: {integrity: sha512-UJ91JjlY3z6fjajoHhhJtKUbgqEr/l6Ie4Viqn0B3Lrbavxg5IgAIvyZZ9fOVtq05MDtCuc610zV6vLOc71G0w==}
+ engines: {node: 16.* || >= 18}
+ peerDependencies:
+ typescript: ^4.8.0 || ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@formatjs/icu-messageformat-parser': 2.7.6
+ '@formatjs/intl': 2.10.0
+ broccoli-caching-writer: 3.0.3
+ broccoli-funnel: 3.0.8
+ broccoli-merge-files: 0.8.0
+ broccoli-merge-trees: 4.2.0
+ broccoli-source: 3.0.1
+ broccoli-stew: 3.0.0
+ calculate-cache-key-for-tree: 2.0.0
+ cldr-core: 44.1.0
+ ember-auto-import: 2.7.2(webpack@5.89.0)
+ ember-cli-babel: 8.2.0(@babel/core@7.24.4)
+ ember-cli-typescript: 5.2.1
+ eventemitter3: 5.0.1
+ extend: 3.0.2
+ fast-memoize: 2.5.2
+ intl-messageformat: 10.5.11
+ js-yaml: 4.1.0
+ json-stable-stringify: 1.1.1
+ silent-error: 1.1.1
+ transitivePeerDependencies:
+ - '@babel/core'
+ - '@glint/template'
+ - supports-color
+ - webpack
+ dev: false
+
/ember-load-initializers@2.1.2(@babel/core@7.23.2):
resolution: {integrity: sha512-CYR+U/wRxLbrfYN3dh+0Tb6mFaxJKfdyz+wNql6cqTrA0BBi9k6J3AaKXj273TqvEpyyXegQFFkZEiuZdYtgJw==}
engines: {node: 6.* || 8.* || >= 10.*}
@@ -9183,14 +9413,14 @@ packages:
- supports-color
dev: true
- /ember-loading@2.0.0(@babel/core@7.23.2):
+ /ember-loading@2.0.0(@babel/core@7.24.4):
resolution: {integrity: sha512-aGFZszIwmrIZ5XINv9TXQGWrfpKIiPwYiakEmRXx0Jvr5ZnUyKtCO84+FaKMyezrbDWsq0UjYqmdiqSAXhIkIA==}
engines: {node: 12.* || 14.* || >= 16}
dependencies:
ember-cli-babel: 7.26.11
ember-cli-htmlbars: 5.7.2
ember-cli-typescript: 4.2.1
- ember-concurrency: 2.3.7(@babel/core@7.23.2)
+ ember-concurrency: 2.3.7(@babel/core@7.24.4)
ember-concurrency-async: 1.0.0(ember-concurrency@2.3.7)
ember-concurrency-ts: 0.3.1(ember-concurrency@2.3.7)
transitivePeerDependencies:
@@ -9198,7 +9428,7 @@ packages:
- supports-color
dev: false
- /ember-local-storage@2.0.7(@babel/core@7.23.2):
+ /ember-local-storage@2.0.7(@babel/core@7.24.4):
resolution: {integrity: sha512-EPvxH/27mIzrX/EEgng+FG6HD0ri/God9OH/9mhmgPSXrgMNq/614Z3NMnooM4QKIEBAvr0p+p1UL2DgrTTMNg==}
engines: {node: 12.* || 14.* || >= 16}
dependencies:
@@ -9210,7 +9440,7 @@ packages:
ember-cli-string-utils: 1.1.0
ember-cli-version-checker: 5.1.2
ember-copy: 2.0.1
- ember-destroyable-polyfill: 2.0.3(@babel/core@7.23.2)
+ ember-destroyable-polyfill: 2.0.3(@babel/core@7.24.4)
transitivePeerDependencies:
- '@babel/core'
- supports-color
@@ -9238,19 +9468,19 @@ packages:
- supports-color
dev: false
- /ember-modifier-manager-polyfill@1.2.0(@babel/core@7.23.2):
+ /ember-modifier-manager-polyfill@1.2.0(@babel/core@7.24.4):
resolution: {integrity: sha512-bnaKF1LLKMkBNeDoetvIJ4vhwRPKIIumWr6dbVuW6W6p4QV8ZiO+GdF8J7mxDNlog9CeL9Z/7wam4YS86G8BYA==}
engines: {node: 6.* || 8.* || >= 10.*}
dependencies:
ember-cli-babel: 7.26.11
ember-cli-version-checker: 2.2.0
- ember-compatibility-helpers: 1.2.7(@babel/core@7.23.2)
+ ember-compatibility-helpers: 1.2.7(@babel/core@7.24.4)
transitivePeerDependencies:
- '@babel/core'
- supports-color
dev: false
- /ember-modifier@3.2.7(@babel/core@7.23.2):
+ /ember-modifier@3.2.7(@babel/core@7.24.4):
resolution: {integrity: sha512-ezcPQhH8jUfcJQbbHji4/ZG/h0yyj1jRDknfYue/ypQS8fM8LrGcCMo0rjDZLzL1Vd11InjNs3BD7BdxFlzGoA==}
engines: {node: 12.* || >= 14}
dependencies:
@@ -9258,7 +9488,7 @@ packages:
ember-cli-normalize-entity-name: 1.0.0
ember-cli-string-utils: 1.1.0
ember-cli-typescript: 5.2.1
- ember-compatibility-helpers: 1.2.7(@babel/core@7.23.2)
+ ember-compatibility-helpers: 1.2.7(@babel/core@7.24.4)
transitivePeerDependencies:
- '@babel/core'
- supports-color
@@ -9298,7 +9528,7 @@ packages:
- supports-color
dev: true
- /ember-power-calendar@0.18.0(@babel/core@7.23.2)(ember-source@5.4.0):
+ /ember-power-calendar@0.18.0(@babel/core@7.24.4)(ember-source@5.4.0):
resolution: {integrity: sha512-bkW5eL8MxS3rmn6XnR7B4QivJZ+Y4SF2kHSZPlUwaVjsw4FqZ7a3I1N1dbC3khcgcFvh1M8aa4/Ek/BwP+sorQ==}
engines: {node: 10.* || >= 12}
dependencies:
@@ -9306,7 +9536,7 @@ packages:
ember-cli-babel: 7.26.11
ember-cli-element-closest-polyfill: 0.0.2
ember-cli-htmlbars: 6.3.0
- ember-concurrency: 2.3.7(@babel/core@7.23.2)
+ ember-concurrency: 2.3.7(@babel/core@7.24.4)
ember-decorators: 6.1.1
ember-element-helper: 0.6.1(ember-source@5.4.0)
ember-truth-helpers: 3.1.1
@@ -9318,22 +9548,22 @@ packages:
- supports-color
dev: false
- /ember-power-select@7.2.0(@babel/core@7.23.2)(ember-source@5.4.0)(webpack@5.89.0):
+ /ember-power-select@7.2.0(@babel/core@7.24.4)(ember-source@5.4.0)(webpack@5.89.0):
resolution: {integrity: sha512-h02M6y4yV5EAYdFXixWQw7qDjb3tuVwB0L/8ZYDezQjqZPdtem86fV7AddsXaejZ3bZsHEhIqzhXD5+TsPxEjg==}
engines: {node: 16.* || >= 18}
dependencies:
- '@ember/render-modifiers': 2.1.0(@babel/core@7.23.2)(ember-source@5.4.0)
+ '@ember/render-modifiers': 2.1.0(@babel/core@7.24.4)(ember-source@5.4.0)
'@ember/string': 3.1.1
'@embroider/util': 1.13.0(ember-source@5.4.0)
- '@glimmer/component': 1.1.2(@babel/core@7.23.2)
+ '@glimmer/component': 1.1.2(@babel/core@7.24.4)
'@glimmer/tracking': 1.1.2
ember-assign-helper: 0.4.0
ember-auto-import: 2.7.2(webpack@5.89.0)
- ember-basic-dropdown: 7.3.0(@babel/core@7.23.2)(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0)
+ ember-basic-dropdown: 7.3.0(@babel/core@7.24.4)(@ember/string@3.1.1)(ember-source@5.4.0)(webpack@5.89.0)
ember-cli-babel: 7.26.11
ember-cli-htmlbars: 6.3.0
ember-cli-typescript: 5.2.1
- ember-concurrency: 2.3.7(@babel/core@7.23.2)
+ ember-concurrency: 2.3.7(@babel/core@7.24.4)
ember-text-measurer: 0.6.0
ember-truth-helpers: 4.0.3(ember-source@5.4.0)
transitivePeerDependencies:
@@ -9378,13 +9608,13 @@ packages:
- webpack-cli
dev: false
- /ember-ref-bucket@4.1.0(@babel/core@7.23.2):
+ /ember-ref-bucket@4.1.0(@babel/core@7.24.4):
resolution: {integrity: sha512-oEUU2mDtuYuMM039U9YEqrrOCVHH6rQfvbFOmh3WxOVEgubmLVyKEpGgU4P/6j0B/JxTqqTwM3ULTQyDto8dKg==}
engines: {node: 10.* || >= 12}
dependencies:
ember-cli-babel: 7.26.11
ember-cli-htmlbars: 6.3.0
- ember-modifier: 3.2.7(@babel/core@7.23.2)
+ ember-modifier: 3.2.7(@babel/core@7.24.4)
transitivePeerDependencies:
- '@babel/core'
- supports-color
@@ -9438,7 +9668,7 @@ packages:
'@ember/test-helpers': 3.2.0(ember-source@5.4.0)(webpack@5.89.0)
'@ember/test-waiters': 3.1.0
'@embroider/addon-shim': 1.8.7
- '@embroider/macros': 1.13.5
+ '@embroider/macros': 1.15.0
ember-cli-is-package-missing: 1.0.0
ember-cookies: 1.1.2
silent-error: 1.1.1
@@ -10479,6 +10709,7 @@ packages:
/file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
+ requiresBuild: true
dev: false
optional: true
@@ -11706,6 +11937,7 @@ packages:
/is-binary-path@1.0.1:
resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==}
engines: {node: '>=0.10.0'}
+ requiresBuild: true
dependencies:
binary-extensions: 1.13.1
dev: false
@@ -12930,6 +13162,7 @@ packages:
/nan@2.19.0:
resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==}
+ requiresBuild: true
dev: false
optional: true
@@ -14421,6 +14654,7 @@ packages:
/readdirp@2.2.1:
resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==}
engines: {node: '>=0.10'}
+ requiresBuild: true
dependencies:
graceful-fs: 4.2.11
micromatch: 3.1.10
@@ -15679,7 +15913,7 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
dependencies:
- '@jridgewell/gen-mapping': 0.3.3
+ '@jridgewell/gen-mapping': 0.3.5
commander: 4.1.1
glob: 10.3.12
lines-and-columns: 1.2.4
@@ -16401,6 +16635,7 @@ packages:
/upath@1.2.0:
resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==}
engines: {node: '>=4'}
+ requiresBuild: true
dev: false
optional: true
diff --git a/server/data/pods.json b/server/data/pods.json
new file mode 100644
index 0000000..7b2b753
--- /dev/null
+++ b/server/data/pods.json
@@ -0,0 +1,328 @@
+[
+ {
+ "id": "pod_x2y4bdc",
+ "name": "Fleetbase-Sync-2024-03-01",
+ "slug": "fleetbase-sync-2024-03-01",
+ "size": "346kb",
+ "updated_at": "May 07, 2024 13:25",
+ "created_at": "May 07, 2024 13:25",
+ "contents": [
+ {
+ "id": "content_wsyz38",
+ "name": "Orders-May-2024",
+ "slug": "orders-may-2024",
+ "size": "80kb",
+ "type": "folder",
+ "updated_at": "May 05, 2024 14:33",
+ "created_at": "May 05, 2024 14:33",
+ "contents": [
+ {
+ "id": "content_wxyz12",
+ "name": "EmployeeHandbook_2024.pdf",
+ "slug": "employeehandbook-2024-pdf",
+ "size": "450kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:22",
+ "created_at": "May 07, 2024 14:22"
+ },
+ {
+ "id": "content_345ghi",
+ "name": "FinancialSummary_Annual_2024.xlsx",
+ "slug": "financialsummary-annual-2024-xlsx",
+ "size": "625kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:24",
+ "created_at": "May 07, 2024 14:24"
+ },
+ {
+ "id": "content_789jkl",
+ "name": "DeveloperGuide_Version2.md",
+ "slug": "developerguide-version2-md",
+ "size": "75kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:26",
+ "created_at": "May 07, 2024 14:26"
+ },
+ {
+ "id": "content_mnopqr",
+ "name": "ProjectTimeline_Roadmap2024.gantt",
+ "slug": "projecttimeline-roadmap2024-gantt",
+ "size": "1.1mb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:28",
+ "created_at": "May 07, 2024 14:28"
+ }
+ ]
+ },
+ {
+ "id": "content_xjdwkj",
+ "name": "RandomCode13.txt",
+ "slug": "random-code-13-txt",
+ "size": "346kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 13:25",
+ "created_at": "May 07, 2024 13:25"
+ },
+ {
+ "id": "content_1a2b3c",
+ "name": "SalesReport_Q1_2024.xlsx",
+ "slug": "salesreport-q1-2024-xlsx",
+ "size": "525kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:10",
+ "created_at": "May 07, 2024 14:10"
+ },
+ {
+ "id": "content_4d5e6f",
+ "name": "CustomerFeedback_May2024.pdf",
+ "slug": "customerfeedback-may2024-pdf",
+ "size": "275kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:12",
+ "created_at": "May 07, 2024 14:12"
+ }
+ ]
+ },
+ {
+ "id": "pod_a9c7jkl",
+ "name": "Fleetbase-Backup-2024-04-19",
+ "slug": "fleetbase-backup-2024-04-19",
+ "size": "420kb",
+ "updated_at": "May 08, 2024 11:00",
+ "created_at": "May 08, 2024 11:00",
+ "contents": [
+ {
+ "id": "content_dn3892",
+ "name": "Vehicles-May-2024",
+ "slug": "vehicles-may-2024",
+ "size": "80kb",
+ "type": "folder",
+ "updated_at": "May 05, 2024 14:33",
+ "created_at": "May 05, 2024 14:33",
+ "contents": [
+ {
+ "id": "content_stuvwx",
+ "name": "HR_PolicyDocument.pdf",
+ "slug": "hr-policydocument-pdf",
+ "size": "350kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:30",
+ "created_at": "May 07, 2024 14:30"
+ },
+ {
+ "id": "content_yza123",
+ "name": "DesignMockup_2024.sketch",
+ "slug": "designmockup-2024-sketch",
+ "size": "3.2mb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:32",
+ "created_at": "May 07, 2024 14:32"
+ },
+ {
+ "id": "content_456bcd",
+ "name": "BugTracker_Report_Apr2024.xlsx",
+ "slug": "bugtracker-report-apr2024-xlsx",
+ "size": "280kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:34",
+ "created_at": "May 07, 2024 14:34"
+ },
+ {
+ "id": "content_789efg",
+ "name": "TrainingMaterials_Mar2024.pptx",
+ "slug": "trainingmaterials-mar2024-pptx",
+ "size": "1.5mb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:36",
+ "created_at": "May 07, 2024 14:36"
+ },
+ {
+ "id": "content_hijklm",
+ "name": "TestPlan_ReleaseCycle_Apr2024.docx",
+ "slug": "testplan-releasecycle-apr2024-docx",
+ "size": "650kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:38",
+ "created_at": "May 07, 2024 14:38"
+ }
+ ]
+ },
+ {
+ "id": "content_7g8h9i",
+ "name": "ProductCatalog_Spring2024.csv",
+ "slug": "productcatalog-spring2024-csv",
+ "size": "1.2mb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:15",
+ "created_at": "May 07, 2024 14:15"
+ },
+ {
+ "id": "content_jklmno",
+ "name": "ProjectPlan_SummerLaunch.docx",
+ "slug": "projectplan-summerlaunch-docx",
+ "size": "825kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:18",
+ "created_at": "May 07, 2024 14:18"
+ },
+ {
+ "id": "content_pqrsuv",
+ "name": "MarketingStrategy_Q3_2024.pptx",
+ "slug": "marketingstrategy-q3-2024-pptx",
+ "size": "2.3mb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:20",
+ "created_at": "May 07, 2024 14:20"
+ },
+ {
+ "id": "content_wxyz12",
+ "name": "EmployeeHandbook_2024.pdf",
+ "slug": "employeehandbook-2024-pdf",
+ "size": "450kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:22",
+ "created_at": "May 07, 2024 14:22"
+ }
+ ]
+ },
+ {
+ "id": "pod_b3z1mno",
+ "name": "Fleetbase-Demo-2024-05-01",
+ "slug": "fleetbase-demo-2024-05-01",
+ "size": "512kb",
+ "updated_at": "May 09, 2024 09:45",
+ "created_at": "May 09, 2024 09:45",
+ "contents": [
+ {
+ "id": "content_dnsus7s",
+ "name": "Issues-May-2024",
+ "slug": "issues-may-2024",
+ "size": "80kb",
+ "type": "folder",
+ "updated_at": "May 05, 2024 14:33",
+ "created_at": "May 05, 2024 14:33",
+ "contents": [
+ {
+ "id": "content_d732sz",
+ "name": "Fleet-Reports-May-2024",
+ "slug": "fleet-reports-may-2024",
+ "size": "80kb",
+ "type": "folder",
+ "updated_at": "May 05, 2024 14:33",
+ "created_at": "May 05, 2024 14:33",
+ "contents": [
+ {
+ "id": "content_pqrstuv",
+ "name": "MockDataSet1.1.json",
+ "slug": "mockdataset1-1-json",
+ "size": "250kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:52",
+ "created_at": "May 07, 2024 14:52"
+ }
+ ]
+ },
+ {
+ "id": "content_nopqrs",
+ "name": "ProjectSpecification_V3.pdf",
+ "slug": "projectspecification-v3-pdf",
+ "size": "990kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:40",
+ "created_at": "May 07, 2024 14:40"
+ },
+ {
+ "id": "content_tuvwxyz",
+ "name": "DeploymentScript_Linux.bash",
+ "slug": "deploymentscript-linux-bash",
+ "size": "45kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:42",
+ "created_at": "May 07, 2024 14:42"
+ },
+ {
+ "id": "content_abc123",
+ "name": "QAReport_EndOfQuarter_Mar2024.pdf",
+ "slug": "qareport-endofquarter-mar2024-pdf",
+ "size": "1.0mb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:44",
+ "created_at": "May 07, 2024 14:44"
+ },
+ {
+ "id": "content_456def",
+ "name": "ReleaseNotes_Patch1.3.json",
+ "slug": "releasenotes-patch1-3-json",
+ "size": "150kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:46",
+ "created_at": "May 07, 2024 14:46"
+ },
+ {
+ "id": "content_789ghi",
+ "name": "SprintRetrospective_May2024.csv",
+ "slug": "sprintretrospective-may2024-csv",
+ "size": "340kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:48",
+ "created_at": "May 07, 2024 14:48"
+ },
+ {
+ "id": "content_jklmno",
+ "name": "CodeReview_Analysis.xlsx",
+ "slug": "codereview-analysis-xlsx",
+ "size": "480kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:50",
+ "created_at": "May 07, 2024 14:50"
+ }
+ ]
+ },
+ {
+ "id": "content_1a2b3c",
+ "name": "SalesReport_Q1_2024.xlsx",
+ "slug": "salesreport-q1-2024-xlsx",
+ "size": "525kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:10",
+ "created_at": "May 07, 2024 14:10"
+ },
+ {
+ "id": "content_4d5e6f",
+ "name": "CustomerFeedback_May2024.pdf",
+ "slug": "customerfeedback-may2024-pdf",
+ "size": "275kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:12",
+ "created_at": "May 07, 2024 14:12"
+ },
+ {
+ "id": "content_7g8h9i",
+ "name": "ProductCatalog_Spring2024.csv",
+ "slug": "productcatalog-spring2024-csv",
+ "size": "1.2mb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:15",
+ "created_at": "May 07, 2024 14:15"
+ },
+ {
+ "id": "content_jklmno",
+ "name": "ProjectPlan_SummerLaunch.docx",
+ "slug": "projectplan-summerlaunch-docx",
+ "size": "825kb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:18",
+ "created_at": "May 07, 2024 14:18"
+ },
+ {
+ "id": "content_pqrsuv",
+ "name": "MarketingStrategy_Q3_2024.pptx",
+ "slug": "marketingstrategy-q3-2024-pptx",
+ "size": "2.3mb",
+ "type": "file",
+ "updated_at": "May 07, 2024 14:20",
+ "created_at": "May 07, 2024 14:20"
+ }
+ ]
+ }
+]
diff --git a/server/src/Client/OpenIDConnectClient.php b/server/src/Client/OpenIDConnectClient.php
index 7df84c6..14833ad 100644
--- a/server/src/Client/OpenIDConnectClient.php
+++ b/server/src/Client/OpenIDConnectClient.php
@@ -86,7 +86,7 @@ public function authenticate(): bool
return parent::authenticate();
}
- private function setClientCredentials(string $clientName = CLIENT_NAME, $clientCredentials, bool $save = false, \Closure $callback = null): OpenIDConnectClient
+ private function setClientCredentials(string $clientName = CLIENT_NAME, $clientCredentials, bool $save = false, ?\Closure $callback = null): OpenIDConnectClient
{
$this->setClientID($clientCredentials->client_id);
$this->setClientName($clientCredentials->client_name);
@@ -156,7 +156,7 @@ private function retrieve(string $key)
return $value;
}
- public function getOpenIdConfiguration(string $key = null)
+ public function getOpenIdConfiguration(?string $key = null)
{
$openIdConfigResponse = $this->solid->get('.well-known/openid-configuration');
if ($openIdConfigResponse instanceof Response) {
diff --git a/server/src/Client/SolidClient.php b/server/src/Client/SolidClient.php
index 8be161f..1cd88bb 100644
--- a/server/src/Client/SolidClient.php
+++ b/server/src/Client/SolidClient.php
@@ -70,7 +70,7 @@ public function getServerUrl(): string
*
* @return string the fully constructed URL
*/
- private function createRequestUrl(string $uri = null): string
+ private function createRequestUrl(?string $uri = null): string
{
if (Str::startsWith($uri, 'http')) {
return $uri;
diff --git a/server/src/Http/Controllers/SolidController.php b/server/src/Http/Controllers/SolidController.php
index b4b0ba6..14ea514 100644
--- a/server/src/Http/Controllers/SolidController.php
+++ b/server/src/Http/Controllers/SolidController.php
@@ -7,8 +7,9 @@
use Fleetbase\Models\Setting;
use Fleetbase\Solid\Client\SolidClient;
use Fleetbase\Solid\Models\SolidIdentity;
-use Fleetbase\Support\Utils;
+use Fleetbase\Solid\Support\Utils;
use Illuminate\Http\Request;
+use Illuminate\Support\Str;
class SolidController extends BaseController
{
@@ -90,9 +91,9 @@ public function play(Request $request)
'remember' => true,
],
[
- 'withoutAuth' => true,
- 'headers' => [
- 'Cookie' => '_interaction=TDQMh2DWuC8wZvkEB2n_G; _interaction.sig=3HHA_FUVo7Cw9up2keCJ7IaQJws; _session.legacy=jdxTxnTGmvWx2ECaiwYeP; _session.legacy.sig=EUGYX6DAKtBNQqZN5PGcbIJ-5ac',
+ 'withoutAuth' => true,
+ 'headers' => [
+ 'Cookie' => '_interaction=TDQMh2DWuC8wZvkEB2n_G; _interaction.sig=3HHA_FUVo7Cw9up2keCJ7IaQJws; _session.legacy=jdxTxnTGmvWx2ECaiwYeP; _session.legacy.sig=EUGYX6DAKtBNQqZN5PGcbIJ-5ac',
],
]
);
@@ -114,4 +115,56 @@ public function play(Request $request)
// dump($createFileResponse->json());
}
}
+
+ public function getPods(Request $request)
+ {
+ // Retrieve search and sort parameters from the request
+ $query = $request->searchQuery();
+ $sort = $request->input('sort', '-created_at');
+ $id = $request->input('id');
+ $slug = $request->input('slug');
+
+ // Collection of pods data
+ $pods = json_decode(file_get_contents(base_path('vendor/fleetbase/solid-api/server/data/pods.json')));
+
+ // Get single content from pod via slug
+ if ($slug) {
+ $result = Utils::searchPods($pods, 'slug', $slug);
+
+ return response()->json($result);
+ }
+
+ // Get a single item via ID
+ if ($id && is_array($pods)) {
+ $result = Utils::searchPods($pods, 'id', $id);
+ if ($result && $query) {
+ $result->contents = array_values(
+ array_filter(
+ data_get($result, 'contents', []),
+ function ($content) use ($query) {
+ return Str::contains(strtolower(data_get($content, 'name')), strtolower($query));
+ }
+ )
+ );
+ }
+
+ return response()->json($result);
+ }
+
+ // Filtering by search query
+ if ($query) {
+ $pods = array_filter($pods, function ($pod) use ($query) {
+ return Str::contains(strtolower(data_get($pod, 'name')), strtolower($query));
+ });
+ }
+
+ // Determine sorting direction and key
+ $sortDesc = substr($sort, 0, 1) === '-';
+ $sortKey = ltrim($sort, '-');
+
+ // Sorting by specified field
+ $pods = collect($pods)->sortBy($sortKey, SORT_REGULAR, $sortDesc);
+
+ return response()->json($pods->values());
+ }
}
diff --git a/server/src/LegacyClient/OIDCClient.php b/server/src/LegacyClient/OIDCClient.php
index 07cb8f6..f275bf9 100644
--- a/server/src/LegacyClient/OIDCClient.php
+++ b/server/src/LegacyClient/OIDCClient.php
@@ -141,7 +141,7 @@ private function base64urlEncode(string $data): string
return rtrim($url, '=');
}
- public function createDPoP(string $method, string $url, bool $includeAth = true, string $accessToken = null): string
+ public function createDPoP(string $method, string $url, bool $includeAth = true, ?string $accessToken = null): string
{
if (null === $this->dpopPrivateKey) {
$this->dpopPrivateKey = JWKFactory::createECKey('P-256', ['use' => 'sig', 'kid' => base64_encode(random_bytes(20))]);
diff --git a/server/src/LegacyClient/SolidClient.php b/server/src/LegacyClient/SolidClient.php
index c8c0241..4c6158c 100644
--- a/server/src/LegacyClient/SolidClient.php
+++ b/server/src/LegacyClient/SolidClient.php
@@ -98,7 +98,7 @@ public function getServerUrl(): string
*
* @return string the fully constructed URL
*/
- private function createRequestUrl(string $uri = null): string
+ private function createRequestUrl(?string $uri = null): string
{
$url = $this->getServerUrl();
@@ -165,6 +165,7 @@ protected function request(string $method, string $uri, array $data = [], array
$url = $this->createRequestUrl($uri);
}
$this->setAuthenticationHeaders($options, $method, $url);
+
return Http::withOptions($options)->{$method}($url, $data);
}
diff --git a/server/src/Support/Utils.php b/server/src/Support/Utils.php
index 0c922b0..3cc7f4b 100644
--- a/server/src/Support/Utils.php
+++ b/server/src/Support/Utils.php
@@ -3,7 +3,45 @@
namespace Fleetbase\Solid\Support;
use Fleetbase\Support\Utils as FleetbaseUtils;
+use Illuminate\Support\Str;
class Utils extends FleetbaseUtils
{
+ /**
+ * Recursively searches through a nested array of pods and their contents
+ * to find an item that matches a given key-value pair.
+ *
+ * This function handles nested structures where each folder may contain
+ * additional folders and files. It returns the first matching item based
+ * on the specified key and value.
+ *
+ * @param array $data the array representing the pods and their nested contents
+ * @param string $key The key used to search items (e.g., 'name', 'id').
+ * @param string $value the value to match against the specified key
+ * @param bool $search whether to perform a search match with string contains
+ *
+ * @return mixed|null returns the first matching item found in the structure or
+ * `null` if no item is found that matches the criteria
+ */
+ public static function searchPods(array $data = [], string $key, string $value, bool $search = false)
+ {
+ foreach ($data as $item) {
+ if ($search === false && data_get($item, $key) && strcasecmp(data_get($item, $key), $value) === 0) {
+ return $item;
+ }
+
+ if ($search === true && data_get($item, $key) && Str::contains(strtolower(data_get($item, $key)), strtolower($value))) {
+ return $item;
+ }
+
+ if (is_array(data_get($item, 'contents'))) {
+ $contentSearchResult = static::searchPods(data_get($item, 'contents', []), $key, $value);
+ if ($contentSearchResult) {
+ return $contentSearchResult;
+ }
+ }
+ }
+
+ return null;
+ }
}
diff --git a/server/src/routes.php b/server/src/routes.php
index 4de2165..e6e4b39 100644
--- a/server/src/routes.php
+++ b/server/src/routes.php
@@ -28,6 +28,7 @@ function ($router) {
$router->group(
['prefix' => 'v1'],
function ($router) {
+ $router->get('pods', 'SolidController@getPods');
$router->get('authenticate/{identifier}', 'SolidController@authenticate');
$router->group(['middleware' => ['fleetbase.protected']], function ($router) {
$router->get('account', 'SolidController@getAccountIndex');
diff --git a/tests/integration/components/explorer-header-test.js b/tests/integration/components/explorer-header-test.js
new file mode 100644
index 0000000..fec6ada
--- /dev/null
+++ b/tests/integration/components/explorer-header-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'dummy/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | explorer-header', 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` `);
+
+ assert.dom().hasText('');
+
+ // Template block usage:
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert.dom().hasText('template block text');
+ });
+});
diff --git a/tests/integration/components/modals/backup-pod-test.js b/tests/integration/components/modals/backup-pod-test.js
new file mode 100644
index 0000000..cc28376
--- /dev/null
+++ b/tests/integration/components/modals/backup-pod-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'dummy/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | modals/backup-pod', 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` `);
+
+ assert.dom().hasText('');
+
+ // Template block usage:
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert.dom().hasText('template block text');
+ });
+});
diff --git a/tests/integration/components/modals/create-pod-test.js b/tests/integration/components/modals/create-pod-test.js
new file mode 100644
index 0000000..bc57bcb
--- /dev/null
+++ b/tests/integration/components/modals/create-pod-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'dummy/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | modals/create-pod', 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` `);
+
+ assert.dom().hasText('');
+
+ // Template block usage:
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert.dom().hasText('template block text');
+ });
+});
diff --git a/tests/integration/components/modals/resync-pod-test.js b/tests/integration/components/modals/resync-pod-test.js
new file mode 100644
index 0000000..c7ddbec
--- /dev/null
+++ b/tests/integration/components/modals/resync-pod-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'dummy/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | modals/resync-pod', 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` `);
+
+ assert.dom().hasText('');
+
+ // Template block usage:
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert.dom().hasText('template block text');
+ });
+});
diff --git a/tests/integration/components/table/cell/pod-content-actions-test.js b/tests/integration/components/table/cell/pod-content-actions-test.js
new file mode 100644
index 0000000..2f65453
--- /dev/null
+++ b/tests/integration/components/table/cell/pod-content-actions-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'dummy/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | table/cell/pod-content-actions', 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` `);
+
+ assert.dom().hasText('');
+
+ // Template block usage:
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert.dom().hasText('template block text');
+ });
+});
diff --git a/tests/integration/components/table/cell/pod-content-name-test.js b/tests/integration/components/table/cell/pod-content-name-test.js
new file mode 100644
index 0000000..4dd708c
--- /dev/null
+++ b/tests/integration/components/table/cell/pod-content-name-test.js
@@ -0,0 +1,26 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'dummy/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | table/cell/pod-content-name', 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` `);
+
+ assert.dom().hasText('');
+
+ // Template block usage:
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert.dom().hasText('template block text');
+ });
+});
diff --git a/tests/unit/controllers/account-test.js b/tests/unit/controllers/account-test.js
new file mode 100644
index 0000000..3ed611e
--- /dev/null
+++ b/tests/unit/controllers/account-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Controller | account', function (hooks) {
+ setupTest(hooks);
+
+ // TODO: Replace this with your real tests.
+ test('it exists', function (assert) {
+ let controller = this.owner.lookup('controller:account');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/home-test.js b/tests/unit/controllers/home-test.js
new file mode 100644
index 0000000..b97c573
--- /dev/null
+++ b/tests/unit/controllers/home-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Controller | home', function (hooks) {
+ setupTest(hooks);
+
+ // TODO: Replace this with your real tests.
+ test('it exists', function (assert) {
+ let controller = this.owner.lookup('controller:home');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/pods/explorer-test.js b/tests/unit/controllers/pods/explorer-test.js
new file mode 100644
index 0000000..c36480c
--- /dev/null
+++ b/tests/unit/controllers/pods/explorer-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Controller | pods/explorer', function (hooks) {
+ setupTest(hooks);
+
+ // TODO: Replace this with your real tests.
+ test('it exists', function (assert) {
+ let controller = this.owner.lookup('controller:pods/explorer');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/pods/explorer/content-test.js b/tests/unit/controllers/pods/explorer/content-test.js
new file mode 100644
index 0000000..738a4ee
--- /dev/null
+++ b/tests/unit/controllers/pods/explorer/content-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Controller | pods/explorer/content', function (hooks) {
+ setupTest(hooks);
+
+ // TODO: Replace this with your real tests.
+ test('it exists', function (assert) {
+ let controller = this.owner.lookup('controller:pods/explorer/content');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/pods/index-test.js b/tests/unit/controllers/pods/index-test.js
new file mode 100644
index 0000000..12251de
--- /dev/null
+++ b/tests/unit/controllers/pods/index-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Controller | pods/index', function (hooks) {
+ setupTest(hooks);
+
+ // TODO: Replace this with your real tests.
+ test('it exists', function (assert) {
+ let controller = this.owner.lookup('controller:pods/index');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/controllers/pods/index/pod-test.js b/tests/unit/controllers/pods/index/pod-test.js
new file mode 100644
index 0000000..8dcb615
--- /dev/null
+++ b/tests/unit/controllers/pods/index/pod-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Controller | pods/index/pod', function (hooks) {
+ setupTest(hooks);
+
+ // TODO: Replace this with your real tests.
+ test('it exists', function (assert) {
+ let controller = this.owner.lookup('controller:pods/index/pod');
+ assert.ok(controller);
+ });
+});
diff --git a/tests/unit/routes/account-test.js b/tests/unit/routes/account-test.js
new file mode 100644
index 0000000..429fa44
--- /dev/null
+++ b/tests/unit/routes/account-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Route | account', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ let route = this.owner.lookup('route:account');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/home-test.js b/tests/unit/routes/home-test.js
new file mode 100644
index 0000000..e6913cf
--- /dev/null
+++ b/tests/unit/routes/home-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Route | home', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ let route = this.owner.lookup('route:home');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/pods/explorer-test.js b/tests/unit/routes/pods/explorer-test.js
new file mode 100644
index 0000000..f2435b2
--- /dev/null
+++ b/tests/unit/routes/pods/explorer-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Route | pods/explorer', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ let route = this.owner.lookup('route:pods/explorer');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/pods/explorer/content-test.js b/tests/unit/routes/pods/explorer/content-test.js
new file mode 100644
index 0000000..c6d5a7d
--- /dev/null
+++ b/tests/unit/routes/pods/explorer/content-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Route | pods/explorer/content', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ let route = this.owner.lookup('route:pods/explorer/content');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/pods/index-test.js b/tests/unit/routes/pods/index-test.js
new file mode 100644
index 0000000..96b6535
--- /dev/null
+++ b/tests/unit/routes/pods/index-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Route | pods/index', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ let route = this.owner.lookup('route:pods/index');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/routes/pods/index/pod-test.js b/tests/unit/routes/pods/index/pod-test.js
new file mode 100644
index 0000000..d0e16e4
--- /dev/null
+++ b/tests/unit/routes/pods/index/pod-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Route | pods/index/pod', function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ let route = this.owner.lookup('route:pods/index/pod');
+ assert.ok(route);
+ });
+});
diff --git a/tests/unit/services/explorer-state-test.js b/tests/unit/services/explorer-state-test.js
new file mode 100644
index 0000000..e4185c1
--- /dev/null
+++ b/tests/unit/services/explorer-state-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'dummy/tests/helpers';
+
+module('Unit | Service | explorer-state', function (hooks) {
+ setupTest(hooks);
+
+ // TODO: Replace this with your real tests.
+ test('it exists', function (assert) {
+ let service = this.owner.lookup('service:explorer-state');
+ assert.ok(service);
+ });
+});