-
Notifications
You must be signed in to change notification settings - Fork 377
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[frontend] Move the banner into a client side react component
This also reconsolidates multiple login related styles into one .less file.
- Loading branch information
1 parent
f4a36e2
commit eb8b264
Showing
17 changed files
with
362 additions
and
246 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
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
29 changes: 29 additions & 0 deletions
29
desktop/core/src/desktop/js/reactComponents/AppBanner/AppBanner.scss
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,29 @@ | ||
// Licensed to Cloudera, Inc. under one | ||
// or more contributor license agreements. See the NOTICE file | ||
// distributed with this work for additional information | ||
// regarding copyright ownership. Cloudera, Inc. licenses this file | ||
// to you under the Apache License, Version 2.0 (the | ||
// "License"); you may not use this file except in compliance | ||
// with the License. You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
@import '../../components/styles/colors.scss'; | ||
@import '../../components/styles/mixins.scss'; | ||
|
||
.app-banner { | ||
@include flex(0 0 auto); | ||
} | ||
|
||
.app-banner--system { | ||
padding: 4px; | ||
text-align: center; | ||
background-color: $fluid-blue-800; | ||
color: $fluid-blue-050; | ||
} |
88 changes: 88 additions & 0 deletions
88
desktop/core/src/desktop/js/reactComponents/AppBanner/AppBanner.test.tsx
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,88 @@ | ||
// Licensed to Cloudera, Inc. under one | ||
// or more contributor license agreements. See the NOTICE file | ||
// distributed with this work for additional information | ||
// regarding copyright ownership. Cloudera, Inc. licenses this file | ||
// to you under the Apache License, Version 2.0 (the | ||
// "License"); you may not use this file except in compliance | ||
// with the License. You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import React from 'react'; | ||
import { render, screen } from '@testing-library/react'; | ||
import '@testing-library/jest-dom'; | ||
|
||
import AppBanner from './AppBanner'; | ||
import { CancellablePromise } from '../../api/cancellablePromise'; | ||
import * as ApiUtils from '../../api/utils'; | ||
|
||
describe('AppBanner', () => { | ||
let apiMock; | ||
|
||
const setupMock = (configured?: string, system?: string) => { | ||
apiMock = jest | ||
.spyOn<ApiUtils, ApiUtils['get']>(ApiUtils, 'get') | ||
.mockReturnValue(CancellablePromise.resolve({ configured, system })); | ||
}; | ||
|
||
afterEach(() => { | ||
apiMock?.mockClear(); | ||
}); | ||
|
||
test('it should show a configured banner', async () => { | ||
const configuredBanner = '<div>Configured text <a href="some">Link</a></div>'; | ||
setupMock(configuredBanner); | ||
|
||
render(<AppBanner />); | ||
|
||
expect((await screen.findByText(/Configured/))?.outerHTML).toEqual(configuredBanner); | ||
}); | ||
|
||
test('it should show a sanitized configured banner', async () => { | ||
const configuredBanner = | ||
'<div>Configured text <a href="some">Link</a><script>alert("xss");</script></div>'; | ||
const expectedBanner = '<div>Configured text <a href="some">Link</a></div>'; | ||
setupMock(configuredBanner); | ||
|
||
render(<AppBanner />); | ||
|
||
expect((await screen.findByText(/Configured/))?.outerHTML).toEqual(expectedBanner); | ||
}); | ||
|
||
test('it should show a configured banner with sanitized styles', async () => { | ||
const configuredBanner = | ||
'<div style="color: #aabbcc; width: expression(alert(\'XSS\'));font-size:1px;">Configured text</div>'; | ||
const expectedBanner = '<div style="color:#aabbcc;font-size:1px">Configured text</div>'; | ||
setupMock(configuredBanner); | ||
|
||
render(<AppBanner />); | ||
|
||
expect((await screen.findByText(/Configured/))?.outerHTML).toEqual(expectedBanner); | ||
}); | ||
|
||
test('it should show a system banner', async () => { | ||
const systemBanner = '<div>System text</div>'; | ||
setupMock(undefined, systemBanner); | ||
|
||
render(<AppBanner />); | ||
|
||
expect((await screen.findByText(/System/))?.outerHTML).toEqual(systemBanner); | ||
}); | ||
|
||
test('it should show a system banner instead of configured if both are present', async () => { | ||
const configuredBanner = '<div>Configured text <a href="some">Link</a></div>'; | ||
const systemBanner = '<div>System text</div>'; | ||
setupMock(configuredBanner, systemBanner); | ||
|
||
render(<AppBanner />); | ||
|
||
expect(await screen.findByText(/System/)).toBeInTheDocument(); | ||
expect(screen.queryByText(/Configured/)).not.toBeInTheDocument(); | ||
}); | ||
}); |
88 changes: 88 additions & 0 deletions
88
desktop/core/src/desktop/js/reactComponents/AppBanner/AppBanner.tsx
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,88 @@ | ||
// Licensed to Cloudera, Inc. under one | ||
// or more contributor license agreements. See the NOTICE file | ||
// distributed with this work for additional information | ||
// regarding copyright ownership. Cloudera, Inc. licenses this file | ||
// to you under the Apache License, Version 2.0 (the | ||
// "License"); you may not use this file except in compliance | ||
// with the License. You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import React, { useEffect, useState } from 'react'; | ||
import sanitizeHtml, { IOptions } from 'sanitize-html'; | ||
|
||
import './AppBanner.scss'; | ||
import { BANNERS_API } from '../../api/urls'; | ||
import { get } from '../../api/utils'; | ||
import deXSS from '../../utils/html/deXSS'; | ||
import noop from '../../utils/timing/noop'; | ||
|
||
interface ApiBanners { | ||
system?: string; | ||
configured?: string; | ||
} | ||
|
||
const allowedCssColorRegex = [ | ||
/^#(0x)?[0-9a-f]+$/i, | ||
/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/ | ||
]; | ||
const allowedCssSizeRegex = [/^[\d.]+(?:px|pt|em|%|rem|vw)$/i]; | ||
|
||
// Based on defaults from https://github.com/apostrophecms/sanitize-html with support for a select set of styles that | ||
// would make sense to use in a banner. | ||
const sanitizeOptions: IOptions = { | ||
allowedAttributes: { | ||
'*': ['style'], | ||
...sanitizeHtml.defaults.allowedAttributes | ||
}, | ||
allowedStyles: { | ||
'*': { | ||
background: allowedCssColorRegex, | ||
'background-color': allowedCssColorRegex, | ||
color: allowedCssColorRegex, | ||
direction: [/^ltr|rtl$/i], | ||
'font-size': allowedCssSizeRegex, | ||
height: allowedCssSizeRegex, | ||
padding: allowedCssSizeRegex, | ||
'padding-bottom': allowedCssSizeRegex, | ||
'padding-left': allowedCssSizeRegex, | ||
'padding-right': allowedCssSizeRegex, | ||
'padding-top': allowedCssSizeRegex, | ||
'text-align': [/^left|right|center$/i], | ||
width: allowedCssSizeRegex | ||
} | ||
} | ||
}; | ||
|
||
export const AppBanner = (): JSX.Element => { | ||
const [banners, setBanners] = useState<ApiBanners>(); | ||
|
||
useEffect(() => { | ||
if (!banners) { | ||
get<ApiBanners>(BANNERS_API).then(setBanners).catch(noop); | ||
} | ||
}); | ||
|
||
return ( | ||
banners && | ||
(banners.system ? ( | ||
<div | ||
className={'app-banner app-banner--system'} | ||
dangerouslySetInnerHTML={{ __html: banners.system }} | ||
/> | ||
) : ( | ||
<div | ||
className={'app-banner'} | ||
dangerouslySetInnerHTML={{ __html: deXSS(banners.configured, sanitizeOptions) }} | ||
/> | ||
)) | ||
); | ||
}; | ||
|
||
export default AppBanner; |
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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.