Files
nomad/ui/app/serializers/dynamic-host-volume.js
Phil Renaud 1976202cd6 Feature: Dynamic Host Volumes in the UI (#25224)
* DHV UI init

* /csi routes to /storage routes and a routeRedirector util (#25163)

* /csi routes to /storage routes and a routeRedirector util

* Tests and routes move csi/ to storage/

* Changelog added

* [ui] Storage UI overhaul + Dynamic Host Volumes UI (#25226)

* Storage index page and DHV model properties

* Naive version of a storage overview page

* Experimental fetch of alloc data dirs

* Fetch ephemeral disks and static host volumes as an ember concurrency task and nice table stylings

* Playing nice with section header labels to make eslint happy even though wcag was already cool with it

* inlined the storage type explainers and reordered things, plus tooltips and keynav

* Bones of a dynamic host volume individual page

* Woooo dynamic host volume model, adapter, and serializer with embedded alloc relationships

* Couple test fixes

* async:false relationship for dhv.hasMany('alloc') to prevent a ton of xhr requests

* DHV request type at index routemodel and better serialization

* Pagination and searching and query params oh my

* Test retrofits for csi volumes

* Really fantastic flake gets fixed

* DHV detail page acceptance test and a bunch of mirage hooks

* Seed so that the actions test has a guaranteed task

* removed ephemeral disk and static host volume manual scanning

* CapacityBytes and capabilities table added to DHV detail page

* Debugging actions flyout test

* was becoming clear that faker.seed editing was causing havoc elsewhere so might as well not boil the ocean and just tell this test to do what I want it to

* Post-create job gets taskCount instead of count

* CSI volumes now get /csi route prefix at detail level

* lazyclick method for unused keynav removed

* keyboard nav and table-watcher for DHV added

* Addressed PR comments, changed up capabilities table and id references, etc.

* Capabilities table for DHV and ID in details header

* Testfixes for pluginID and capabilities table on DHV page
2025-03-10 14:46:02 -04:00

80 lines
2.5 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import ApplicationSerializer from './application';
import { get, set } from '@ember/object';
import { capitalize } from '@ember/string';
import classic from 'ember-classic-decorator';
@classic
export default class DynamicHostVolumeSerializer extends ApplicationSerializer {
embeddedRelationships = ['allocations'];
separateNanos = ['CreateTime', 'ModifyTime'];
// Volumes treat Allocations as embedded records. Ember has an
// EmbeddedRecords mixin, but it assumes an application is using
// the REST serializer and Nomad does not.
normalize(typeHash, hash) {
hash.PlainId = hash.ID;
hash.ID = JSON.stringify([hash.ID, hash.Namespace || 'default']);
const normalizedHash = super.normalize(typeHash, hash);
return this.extractEmbeddedRecords(
this,
this.store,
typeHash,
normalizedHash
);
}
keyForRelationship(attr, relationshipType) {
//Embedded relationship attributes don't end in IDs
if (this.embeddedRelationships.includes(attr)) return capitalize(attr);
return super.keyForRelationship(attr, relationshipType);
}
extractEmbeddedRecords(serializer, store, typeHash, partial) {
partial.included = partial.included || [];
this.embeddedRelationships.forEach((embed) => {
const relationshipMeta = typeHash.relationshipsByName.get(embed);
const relationship = get(partial, `data.relationships.${embed}.data`);
if (!relationship) return;
const hasMany = new Array(relationship.length);
relationship.forEach((alloc, idx) => {
const { data, included } = this.normalizeEmbeddedRelationship(
store,
relationshipMeta,
alloc
);
partial.included.push(data);
if (included) {
partial.included.push(...included);
}
// In JSONAPI, the main payload value is an array of IDs that
// map onto the objects in the included array.
hasMany[idx] = { id: data.id, type: data.type };
});
const relationshipJson = { data: hasMany };
set(partial, `data.relationships.${embed}`, relationshipJson);
});
return partial;
}
normalizeEmbeddedRelationship(store, relationshipMeta, relationshipHash) {
const modelName = relationshipMeta.type;
const modelClass = store.modelFor(modelName);
const serializer = store.serializerFor(modelName);
return serializer.normalize(modelClass, relationshipHash, null);
}
}