From 9cf674d1b92be7468ce843dade108397a616d3b0 Mon Sep 17 00:00:00 2001 From: Joseph Axisa Date: Tue, 16 May 2023 18:06:10 +0000 Subject: [PATCH 1/2] feat: minor tweaks to embed-components and embed-services --- packages/embed-components/package.json | 7 +-- .../src/QuickEmbed/QuickEmbed.spec.tsx | 6 +-- .../src/QuickEmbed/QuickEmbed.tsx | 2 +- packages/embed-services/src/EmbedUrl.ts | 26 +++++----- packages/embed-services/src/ItemList.spec.ts | 5 +- packages/embed-services/src/ItemList.ts | 47 +++++++++---------- .../embed-services/src/ServiceFactory.spec.ts | 4 +- packages/embed-services/src/ServiceFactory.ts | 16 ++++--- .../embed-services/src/ThemeService.spec.ts | 9 ++-- packages/embed-services/src/ThemeService.ts | 14 +++--- test/data.yml.json | 39 ++++++++++++++- 11 files changed, 108 insertions(+), 67 deletions(-) diff --git a/packages/embed-components/package.json b/packages/embed-components/package.json index dd24fa977..62ca61c33 100644 --- a/packages/embed-components/package.json +++ b/packages/embed-components/package.json @@ -35,7 +35,7 @@ "homepage": "https://github.com/looker-open-source/sdk-codegen/tree/master/packages/embed-components", "devDependencies": { "redux-saga-tester": "^1.0.874", - "@looker/sdk-node": "^23.8.1", + "@looker/sdk-node": "*", "@testing-library/react": "^11.2.7", "@looker/components-test-utils": "^1.5.27", "react-redux": "^7.2.9", @@ -44,9 +44,10 @@ }, "dependencies": { "@looker/components": "^4.1.3", - "@looker/embed-services": "23.8.1", + "@looker/embed-services": "*", "@looker/redux": "^0.0.1", - "@looker/sdk": "^23.8.1", + "@looker/sdk": "*", + "@looker/sdk-rtl": "*", "@reduxjs/toolkit": "^1.9.3", "@styled-icons/material-outlined": "^10.47.0", "react": "16.14.0", diff --git a/packages/embed-components/src/QuickEmbed/QuickEmbed.spec.tsx b/packages/embed-components/src/QuickEmbed/QuickEmbed.spec.tsx index c996ae19c..7f777c057 100644 --- a/packages/embed-components/src/QuickEmbed/QuickEmbed.spec.tsx +++ b/packages/embed-components/src/QuickEmbed/QuickEmbed.spec.tsx @@ -72,7 +72,7 @@ describe('QuickEmbed', () => { renderWithTheme() expect( - screen.getByRole('heading', { name: 'Get embed url' }) + screen.getByRole('heading', { name: 'Get embed URL' }) ).toBeInTheDocument() const textboxes = screen.getAllByRole('textbox') @@ -106,7 +106,7 @@ describe('QuickEmbed', () => { renderWithTheme() expect( - screen.getByRole('heading', { name: 'Get embed url' }) + screen.getByRole('heading', { name: 'Get embed URL' }) ).toBeInTheDocument() expect(screen.queryByText(/Apply theme to/)).not.toBeInTheDocument() @@ -127,7 +127,7 @@ describe('QuickEmbed', () => { renderWithTheme() expect( - screen.getByRole('heading', { name: 'Get embed url' }) + screen.getByRole('heading', { name: 'Get embed URL' }) ).toBeInTheDocument() expect(screen.getByText('Apply theme to dashboard URL')).toBeInTheDocument() diff --git a/packages/embed-components/src/QuickEmbed/QuickEmbed.tsx b/packages/embed-components/src/QuickEmbed/QuickEmbed.tsx index f44441204..60d48e884 100644 --- a/packages/embed-components/src/QuickEmbed/QuickEmbed.tsx +++ b/packages/embed-components/src/QuickEmbed/QuickEmbed.tsx @@ -77,7 +77,7 @@ export const QuickEmbed = ({ onClose }: QuickEmbedProps) => { return (
- Get embed url + Get embed URL diff --git a/packages/embed-services/src/EmbedUrl.ts b/packages/embed-services/src/EmbedUrl.ts index 1c83821df..dce06fb42 100644 --- a/packages/embed-services/src/EmbedUrl.ts +++ b/packages/embed-services/src/EmbedUrl.ts @@ -37,14 +37,27 @@ const THEMABLE_CONTENT: ContentType[] = [ ] export interface IEmbedUrl { + /** Current url */ readonly url: string + /** Path of the current page */ readonly path: string + /** Search string of the current url */ readonly searchParams: Record + /** Determines whether the current URL is for a Dashboard */ readonly isDashboard: boolean + /** Determines whether the current URL is for an Explore */ readonly isExplore: boolean + /** Determines whether the current URl is for a Look */ readonly isLook: boolean + /** Type of content the URL represents */ readonly contentType: ContentType + /** Determines if current URL represents themable content */ readonly isThemable: boolean + /** + * Builds the embed target url + * @param includeSearchParams switch determining whether to include search params from target url + * @param overrides any search key values to include in embed url e.g. 'k1=v1&k2=v2' + */ embedUrl(includeSearchParams: boolean, overrides: Record): string } @@ -52,21 +65,13 @@ export interface IEmbedUrl { * A class for use when implementer requires components to be context aware */ export class EmbedUrl implements IEmbedUrl { - /** Current url */ private _url: URL - /** Path of the current page */ readonly path: string - /** Search string of the current url */ readonly searchParams: Record - /** Determines whether the current URL is for a Dashboard */ readonly isDashboard: boolean - /** Determines whether the current URL is for an Explore */ readonly isExplore: boolean - /** Determines whether the current URl is for a Look */ readonly isLook: boolean - /** Determines if current URL represents themable content */ readonly isThemable: boolean - /** Type of content the URL represents */ readonly contentType: ContentType private readonly _embedUrl: string @@ -106,11 +111,6 @@ export class EmbedUrl implements IEmbedUrl { return type } - /** - * Builds the embed target url - * @param includeSearchParams switch determining whether to include search params from target url - * @param overrides any search key values to include in embed url e.g. 'k1=v1&k2=v2' - */ embedUrl(includeSearchParams = false, overrides: Record = {}) { if (this.contentType === ContentType.Invalid) { throw new Error('Invalid content type') diff --git a/packages/embed-services/src/ItemList.spec.ts b/packages/embed-services/src/ItemList.spec.ts index af728f915..8661bda12 100644 --- a/packages/embed-services/src/ItemList.spec.ts +++ b/packages/embed-services/src/ItemList.spec.ts @@ -140,7 +140,10 @@ describe('ItemList', () => { describe('getCacheDefault', () => { it('gets the default', () => { - const actual = ItemList.getCacheDefault() + let actual = ItemList.getCacheDefault() + expect(actual).toBe(true) + + actual = ItemList.getCacheDefault({ useCache: undefined }) expect(actual).toBe(true) }) diff --git a/packages/embed-services/src/ItemList.ts b/packages/embed-services/src/ItemList.ts index c6c3f8a95..74ca939a0 100644 --- a/packages/embed-services/src/ItemList.ts +++ b/packages/embed-services/src/ItemList.ts @@ -37,14 +37,31 @@ export interface GetOptions { export interface IItemList { /** Cache time to live in seconds, defaults to 15 minutes */ readonly timeToLive: number + /** Cached items */ items: T[] + /** Expiration time */ readonly expiresAt: number + /** Creates an indexed collection from the cached items */ index(key?: keyof T): ItemList + /** An indexed collection of items */ indexedItems: Record + /** Determines if the cache has expired */ expired(): boolean + /** Computes the expiration time based on timeToLive */ setExpiration(): void + /** Ejects cache if expired */ clearIfExpired(): void + /** + * Searches the collection for an item with the specified key/value pair + * @param key or keys to search + * @param expression to match + */ find(key: keyof T | Array, value: any): T | undefined + /** + * Gets the cache option value if present, otherwise defaults to true + * @param options to check + */ + getCacheDefault(options?: GetOptions): boolean } export interface IEntityService extends IItemList { @@ -58,11 +75,8 @@ export abstract class ItemList> extends EntityService implements IItemList { - /** Cached items */ items: T[] = [] - /** An indexed collection of items */ indexedItems: Record = {} - /** Time when cache expires */ expiresAt = 0 /** Key to index by */ private keyField = 'id' @@ -71,9 +85,6 @@ export abstract class ItemList> super(sdk, timeToLive) } - /** - * Creates an indexed collection from the cached items - */ index(key: keyof T = this.keyField) { this.keyField = key as string this.indexedItems = {} @@ -85,21 +96,14 @@ export abstract class ItemList> return this } - /** Computes the expiration time based on timeToLive */ setExpiration() { this.expiresAt = Date.now() + this.timeToLive * 1000 } - /** - * Determines if the cache has expired - */ expired() { return this.expiresAt <= Date.now() } - /** - * Ejects cache if expired - */ clearIfExpired() { if (this.expired()) { this.items = [] @@ -107,11 +111,6 @@ export abstract class ItemList> } } - /** - * Searches the collection for an item with the specified key/value pair - * @param key or keys to search - * @param expression to match - */ find(key: keyof T | Array, expression: string): T | undefined { let result: T | undefined let keys: Array @@ -122,9 +121,8 @@ export abstract class ItemList> keys = key as Array } - let rx: RegExp try { - rx = new RegExp(expression, 'i') + const rx = new RegExp(expression, 'i') for (const item of this.items) { for (const k of keys) { @@ -141,12 +139,11 @@ export abstract class ItemList> } } - /** - * Gets the cache option value if present, otherwise defaults to true - * @param options to check - */ getCacheDefault(options?: GetOptions) { - const cache = options && 'useCache' in options ? options.useCache : true + const cache = + options && 'useCache' in options && options.useCache !== undefined + ? options.useCache + : true return cache } } diff --git a/packages/embed-services/src/ServiceFactory.spec.ts b/packages/embed-services/src/ServiceFactory.spec.ts index 82e91611c..b2ad46cc1 100644 --- a/packages/embed-services/src/ServiceFactory.spec.ts +++ b/packages/embed-services/src/ServiceFactory.spec.ts @@ -23,14 +23,14 @@ SOFTWARE. */ -import { Looker40SDK as LookerSDK } from '@looker/sdk' +import { functionalSdk40 as funSdk } 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: IAPIMethods = new LookerSDK(session) + const sdk: IAPIMethods = funSdk(session) afterEach(() => { destroyFactory() diff --git a/packages/embed-services/src/ServiceFactory.ts b/packages/embed-services/src/ServiceFactory.ts index 4306d7737..ae978b00b 100644 --- a/packages/embed-services/src/ServiceFactory.ts +++ b/packages/embed-services/src/ServiceFactory.ts @@ -28,7 +28,17 @@ import type { IAPIMethods } from '@looker/sdk-rtl' export type ServiceCreatorFunc = (sdk: IAPIMethods, timeToLive?: number) => T export interface IServiceFactory { + /** + * Retrieves a service + * @param serviceName to retrieve + */ get(serviceName: string): T + /** + * 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, @@ -51,12 +61,6 @@ class ServiceFactory implements IServiceFactory { 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, diff --git a/packages/embed-services/src/ThemeService.spec.ts b/packages/embed-services/src/ThemeService.spec.ts index 31d206bdd..f09af6aab 100644 --- a/packages/embed-services/src/ThemeService.spec.ts +++ b/packages/embed-services/src/ThemeService.spec.ts @@ -24,7 +24,7 @@ */ import { - Looker40SDK as LookerSDK, + functionalSdk40 as funSdk, all_themes, update_theme, create_theme, @@ -38,11 +38,10 @@ 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: IAPIMethods = new LookerSDK(session) + const config = TestConfig() + const themes = config.testData.themes + const sdk: IAPIMethods = funSdk(session) let service: IThemeService let testThemes: ITheme[] const themeCount = themes.length + 1 // includes the Looker theme diff --git a/packages/embed-services/src/ThemeService.ts b/packages/embed-services/src/ThemeService.ts index dfcd5da91..a942a7e05 100644 --- a/packages/embed-services/src/ThemeService.ts +++ b/packages/embed-services/src/ThemeService.ts @@ -41,7 +41,14 @@ export interface IThemeService extends IItemList, IEntityService { defaultTheme?: ITheme + /** + * Gets the default theme + * @param ts Timestamp representing the target datetime for the active period. Defaults to 'now' + */ getDefaultTheme(ts?: Date, options?: GetOptions): Promise + /** + * Retrieves all themes and the default theme + */ load(options?: GetOptions): Promise } @@ -101,10 +108,6 @@ class ThemeService extends ItemList implements IThemeService { return theme } - /** - * Gets the default theme - * @param ts Timestamp representing the target datetime for the active period. Defaults to 'now' - */ async getDefaultTheme(ts?: Date) { if (this.expired()) { this.defaultTheme = await this.sdk.ok(default_theme(this.sdk, ts)) @@ -123,9 +126,6 @@ class ThemeService extends ItemList implements IThemeService { this.index() } - /** - * Retrieves all themes and the default theme - */ async load(options?: GetOptions) { await this.getDefaultTheme() this.items = await this.sdk.ok(all_themes(this.sdk, options?.fields)) 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 9b8fc1b516aa48cd751bf93d475a9eba319b2b63 Mon Sep 17 00:00:00 2001 From: Joseph Axisa Date: Mon, 22 May 2023 19:46:27 +0000 Subject: [PATCH 2/2] added test themes to data.yml and generated data.ymj.json --- test/data.yml | 31 ++++++++++++++++++++++++++++++ test/data.yml.json | 47 +++++++++++++++++++++++----------------------- 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/test/data.yml b/test/data.yml index 138b9a1f7..fd890f3ed 100644 --- a/test/data.yml +++ b/test/data.yml @@ -85,6 +85,37 @@ dashboards: body_text: "Data Body" # this is a test data convention to reference the query by some identifying tag query_id: "#user_query" +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" looks: - title: An SDK Look description: An SDK test look about system activity diff --git a/test/data.yml.json b/test/data.yml.json index d3a140428..52c09a8eb 100644 --- a/test/data.yml.json +++ b/test/data.yml.json @@ -124,27 +124,6 @@ ] } ], - "looks": [ - { - "title": "An SDK Look", - "description": "An SDK test look about system activity", - "deleted": false, - "is_run_on_load": true, - "public": true, - "query": [ - { - "id": "#dashboard_query_system_activity", - "model": "system__activity", - "view": "dashboard", - "fields": [ - "dashboard.count", - "dashboard.id" - ], - "limit": 100 - } - ] - } - ], "themes": [ { "name": "First_SDK_Theme", @@ -180,7 +159,29 @@ "title_color": "#3a4245", "warn_button_color": "#980c11", "tile_title_alignment": "center" - }} + } + } + ], + "looks": [ + { + "title": "An SDK Look", + "description": "An SDK test look about system activity", + "deleted": false, + "is_run_on_load": true, + "public": true, + "query": [ + { + "id": "#dashboard_query_system_activity", + "model": "system__activity", + "view": "dashboard", + "fields": [ + "dashboard.count", + "dashboard.id" + ], + "limit": 100 + } + ] + } ], "content_types": { "string": [ @@ -222,4 +223,4 @@ "image/" ] } -} +} \ No newline at end of file