Skip to content

Commit

Permalink
Use one-way binding for loading-state (#4186)
Browse files Browse the repository at this point in the history
Also, make some code health improvements while I'm here:
- Mark private methods with an underscore
- Use console.error for error messages
- Use numerice comparison for numeric variables
- Make isLoading read-only
- Add comments
  • Loading branch information
past authored Jan 3, 2025
1 parent 8d447a4 commit 0c1ef56
Showing 1 changed file with 50 additions and 14 deletions.
64 changes: 50 additions & 14 deletions webapp/components/loading-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,74 @@
* found in the LICENSE file.
*/

/*
LoadingState is a behaviour component for indicating when information is
still being loaded (generally, fetched).
*/


/**
* LoadingState is a behaviour component for indicating when information is
* still being loaded (generally, fetched).
*/
const LoadingState = (superClass) => class extends superClass {
static get properties() {
return {
/**
* The number of active loading operations.
*/
loadingCount: {
type: Number,
value: 0,
observer: 'loadingCountChanged',
observer: '_loadingCountChanged',
},
/**
* Whether the component is currently loading data.
* Computed based on `loadingCount`.
*/
isLoading: {
type: Boolean,
computed: 'computeIsLoading(loadingCount)',
notify: true,
value: false,
computed: '_computeIsLoading(loadingCount)',
readOnly: true,
},
/**
* A callback function to be executed when loading is complete.
*/
onLoadingComplete: {
type: Function,
},
onLoadingComplete: Function,
};
}

computeIsLoading(loadingCount) {
return !!loadingCount;
/**
* Computes the `isLoading` property based on `loadingCount`.
* @param {number} loadingCount The current loading count.
* @return {boolean} True if loading, false otherwise.
*/
_computeIsLoading(loadingCount) {
return loadingCount > 0;
}

loadingCountChanged(now, then) {
/**
* Observer for `loadingCount` changes.
* Calls `onLoadingComplete` when loading finishes.
* @param {number} now The new loading count.
* @param {number} then The previous loading count.
*/
_loadingCountChanged(now, then) {
if (now === 0 && then > 0 && this.onLoadingComplete) {
this.onLoadingComplete();
}
}

/**
* Tracks a promise, incrementing `loadingCount` while it's pending.
* @param {Promise} promise The promise to track.
* @param {Function} opt_errHandler An optional error handler.
* @return {Promise} A promise that resolves/rejects with the original promise.
*/
async load(promise, opt_errHandler) {
this.loadingCount++;
try {
return await promise;
} catch (e) {
// eslint-disable-next-line no-console
console.log(`Failed to load: ${e}`);
console.error(`Failed to load: ${e}`);
if (opt_errHandler) {
opt_errHandler(e);
}
Expand All @@ -52,6 +80,14 @@ const LoadingState = (superClass) => class extends superClass {
}
}

/**
* Retries a function with exponential backoff.
* @param {Function} f The function to retry.
* @param {Function} shouldRetry A function that determines if retrying should continue.
* @param {number} num The maximum number of retries.
* @param {number} wait The initial wait time in milliseconds.
* @return {Promise} A promise that resolves with the result of `f` or rejects.
*/
retry(f, shouldRetry, num, wait) {
let count = 0;
const retry = () => {
Expand Down

0 comments on commit 0c1ef56

Please sign in to comment.