Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.x] Backport PR for build, maps, branding logging #1119

Merged
merged 5 commits into from
Jan 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion config/opensearch_dashboards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,8 @@
# defaultUrl: ""
# darkModeUrl: ""
# faviconUrl: ""
# applicationTitle: ""
# applicationTitle: ""

# Set the value of this setting to true to capture region blocked warnings and errors
# for your map rendering services.
# map.showRegionBlockedWarning: false
94 changes: 94 additions & 0 deletions packages/osd-plugin-helpers/src/integration_tests/build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,17 @@ import globby from 'globby';
import loadJsonFile from 'load-json-file';

const OPENSEARCH_DASHBOARDS_VERSION = '1.0.0';
const OPENSEARCH_DASHBOARDS_VERSION_X = '1.0.0.x';
const PLUGIN_DIR = Path.resolve(REPO_ROOT, 'plugins/foo_test_plugin');
const PLUGIN_BUILD_DIR = Path.resolve(PLUGIN_DIR, 'build');
const PLUGIN_ARCHIVE = Path.resolve(
PLUGIN_BUILD_DIR,
`fooTestPlugin-${OPENSEARCH_DASHBOARDS_VERSION}.zip`
);
const PLUGIN_ARCHIVE_X = Path.resolve(
PLUGIN_BUILD_DIR,
`fooTestPlugin-${OPENSEARCH_DASHBOARDS_VERSION_X}.zip`
);
const TMP_DIR = Path.resolve(__dirname, '__tmp__');

expect.addSnapshotSerializer(createReplaceSerializer(/[\d\.]+ sec/g, '<time>'));
Expand Down Expand Up @@ -150,3 +155,92 @@ it('builds a generated plugin into a viable archive', async () => {
}
`);
});

it('builds a non-semver generated plugin into a viable archive', async () => {
const generateProc = await execa(
process.execPath,
['scripts/generate_plugin', '-y', '--name', 'fooTestPlugin'],
{
cwd: REPO_ROOT,
all: true,
}
);

expect(generateProc.all).toMatchInlineSnapshot(`
" succ 🎉

Your plugin has been created in plugins/foo_test_plugin
"
`);

const buildProc = await execa(
process.execPath,
[
'../../scripts/plugin_helpers',
'build',
'--opensearch-dashboards-version',
OPENSEARCH_DASHBOARDS_VERSION_X,
],
{
cwd: PLUGIN_DIR,
all: true,
}
);

expect(buildProc.all).toMatchInlineSnapshot(`
" info deleting the build and target directories
info running @osd/optimizer
│ info initialized, 0 bundles cached
│ info starting worker [1 bundle]
│ warn worker stderr Browserslist: caniuse-lite is outdated. Please run:
│ warn worker stderr npx browserslist@latest --update-db
│ succ 1 bundles compiled successfully after <time>
info copying assets from \`public/assets\` to build
info copying server source into the build and converting with babel
info running yarn to install dependencies
info compressing plugin into [fooTestPlugin-1.0.0.x.zip]"
`);

await extract(PLUGIN_ARCHIVE_X, { dir: TMP_DIR }, () => {});

const files = await globby(['**/*'], { cwd: TMP_DIR });
files.sort((a, b) => a.localeCompare(b));

expect(files).toMatchInlineSnapshot(`
Array [
"opensearch-dashboards/fooTestPlugin/common/index.js",
"opensearch-dashboards/fooTestPlugin/opensearch_dashboards.json",
"opensearch-dashboards/fooTestPlugin/package.json",
"opensearch-dashboards/fooTestPlugin/server/index.js",
"opensearch-dashboards/fooTestPlugin/server/plugin.js",
"opensearch-dashboards/fooTestPlugin/server/routes/index.js",
"opensearch-dashboards/fooTestPlugin/server/types.js",
"opensearch-dashboards/fooTestPlugin/target/public/fooTestPlugin.chunk.1.js",
"opensearch-dashboards/fooTestPlugin/target/public/fooTestPlugin.chunk.1.js.br",
"opensearch-dashboards/fooTestPlugin/target/public/fooTestPlugin.chunk.1.js.gz",
"opensearch-dashboards/fooTestPlugin/target/public/fooTestPlugin.plugin.js",
"opensearch-dashboards/fooTestPlugin/target/public/fooTestPlugin.plugin.js.br",
"opensearch-dashboards/fooTestPlugin/target/public/fooTestPlugin.plugin.js.gz",
"opensearch-dashboards/fooTestPlugin/translations/ja-JP.json",
"opensearch-dashboards/fooTestPlugin/tsconfig.json",
]
`);

