Skip to content

Commit

Permalink
improvements to current user service, universe service, and url searc…
Browse files Browse the repository at this point in the history
…h params service, and fixed child service injection for engineService decorator
  • Loading branch information
roncodes committed Oct 1, 2024
1 parent 2c61c2d commit f0bedd3
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 39 deletions.
2 changes: 2 additions & 0 deletions addon/services/current-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export default class CurrentUserService extends Service.extend(Evented) {
@alias('user.is_admin') isAdmin;
@alias('user.company_uuid') companyId;
@alias('user.company_name') companyName;
@alias('user.role_name') roleName;
@alias('user.role') role;

@computed('id') get optionsPrefix() {
return `${this.id}:`;
Expand Down
61 changes: 59 additions & 2 deletions addon/services/universe.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import config from 'ember-get-config';
export default class UniverseService extends Service.extend(Evented) {
@service router;
@service intl;
@service urlSearchParams;
@tracked applicationInstance;
@tracked enginesBooted = false;
@tracked bootedExtensions = A([]);
Expand Down Expand Up @@ -136,6 +137,17 @@ export default class UniverseService extends Service.extend(Evented) {
return this.router.transitionTo(route, ...args);
}

/**
* Sets the application instance.
*
* @param {ApplicationInstance} - The application instance object.
* @return {void}
*/
setApplicationInstance(instance) {
window.Fleetbase = instance;
this.applicationInstance = instance;
}

/**
* Retrieves the application instance.
*
Expand Down Expand Up @@ -262,6 +274,43 @@ export default class UniverseService extends Service.extend(Evented) {
return this.router.transitionTo(route, slug);
}

/**
* Redirects to a virtual route if a corresponding menu item exists based on the current URL slug.
*
* This asynchronous function checks whether a virtual route exists by extracting the slug from the current
* window's pathname and looking up a matching menu item in a specified registry. If a matching menu item
* is found, it initiates a transition to the given route associated with that menu item and returns the
* transition promise.
*
* @async
*
* @param {Object} transition - The current transition object from the router.
* Used to retrieve additional information required for the menu item lookup.
* @param {string} registryName - The name of the registry to search for the menu item.
* This registry should contain menu items mapped by their slugs.
* @param {string} route - The name of the route to transition to if the menu item is found.
* This is typically the route associated with displaying the menu item's content.
*
* @returns {Promise|undefined} - Returns a promise that resolves when the route transition completes
* if a matching menu item is found. If no matching menu item is found, the function returns undefined.
*
*/
async virtualRouteRedirect(transition, registryName, route, options = {}) {
const view = this.getViewFromTransition(transition);
const slug = window.location.pathname.replace('/', '');
const queryParams = this.urlSearchParams.all();
const menuItem = await this.lookupMenuItemFromRegistry(registryName, slug, view);
if (menuItem && transition.from === null) {
return this.transitionMenuItem(route, menuItem, { queryParams }).then((transition) => {
if (options && options.restoreQueryParams === true) {
this.urlSearchParams.setParamsToCurrentUrl(queryParams);
}

return transition;
});
}
}

/**
* @action
* Creates a new registry with the given name and options.
Expand Down Expand Up @@ -1396,6 +1445,14 @@ export default class UniverseService extends Service.extend(Evented) {
isLoading,
};

// make the menu item and universe object a default param of the onClick handler
if (typeof onClick === 'function') {
const universe = this;
menuItem.onClick = function () {
return onClick(menuItem, universe);
};
}

return menuItem;
}

Expand Down Expand Up @@ -1746,7 +1803,7 @@ export default class UniverseService extends Service.extend(Evented) {
}

// Set application instance
this.applicationInstance = owner;
this.setApplicationInstance(owner);

const tryBootEngine = (extension) => {
return this.loadEngine(extension.name).then((engineInstance) => {
Expand Down Expand Up @@ -1838,7 +1895,7 @@ export default class UniverseService extends Service.extend(Evented) {
}

// Set application instance
this.applicationInstance = owner;
this.setApplicationInstance(owner);

const tryBootEngine = (extension) => {
return this.loadEngine(extension.name).then((engineInstance) => {
Expand Down
224 changes: 189 additions & 35 deletions addon/services/url-search-params.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { debounce } from '@ember/runloop';
import hasJsonStructure from '../utils/has-json-structure';

/**
* Service for manipulating URL search parameters.
*
* This service provides methods to get, set, remove, and check URL query parameters.
* It also allows updating the browser's URL without reloading the page.
*
* @extends Service
*/
export default class UrlSearchParamsService extends Service {
/**
* The active URL params
* Getter for `urlParams` that ensures it's always up-to-date with the current URL.
*
* @var {Array}
* @type {URLSearchParams}
* @private
*/
@tracked urlParams;

/**
* Update the URL params
*
* @void
*/
setSearchParams() {
this.urlParams = new URLSearchParams(window.location.search);

return this;
get urlParams() {
return new URLSearchParams(window.location.search);
}

/**
* Get a param
* Retrieves the value of a specific query parameter.
*
* @param {String} key the url param
* @return mixed
* If the parameter value is a JSON string, it will be parsed into an object or array.
*
* @param {string} key - The name of the query parameter to retrieve.
* @returns {*} The value of the query parameter, parsed from JSON if applicable, or null if not found.
*/
getParam(key) {
this.setSearchParams();

let value = this.urlParams.get(key);

if (hasJsonStructure(value)) {
Expand All @@ -40,47 +40,102 @@ export default class UrlSearchParamsService extends Service {
}

/**
* Get a param
* Sets or updates a query parameter in the URL search parameters.
*
* If the value is an object or array, it will be stringified to JSON.
*
* @param {string} key - The name of the query parameter to set.
* @param {*} value - The value of the query parameter.
* @returns {this} Returns the service instance for chaining.
*/
setParam(key, value) {
if (typeof value === 'object') {
value = JSON.stringify(value);
} else {
value = encodeURIComponent(value);
}

this.urlParams.set(key, value);

return this;
}

/**
* Alias for `getParam`.
*
* @param {String} key the url param
* @return mixed
* @param {string} key - The name of the query parameter to retrieve.
* @returns {*} The value of the query parameter.
*/
get(key) {
return this.getParam(key);
}

/**
* Determines if a queryParam exists
* Sets or updates a query parameter with multiple values.
*
* @param {String} key the url param
* @var {Boolean}
* @param {string} key - The name of the query parameter to set.
* @param {Array} values - An array of values for the parameter.
* @returns {this} Returns the service instance for chaining.
*/
setParamArray(key, values) {
this.urlParams.delete(key);
values.forEach((value) => {
this.urlParams.append(key, value);
});

return this;
}

/**
* Retrieves all values of a specific query parameter.
*
* @param {string} key - The name of the query parameter.
* @returns {Array} An array of values for the parameter.
*/
getParamArray(key) {
return this.urlParams.getAll(key);
}

/**
* Checks if a specific query parameter exists in the URL.
*
* @param {string} key - The name of the query parameter to check.
* @returns {boolean} True if the parameter exists, false otherwise.
*/
exists(key) {
this.setSearchParams();
return this.urlParams.has(key);
}

/**
* Checks if a specific query parameter has in the URL.
*
* @param {string} key - The name of the query parameter to check.
* @returns {boolean} True if the parameter exists, false otherwise.
*/
has(key) {
return this.urlParams.has(key);
}

/**
* Remove a queryparam
* Removes a specific query parameter from the URL search parameters.
*
* @param {String} key the url param
* @void
* @param {string} key - The name of the query parameter to remove.
* @returns {this} Returns the service instance for chaining.
*/
remove(key) {
this.setSearchParams();
this.urlParams.delete(key);

return this.urlParams.delete(key);
return this;
}

/**
* Returns object of all params
* Retrieves all query parameters as an object.
*
* @return {Array}
* Each parameter value is processed by `getParam`, which parses JSON values if applicable.
*
* @returns {Object} An object containing all query parameters and their values.
*/
all() {
this.setSearchParams();

const all = {};

for (let key of this.urlParams.keys()) {
Expand All @@ -89,4 +144,103 @@ export default class UrlSearchParamsService extends Service {

return all;
}

/**
* Updates the browser's URL with the current `urlParams` without reloading the page.
*
* @returns {void}
*/
updateUrl() {
const url = new URL(window.location.href);
url.search = this.urlParams.toString();
window.history.pushState({ path: url.href }, '', url.href);
}

/**
* Updates the browser's URL with the current `urlParams`, debounced to prevent excessive calls.
*
* @returns {void}
*/
updateUrlDebounced() {
debounce(this, this.updateUrl, 100);
}

/**
* Clears all query parameters from the URL search parameters.
*
* @returns {this} Returns the service instance for chaining.
*/
clear() {
this.urlParams = new URLSearchParams();

return this;
}

/**
* Returns the full URL as a string with the current `urlParams`.
*
* @returns {string} The full URL with updated query parameters.
*/
getFullUrl() {
const url = new URL(window.location.href);
url.search = this.urlParams.toString();

return url.toString();
}

/**
* Returns the current path with the updated query parameters.
*
* @returns {string} The path and search portion of the URL.
*/
getPathWithParams() {
return `${window.location.pathname}?${this.urlParams.toString()}`;
}

/**
* Removes a query parameter from the current URL and updates the browser history.
*
* This method modifies the browser's URL by removing the specified parameter and uses the History API
* to update the URL without reloading the page.
*
* @param {string} paramToRemove - The name of the query parameter to remove from the URL.
* @returns {void}
*/
removeParamFromCurrentUrl(paramToRemove) {
const url = new URL(window.location.href);
url.searchParams.delete(paramToRemove);
window.history.pushState({ path: url.href }, '', url.href);
}

/**
* Adds or updates a query parameter in the current URL and updates the browser history.
*
* This method modifies the browser's URL by adding or updating the specified parameter and uses the History API
* to update the URL without reloading the page.
*
* @param {string} paramName - The name of the query parameter to add or update.
* @param {string} paramValue - The value of the query parameter.
* @returns {void}
*/
addParamToCurrentUrl(paramName, paramValue) {
const url = new URL(window.location.href);
url.searchParams.set(paramName, paramValue);
window.history.pushState({ path: url.href }, '', url.href);
}

/**
* Adds or updates a query parameters from a provided object into the current URL and updates the browser history.
*
* This method modifies the browser's URL by adding or updating the specified parameters and uses the History API
* to update the URL without reloading the page.
*
* @param {Object} params - The query parameters to add or update.
* @returns {void}
*/
setParamsToCurrentUrl(params = {}) {
for (let param in params) {
const value = params[param];
this.addParamToCurrentUrl(param, value);
}
}
}
Loading

0 comments on commit f0bedd3

Please sign in to comment.