-
Notifications
You must be signed in to change notification settings - Fork 917
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Tyler Ohlsen <[email protected]>
- Loading branch information
Showing
18 changed files
with
540 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
66 changes: 66 additions & 0 deletions
66
src/plugins/vis_augmenter/public/saved_augment_vis/_saved_augment_vis.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
/** | ||
* @name SavedAugmentVis | ||
* | ||
* @extends SavedObject. | ||
*/ | ||
import { get } from 'lodash'; | ||
import { | ||
createSavedObjectClass, | ||
SavedObject, | ||
SavedObjectOpenSearchDashboardsServices, | ||
} from '../../../saved_objects/public'; | ||
import { IIndexPattern } from '../../../data/public'; | ||
import { extractReferences, injectReferences } from './saved_augment_vis_references'; | ||
|
||
export function createSavedAugmentVisClass(services: SavedObjectOpenSearchDashboardsServices) { | ||
const SavedObjectClass = createSavedObjectClass(services); | ||
|
||
class SavedAugmentVis extends SavedObjectClass { | ||
public static type: string = 'augment-vis'; | ||
public static mapping: Record<string, string> = { | ||
description: 'text', | ||
pluginResourceId: 'text', | ||
visId: 'keyword', | ||
visLayerExpressionFn: 'object', | ||
version: 'integer', | ||
}; | ||
|
||
constructor(opts: Record<string, unknown> | string = {}) { | ||
if (typeof opts !== 'object') { | ||
opts = { id: opts }; | ||
} | ||
super({ | ||
type: SavedAugmentVis.type, | ||
mapping: SavedAugmentVis.mapping, | ||
extractReferences, | ||
injectReferences, | ||
id: (opts.id as string) || '', | ||
indexPattern: opts.indexPattern as IIndexPattern, | ||
defaults: { | ||
description: get(opts, 'description', ''), | ||
pluginResourceId: get(opts, 'pluginResourceId', ''), | ||
visId: get(opts, 'visId', ''), | ||
visLayerExpressionFn: get(opts, 'visLayerExpressionFn', {}), | ||
version: 1, | ||
}, | ||
}); | ||
// TODO: determine if this saved obj should be visible in saved_obj_management plugin. | ||
// if not, we can set showInRecentlyAccessed to false and not persist any edit URL | ||
// probably set to false since this saved obj should be hidden by default | ||
this.showInRecentlyAccessed = false; | ||
|
||
// we probably don't need this below field. we aren't going to need a full path | ||
// since we aren't going to allow editing by default | ||
// this.getFullPath = () => { | ||
// return `/app/visualize#/edit/${this.id}`; | ||
// }; | ||
} | ||
} | ||
|
||
return SavedAugmentVis as new (opts: Record<string, unknown> | string) => SavedObject; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
export * from './saved_augment_vis'; | ||
export * from './utils'; |
41 changes: 41 additions & 0 deletions
41
src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { VisLayerExpressionFn } from '../types'; | ||
import { | ||
createSavedAugmentVisLoader, | ||
SavedObjectOpenSearchDashboardsServicesWithAugmentVis, | ||
} from './saved_augment_vis'; | ||
import { generateAugmentVisSavedObject, getMockAugmentVisSavedObjectClient } from './utils'; | ||
|
||
describe('SavedObjectLoaderAugmentVis', () => { | ||
const fn = { | ||
// TODO: VisLayerTypes will resolve after rebasing with earlier PR | ||
type: VisLayerTypes.PointInTimeEventsLayer, | ||
name: 'test-fn', | ||
args: { | ||
testArg: 'test-value', | ||
}, | ||
} as VisLayerExpressionFn; | ||
const obj1 = generateAugmentVisSavedObject('test-id-1', fn); | ||
const obj2 = generateAugmentVisSavedObject('test-id-2', fn); | ||
|
||
it('findAll returns single saved obj', async () => { | ||
const loader = createSavedAugmentVisLoader({ | ||
savedObjectsClient: getMockAugmentVisSavedObjectClient([obj1]), | ||
} as SavedObjectOpenSearchDashboardsServicesWithAugmentVis); | ||
const resp = await loader.findAll(); | ||
expect(resp.hits.length === 1); | ||
}); | ||
|
||
// TODO: once done rebasing after VisLayer PR, can finish creating test cases here. | ||
// right now they are failing since there is missing imports | ||
|
||
// add test for empty response | ||
// add test for multi obj response | ||
// add test for invalid VisLayerType | ||
// add test for missing reference | ||
// add test for missing visLayerExpressionFn | ||
}); |
62 changes: 62 additions & 0 deletions
62
src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { get, isEmpty } from 'lodash'; | ||
import { | ||
SavedObjectLoader, | ||
SavedObjectOpenSearchDashboardsServices, | ||
} from '../../../saved_objects/public'; | ||
import { createSavedAugmentVisClass } from './_saved_augment_vis'; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
export interface SavedObjectOpenSearchDashboardsServicesWithAugmentVis | ||
extends SavedObjectOpenSearchDashboardsServices {} | ||
export type SavedAugmentVisLoader = ReturnType<typeof createSavedAugmentVisLoader>; | ||
export function createSavedAugmentVisLoader( | ||
services: SavedObjectOpenSearchDashboardsServicesWithAugmentVis | ||
) { | ||
const { savedObjectsClient } = services; | ||
|
||
class SavedObjectLoaderAugmentVis extends SavedObjectLoader { | ||
mapHitSource = (source: Record<string, any>, id: string) => { | ||
source.id = id; | ||
source.visId = get(source, 'visReference.id', ''); | ||
|
||
if (isEmpty(source.visReference)) { | ||
source.error = 'visReference is missing in augment-vis saved object'; | ||
} | ||
if (isEmpty(source.visLayerExpressionFn)) { | ||
source.error = 'visLayerExpressionFn is missing in augment-vis saved object'; | ||
} | ||
// TODO: will resolve after rebasing with earlier PR | ||
if (!(get(source, 'visLayerExpressionFn.type', '') in VisLayerTypes)) { | ||
source.error = 'Unknown VisLayer expression function type'; | ||
} | ||
|
||
delete source.visReference; | ||
delete source.visName; | ||
return source; | ||
}; | ||
|
||
/** | ||
* Updates hit.attributes to contain an id related to the referenced visualization | ||
* (visId) and returns the updated attributes object. | ||
* @param hit | ||
* @returns {hit.attributes} The modified hit.attributes object, with an id and url field. | ||
*/ | ||
mapSavedObjectApiHits(hit: { | ||
references: any[]; | ||
attributes: Record<string, unknown>; | ||
id: string; | ||
}) { | ||
// For now we are assuming only one vis reference per saved object. | ||
// If we change to multiple, we will need to dynamically handle that | ||
const visReference = hit.references[0]; | ||
return this.mapHitSource({ ...hit.attributes, visReference }, hit.id); | ||
} | ||
} | ||
const SavedAugmentVis = createSavedAugmentVisClass(services); | ||
return new SavedObjectLoaderAugmentVis(SavedAugmentVis, savedObjectsClient) as SavedObjectLoader; | ||
} |
110 changes: 110 additions & 0 deletions
110
src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { extractReferences, injectReferences } from './saved_augment_vis_references'; | ||
import { AugmentVisSavedObject } from '../types'; | ||
|
||
describe('extractReferences()', () => { | ||
test('extracts nothing if visId is null', () => { | ||
const doc = { | ||
id: '1', | ||
attributes: { | ||
foo: true, | ||
}, | ||
references: [], | ||
}; | ||
const updatedDoc = extractReferences(doc); | ||
expect(updatedDoc).toMatchInlineSnapshot(` | ||
Object { | ||
"attributes": Object { | ||
"foo": true, | ||
}, | ||
"references": Array [], | ||
} | ||
`); | ||
}); | ||
|
||
test('extracts references from visId', () => { | ||
const doc = { | ||
id: '1', | ||
attributes: { | ||
foo: true, | ||
visId: 'test-id', | ||
}, | ||
references: [], | ||
}; | ||
const updatedDoc = extractReferences(doc); | ||
expect(updatedDoc).toMatchInlineSnapshot(` | ||
Object { | ||
"attributes": Object { | ||
"foo": true, | ||
"visName": "visualization_0", | ||
}, | ||
"references": Array [ | ||
Object { | ||
"id": "test-id", | ||
"name": "visualization_0", | ||
"type": "visualization", | ||
}, | ||
], | ||
} | ||
`); | ||
}); | ||
}); | ||
|
||
describe('injectReferences()', () => { | ||
test('injects nothing when visName is null', () => { | ||
const context = ({ | ||
id: '1', | ||
pluginResourceId: 'test-resource-id', | ||
visLayerExpressionFn: 'test-fn', | ||
} as unknown) as AugmentVisSavedObject; | ||
injectReferences(context, []); | ||
expect(context).toMatchInlineSnapshot(` | ||
Object { | ||
"id": "1", | ||
"pluginResourceId": "test-resource-id", | ||
"visLayerExpressionFn": "test-fn", | ||
} | ||
`); | ||
}); | ||
|
||
test('injects references into context', () => { | ||
const context = ({ | ||
id: '1', | ||
pluginResourceId: 'test-resource-id', | ||
visLayerExpressionFn: 'test-fn', | ||
visName: 'visualization_0', | ||
} as unknown) as AugmentVisSavedObject; | ||
const references = [ | ||
{ | ||
name: 'visualization_0', | ||
type: 'visualization', | ||
id: 'test-id', | ||
}, | ||
]; | ||
injectReferences(context, references); | ||
expect(context).toMatchInlineSnapshot(` | ||
Object { | ||
"id": "1", | ||
"pluginResourceId": "test-resource-id", | ||
"visId": "test-id", | ||
"visLayerExpressionFn": "test-fn", | ||
} | ||
`); | ||
}); | ||
|
||
test(`fails when it can't find the saved object reference in the array`, () => { | ||
const context = ({ | ||
id: '1', | ||
pluginResourceId: 'test-resource-id', | ||
visLayerExpressionFn: 'test-fn', | ||
visName: 'visualization_0', | ||
} as unknown) as AugmentVisSavedObject; | ||
expect(() => injectReferences(context, [])).toThrowErrorMatchingInlineSnapshot( | ||
`"Could not find visualization reference \\"visualization_0\\""` | ||
); | ||
}); | ||
}); |
65 changes: 65 additions & 0 deletions
65
src/plugins/vis_augmenter/public/saved_augment_vis/saved_augment_vis_references.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { SavedObjectAttributes, SavedObjectReference } from '../../../../core/public'; | ||
import { AugmentVisSavedObject } from '../types'; | ||
|
||
/** | ||
* Note that references aren't stored in the object's client-side interface (AugmentVisSavedObject). | ||
* Rather, just the ID/type is. The concept of references is a server-side definition used to define | ||
* relationships between saved objects. They are visible in the saved objs management page or | ||
* when making direct saved obj API calls. | ||
* | ||
* So, we need helper fns to construct & deconstruct references when creating and reading the | ||
* indexed/stored saved objects, respectively. | ||
*/ | ||
|
||
/** | ||
* Used during creation. Converting from AugmentVisSavedObject to the actual indexed saved object | ||
* with references. | ||
*/ | ||
export function extractReferences({ | ||
attributes, | ||
references = [], | ||
}: { | ||
attributes: SavedObjectAttributes; | ||
references: SavedObjectReference[]; | ||
}) { | ||
const updatedAttributes = { ...attributes }; | ||
const updatedReferences = [...references]; | ||
|
||
// Extract saved object | ||
if (updatedAttributes.visId) { | ||
updatedReferences.push({ | ||
name: 'visualization_0', | ||
type: 'visualization', | ||
id: String(updatedAttributes.visId), | ||
}); | ||
delete updatedAttributes.visId; | ||
updatedAttributes.visName = 'visualization_0'; | ||
} | ||
return { | ||
references: updatedReferences, | ||
attributes: updatedAttributes, | ||
}; | ||
} | ||
|
||
/** | ||
* Used during reading. Converting from the indexed saved object with references | ||
* to a AugmentVisSavedObject | ||
*/ | ||
export function injectReferences( | ||
savedObject: AugmentVisSavedObject, | ||
references: SavedObjectReference[] | ||
) { | ||
if (savedObject.visName) { | ||
const visReference = references.find((reference) => reference.name === savedObject.visName); | ||
if (!visReference) { | ||
throw new Error(`Could not find visualization reference "${savedObject.visName}"`); | ||
} | ||
savedObject.visId = visReference.id; | ||
delete savedObject.visName; | ||
} | ||
} |
Oops, something went wrong.