From 8fe548732445b1e19b7ab42cc8d4c18a9add0752 Mon Sep 17 00:00:00 2001 From: Joseph Axisa Date: Wed, 12 Apr 2023 23:45:50 +0000 Subject: [PATCH 1/2] feat: singleton factory and theme service --- packages/embed-services/package.json | 4 +- .../embed-services/src/ServiceFactory.spec.ts | 55 ++++++ packages/embed-services/src/ServiceFactory.ts | 95 ++++++++++ .../embed-services/src/ThemeService.spec.ts | 175 ++++++++++++++++++ packages/embed-services/src/ThemeService.ts | 147 +++++++++++++++ packages/embed-services/src/index.ts | 2 + .../embed-services/src/test-utils/index.ts | 26 +++ .../embed-services/src/test-utils/utils.ts | 54 ++++++ test/data.yml.json | 39 +++- 9 files changed, 595 insertions(+), 2 deletions(-) create mode 100644 packages/embed-services/src/ServiceFactory.spec.ts create mode 100644 packages/embed-services/src/ServiceFactory.ts create mode 100644 packages/embed-services/src/ThemeService.spec.ts create mode 100644 packages/embed-services/src/ThemeService.ts create mode 100644 packages/embed-services/src/test-utils/index.ts create mode 100644 packages/embed-services/src/test-utils/utils.ts diff --git a/packages/embed-services/package.json b/packages/embed-services/package.json index 0e4ba04b6..2e4407095 100644 --- a/packages/embed-services/package.json +++ b/packages/embed-services/package.json @@ -34,9 +34,11 @@ }, "homepage": "https://github.com/looker-open-source/sdk-codegen/tree/master/packages/embed-services", "devDependencies": { + "@looker/sdk-node": "^23.4.0" }, "dependencies": { - "@looker/sdk-rtl": "^21.6.0" + "@looker/sdk-rtl": "^21.6.0", + "@looker/sdk": "^23.6.0" }, "keywords": [ "Looker", diff --git a/packages/embed-services/src/ServiceFactory.spec.ts b/packages/embed-services/src/ServiceFactory.spec.ts new file mode 100644 index 000000000..bbee16a7b --- /dev/null +++ b/packages/embed-services/src/ServiceFactory.spec.ts @@ -0,0 +1,55 @@ +/* + + MIT License + + Copyright (c) 2023 Looker Data Sciences, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + */ +import { Looker40SDK as LookerSDK } from '@looker/sdk' +import { session } from './test-utils' +import { createFactory, destroyFactory, getFactory } from './ServiceFactory' +import { getThemeService, registerThemeService } from './ThemeService' + +describe('ServiceFactory', () => { + const sdk = new LookerSDK(session) + + afterEach(() => { + destroyFactory() + }) + + it('createFactory creates', () => { + createFactory(sdk) + expect(getFactory()).toBeDefined() + }) + + it('getFactory throws when no factory exists', () => { + expect(getFactory).toThrow('Factory must be created with an SDK') + }) + + it('registers and gets a service', async () => { + createFactory(sdk) + registerThemeService() + const service = getThemeService() + expect(service).toBeDefined() + await service.getDefaultTheme() + expect(service.defaultTheme?.name).toEqual('Looker') + }) +}) diff --git a/packages/embed-services/src/ServiceFactory.ts b/packages/embed-services/src/ServiceFactory.ts new file mode 100644 index 000000000..14334a6a4 --- /dev/null +++ b/packages/embed-services/src/ServiceFactory.ts @@ -0,0 +1,95 @@ +/* + + MIT License + + Copyright (c) 2023 Looker Data Sciences, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + */ +import type { IAPIMethods } from '@looker/sdk-rtl' + +export type ServiceCreatorFunc = (sdk: IAPIMethods, timeToLive?: number) => T + +export interface IServiceFactory { + get(serviceName: string): T + register(serviceName: string, serviceCreator: ServiceCreatorFunc): void +} + +/** + * A factory for registering and maintaining services + */ +class ServiceFactory implements IServiceFactory { + servicesMap: Record = {} + constructor(private sdk: IAPIMethods) {} + + get(serviceName: string): T { + const service = this.servicesMap[serviceName] + if (!service) { + throw new Error(`Service ${serviceName} not found`) + } + return service + } + + /** + * Registers or creates a service + * @param serviceName name of service. + * @param serviceCreator function that creates the service. + * @param timeToLive in seconds, for the service cache. Defaults to 15 minutes. + */ + register( + serviceName: string, + serviceCreator: ServiceCreatorFunc, + timeToLive?: number + ) { + let service = this.servicesMap[serviceName] + if (!service) { + service = serviceCreator(this.sdk, timeToLive) + this.servicesMap[serviceName] = service + } + return service + } +} + +let factory: IServiceFactory | undefined + +/** + * Helper method for creating a singleton factory + * @param sdk + */ +export function createFactory(sdk: IAPIMethods) { + factory = new ServiceFactory(sdk) +} + +/** + * Helper method for getting the factory + */ +export function getFactory() { + if (!factory) { + throw new Error('Factory must be created with an SDK.') + } + return factory +} + +/** + * Helper method for destroying the factory + */ +export function destroyFactory() { + factory = undefined +} diff --git a/packages/embed-services/src/ThemeService.spec.ts b/packages/embed-services/src/ThemeService.spec.ts new file mode 100644 index 000000000..31d0f0da6 --- /dev/null +++ b/packages/embed-services/src/ThemeService.spec.ts @@ -0,0 +1,175 @@ +/* + + MIT License + + Copyright (c) 2023 Looker Data Sciences, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + */ +import { Looker40SDK as LookerSDK, all_themes } from '@looker/sdk' +import type { ITheme } from '@looker/sdk' + +import { themeServiceCreator } from './ThemeService' +import type { IThemeService } from './ThemeService' +import { TestConfig, session, timeout } from './test-utils' + +const config = TestConfig() +const themes = config.testData.themes + +describe('ThemeService', () => { + const sdk = new LookerSDK(session) + let service: IThemeService + let testThemes: ITheme[] + const themeCount = themes.length + 1 // includes the Looker theme + + beforeEach(() => { + service = themeServiceCreator(sdk) + }) + + const createTestThemes = async () => { + for (const t of themes) { + const searched = await sdk.ok(sdk.search_themes({ name: t.name })) + if (searched.length > 0) { + // update theme with expected values if found + await sdk.ok(sdk.update_theme(searched[0].id!, t)) + } else { + // create theme if not found + await sdk.ok(sdk.create_theme(t)) + } + } + } + + const removeTestThemes = async () => { + for (const t of themes) { + const searched = await sdk.ok(sdk.search_themes({ id: t.id })) + if (searched.length > 0) { + await sdk.ok(sdk.delete_theme(searched[0].id!)) + } + } + } + + beforeAll(async () => { + await removeTestThemes() + await createTestThemes() + // get themes from instance to have their ids + testThemes = await sdk.ok(all_themes(sdk, 'id, name')) + }, timeout) + + afterAll(async () => { + await sdk.authSession.logout() + }) + + describe('getAll', () => { + it('gets and caches', async () => { + await service.getAll() + expect(service.items).toHaveLength(themeCount) + expect(Object.keys(service.indexedItems)).toHaveLength(themeCount) + expect(service.expiresAt).toBeGreaterThan(0) + }) + }) + + describe('get', () => { + it('gets and caches', async () => { + expect(service.items).toHaveLength(0) + const actual = await service.get(testThemes[0].id!) + expect(actual.name).toEqual(testThemes[0].name) + expect(service.indexedItems[testThemes[0].id!].name).toEqual( + testThemes[0].name + ) + }) + + it('retrieves from cache when possible', async () => { + const themes = (await service.getAll()).items + const cachedTheme = themes[0] + const expectedName = cachedTheme.name + 'cached' + cachedTheme.name = expectedName + const actual = await service.get(cachedTheme.id!) + expect(actual.name).toEqual(expectedName) + }) + + it('bypasses cache when expired', async () => { + service = themeServiceCreator(sdk, -1000) // set time to live in the past + const themes = (await service.getAll()).items + const cachedTheme = themes[0] + const expectedName = cachedTheme.name + cachedTheme.name += 'cached' + const actual = await service.get(cachedTheme.id!) + expect(actual.name).toEqual(expectedName) + }) + + it('bypasses cache if cache=false', async () => { + service = themeServiceCreator(sdk) + const themes = (await service.getAll()).items + const cachedTheme = themes[0] + const expectedName = cachedTheme.name + cachedTheme.name += 'cached' + const actual = await service.get(cachedTheme.id!, { itemCache: false }) + expect(actual.name).toEqual(expectedName) + }) + }) + + describe('set', () => { + it('sets and caches', async () => { + const theme = testThemes.find((t) => t.name === themes[0].name)! + const updatedTheme = { ...theme, name: 'updated_theme' } + await service.set(updatedTheme.id!, updatedTheme) + expect(service.indexedItems[updatedTheme.id!].name).toEqual( + 'updated_theme' + ) + }) + }) + + describe('delete', () => { + afterEach(async () => { + // recreate any deleted themes + await createTestThemes() + }) + + it('deletes', async () => { + const themes = (await service.getAll()).items + expect(themes).toHaveLength(themeCount) + + const targetTheme = themes.find( + (t) => t.name !== 'Looker' // Default Looker theme cannot be deleted + )! + await service.delete(targetTheme.id!) + + expect(service.items).toHaveLength(themeCount - 1) + expect(service.indexedItems[targetTheme.id!]).toBeUndefined() + }) + }) + + describe('getDefaultTheme', () => { + it('gets default theme', async () => { + expect(service.defaultTheme).toBeUndefined() + await service.getDefaultTheme() + expect(service.defaultTheme).toBeDefined() + }) + }) + + describe('load', () => { + it('loads', async () => { + expect(service.items).toHaveLength(0) + await service.load() + expect(service.items).toHaveLength(themeCount) + expect(service.defaultTheme?.name).toBe('Looker') + }) + }) +}) diff --git a/packages/embed-services/src/ThemeService.ts b/packages/embed-services/src/ThemeService.ts new file mode 100644 index 000000000..3738ddf5b --- /dev/null +++ b/packages/embed-services/src/ThemeService.ts @@ -0,0 +1,147 @@ +/* + + MIT License + + Copyright (c) 2023 Looker Data Sciences, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + */ +import type { ITheme } from '@looker/sdk' +import { + all_themes, + default_theme, + delete_theme, + theme, + update_theme, +} from '@looker/sdk' +import type { IAPIMethods } from '@looker/sdk-rtl' +import { ItemList } from './ItemList' +import type { IEntityService, IItemList, GetOptions } from './ItemList' +import type { ServiceCreatorFunc } from './ServiceFactory' +import { getFactory } from './ServiceFactory' + +export interface IThemeService + extends IItemList, + IEntityService { + defaultTheme?: ITheme + getDefaultTheme(ts?: Date): Promise + load(): Promise +} + +class ThemeService extends ItemList implements IThemeService { + public defaultTheme?: ITheme + + /** + * Get theme by id + * @param id of theme to retrieve + * @param options to get + */ + async get(id: string, options?: GetOptions): Promise> { + // TODO: implement logic to check if requested fields are already cached. + const cache = this.getCacheDefault(options) + this.clearIfExpired() + let item = this.indexedItems[id] + + if (cache && item) { + return item + } + + item = await this.sdk.ok(theme(this.sdk, id, options?.fields)) + + if (item) { + this.items = [...this.items, item] + this.index() + this.setExpiration() + } + return item + } + + /** + * Get all themes + * @param fields to retrieve + */ + async getAll(fields?: string) { + this.items = await this.sdk.ok(all_themes(this.sdk, fields)) + this.index() + this.setExpiration() + return this + } + + /** + * Updates a theme + * @param id id of theme to update + * @param item with updated fields + */ + async set(id: string, item: ITheme) { + this.clearIfExpired() + const theme = await this.sdk.ok(update_theme(this.sdk, id, item)) + if (theme) { + this.items = [...this.items, theme] + this.index() + this.setExpiration() + } + return theme + } + + /** + * Gets the default theme + * @param ts Timestamp representing the target datetime for the active period. Defaults to 'now' + */ + async getDefaultTheme(ts?: Date) { + this.defaultTheme = await this.sdk.ok(default_theme(this.sdk, ts)) + return this.defaultTheme + } + + /** + * Deletes a theme + * @param id of theme to delete + */ + async delete(id: string) { + this.clearIfExpired() + await this.sdk.ok(delete_theme(this.sdk, id)) + this.items = this.items.filter((item) => item.id !== id) + this.index() + } + + /** + * Retrieves all themes and the default theme + */ + async load() { + await this.getAll() + await this.getDefaultTheme() + return this + } +} + +export const THEME_SERVICE_NAME = 'ThemeService' + +export const themeServiceCreator: ServiceCreatorFunc = ( + sdk: IAPIMethods, + timeToLive?: number +) => { + return new ThemeService(sdk, timeToLive) +} + +export const registerThemeService = () => { + getFactory().register(THEME_SERVICE_NAME, themeServiceCreator) +} + +export const getThemeService = () => + getFactory().get(THEME_SERVICE_NAME) diff --git a/packages/embed-services/src/index.ts b/packages/embed-services/src/index.ts index 6f22346c0..54f6417de 100644 --- a/packages/embed-services/src/index.ts +++ b/packages/embed-services/src/index.ts @@ -23,3 +23,5 @@ SOFTWARE. */ +export * from './ServiceFactory' +export * from './ThemeService' diff --git a/packages/embed-services/src/test-utils/index.ts b/packages/embed-services/src/test-utils/index.ts new file mode 100644 index 000000000..266c27cf8 --- /dev/null +++ b/packages/embed-services/src/test-utils/index.ts @@ -0,0 +1,26 @@ +/* + + MIT License + + Copyright (c) 2023 Looker Data Sciences, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + */ +export * from './utils' diff --git a/packages/embed-services/src/test-utils/utils.ts b/packages/embed-services/src/test-utils/utils.ts new file mode 100644 index 000000000..3aeb6524f --- /dev/null +++ b/packages/embed-services/src/test-utils/utils.ts @@ -0,0 +1,54 @@ +/* + + MIT License + + Copyright (c) 2023 Looker Data Sciences, Inc. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + */ +import path from 'path' +import * as fs from 'fs' +import { environmentPrefix } from '@looker/sdk' +import { NodeSession, NodeSettingsIniFile } from '@looker/sdk-node' + +const homeToRoost = '../../../../' + +export const getRootPath = () => path.join(__dirname, homeToRoost) +export const rootFile = (fileName = '') => path.join(getRootPath(), fileName) +const localIni = process.env.LOOKERSDK_INI || rootFile('looker.ini') + +const settings = new NodeSettingsIniFile(environmentPrefix, localIni, 'Looker') +export const session = new NodeSession(settings) + +export const timeout = 3600000 // 1 hr + +interface ITestConfig { + testData: any +} + +export const TestConfig = (): ITestConfig => { + const testFile = 'data.yml.json' + const testPath = rootFile('test/') + const dataFile = `${testPath}${testFile}` + const testData = JSON.parse(fs.readFileSync(dataFile, 'utf-8')) + return { + testData, + } +} diff --git a/test/data.yml.json b/test/data.yml.json index 5f5fdf1db..d3a140428 100644 --- a/test/data.yml.json +++ b/test/data.yml.json @@ -145,6 +145,43 @@ ] } ], + "themes": [ + { + "name": "First_SDK_Theme", + "settings": { + "background_color": "#b83232", + "base_font_size": "12px", + "font_color": "rgb(62, 63, 64)", + "font_family": "Gotham", + "font_source": "", + "info_button_color": "#0087e1", + "primary_button_color": "#e32645", + "text_tile_text_color": "", + "tile_background_color": "white", + "text_tile_background_color": "", + "tile_text_color": "#20272D", + "title_color": "#e0060b", + "warn_button_color": "#f2ad43" + } + }, + { + "name": "Second_SDK_Theme", + "settings": { + "background_color": "#f6f8fa", + "base_font_size": "12px", + "font_color": "#3e3f40", + "font_family": "\"Comic Sans MS\"", + "font_source": "", + "info_button_color": "#0087e1", + "primary_button_color": "#64518a", + "tile_background_color": "#ffffff", + "text_tile_background_color": "", + "tile_text_color": "#3a4245", + "title_color": "#3a4245", + "warn_button_color": "#980c11", + "tile_title_alignment": "center" + }} + ], "content_types": { "string": [ "image/svg+xml", @@ -185,4 +222,4 @@ "image/" ] } -} \ No newline at end of file +} From 07fdb598c81c03cb4a460ea44ae0403135b197ff Mon Sep 17 00:00:00 2001 From: Joseph Axisa Date: Thu, 13 Apr 2023 00:17:26 +0000 Subject: [PATCH 2/2] feedback --- .../embed-services/src/ServiceFactory.spec.ts | 3 ++- .../embed-services/src/ThemeService.spec.ts | 22 +++++++++++++------ packages/embed-services/src/ThemeService.ts | 6 ++--- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/packages/embed-services/src/ServiceFactory.spec.ts b/packages/embed-services/src/ServiceFactory.spec.ts index bbee16a7b..82e91611c 100644 --- a/packages/embed-services/src/ServiceFactory.spec.ts +++ b/packages/embed-services/src/ServiceFactory.spec.ts @@ -24,12 +24,13 @@ */ import { Looker40SDK as LookerSDK } from '@looker/sdk' +import type { IAPIMethods } from '@looker/sdk-rtl' import { session } from './test-utils' import { createFactory, destroyFactory, getFactory } from './ServiceFactory' import { getThemeService, registerThemeService } from './ThemeService' describe('ServiceFactory', () => { - const sdk = new LookerSDK(session) + const sdk: IAPIMethods = new LookerSDK(session) afterEach(() => { destroyFactory() diff --git a/packages/embed-services/src/ThemeService.spec.ts b/packages/embed-services/src/ThemeService.spec.ts index 31d0f0da6..70114107f 100644 --- a/packages/embed-services/src/ThemeService.spec.ts +++ b/packages/embed-services/src/ThemeService.spec.ts @@ -23,8 +23,16 @@ SOFTWARE. */ -import { Looker40SDK as LookerSDK, all_themes } from '@looker/sdk' +import { + Looker40SDK as LookerSDK, + all_themes, + update_theme, + create_theme, + delete_theme, + search_themes, +} from '@looker/sdk' import type { ITheme } from '@looker/sdk' +import type { IAPIMethods } from '@looker/sdk-rtl' import { themeServiceCreator } from './ThemeService' import type { IThemeService } from './ThemeService' @@ -34,7 +42,7 @@ const config = TestConfig() const themes = config.testData.themes describe('ThemeService', () => { - const sdk = new LookerSDK(session) + const sdk: IAPIMethods = new LookerSDK(session) let service: IThemeService let testThemes: ITheme[] const themeCount = themes.length + 1 // includes the Looker theme @@ -45,22 +53,22 @@ describe('ThemeService', () => { const createTestThemes = async () => { for (const t of themes) { - const searched = await sdk.ok(sdk.search_themes({ name: t.name })) + const searched = await sdk.ok(search_themes(sdk, { name: t.name })) if (searched.length > 0) { // update theme with expected values if found - await sdk.ok(sdk.update_theme(searched[0].id!, t)) + await sdk.ok(update_theme(sdk, searched[0].id!, t)) } else { // create theme if not found - await sdk.ok(sdk.create_theme(t)) + await sdk.ok(create_theme(sdk, t)) } } } const removeTestThemes = async () => { for (const t of themes) { - const searched = await sdk.ok(sdk.search_themes({ id: t.id })) + const searched = await sdk.ok(search_themes(sdk, { id: t.id })) if (searched.length > 0) { - await sdk.ok(sdk.delete_theme(searched[0].id!)) + await sdk.ok(delete_theme(sdk, searched[0].id!)) } } } diff --git a/packages/embed-services/src/ThemeService.ts b/packages/embed-services/src/ThemeService.ts index 3738ddf5b..a16e3ebaf 100644 --- a/packages/embed-services/src/ThemeService.ts +++ b/packages/embed-services/src/ThemeService.ts @@ -75,10 +75,10 @@ class ThemeService extends ItemList implements IThemeService { /** * Get all themes - * @param fields to retrieve + * @param options to get */ - async getAll(fields?: string) { - this.items = await this.sdk.ok(all_themes(this.sdk, fields)) + async getAll(options?: GetOptions) { + this.items = await this.sdk.ok(all_themes(this.sdk, options?.fields)) this.index() this.setExpiration() return this