expect(
loadJsonFile.sync(
Path.resolve(TMP_DIR, 'opensearch-dashboards', 'fooTestPlugin', 'opensearch_dashboards.json')
)
).toMatchInlineSnapshot(`
Object {
"id": "fooTestPlugin",
"opensearchDashboardsVersion": "1.0.0.x",
"optionalPlugins": Array [],
"requiredPlugins": Array [
"navigation",
],
"server": true,
"ui": true,
"version": "1.0.0",
}
`);
});
10 changes: 2 additions & 8 deletions packages/osd-plugin-helpers/src/tasks/write_server_files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import { pipeline } from 'stream';
import { promisify } from 'util';

import semver from 'semver';
import vfs from 'vinyl-fs';
import { transformFileWithBabel, transformFileStream } from '@osd/dev-utils';

Expand All @@ -51,17 +50,12 @@ export async function writeServerFiles({
}: BuildContext) {
log.info('copying server source into the build and converting with babel');

const OPENSEARCH_DASHBOARDS_VERSION_79 = semver.satisfies(opensearchDashboardsVersion, '~7.9.0');

// copy source files and apply some babel transformations in the process
await asyncPipeline(
vfs.src(
[
'opensearch_dashboards.json',
// always copy over the package.json file if we're building for 7.9
...(OPENSEARCH_DASHBOARDS_VERSION_79 ? ['package.json'] : []),
// always copy over server files if we're building for 7.9, otherwise rely on `server: true` in opensearch_dashboards.json manifest
...(OPENSEARCH_DASHBOARDS_VERSION_79 || plugin.manifest.server
...(plugin.manifest.server
? config.serverSourcePatterns || [
'yarn.lock',
'tsconfig.json',
Expand All @@ -86,7 +80,7 @@ export async function writeServerFiles({
),

// add opensearchDashboardsVersion to opensearch_dashboards.json files and opensearchDashboards.version to package.json files
// we don't check for `opensearchDashboards.version` in 7.10+ but the plugin helpers can still be used
// we don't check for `opensearchDashboards.version` in 1.0+ but the plugin helpers can still be used
// to build plugins for older OpenSearch Dashboards versions so we do our best to support those needs by
// setting the property if the package.json file is encountered
transformFileStream((file) => {
Expand Down
2 changes: 1 addition & 1 deletion src/core/CONVENTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Definition of done for a feature:
## Technical Conventions
### Plugin Structure

All OpenSearch Dashboards plugins built at Elastic should follow the same structure.
All OpenSearch Dashboards plugins should follow the same structure.

```
my_plugin/
Expand Down
5 changes: 5 additions & 0 deletions src/core/server/rendering/rendering_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ describe('RenderingService', () => {
const result = await service.isUrlValid('http://notfound.svg', 'config');
expect(result).toEqual(false);
});

it('checks default URL returns false', async () => {
const result = await service.isUrlValid('/', 'config');
expect(result).toEqual(false);
});
});

describe('isTitleValid()', () => {
Expand Down
19 changes: 13 additions & 6 deletions src/core/server/rendering/rendering_service.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -315,16 +315,21 @@ export class RenderingService {
* @returns {boolean} indicate if the URL is valid/invalid
*/
public isUrlValid = async (url: string, configName?: string): Promise<boolean> => {
if (url === '/') {
return false;
}
if (url.match(/\.(png|svg|gif|PNG|SVG|GIF)$/) === null) {
this.logger.get('branding').info(configName + ' config is not found or invalid.');
this.logger.get('branding').error(`${configName} config is invalid. Using default branding.`);
return false;
}
return await Axios.get(url, { adapter: AxiosHttpAdapter, maxRedirects: 0 })
.then(() => {
return true;
})
.catch(() => {
this.logger.get('branding').info(configName + ' config is not found or invalid');
this.logger
.get('branding')
.error(`${configName} URL was not found or invalid. Using default branding.`);
return false;
});
};
Expand All @@ -338,12 +343,14 @@ export class RenderingService {
* @returns {boolean} indicate if user input title is valid/invalid
*/
public isTitleValid = (title: string, configName?: string): boolean => {
if (!title || title.length > 36) {
if (!title) {
return false;
}
if (title.length > 36) {
this.logger
.get('branding')
.info(
configName +
' config is not found or invalid. Title length should be between 1 to 36 characters.'
.error(
`${configName} config is not found or invalid. Title length should be between 1 to 36 characters. Using default title.`
);
return false;
}
Expand Down
1 change: 1 addition & 0 deletions src/legacy/server/config/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export default () =>
map: Joi.object({
includeOpenSearchMapsService: Joi.boolean().default(true),
proxyOpenSearchMapsServiceInMaps: Joi.boolean().default(false),
showRegionBlockedWarning: Joi.boolean().default(false),
tilemap: Joi.object({
url: Joi.string(),
options: Joi.object({
Expand Down
29 changes: 29 additions & 0 deletions src/plugins/data/common/field_formats/converters/url.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,5 +306,34 @@ describe('UrlFormat', () => {
'<span ng-non-bindable><a href="http://opensearch-dashboards.host.com/app/opensearch-dashboards#/dashboard/" target="_blank" rel="noopener noreferrer">#/dashboard/</a></span>'
);
});

test('should support multiple types of urls w/o basePath from legacy app', () => {
const parsedUrl = {
origin: 'http://opensearch-dashboards.host.com',
pathname: '/app/kibana',
};
const url = new UrlFormat({ parsedUrl });
const converter = url.getConverterFor(HTML_CONTEXT_TYPE) as Function;

expect(converter('10.22.55.66')).toBe(
'<span ng-non-bindable><a href="http://opensearch-dashboards.host.com/app/10.22.55.66" target="_blank" rel="noopener noreferrer">10.22.55.66</a></span>'
);

expect(converter('http://www.domain.name/app/kibana#/dashboard/')).toBe(
'<span ng-non-bindable><a href="http://www.domain.name/app/kibana#/dashboard/" target="_blank" rel="noopener noreferrer">http://www.domain.name/app/kibana#/dashboard/</a></span>'
);

expect(converter('/app/kibana')).toBe(
'<span ng-non-bindable><a href="http://opensearch-dashboards.host.com/app/kibana" target="_blank" rel="noopener noreferrer">/app/kibana</a></span>'
);

expect(converter('kibana#/dashboard/')).toBe(
'<span ng-non-bindable><a href="http://opensearch-dashboards.host.com/app/kibana#/dashboard/" target="_blank" rel="noopener noreferrer">kibana#/dashboard/</a></span>'
);

expect(converter('#/dashboard/')).toBe(
'<span ng-non-bindable><a href="http://opensearch-dashboards.host.com/app/kibana#/dashboard/" target="_blank" rel="noopener noreferrer">#/dashboard/</a></span>'
);
});
});
});
1 change: 1 addition & 0 deletions src/plugins/maps_legacy/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { configSchema as regionmapSchema } from '../region_map/config';
export const configSchema = schema.object({
includeOpenSearchMapsService: schema.boolean({ defaultValue: true }),
proxyOpenSearchMapsServiceInMaps: schema.boolean({ defaultValue: false }),
showRegionBlockedWarning: schema.boolean({ defaultValue: false }),
tilemap: tilemapSchema,
regionmap: regionmapSchema,
manifestServiceUrl: schema.string({ defaultValue: '' }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ export class OpenSearchDashboardsMap extends EventEmitter {
this.emit('baseLayer:loading');
});
baseLayer.on('tileerror', () => {
if (baseLayer._url.includes('search-services.aws.a2z.com')) {
if (settings.options.showRegionBlockedWarning) {
createRegionBlockedWarning();
}
});
Expand Down
1 change: 1 addition & 0 deletions src/plugins/maps_legacy/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const config: PluginConfigDescriptor<MapsLegacyConfig> = {
exposeToBrowser: {
includeOpenSearchMapsService: true,
proxyOpenSearchMapsServiceInMaps: true,
showRegionBlockedWarning: true,
tilemap: true,
regionmap: true,
manifestServiceUrl: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,22 @@ describe('format', () => {
`"http://localhost:5601/oxf/app/opensearch-dashboards#?test=test&test1=test1"`
);
});

it('should add hash query to url without hash with legacy app', () => {
const url = 'http://localhost:5601/oxf/app/kibana';
expect(replaceUrlHashQuery(url, () => ({ test: 'test' }))).toMatchInlineSnapshot(
`"http://localhost:5601/oxf/app/kibana#?test=test"`
);
});

it('should replace hash query with legacy app', () => {
const url = 'http://localhost:5601/oxf/app/kibana#?test=test';
expect(
replaceUrlHashQuery(url, (query) => ({
...query,
test1: 'test1',
}))
).toMatchInlineSnapshot(`"http://localhost:5601/oxf/app/kibana#?test=test&test1=test1"`);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,36 @@ describe('hash unhash url', () => {
expect(hashUrl(url)).toBe(url);
});

it('if just a path with legacy app', () => {
const url = 'https://localhost:5601/app/kibana';
expect(hashUrl(url)).toBe(url);
});

it('if just a path and query with legacy app', () => {
const url = 'https://localhost:5601/app/kibana?foo=bar';
expect(hashUrl(url)).toBe(url);
});

it('if empty hash with query with legacy app', () => {
const url = 'https://localhost:5601/app/kibana?foo=bar#';
expect(hashUrl(url)).toBe(url);
});

it('if query parameter matches and there is no hash with legacy app', () => {
const url = 'https://localhost:5601/app/kibana?testParam=(yes:!t)';
expect(hashUrl(url)).toBe(url);
});

it(`if query parameter matches and it's before the hash with legacy app`, () => {
const url = 'https://localhost:5601/app/kibana?testParam=(yes:!t)';
expect(hashUrl(url)).toBe(url);
});

it('if empty hash without query with legacy app', () => {
const url = 'https://localhost:5601/app/kibana#';
expect(hashUrl(url)).toBe(url);
});

it('if hash is just a path', () => {
const url = 'https://localhost:5601/app/discover#/';
expect(hashUrl(url)).toBe(url);
Expand Down Expand Up @@ -189,6 +219,26 @@ describe('hash unhash url', () => {
expect(unhashUrl(url)).toBe(url);
});

it('if just a path with legacy app', () => {
const url = 'https://localhost:5601/app/kibana';
expect(unhashUrl(url)).toBe(url);
});

it('if just a path and query with legacy app', () => {
const url = 'https://localhost:5601/app/kibana?foo=bar';
expect(unhashUrl(url)).toBe(url);
});

it('if empty hash with query with legacy app', () => {
const url = 'https://localhost:5601/app/kibana?foo=bar#';
expect(unhashUrl(url)).toBe(url);
});

it('if empty hash without query with legacy app', () => {
const url = 'https://localhost:5601/app/kibana#';
expect(unhashUrl(url)).toBe(url);
});

it('if hash is just a path', () => {
const url = 'https://localhost:5601/app/discover#/';
expect(unhashUrl(url)).toBe(url);
Expand Down
Loading