Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ MetacatUI is an open source, community project. We [welcome contributions](https

Cite this software as:

> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix, Ian Nesbitt, Yvonne Shi, Ian Guerin, Doug Hungarter. 2024. MetacatUI: A client-side web interface for DataONE data repositories (version 2.34.0). Arctic Data Center. [doi:10.18739/A2W669B2R](https://doi.org/10.18739/A2W669B2R)
> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix, Ian Nesbitt, Yvonne Shi, Ian Guerin, Doug Hungarter. 2024. MetacatUI: A client-side web interface for DataONE data repositories (version 2.34.1). Arctic Data Center. [doi:10.18739/A2W669B2R](https://doi.org/10.18739/A2W669B2R)

## Screenshots

Expand Down
2 changes: 1 addition & 1 deletion docs/_config.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
url: "/metacatui"
highlighter: "rouge"
version: "2.34.0"
version: "2.34.1"
468 changes: 428 additions & 40 deletions docs/docs/ResourceMapResolver.html

Large diffs are not rendered by default.

2,545 changes: 2,072 additions & 473 deletions docs/docs/VersionTracker.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/docs/global.html
Original file line number Diff line number Diff line change
Expand Up @@ -21509,7 +21509,7 @@ <h5 class="subsection-title">Properties:</h5>

<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="src_js_models_resourceMap_ResourceMapResolver.js.html">src/js/models/resourceMap/ResourceMapResolver.js</a>, <a href="src_js_models_resourceMap_ResourceMapResolver.js.html#line113">line 113</a>
<a href="src_js_models_resourceMap_ResourceMapResolver.js.html">src/js/models/resourceMap/ResourceMapResolver.js</a>, <a href="src_js_models_resourceMap_ResourceMapResolver.js.html#line117">line 117</a>
</li></ul></dd>


Expand Down
72 changes: 69 additions & 3 deletions docs/docs/src_js_models_resourceMap_ResourceMapResolver.js.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ <h1 class="page-title">Source: src/js/models/resourceMap/ResourceMapResolver.js<
const STATUS = Object.freeze({
// matches
indexMatch: "Resource map pid found in index",
multiRMMatch:
"Multiple versions of resource map found in index and could resolve to the most recent",
storageMatch: "Resource map pid found in local storage",
smMatch: "Resource map pid found by walking sysmeta",
guessMatch: "Resource map pid guessed based on naming convention",
Expand All @@ -78,6 +80,8 @@ <h1 class="page-title">Source: src/js/models/resourceMap/ResourceMapResolver.js<
storageMiss: "Resource map pid not found in local storage",
smMiss: "Resource map pid not found by walking sysmeta",
guessMiss: "Resource map pid not found by guessing",
multiRMMiss:
"Multiple resource maps found in index, but could not resolve to a single RM. They are either not versions of each other and/or are all are obsoleted.",
// special cases
pidIsSeriesId: "PID is a series ID, not an object PID",
noPidForSeriesId: "PID not found for series ID",
Expand Down Expand Up @@ -193,6 +197,23 @@ <h1 class="page-title">Source: src/js/models/resourceMap/ResourceMapResolver.js<
this.status(pid, STATUS.pidIsSeriesId, null, indexResult.meta);
return this.resolveFromSeriesId(pid);
}
if (indexResult?.meta?.rms?.length > 1) {
// Multiple resource maps found. If they are all versions of each other
// and one is not yet obsoleted, then that is the one we want.
const multiResult = await this.mutliRMCheck(pid, indexResult.meta.rms);
const singleRM = multiResult.rm;
if (singleRM) {
return this.status(
pid,
STATUS.multiRMMatch,
singleRM,
multiResult.meta,
);
}
// If not found, then continue with the resolution process
this.status(pid, STATUS.multiRMMiss, null, multiResult.meta);
}

this.status(pid, STATUS.indexMiss, null, indexResult.meta);

// ---- STORAGE ----
Expand Down Expand Up @@ -269,6 +290,51 @@ <h1 class="page-title">Source: src/js/models/resourceMap/ResourceMapResolver.js<
return result;
}

/**
* When 2 or more resource maps are found in the index for a PID, then this
* method is called to check if they are all versions of each other and if
* one is not yet obsoleted.
* @param {string} pid - The PID to check for multiple resource maps
* @param {Array&lt;string>} rms - An array of resource map PIDs to check
* @returns {Promise&lt;object>} - An object containing the PID, the resolved
* resource map PID if found, and metadata about the search.
* @since 2.34.1
*/
async mutliRMCheck(pid, rms) {
const result = { pid, rm: null, meta: {} };

// Get obsoletes and obsoletedBy from the sysMeta for each RM.
const rmRecords = await Promise.all(
rms.map((rm) => this.versionTracker.getAdjacent(rm, true)),
);

// Get a unique list of all PIDs from the records
const allPids = new Set(
rmRecords.flatMap((record) => [record.prev, record.next]),
);

// If any of the RM pids are not in the allPids set, then they are not
// versions of each other, so we cannot resolve to a single RM.
if (!rms.every((rm) => allPids.has(rm))) {
result.meta.multipleRMsNotVersions = true;
return result;
}

// All RMs are versions of each other, so find one that is not yet
// obsoleted
const validRms = rmRecords.filter((record) => !record.next?.length);

if (validRms.length === 1) {
result.rm = validRms[0].pid;
return result;
}

// Otherwise, we have multiple RMs that are versions of each other but not
// the most recent one, so we cannot resolve to a single RM.
result.meta.multipleRMsAllObsoleted = true;
return result;
}

/**
* Gets the PID for a given series ID (SID) using sys metadata. Ensures that
* the most recent PID is returned, even if indexing is not complete.
Expand All @@ -277,7 +343,7 @@ <h1 class="page-title">Source: src/js/models/resourceMap/ResourceMapResolver.js<
* or null if not found
*/
async getPidForSid(sid) {
const record = await this.versionTracker.getNth(sid, 0, false, true);
const record = await this.versionTracker.getNth(sid, 0, true, true);
const sysmeta = record.sysMeta;
return sysmeta?.identifier;
}
Expand Down Expand Up @@ -476,7 +542,7 @@ <h1 class="page-title">Source: src/js/models/resourceMap/ResourceMapResolver.js<
while (steps &lt; this.maxSteps &amp;&amp; currentPid) {
steps += 1;
const offset = steps * -1; // Walk backward
currentPid = await this.versionTracker.getNth(pid, offset);
currentPid = await this.versionTracker.getNth(pid, offset, true);
const record = await this.versionTracker.record(currentPid || pid);
if (record?.unauthorized) meta.unauthorized = true;
if (record?.errors) meta.errors = record.errors;
Expand All @@ -498,7 +564,7 @@ <h1 class="page-title">Source: src/js/models/resourceMap/ResourceMapResolver.js<
if (!rm) return { rm, meta };

// Walk forward same # steps to find the current RM
const currentRM = await this.versionTracker.getNth(rm, steps);
const currentRM = await this.versionTracker.getNth(rm, steps, true);
return { rm: currentRM, meta };
}

Expand Down
78 changes: 69 additions & 9 deletions docs/docs/src_js_models_sysmeta_VersionTracker.js.html
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ <h1 class="page-title">Source: src/js/models/sysmeta/VersionTracker.js</h1>
* milliseconds. Defaults to 24 hours (1 day).
* @param {number} [options.maxChainHops] - Maximum number of hops in the
* version chain to cache. Defaults to 200 hops.
* @param {number} [options.maxCacheRecords] - Maximum number of in-memory cache records. Defaults to 5000.
* @param {number} [options.maxCacheRecords] - Maximum number of in-memory
* cache records. Defaults to 5000.
*/
constructor({
metaServiceUrl,
Expand Down Expand Up @@ -184,8 +185,8 @@ <h1 class="page-title">Source: src/js/models/sysmeta/VersionTracker.js</h1>
"Invalid store provided to VersionTracker. Must be a localforage instance.",
);
}
// use a name based on the SysMeta service URL to avoid conflicts
// with other instances that might use different URLs
// use a name based on the SysMeta service URL to avoid conflicts with
// other instances that might use different URLs
const storeName = `vt_${md5(this.metaServiceUrl)}`;
this.store =
store || localforage.createInstance({ name: storeName, storeName });
Expand All @@ -199,8 +200,8 @@ <h1 class="page-title">Source: src/js/models/sysmeta/VersionTracker.js</h1>
* same PID, +n newer, -n older
* @param {boolean} [ignoreEnd] Set to true to allow walking beyond cached
* chain end (e.g. to re-check whether there's a newer version)
* @param {boolean} [withMeta] - If true, return arrays of { pid,
* sysMeta } instead of bare PIDs.
* @param {boolean} [withMeta] - If true, return arrays of { pid, sysMeta }
* instead of bare PIDs.
* @returns {Promise&lt;VersionResult|string|null>} - resolves to the requested
* PID at the given offset, or null if no such version exists. If `withMeta`
* is true, resolves to an object with { pid, sysMeta }.
Expand Down Expand Up @@ -234,7 +235,8 @@ <h1 class="page-title">Source: src/js/models/sysmeta/VersionTracker.js</h1>
const forward = offset > 0;
await this.fillVersionChain(pid, steps, forward, ignoreEnd);

// Get the record from the cached chain and return the requested PID and sysMeta
// Get the record from the cached chain and return the requested PID and
// sysMeta
const rec = await this.record(pid);

const list = forward ? rec.next : rec.prev;
Expand All @@ -253,8 +255,8 @@ <h1 class="page-title">Source: src/js/models/sysmeta/VersionTracker.js</h1>
* Get the complete version chain for the given PID.
* @param {string} pid - PID to get the chain for
* @param {boolean} [ignoreEnd] - Re‑probe past cached end flags
* @param {boolean} [withMeta] - If true, return arrays of { pid,
* sysMeta } instead of bare PIDs.
* @param {boolean} [withMeta] - If true, return arrays of { pid, sysMeta }
* instead of bare PIDs.
* @returns {Promise&lt;VersionRecord>} - resolves to an object with `prev`,
* `next`, `sysMeta`, `endPrev`, and `endNext` properties.
*/
Expand Down Expand Up @@ -292,7 +294,7 @@ <h1 class="page-title">Source: src/js/models/sysmeta/VersionTracker.js</h1>
* re-checking if a newer version exists.
* @param {boolean} [withMeta] - If true, the SysMeta will be fetched if not
* already available in the cache.
* @return {Promise&lt;string|VersionResult>} - resolves to the latest PID in
* @returns {Promise&lt;string|VersionResult>} - resolves to the latest PID in
* the chain, or an object with { pid, sysMeta } if `withMeta` is true. If
* no versions are found, resolves to the original PID.
*/
Expand Down Expand Up @@ -400,6 +402,64 @@ <h1 class="page-title">Source: src/js/models/sysmeta/VersionTracker.js</h1>
this.notify(newPid);
}

/**
* Get the next most recent version after the given PID.
* @param {string} pid - the PID to get the next version for
* @param {boolean} [ignoreEnd] - If true, ignore end flags and continue
* walking the chain even if it appears complete.
* @param {boolean} [withMeta] - If true, the SysMeta will be fetched if not
* already available in the cache.
* @returns {Promise&lt;VersionResult>} - resolves to the next version PID or
* an object with { pid, sysMeta } if `withMeta` is true. If no next version
* is found, resolves to the original PID.
* @since 2.34.1
*/
getNext(pid, ignoreEnd = false, withMeta = false) {
return this.getNth(pid, 1, ignoreEnd, withMeta);
}

/**
* Get the previous version before the given PID.
* @param {string} pid - the PID to get the previous version for
* @param {boolean} [ignoreEnd] - If true, ignore end flags and continue
* walking the chain even if it appears complete.
* @param {boolean} [withMeta] - If true, the SysMeta will be fetched if not
* already available in the cache.
* @returns {Promise&lt;VersionResult>} - resolves to the previous version PID
* or an object with { pid, sysMeta } if `withMeta` is true. If no previous
* version is found, resolves to the original PID.
* @since 2.34.1
*/
getPrev(pid, ignoreEnd = false, withMeta = false) {
return this.getNth(pid, -1, ignoreEnd, withMeta);
}

/**
* Get the version before and after the given PID, if available.
* @param {string} pid - the PID to get adjacent versions for
* @param {boolean} [ignoreEnd] - If true, ignore end flags and continue
* walking the chain even if it appears complete.
* @param {boolean} [withMeta] - If true, the SysMeta will be fetched if not
* already available in the cache.
* @returns {Promise&lt;{pid: string, prev: VersionResult, next:
* VersionResult}>}
* - resolves to an object with `pid`, `prev`, and `next` properties. `prev`
* and `next` are either PIDs or objects with { pid, sysMeta } if
* `withMeta` is true. If no previous or next version is found, the
* respective property will be null.
* @since 2.34.1
*/
async getAdjacent(pid, ignoreEnd = false, withMeta = false) {
return Promise.all([
this.getPrev(pid, ignoreEnd, withMeta),
this.getNext(pid, ignoreEnd, withMeta),
]).then(([prev, next]) => ({
pid,
prev,
next,
}));
}

/**
* Notify that a specific the chain for a specific PID has been updated.
* This is called internally after a new version is added or the chain is
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/src_js_views_metadata_EML211EditorView.js.html
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ <h1 class="page-title">Source: src/js/views/metadata/EML211EditorView.js</h1>
}

// TODO - get latest version should happen in DataONE object.
const latestPid = await versionTracker.getLatestVersion(metaPid);
const latestPid = await versionTracker.getLatestVersion(metaPid, true);
if (latestPid !== metaPid) {
// MetacatUI.rootDataPackage.packageModel.set("sysMetaXML", null);
metaModel.set("latestVersion", latestPid);
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ MetacatUI is an open source, community project. We [welcome contributions](https

Cite this software as:

> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix, Ian Nesbitt, Yvonne Shi, Ian Guerin, Doug Hungarter. 2024. MetacatUI: A client-side web interface for DataONE data repositories (version 2.34.0). Arctic Data Center. [doi:10.18739/A2W669B2R](https://doi.org/10.18739/A2W669B2R)
> Matthew B. Jones, Chris Jones, Lauren Walker, Robyn Thiessen-Bock, Ben Leinfelder, Peter Slaughter, Bryce Mecum, Rushiraj Nenuji, Hesham Elbashandy, Val Hendrix, Ian Nesbitt, Yvonne Shi, Ian Guerin, Doug Hungarter. 2024. MetacatUI: A client-side web interface for DataONE data repositories (version 2.34.1). Arctic Data Center. [doi:10.18739/A2W669B2R](https://doi.org/10.18739/A2W669B2R)

## Related Projects

Expand Down
4 changes: 2 additions & 2 deletions helm/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.0.8
version: 1.0.9

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "2.34.0"
appVersion: "2.34.1"
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "metacatui",
"version": "2.34.0",
"version": "2.34.1",
"description": "MetacatUI: A client-side web interface for DataONE data repositories",
"main": "server.js",
"dependencies": {
Expand Down
Loading
Loading