* refactor: 💡 move model hook to session-recordings/index route ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130 * test: 💍 add missing tests for session recordings controller ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130 * feat: 🎸 paginate session-recordings and search ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130 * refactor: 💡 fix failing redirect and tests ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130 * test: 💍 add search tests for session recordings ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130 * feat: 🎸 add user filtering for session recordings ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130 * feat: 🎸 add more attributes to indexed-db session recordings ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130 * feat: 🎸 add target filter for session recordings ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130 * refactor: 💡 update filterOptions method ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15130 * feat: 🎸 add scopes filtering to session recording ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * feat: 🎸 add time filter to session recordings ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * refactor: 💡 add no filter results text ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * refactor: 💡 update Exist variables to doExist ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * refactor: 💡 updates from PR feedback ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * refactor: 💡 remove scope_id filter ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * refactor: 💡 change session recording placeholder text ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * chore: 🤖 increment indexedDB version ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * test: 💍 add Date object tests for indexed-db ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * refactor: 💡 small changes from PR feedback ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * refactor: 💡 change times filter array to time date object ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * test: 💍 add more date specific indexed-db test ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * refactor: 💡 change Today time shortcut to "Last 24 hours" ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181 * test: 💍 fix date mock in session-recording controller tests ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-15181
152 lines
5.5 KiB
JavaScript
152 lines
5.5 KiB
JavaScript
/**
|
|
* Copyright (c) HashiCorp, Inc.
|
|
* SPDX-License-Identifier: BUSL-1.1
|
|
*/
|
|
|
|
import Service from '@ember/service';
|
|
import Dexie from 'dexie';
|
|
import { typeOf } from '@ember/utils';
|
|
|
|
// List of resources we support to be cached and searched in
|
|
// indexedDb. Any field that can be searched upon should be added to
|
|
// this index. Increment the version number of the database whenever
|
|
// indexes change.
|
|
export const modelIndexes = {
|
|
token: '&id, token',
|
|
target:
|
|
'&id, attributes.created_time, attributes.type, attributes.name, attributes.description, attributes.address, attributes.scope.scope_id',
|
|
session:
|
|
'&id, attributes.created_time, attributes.type, attributes.status, attributes.endpoint, attributes.target_id, attributes.user_id, attributes.scope.scope_id',
|
|
user: '&id, attributes.created_time, attributes.name, attributes.description, attributes.scope.scope_id',
|
|
group:
|
|
'&id, attributes.created_time, attributes.name, attributes.description, attributes.scope.scope_id',
|
|
role: '&id, attributes.created_time, attributes.name, attributes.description, attributes.scope.scope_id',
|
|
scope:
|
|
'&id, attributes.created_time, attributes.type, attributes.name, attributes.description, attributes.scope.scope_id',
|
|
'credential-store':
|
|
'&id, attributes.created_time, attributes.name, attributes.description, attributes.type, attributes.scope.scope_id',
|
|
'host-catalog':
|
|
'&id, attributes.created_time, attributes.type, attributes.name, attributes.description, attributes.scope.scope_id, attributes.plugin.name',
|
|
'auth-method':
|
|
'&id, attributes.created_time, attributes.type, attributes.name, attributes.description, attributes.is_primary, attributes.scope.scope_id',
|
|
'session-recording':
|
|
'&id, attributes.created_time, attributes.type, attributes.state, attributes.start_time, attributes.end_time, attributes.duration, attributes.scope.scope_id, attributes.create_time_values.user.id, attributes.create_time_values.user.name, attributes.create_time_values.target.id, attributes.create_time_values.target.name, attributes.create_time_values.target.scope.id, attributes.create_time_values.target.scope.name',
|
|
alias:
|
|
'&id, attributes.created_time, attributes.type, attributes.value, attributes.name, attributes.description, attributes.destination_id, attributes.scope.scope_id',
|
|
};
|
|
|
|
export const formatDbName = (userId, clusterUrl) =>
|
|
`boundary-${userId}-${clusterUrl}`;
|
|
|
|
/**
|
|
* Recursively copy over the object and convert any booleans to "true" or "false" so they can be indexed.
|
|
* Also converts any ember-like arrays back to a standard array.
|
|
* @param result
|
|
* @param object
|
|
* @returns {*}
|
|
*/
|
|
const convertFields = (result, object) => {
|
|
Object.entries(object).forEach(([key, value]) => {
|
|
if (typeOf(value) === 'object') {
|
|
result[key] = convertFields({}, value);
|
|
} else if (typeOf(value) === 'boolean') {
|
|
result[key] = value ? 'true' : 'false';
|
|
} else if (typeOf(value) === 'array') {
|
|
result[key] = [...value];
|
|
} else {
|
|
result[key] = value;
|
|
}
|
|
});
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Recursively copy over the object and convert any string "true" or "false" back to booleans.
|
|
* Will also convert any array fields back using their model transformation.
|
|
* @param result
|
|
* @param object
|
|
* @param schema
|
|
* @param serializer
|
|
* @returns {*}
|
|
*/
|
|
const unconvertFields = (result, object, schema, serializer) => {
|
|
Object.entries(object).forEach(([key, value]) => {
|
|
if (typeOf(value) === 'object') {
|
|
result[key] = unconvertFields({}, value, schema, serializer);
|
|
} else if (value === 'true' || value === 'false') {
|
|
result[key] = value === 'true';
|
|
} else if (typeOf(value) === 'array') {
|
|
const attribute = schema.attributes.get(key);
|
|
|
|
// If attribute type is array, we transform it back to a tracked array
|
|
if (attribute?.type === 'array') {
|
|
const transformer = serializer.transformFor(attribute.type);
|
|
result[key] = transformer.deserialize(value, attribute.options);
|
|
return;
|
|
}
|
|
|
|
result[key] = value;
|
|
} else {
|
|
result[key] = value;
|
|
}
|
|
});
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Service to encapsulate the IndexedDB implementation. To use this service, call
|
|
* `setup` from the application root and
|
|
*/
|
|
export default class IndexedDbService extends Service {
|
|
// =attributes
|
|
#db;
|
|
get db() {
|
|
return this.#db;
|
|
}
|
|
|
|
setup(dbName) {
|
|
// Don't run setup again if we already have one or if we didn't get a name
|
|
if (this.#db || !dbName) {
|
|
return;
|
|
}
|
|
|
|
this.#db = new Dexie(dbName);
|
|
this.#db.version(2).stores(modelIndexes);
|
|
}
|
|
|
|
/**
|
|
* Cleanup the data by converting all fields to plain javascript objects.
|
|
* We will also convert booleans to "false" or "true".
|
|
* IndexedDB doesn't support indexes on boolean values so we have to
|
|
* convert them to be able to support using boolean values.
|
|
*
|
|
* Undo the operation by setting `convertFields` to false.
|
|
*
|
|
* @param {Object} data
|
|
* @param {Boolean} cleanData
|
|
* @param {Object} schema
|
|
* @param {Object} serializer
|
|
* @return {{id, type, attributes: {}, relationships: {}}}
|
|
*/
|
|
normalizeData({ data, cleanData, schema, serializer }) {
|
|
if (!data) {
|
|
return data;
|
|
}
|
|
|
|
let { id, type, attributes = {}, relationships = {} } = data;
|
|
|
|
return {
|
|
id,
|
|
type,
|
|
attributes: cleanData
|
|
? convertFields({}, attributes)
|
|
: unconvertFields({}, attributes, schema, serializer),
|
|
relationships: cleanData
|
|
? convertFields({}, relationships)
|
|
: unconvertFields({}, relationships, schema, serializer),
|
|
};
|
|
}
|
|
}
|