1
0
mirror of https://github.com/mattermost/focalboard.git synced 2025-01-17 18:26:17 +02:00

Removing references to isFocalboardPlugin and isFocalboardLegacy (#4583)

* removing references to isFocalboardPlugin and isFocalboardLegacy

* fixing snapshots

* cleaning up wsClient, isProduct and tests

* removing buildURL function

* lint

* updating test due to utils issue

* lint

* remove console logs

* revert table changes

* lint

* removing unused comments

* temporarily disable cypress tests

---------

Co-authored-by: Benjamin Cooke <benjamincooke@Benjamins-MacBook-Pro.local>
Co-authored-by: Doug Lauder <wiggin77@warpmail.net>
Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Ben Cooke 2023-02-24 13:24:37 -05:00 committed by GitHub
parent c5d16b75b8
commit 70003b89d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 1610 additions and 3802 deletions

View File

@ -34,8 +34,6 @@ describe('components/boardsUnfurl/BoardsUnfurl', () => {
}
beforeEach(() => {
// This is done to the websocket not to try to connect directly
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
jest.clearAllMocks()
})

View File

@ -25,7 +25,6 @@ import {useAppSelector, useAppDispatch} from '../../../../webapp/src/store/hooks
import AddIcon from '../../../../webapp/src/widgets/icons/add'
import Button from '../../../../webapp/src/widgets/buttons/button'
import {Utils} from '../../../../webapp/src/utils'
import {WSClient} from '../../../../webapp/src/wsclient'
import boardsScreenshots from '../../../../webapp/static/boards-screenshots.png'
@ -116,7 +115,7 @@ const RHSChannelBoards = () => {
defaultMessage='Boards is a project management tool that helps define, organize, track and manage work across teams, using a familiar kanban board view.'
/>
</div>
<div className='boards-screenshots'><img src={Utils.buildURL(boardsScreenshots, true)}/></div>
<div className='boards-screenshots'><img src={boardsScreenshots}/></div>
{me?.permissions?.find((s) => s === 'create_post') &&
<Button
onClick={() => dispatch(setLinkToChannel(currentChannel.id))}

View File

@ -7,7 +7,6 @@ import {getMessages} from '../../../../webapp/src/i18n'
import {getLanguage} from '../../../../webapp/src/store/language'
import {getCurrentChannel} from '../../../../webapp/src/store/channels'
import {useAppSelector} from '../../../../webapp/src/store/hooks'
import {Utils} from '../../../../webapp/src/utils'
import appBarIcon from '../../../../webapp/static/app-bar-icon.png'
@ -27,7 +26,7 @@ const RHSChannelBoardsHeader = () => {
<div>
<img
className='boards-rhs-header-logo'
src={Utils.buildURL(appBarIcon, true)}
src={appBarIcon}
/>
<span>
<FormattedMessage

View File

@ -17,9 +17,8 @@ import {UserSettings} from '../../../webapp/src/userSettings'
import {getMessages, getCurrentLanguage} from '../../../webapp/src/i18n'
const windowAny = (window as SuiteWindow)
windowAny.baseURL = process.env.TARGET_IS_PRODUCT ? '/plugins/boards' : '/plugins/focalboard'
windowAny.baseURL = '/plugins/boards'
windowAny.frontendBaseURL = '/boards'
windowAny.isFocalboardPlugin = true
import App from '../../../webapp/src/app'
import store from '../../../webapp/src/store'
@ -203,7 +202,7 @@ export default class Plugin {
let theme = mmStore.getState().entities.preferences.myPreferences.theme
setMattermostTheme(theme)
const productID = process.env.TARGET_IS_PRODUCT ? 'boards' : manifest.id
const productID = 'boards'
// register websocket handlers
this.registry?.registerWebSocketEventHandler(`custom_${productID}_${ACTION_UPDATE_BOARD}`, (e: any) => wsClient.updateHandler(e.data))
@ -336,7 +335,7 @@ export default class Plugin {
}
if (this.registry.registerAppBarComponent) {
this.registry.registerAppBarComponent(Utils.buildURL(appBarIcon, true), () => mmStore.dispatch(toggleRHSPlugin), intl.formatMessage({id: 'AppBar.Tooltip', defaultMessage: 'Toggle Linked Boards'}))
this.registry.registerAppBarComponent(appBarIcon, () => mmStore.dispatch(toggleRHSPlugin), intl.formatMessage({id: 'AppBar.Tooltip', defaultMessage: 'Toggle Linked Boards'}))
}
if (this.registry.registerActionAfterChannelCreation) {

View File

@ -12,7 +12,6 @@ const tsTransformer = require('@formatjs/ts-transformer');
const PLUGIN_ID = require('../plugin.json').id;
const NPM_TARGET = process.env.npm_lifecycle_event; //eslint-disable-line no-process-env
const TARGET_IS_PRODUCT = NPM_TARGET?.endsWith(':product');
let mode = 'production';
let devtool;
@ -53,7 +52,7 @@ if (NPM_TARGET === 'build:watch' || NPM_TARGET === 'debug:watch' || NPM_TARGET =
}
const config = {
entry: TARGET_IS_PRODUCT ? './src/remote_entry.ts' : './src/plugin_entry.ts',
entry: './src/remote_entry.ts',
resolve: {
modules: [
'src',
@ -116,7 +115,7 @@ const config = {
type: 'asset/resource',
generator: {
filename: '[name][ext]',
publicPath: TARGET_IS_PRODUCT ? undefined : '/static/',
publicPath: undefined,
}
},
],
@ -126,75 +125,50 @@ const config = {
plugins,
};
if (TARGET_IS_PRODUCT) {
// Set up module federation
function makeSingletonSharedModules(packageNames) {
const sharedObject = {};
// Set up module federation
function makeSingletonSharedModules(packageNames) {
const sharedObject = {};
for (const packageName of packageNames) {
// Set both versions to false so that the version of this module provided by the web app will be used
sharedObject[packageName] = {
requiredVersion: false,
singleton: true,
version: false,
};
}
return sharedObject;
for (const packageName of packageNames) {
// Set both versions to false so that the version of this module provided by the web app will be used
sharedObject[packageName] = {
requiredVersion: false,
singleton: true,
version: false,
};
}
config.plugins.push(new ModuleFederationPlugin({
name: 'boards',
filename: 'remote_entry.js',
exposes: {
'.': './src/index',
// This probably won't need to be exposed in the long run, but its a POC for exposing multiple modules
'./manifest': './src/manifest',
},
shared: [
'@mattermost/client',
'prop-types',
makeSingletonSharedModules([
'react',
'react-dom',
'react-intl',
'react-redux',
'react-router-dom',
]),
],
}));
config.plugins.push(new webpack.DefinePlugin({
'process.env.TARGET_IS_PRODUCT': TARGET_IS_PRODUCT, // TODO We might want a better name for this
}));
config.output = {
path: path.join(__dirname, '/dist'),
chunkFilename: '[name].[contenthash].js',
};
} else {
config.resolve.alias['react-intl'] = path.resolve(__dirname, '../../webapp/node_modules/react-intl/');
config.externals = {
react: 'React',
'react-dom': 'ReactDOM',
redux: 'Redux',
'react-redux': 'ReactRedux',
'mm-react-router-dom': 'ReactRouterDom',
'prop-types': 'PropTypes',
'react-bootstrap': 'ReactBootstrap',
};
config.output = {
devtoolNamespace: PLUGIN_ID,
path: path.join(__dirname, '/dist'),
publicPath: '/',
filename: 'main.js',
};
return sharedObject;
}
config.plugins.push(new ModuleFederationPlugin({
name: 'boards',
filename: 'remote_entry.js',
exposes: {
'.': './src/index',
// This probably won't need to be exposed in the long run, but its a POC for exposing multiple modules
'./manifest': './src/manifest',
},
shared: [
'@mattermost/client',
'prop-types',
makeSingletonSharedModules([
'react',
'react-dom',
'react-intl',
'react-redux',
'react-router-dom',
]),
],
}));
config.output = {
path: path.join(__dirname, '/dist'),
chunkFilename: '[name].[contenthash].js',
};
const env = {};
env.RUDDER_KEY = JSON.stringify(process.env.RUDDER_KEY || ''); //eslint-disable-line no-process-env
env.RUDDER_DATAPLANE_URL = JSON.stringify(process.env.RUDDER_DATAPLANE_URL || ''); //eslint-disable-line no-process-env

View File

@ -13,21 +13,22 @@ exports[`components/centerPanel Clicking on the Hidden card count should open a
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -721,21 +722,22 @@ exports[`components/centerPanel return centerPanel and click on card to show car
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -1274,21 +1276,22 @@ exports[`components/centerPanel return centerPanel and click on new card to edit
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -1932,21 +1935,22 @@ exports[`components/centerPanel return centerPanel and press touch 1 with readon
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -2331,21 +2335,22 @@ exports[`components/centerPanel return centerPanel and press touch ctrl+d for on
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -2989,21 +2994,22 @@ exports[`components/centerPanel return centerPanel and press touch del for one c
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -3647,21 +3653,22 @@ exports[`components/centerPanel return centerPanel and press touch esc for one c
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -4305,21 +4312,22 @@ exports[`components/centerPanel return centerPanel and press touch esc for one c
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -4963,21 +4971,22 @@ exports[`components/centerPanel return centerPanel and press touch esc for two c
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -5621,21 +5630,22 @@ exports[`components/centerPanel return centerPanel and press touch esc for two c
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -6279,21 +6289,22 @@ exports[`components/centerPanel return centerPanel and press touch esc for two c
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -6937,21 +6948,22 @@ exports[`components/centerPanel return centerPanel and select one card and click
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -7595,21 +7607,22 @@ exports[`components/centerPanel return centerPanel and select one card and click
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -8253,21 +8266,22 @@ exports[`components/centerPanel should match snapshot for Gallery 1`] = `
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -8528,21 +8542,22 @@ exports[`components/centerPanel should match snapshot for Kanban 1`] = `
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -9047,21 +9062,22 @@ exports[`components/centerPanel should match snapshot for Kanban, not shared 1`]
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -9566,21 +9582,22 @@ exports[`components/centerPanel should match snapshot for Table 1`] = `
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"

View File

@ -26,29 +26,3 @@ exports[`src/components/topBar should match snapshot for focalboardPlugin 1`] =
</div>
</div>
`;
exports[`src/components/topBar should match snapshot for none focalboardPlugin 1`] = `
<div>
<div
class="TopBar"
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
</div>
</div>
`;

View File

@ -9,62 +9,8 @@ exports[`src/components/workspace return workspace and showcard 1`] = `
class="Sidebar octo-sidebar"
>
<div
class="octo-sidebar-header"
class="WorkspaceTitle"
>
<div
class="heading"
>
<div
class="SidebarUserMenu"
>
<div
class="ModalWrapper"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="logo"
>
<div
class="logo-title"
>
<svg
class="FocalboardLogoIcon Icon"
version="1.1"
viewBox="0 0 52.589677 64"
x="0px"
y="0px"
>
<path
d="m 33.071077,12.069805 c -12.663,-3.4670001 -27.0530002,3.289 -31.6760002,16.943 -4.655,13.75 2.719,28.67 16.4690002,33.325 13.75,4.655 28.67,-2.719 33.326,-16.469 3.804,-11.235 -0.462,-22.701 -8.976,-29.249 l -0.46,4.871 h -0.001 c 4.631,4.896 6.709,11.941 4.325,18.985 -3.362,9.931 -14.447,15.151 -24.76,11.66 -10.313,-3.49 -15.9480002,-14.37 -12.5870002,-24.301 2.9750002,-8.788 11.9980002,-13.715 20.7430002,-12.625 v -10e-4 z m -6.175,16.488 c 3.456,-0.665 6.986,2.754 5.762,6.37 -0.854,2.522 -3.67,3.85 -6.291,2.962 -2.62,-0.887 -4.052,-3.651 -3.197,-6.174 0.573,-1.697 2.034,-2.852 3.726,-3.158 z m -1.285,-4.944 c -1.786,0.323 -3.45,1.104 -4.812,2.258 -1.299,1.101 -2.319,2.545 -2.898,4.258 -0.879,2.597 -0.579,5.323 0.617,7.632 1.206,2.329 3.325,4.234 6.07,5.164 2.744,0.929 5.584,0.701 7.959,-0.417 2.352,-1.107 4.246,-3.091 5.125,-5.688 0.555,-1.639 0.633,-3.254 0.344,-4.761 -0.21,-1.093 -0.615,-2.134 -1.174,-3.091 l 1.019,-5.107 c 0.189,0.187 0.374,0.378 0.552,0.574 1.75,1.919 3.008,4.283 3.508,6.877 0.415,2.154 0.304,4.457 -0.484,6.784 -1.239,3.661 -3.898,6.453 -7.193,8.005 -3.273,1.541 -7.175,1.858 -10.93,0.588 -3.754,-1.271 -6.661,-3.895 -8.326,-7.108 -1.674,-3.233 -2.09,-7.065 -0.851,-10.728 0.819,-2.419 2.26,-4.46 4.097,-6.016 1.88,-1.593 4.181,-2.673 6.656,-3.125 l -0.001,-0.004 c 1.759,-0.339 3.522,-0.313 5.213,0.016 l -3.583,3.761 c -0.294,0.028 -0.588,0.071 -0.883,0.127 h -0.025 z"
/>
<polygon
points="26.057,32.594 37.495,11.658 36.79,8.44 41.066,0.207 43.683,4.611 48.803,4.434 44.185,12.48 40.902,13.697 29.542,34.491 "
transform="translate(7.6780426e-5,-0.21919512)"
/>
</svg>
<span>
Focalboard
</span>
<div
class="versionFrame"
>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="octo-spacer"
/>
@ -89,9 +35,6 @@ exports[`src/components/workspace return workspace and showcard 1`] = `
</button>
</div>
</div>
<div
class="WorkspaceTitle"
/>
<div
class="BoardsSwitcherWrapper"
>
@ -107,6 +50,19 @@ exports[`src/components/workspace return workspace and showcard 1`] = `
</span>
</div>
</div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
type="button"
>
<i
class="CompassIcon icon-plus AddIcon"
/>
</button>
</div>
</div>
<div
class="octo-sidebar-list"
@ -238,26 +194,6 @@ exports[`src/components/workspace return workspace and showcard 1`] = `
<div
class="octo-spacer"
/>
<div
class="add-board"
>
+ Add board
</div>
<div
class="SidebarSettingsMenu"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="menu-entry"
>
Settings
</div>
</div>
</div>
</div>
<div
class="mainFrame"
@ -273,21 +209,22 @@ exports[`src/components/workspace return workspace and showcard 1`] = `
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -811,21 +748,22 @@ exports[`src/components/workspace return workspace readonly and showcard 1`] = `
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -1120,62 +1058,8 @@ exports[`src/components/workspace should match snapshot 1`] = `
class="Sidebar octo-sidebar"
>
<div
class="octo-sidebar-header"
class="WorkspaceTitle"
>
<div
class="heading"
>
<div
class="SidebarUserMenu"
>
<div
class="ModalWrapper"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="logo"
>
<div
class="logo-title"
>
<svg
class="FocalboardLogoIcon Icon"
version="1.1"
viewBox="0 0 52.589677 64"
x="0px"
y="0px"
>
<path
d="m 33.071077,12.069805 c -12.663,-3.4670001 -27.0530002,3.289 -31.6760002,16.943 -4.655,13.75 2.719,28.67 16.4690002,33.325 13.75,4.655 28.67,-2.719 33.326,-16.469 3.804,-11.235 -0.462,-22.701 -8.976,-29.249 l -0.46,4.871 h -0.001 c 4.631,4.896 6.709,11.941 4.325,18.985 -3.362,9.931 -14.447,15.151 -24.76,11.66 -10.313,-3.49 -15.9480002,-14.37 -12.5870002,-24.301 2.9750002,-8.788 11.9980002,-13.715 20.7430002,-12.625 v -10e-4 z m -6.175,16.488 c 3.456,-0.665 6.986,2.754 5.762,6.37 -0.854,2.522 -3.67,3.85 -6.291,2.962 -2.62,-0.887 -4.052,-3.651 -3.197,-6.174 0.573,-1.697 2.034,-2.852 3.726,-3.158 z m -1.285,-4.944 c -1.786,0.323 -3.45,1.104 -4.812,2.258 -1.299,1.101 -2.319,2.545 -2.898,4.258 -0.879,2.597 -0.579,5.323 0.617,7.632 1.206,2.329 3.325,4.234 6.07,5.164 2.744,0.929 5.584,0.701 7.959,-0.417 2.352,-1.107 4.246,-3.091 5.125,-5.688 0.555,-1.639 0.633,-3.254 0.344,-4.761 -0.21,-1.093 -0.615,-2.134 -1.174,-3.091 l 1.019,-5.107 c 0.189,0.187 0.374,0.378 0.552,0.574 1.75,1.919 3.008,4.283 3.508,6.877 0.415,2.154 0.304,4.457 -0.484,6.784 -1.239,3.661 -3.898,6.453 -7.193,8.005 -3.273,1.541 -7.175,1.858 -10.93,0.588 -3.754,-1.271 -6.661,-3.895 -8.326,-7.108 -1.674,-3.233 -2.09,-7.065 -0.851,-10.728 0.819,-2.419 2.26,-4.46 4.097,-6.016 1.88,-1.593 4.181,-2.673 6.656,-3.125 l -0.001,-0.004 c 1.759,-0.339 3.522,-0.313 5.213,0.016 l -3.583,3.761 c -0.294,0.028 -0.588,0.071 -0.883,0.127 h -0.025 z"
/>
<polygon
points="26.057,32.594 37.495,11.658 36.79,8.44 41.066,0.207 43.683,4.611 48.803,4.434 44.185,12.48 40.902,13.697 29.542,34.491 "
transform="translate(7.6780426e-5,-0.21919512)"
/>
</svg>
<span>
Focalboard
</span>
<div
class="versionFrame"
>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="octo-spacer"
/>
@ -1200,9 +1084,6 @@ exports[`src/components/workspace should match snapshot 1`] = `
</button>
</div>
</div>
<div
class="WorkspaceTitle"
/>
<div
class="BoardsSwitcherWrapper"
>
@ -1218,6 +1099,19 @@ exports[`src/components/workspace should match snapshot 1`] = `
</span>
</div>
</div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
type="button"
>
<i
class="CompassIcon icon-plus AddIcon"
/>
</button>
</div>
</div>
<div
class="octo-sidebar-list"
@ -1349,26 +1243,6 @@ exports[`src/components/workspace should match snapshot 1`] = `
<div
class="octo-spacer"
/>
<div
class="add-board"
>
+ Add board
</div>
<div
class="SidebarSettingsMenu"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="menu-entry"
>
Settings
</div>
</div>
</div>
</div>
<div
class="mainFrame"
@ -1384,21 +1258,22 @@ exports[`src/components/workspace should match snapshot 1`] = `
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -1922,21 +1797,22 @@ exports[`src/components/workspace should match snapshot with readonly 1`] = `
>
<a
class="link"
href="https://www.focalboard.com/fwlink/feedback-focalboard.html?v=1.0.0"
href="https://www.focalboard.com/fwlink/feedback-boards.html?v=1.0.0"
rel="noreferrer"
target="_blank"
>
Give feedback
</a>
<a
href="https://www.focalboard.com/guide/user?utm_source=webapp"
rel="noreferrer"
target="_blank"
<div
class="versionFrame"
>
<i
class="CompassIcon icon-help-circle-outline HelpIcon"
/>
</a>
<div
class="version"
title="v1.0.0"
>
v1.0.0
</div>
</div>
</div>
<div
class="mid-head"
@ -2250,6 +2126,14 @@ exports[`src/components/workspace show add new view tooltip 1`] = `
>
Go here to create a new view to organise your board using different layouts.
</div>
<div
class="tutorial-tour-tip__image"
>
<img
alt="tutorial tour tip product image"
src="test-file-stub"
/>
</div>
<div
class="tutorial-tour-tip__footer"
>
@ -2353,6 +2237,14 @@ exports[`src/components/workspace show copy link tooltip 1`] = `
>
You can share your cards with teammates by copying the link and pasting it in a channel, direct message, or group message.
</div>
<div
class="tutorial-tour-tip__image"
>
<img
alt="tutorial tour tip product image"
src="test-file-stub"
/>
</div>
<div
class="tutorial-tour-tip__footer"
>

View File

@ -468,168 +468,3 @@ exports[`components/boardTemplateSelector/boardTemplateSelector a focalboard Plu
</div>
</div>
`;
exports[`components/boardTemplateSelector/boardTemplateSelector not a focalboard Plugin should match snapshot 1`] = `
<div>
<div
class="BoardTemplateSelector__container "
>
<div
class="BoardTemplateSelector__backdrop"
/>
<div
class="BoardTemplateSelector"
>
<div
class="toolbar"
>
<button
aria-label="Close"
title="Close"
type="button"
>
<i
class="CompassIcon icon-close CloseIcon"
/>
</button>
</div>
<div
class="header"
>
<h1
class="title"
>
Create a board
</h1>
<p
class="description"
>
Add a board to the sidebar using any of the templates defined below or start from scratch.
</p>
</div>
<div
class="templates"
>
<div
class="templates-sidebar"
>
<div
class="templates-list"
>
<button
type="button"
>
<i
class="CompassIcon icon-plus"
/>
<span>
Create new template
</span>
</button>
<div
class="BoardTemplateSelectorItem active"
>
<span
class="template-icon"
>
🚴🏻‍♂️
</span>
<span
class="template-name"
>
Template Global
</span>
</div>
<div
class="BoardTemplateSelectorItem"
>
<span
class="template-icon"
>
🚴🏻‍♂️
</span>
<span
class="template-name"
>
Template 1
</span>
<div
class="actions"
>
<button
aria-label="Delete"
title="Delete"
type="button"
>
<i
class="CompassIcon icon-trash-can-outline DeleteIcon trash-can-outline"
/>
</button>
<button
aria-label="Edit"
title="Edit"
type="button"
>
<i
class="CompassIcon icon-pencil-outline EditIcon"
/>
</button>
</div>
</div>
<div
class="BoardTemplateSelectorItem"
>
<span
class="template-icon"
>
❄️
</span>
<span
class="template-name"
>
Welcome to Boards!
</span>
</div>
</div>
<div
class="templates-sidebar__footer"
>
<button
type="button"
>
<i
class="CompassIcon icon-kanban"
/>
<span>
Create empty board
</span>
</button>
</div>
</div>
<div
class="templates-content"
>
<div
class="template-preview-box"
>
<div
class="BoardTemplateSelectorPreview"
/>
</div>
<div
class="buttons"
>
<button
type="button"
>
<span>
Use this template
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -13,7 +13,6 @@ import {Provider as ReduxProvider} from 'react-redux'
import {MemoryRouter, Router} from 'react-router-dom'
import Mutator from '../../mutator'
import {Utils} from '../../utils'
import {Team} from '../../store/teams'
import {createBoard, Board} from '../../blocks/board'
import {IUser} from '../../user'
@ -41,14 +40,13 @@ jest.mock('../../octoClient', () => {
patchUserConfig: jest.fn(() => Promise.resolve({})),
}
})
jest.mock('../../utils')
jest.mock('../../mutator')
jest.mock('../../utils')
jest.mock('../../telemetry/telemetryClient')
const mockedTelemetry = mocked(TelemetryClient, true)
describe('components/boardTemplateSelector/boardTemplateSelector', () => {
const mockedUtils = mocked(Utils, true)
const mockedMutator = mocked(Mutator, true)
const mockedOctoClient = mocked(client, true)
const team1: Team = {
@ -159,24 +157,7 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => {
store = mockStateStore([], state)
jest.useRealTimers()
})
describe('not a focalboard Plugin', () => {
beforeAll(() => {
mockedUtils.isFocalboardPlugin.mockReturnValue(false)
})
test('should match snapshot', () => {
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>
<BoardTemplateSelector onClose={jest.fn()}/>
</ReduxProvider>
,
), {wrapper: MemoryRouter})
expect(container).toMatchSnapshot()
})
})
describe('a focalboard Plugin', () => {
beforeAll(() => {
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
})
test('should match snapshot', () => {
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>

View File

@ -100,7 +100,7 @@ const BoardsSwitcher = (props: Props): JSX.Element => {
</div>
{shouldViewSearchForBoardsTour && <div><SearchForBoardsTourStep/></div>}
{
Utils.isFocalboardPlugin() && !props.userIsGuest &&
!props.userIsGuest &&
<MenuWrapper>
<IconButton
size='small'

View File

@ -27,7 +27,6 @@ const mockedUtils = mocked(Utils, true)
const mockedMutator = mocked(mutator, true)
const mockedOctoClient = mocked(octoClient, true)
mockedUtils.createGuid.mockReturnValue('test-id')
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
beforeAll(() => {
mockDOM()

View File

@ -159,7 +159,7 @@ const CardDialog = (props: Props): JSX.Element => {
const attachmentBlock = createAttachmentBlock(uploadingBlock)
attachmentBlock.isUploading = true
dispatch(updateAttachments([attachmentBlock]))
if (attachment.size > clientConfig.maxFileSize && Utils.isFocalboardPlugin()) {
if (attachment.size > clientConfig.maxFileSize) {
removeUploadingAttachment(uploadingBlock)
sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.failed', defaultMessage: 'Unable to upload the file. Attachment size limit reached.'}), severity: 'normal'})
} else {
@ -263,7 +263,7 @@ const CardDialog = (props: Props): JSX.Element => {
</>
)
if (!isTemplate && Utils.isFocalboardPlugin() && !card?.limited) {
if (!isTemplate && !card?.limited) {
return (<>{attachBtn()}{following ? unfollowBtn : followBtn}</>)
}
return (<>{attachBtn()}</>)

View File

@ -86,7 +86,7 @@ const KanbanCard = (props: Props) => {
}, [props.onClick, card])
const isOnboardingCard = card.title === 'Create a new card'
const showOnboarding = isOnboardingCard && !match.params.cardId && !board.isTemplate && Utils.isFocalboardPlugin()
const showOnboarding = isOnboardingCard && !match.params.cardId && !board.isTemplate
return (
<>

View File

@ -1,8 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/messages/CloudMessage not plugin mode, close message 1`] = `<div />`;
exports[`components/messages/CloudMessage not plugin mode, show message, close message 1`] = `
exports[`components/messages/CloudMessage plugin mode, no display 1`] = `
<div>
<div
class="CloudMessage"
@ -15,6 +13,7 @@ exports[`components/messages/CloudMessage not plugin mode, show message, close m
/>
Get your own free cloud server.
<button
class="Button emphasis--primary size--xsmall"
title="Learn more"
type="button"
>
@ -25,6 +24,7 @@ exports[`components/messages/CloudMessage not plugin mode, show message, close m
</div>
<button
aria-label="Close dialog"
class="IconButton margin-right size--small"
title="Close dialog"
type="button"
>
@ -35,39 +35,3 @@ exports[`components/messages/CloudMessage not plugin mode, show message, close m
</div>
</div>
`;
exports[`components/messages/CloudMessage not plugin mode, single user, close message 1`] = `
<div>
<div
class="CloudMessage"
>
<div
class="banner"
>
<i
class="CompassIcon icon-information-outline CompassIcon"
/>
Get your own free cloud server.
<button
title="Learn more"
type="button"
>
<span>
Learn more
</span>
</button>
</div>
<button
aria-label="Close dialog"
title="Close dialog"
type="button"
>
<i
class="CompassIcon icon-close CloseIcon"
/>
</button>
</div>
</div>
`;
exports[`components/messages/CloudMessage plugin mode, no display 1`] = `<div />`;

View File

@ -4,39 +4,24 @@
import React from 'react'
import {Provider as ReduxProvider} from 'react-redux'
import {render, screen} from '@testing-library/react'
import {mocked} from 'jest-mock'
import userEvent from '@testing-library/user-event'
import {render} from '@testing-library/react'
import configureStore from 'redux-mock-store'
import {Utils} from '../../utils'
import {IUser} from '../../user'
import {wrapIntl} from '../../testUtils'
import client from '../../octoClient'
import {UserSettings} from '../../userSettings'
import CloudMessage from './cloudMessage'
jest.mock('../../utils')
jest.mock('../../octoClient')
const mockedOctoClient = mocked(client, true)
describe('components/messages/CloudMessage', () => {
beforeEach(() => {
jest.clearAllMocks()
})
const mockedUtils = mocked(Utils, true)
const mockStore = configureStore([])
test('plugin mode, no display', () => {
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const me: IUser = {
id: 'user-id-1',
username: 'username_1',
@ -68,123 +53,4 @@ describe('components/messages/CloudMessage', () => {
const {container} = render(component)
expect(container).toMatchSnapshot()
})
test('not plugin mode, close message', () => {
const me: IUser = {
id: 'user-id-1',
username: 'username_1',
email: '',
nickname: '',
firstname: '',
lastname: '',
create_at: 0,
update_at: 0,
is_bot: false,
is_guest: false,
roles: 'system_user',
props: {},
}
const state = {
users: {
me,
myConfig: {
cloudMessageCanceled: {value: 'true'},
},
},
}
const store = mockStore(state)
mockedUtils.isFocalboardPlugin.mockReturnValue(false)
const component = wrapIntl(
<ReduxProvider store={store}>
<CloudMessage/>
</ReduxProvider>,
)
const {container} = render(component)
expect(container).toMatchSnapshot()
})
test('not plugin mode, show message, close message', () => {
const me: IUser = {
id: 'user-id-1',
username: 'username_1',
email: '',
nickname: '',
firstname: '',
lastname: '',
props: {},
create_at: 0,
update_at: 0,
is_bot: false,
is_guest: false,
roles: 'system_user',
}
const state = {
users: {
me,
},
}
const store = mockStore(state)
mockedUtils.isFocalboardPlugin.mockReturnValue(false)
const component = wrapIntl(
<ReduxProvider store={store}>
<CloudMessage/>
</ReduxProvider>,
)
const {container} = render(component)
expect(container).toMatchSnapshot()
const buttonElement = screen.getByRole('button', {name: 'Close dialog'})
userEvent.click(buttonElement)
expect(mockedOctoClient.patchUserConfig).toBeCalledWith('user-id-1', {
updatedFields: {
cloudMessageCanceled: 'true',
},
})
})
test('not plugin mode, single user, close message', () => {
const me: IUser = {
id: 'single-user',
username: 'single-user',
email: 'single-user',
nickname: '',
firstname: '',
lastname: '',
props: {},
create_at: 0,
update_at: Date.now() - (1000 * 60 * 60 * 24), //24 hours,
is_bot: false,
is_guest: false,
roles: 'system_user',
}
const state = {
users: {
me,
},
}
const store = mockStore(state)
const hideCloudMessageSpy = jest.spyOn(UserSettings, 'hideCloudMessage', 'set')
mockedUtils.isFocalboardPlugin.mockReturnValue(false)
const component = wrapIntl(
<ReduxProvider store={store}>
<CloudMessage/>
</ReduxProvider>,
)
const {container} = render(component)
expect(container).toMatchSnapshot()
const buttonElement = screen.getByRole('button', {name: 'Close dialog'})
userEvent.click(buttonElement)
expect(mockedOctoClient.patchUserConfig).toBeCalledTimes(0)
expect(hideCloudMessageSpy).toHaveBeenCalledWith(true)
expect(UserSettings.hideCloudMessage).toBe(true)
})
})

View File

@ -4,7 +4,6 @@ import React from 'react'
import {useIntl, FormattedMessage} from 'react-intl'
import {Utils} from '../../utils'
import IconButton from '../../widgets/buttons/iconButton'
import Button from '../../widgets/buttons/button'
@ -61,7 +60,7 @@ const CloudMessage = React.memo(() => {
}
}
if (Utils.isFocalboardPlugin() || cloudMessageCanceled) {
if (cloudMessageCanceled) {
return null
}

View File

@ -7,7 +7,6 @@ import {FormattedMessage} from 'react-intl'
import {useMeasurePunchouts} from '../../tutorial_tour_tip/hooks'
import './add_comments.scss'
import {Utils} from '../../../utils'
import addComment from '../../../../static/comment.gif'
import {CardTourSteps, TOUR_CARD} from '../index'
@ -41,7 +40,7 @@ const AddCommentTourStep = (): JSX.Element | null => {
classname='AddCommentTourStep'
telemetryTag='tourPoint2b'
placement={'right-end'}
imageURL={Utils.buildURL(addComment, true)}
imageURL={addComment}
hideBackdrop={true}
/>
)

View File

@ -7,7 +7,6 @@ import {FormattedMessage} from 'react-intl'
import {useMeasurePunchouts} from '../../tutorial_tour_tip/hooks'
import './add_description.scss'
import {Utils} from '../../../utils'
import addDescription from '../../../../static/addDescription.png'
import {CardTourSteps, TOUR_CARD} from '../index'
@ -41,7 +40,7 @@ const AddDescriptionTourStep = (): JSX.Element | null => {
classname='AddDescriptionTourStep'
telemetryTag='tourPoint2c'
placement={'top-start'}
imageURL={Utils.buildURL(addDescription, true)}
imageURL={addDescription}
hideBackdrop={true}
/>
)

View File

@ -7,7 +7,6 @@ import {FormattedMessage} from 'react-intl'
import {useMeasurePunchouts} from '../../tutorial_tour_tip/hooks'
import './add_properties.scss'
import {Utils} from '../../../utils'
import addProperty from '../../../../static/addProperty.gif'
import {BaseTourSteps, CardTourSteps, TOUR_BASE, TOUR_CARD} from '../index'
@ -101,7 +100,7 @@ const AddPropertiesTourStep = (): JSX.Element | null => {
classname='AddPropertiesTourStep'
telemetryTag='tourPoint2a'
placement={'right-end'}
imageURL={Utils.buildURL(addProperty, true)}
imageURL={addProperty}
hideBackdrop={true}
/>
)

View File

@ -7,7 +7,6 @@ import {FormattedMessage} from 'react-intl'
import {useMeasurePunchouts} from '../../tutorial_tour_tip/hooks'
import './add_view.scss'
import {Utils} from '../../../utils'
import changeViews from '../../../../static/changeViews.gif'
import {BoardTourSteps, TOUR_BOARD} from '../index'
@ -41,7 +40,7 @@ const AddViewTourStep = (): JSX.Element => {
classname='AddViewTourStep'
telemetryTag='tourPoint3a'
placement={'bottom-start'}
imageURL={Utils.buildURL(changeViews, true)}
imageURL={changeViews}
hideBackdrop={false}
/>
)

View File

@ -7,7 +7,6 @@ import {FormattedMessage} from 'react-intl'
import {useMeasurePunchouts} from '../../tutorial_tour_tip/hooks'
import './copy_link.scss'
import {Utils} from '../../../utils'
import copyLink from '../../../../static/copyLink.gif'
import {BoardTourSteps, TOUR_BOARD} from '../index'
@ -42,7 +41,7 @@ const CopyLinkTourStep = (): JSX.Element | null => {
classname='CopyLinkTourStep'
telemetryTag='tourPoint3b'
placement={'right-start'}
imageURL={Utils.buildURL(copyLink, true)}
imageURL={copyLink}
hideBackdrop={true}
/>
)

View File

@ -7,7 +7,6 @@ import {FormattedMessage} from 'react-intl'
import {useMeasurePunchouts} from '../../tutorial_tour_tip/hooks'
import './shareBoard.scss'
import {Utils} from '../../../utils'
import shareBoard from '../../../../static/share.gif'
import {BoardTourSteps, TOUR_BOARD} from '../index'
@ -45,7 +44,7 @@ const ShareBoardTourStep = (): JSX.Element | null => {
classname='ShareBoardTourStep'
telemetryTag='tourPoint2b'
placement={'bottom-end'}
imageURL={Utils.buildURL(shareBoard, true)}
imageURL={shareBoard}
hideBackdrop={true}
/>
)

View File

@ -281,8 +281,6 @@ exports[`src/components/shareBoard/channelPermissionsRow should match snapshot i
exports[`src/components/shareBoard/channelPermissionsRow should match snapshot when board has no channel id 1`] = `<div />`;
exports[`src/components/shareBoard/channelPermissionsRow should match snapshot when no plugin mode 1`] = `<div />`;
exports[`src/components/shareBoard/channelPermissionsRow should match snapshot with menu open 1`] = `
<div>
<div

View File

@ -1,215 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`src/components/shareBoard/teamPermissionsRow should match snapshot 1`] = `
<div>
<div
class="user-item"
>
<div
class="user-item__content"
>
<div
class="ml-3"
>
<strong>
Everyone at Test Team Team
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper override menuOpened"
role="button"
>
<button
class="user-item__button"
>
None
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
<div
class="Menu noselect left "
>
<div
class="menu-contents"
>
<div
class="menu-options"
>
<div>
<div
aria-label="Editor"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Editor
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Commenter"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Commenter
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Viewer"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Viewer
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="None"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<svg
class="CheckIcon Icon"
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="20,60 40,80 80,40"
/>
</svg>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
None
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
<div
class="menu-spacer hideOnWidescreen"
/>
<div
class="menu-options hideOnWidescreen"
>
<div
aria-label="Cancel"
class="MenuOption TextOption menu-option menu-cancel"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Cancel
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`src/components/shareBoard/teamPermissionsRow should match snapshot in plugin mode 1`] = `
<div>
<div

View File

@ -1,256 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`src/components/shareBoard/userPermissionsRow should match snapshot 1`] = `
<div>
<div
class="user-item"
>
<div
class="user-item__content"
>
<div
class="ml-3"
>
<strong />
<strong
class="ml-2 text-light"
>
@username_1
</strong>
<strong
class="ml-2 text-light"
>
(You)
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper override menuOpened"
role="button"
>
<button
class="user-item__button"
>
Admin
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
<div
class="Menu noselect left "
style="top: 40px;"
>
<div
class="menu-contents"
>
<div
class="menu-options"
>
<div>
<div
aria-label="Viewer"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Viewer
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Commenter"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Commenter
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Editor"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Editor
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Admin"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<svg
class="CheckIcon Icon"
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="20,60 40,80 80,40"
/>
</svg>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Admin
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
class="MenuOption MenuSeparator menu-separator"
/>
</div>
<div>
<div
aria-label="Remove member"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Remove member
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
<div
class="menu-spacer hideOnWidescreen"
/>
<div
class="menu-options hideOnWidescreen"
>
<div
aria-label="Cancel"
class="MenuOption TextOption menu-option menu-cancel"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Cancel
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`src/components/shareBoard/userPermissionsRow should match snapshot in plugin mode 1`] = `
<div>
<div
@ -728,263 +477,3 @@ exports[`src/components/shareBoard/userPermissionsRow should match snapshot in t
</div>
</div>
`;
exports[`src/components/shareBoard/userPermissionsRow should match snapshot-admin 1`] = `
<div>
<div
class="user-item"
>
<div
class="user-item__content"
>
<div
class="ml-3"
>
<strong />
<strong
class="ml-2 text-light"
>
@username_1
</strong>
<strong
class="ml-2 text-light"
>
(You)
</strong>
<div
class="AdminBadge"
>
<div
class="AdminBadge__box"
>
Admin
</div>
</div>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper override menuOpened"
role="button"
>
<button
class="user-item__button"
>
Admin
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
<div
class="Menu noselect left "
style="top: 40px;"
>
<div
class="menu-contents"
>
<div
class="menu-options"
>
<div>
<div
aria-label="Viewer"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Viewer
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Commenter"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Commenter
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Editor"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Editor
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Admin"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<svg
class="CheckIcon Icon"
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="20,60 40,80 80,40"
/>
</svg>
</div>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Admin
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
class="MenuOption MenuSeparator menu-separator"
/>
</div>
<div>
<div
aria-label="Remove member"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Remove member
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
<div
class="menu-spacer hideOnWidescreen"
/>
<div
class="menu-options hideOnWidescreen"
>
<div
aria-label="Cancel"
class="MenuOption TextOption menu-option menu-cancel"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-option__content"
>
<div
class="menu-name"
>
Cancel
</div>
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -14,7 +14,6 @@ import {Channel} from '../../store/channels'
import {TestBlockFactory} from '../../test/testBlockFactory'
import {mockStateStore, wrapDNDIntl} from '../../testUtils'
import client from '../../octoClient'
import {Utils} from '../../utils'
import ChannelPermissionsRow from './channelPermissionsRow'
@ -22,11 +21,9 @@ jest.useFakeTimers()
const boardId = '1'
jest.mock('../../utils')
jest.mock('../../octoClient')
const mockedOctoClient = mocked(client, true)
const mockedUtils = mocked(Utils, true)
const board = TestBlockFactory.createBoard()
board.id = boardId
@ -80,7 +77,6 @@ describe('src/components/shareBoard/channelPermissionsRow', () => {
test('should match snapshot', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const store = mockStateStore([thunk], state)
await act(async () => {
const result = render(
@ -98,7 +94,6 @@ describe('src/components/shareBoard/channelPermissionsRow', () => {
test('should match snapshot with unknown channel', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
mockedOctoClient.getChannel.mockResolvedValue(undefined)
const store = mockStateStore([thunk], state)
await act(async () => {
@ -117,7 +112,6 @@ describe('src/components/shareBoard/channelPermissionsRow', () => {
test('should match snapshot with menu open', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const store = mockStateStore([thunk], state)
await act(async () => {
const result = render(
@ -137,27 +131,8 @@ describe('src/components/shareBoard/channelPermissionsRow', () => {
expect(container).toMatchSnapshot()
})
test('should match snapshot when no plugin mode', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(false)
const store = mockStateStore([thunk], state)
await act(async () => {
const result = render(
wrapDNDIntl(
<ReduxProvider store={store}>
<ChannelPermissionsRow/>
</ReduxProvider>),
{wrapper: MemoryRouter},
)
container = result.container
})
expect(container).toMatchSnapshot()
})
test('should match snapshot when board has no channel id', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const newState = {
...state,
boards: {
@ -184,7 +159,6 @@ describe('src/components/shareBoard/channelPermissionsRow', () => {
test('should match snapshot in plugin mode', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const store = mockStateStore([thunk], state)
await act(async () => {
const result = render(
@ -206,7 +180,6 @@ describe('src/components/shareBoard/channelPermissionsRow', () => {
test('should match snapshot in template', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const testState = {
...state,
boards: {

View File

@ -44,7 +44,7 @@ const ChannelPermissionsRow = (props: Props): JSX.Element => {
}
useEffect(() => {
if (!Utils.isFocalboardPlugin() || !board.channelId) {
if (!board.channelId) {
setLinkedChannel(null)
return
}

View File

@ -24,6 +24,7 @@ jest.useFakeTimers()
const boardId = '1'
const workspaceId: string|undefined = boardId
const viewId = boardId
const teamId = 'team-id'
jest.mock('../../octoClient')
jest.mock('../../utils')
@ -50,7 +51,7 @@ jest.mock('react-router', () => {
const board = TestBlockFactory.createBoard()
board.id = boardId
board.teamId = 'team-id'
board.teamId = teamId
board.cardProperties = [
{
id: 'property1',
@ -128,7 +129,7 @@ describe('src/components/shareBoard/shareBoard', () => {
const state = {
teams: {
current: {id: 'team-id', title: 'Test Team'},
current: {id: teamId, title: 'Test Team'},
},
users: {
me,
@ -187,9 +188,11 @@ describe('src/components/shareBoard/shareBoard', () => {
const store = mockStateStore([thunk], state)
beforeEach(() => {
jest.clearAllMocks()
mockedUtils.buildURL.mockImplementation((path) => (w.baseURL || '') + path)
// mockedUtils.buildURL.mockImplementation((path) => (w.baseURL || '') + path)
params = {
teamId,
boardId,
viewId,
workspaceId,
@ -438,33 +441,6 @@ describe('src/components/shareBoard/shareBoard', () => {
expect(container).toMatchSnapshot()
})
test('should match snapshot with sharing and without workspaceId and subpath', async () => {
w.baseURL = '/test-subpath/plugins/boards'
const sharing: ISharing = {
id: boardId,
enabled: true,
token: 'oneToken',
}
params = {
boardId,
viewId,
}
mockedOctoClient.getSharing.mockResolvedValue(sharing)
let container
await act(async () => {
const result = render(wrapDNDIntl(
<ReduxProvider store={store}>
<ShareBoard
onClose={jest.fn()}
enableSharedBoards={true}
/>
</ReduxProvider>),
{wrapper: MemoryRouter})
container = result.container
})
expect(container).toMatchSnapshot()
})
test('should match snapshot with sharing and subpath', async () => {
w.baseURL = '/test-subpath/plugins/boards'
const sharing: ISharing = {
@ -495,7 +471,6 @@ describe('src/components/shareBoard/shareBoard', () => {
token: '',
}
mockedOctoClient.getSharing.mockResolvedValue(sharing)
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
mockedUtils.getUserDisplayName.mockImplementation((u) => u.username)
const users: IUser[] = [
@ -596,7 +571,6 @@ describe('src/components/shareBoard/shareBoard', () => {
token: '',
}
mockedOctoClient.getSharing.mockResolvedValue(sharing)
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
let container: Element | DocumentFragment | null = null
await act(async () => {
@ -671,7 +645,6 @@ describe('src/components/shareBoard/shareBoard', () => {
token: '',
}
mockedOctoClient.getSharing.mockResolvedValue(sharing)
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
mockedUtils.getUserDisplayName.mockImplementation((u) => u.username)
const users: IUser[] = [

View File

@ -117,7 +117,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element {
const [publish, setPublish] = useState(false)
const intl = useIntl()
const match = useRouteMatch<{teamId?: string, boardId: string, viewId: string}>()
const match = useRouteMatch<{teamId: string, boardId: string, viewId: string}>()
const hasSharePermissions = useHasPermissions(board.teamId, boardId, [Permission.ShareBoard])
@ -254,33 +254,19 @@ export default function ShareBoardDialog(props: Props): JSX.Element {
shareUrl.searchParams.set('r', readToken)
const boardUrl = new URL(window.location.toString())
if (match.params.teamId) {
const newPath = generatePath('/team/:teamId/shared/:boardId/:viewId', {
boardId: match.params.boardId,
viewId: match.params.viewId,
teamId: match.params.teamId,
})
shareUrl.pathname = Utils.buildURL(newPath)
const newPath = generatePath('/team/:teamId/shared/:boardId/:viewId', {
boardId: match.params.boardId,
viewId: match.params.viewId,
teamId: match.params.teamId,
})
shareUrl.pathname = newPath
const boardPath = generatePath('/team/:teamId/:boardId/:viewId', {
boardId: match.params.boardId,
viewId: match.params.viewId,
teamId: match.params.teamId,
})
boardUrl.pathname = Utils.getFrontendBaseURL() + boardPath
} else {
const newPath = generatePath('/shared/:boardId/:viewId', {
boardId: match.params.boardId,
viewId: match.params.viewId,
})
shareUrl.pathname = Utils.buildURL(newPath)
boardUrl.pathname = Utils.buildURL(
generatePath(':boardId/:viewId', {
boardId: match.params.boardId,
viewId: match.params.viewId,
},
))
}
const boardPath = generatePath('/team/:teamId/:boardId/:viewId', {
boardId: match.params.boardId,
viewId: match.params.viewId,
teamId: match.params.teamId,
})
boardUrl.pathname = Utils.getFrontendBaseURL() + boardPath
const shareBoardTitle = (
<FormattedMessage
@ -301,12 +287,10 @@ export default function ShareBoardDialog(props: Props): JSX.Element {
const user = userOrChannel as IUser
return (
<div className='user-item'>
{Utils.isFocalboardPlugin() &&
<img
src={Utils.getProfilePicture(user.id)}
className='user-item__img'
/>
}
<img
src={Utils.getProfilePicture(user.id)}
className='user-item__img'
/>
<div className='ml-3'>
<strong>{Utils.getUserDisplayName(user, clientConfig.teammateNameDisplay)}</strong>
<strong className='ml-2 text-light'>{`@${user.username}`}</strong>
@ -317,10 +301,6 @@ export default function ShareBoardDialog(props: Props): JSX.Element {
)
}
if (!Utils.isFocalboardPlugin()) {
return null
}
const channel = userOrChannel as Channel
return (
<div className='user-item'>
@ -380,22 +360,18 @@ export default function ShareBoardDialog(props: Props): JSX.Element {
}}
loadOptions={async (inputValue: string) => {
const result = []
if (Utils.isFocalboardPlugin()) {
const excludeBots = true
const users = await client.searchTeamUsers(inputValue, excludeBots)
if (users) {
result.push({label: intl.formatMessage({id: 'shareBoard.members-select-group', defaultMessage: 'Members'}), options: users || []})
}
if (!board.isTemplate) {
const channels = await client.searchUserChannels(match.params.teamId || '', inputValue)
if (channels) {
result.push({label: intl.formatMessage({id: 'shareBoard.channels-select-group', defaultMessage: 'Channels'}), options: channels || []})
}
}
} else {
const users = await client.searchTeamUsers(inputValue) || []
result.push(...users)
const excludeBots = true
const users = await client.searchTeamUsers(inputValue, excludeBots)
if (users) {
result.push({label: intl.formatMessage({id: 'shareBoard.members-select-group', defaultMessage: 'Members'}), options: users || []})
}
if (!board.isTemplate) {
const channels = await client.searchUserChannels(match.params.teamId || '', inputValue)
if (channels) {
result.push({label: intl.formatMessage({id: 'shareBoard.channels-select-group', defaultMessage: 'Channels'}), options: channels || []})
}
}
return result
}}
components={{DropdownIndicator: () => null, IndicatorSeparator: () => null}}

View File

@ -7,7 +7,6 @@ import {generatePath, useRouteMatch, useHistory} from 'react-router-dom'
import Button from '../../widgets/buttons/button'
import TelemetryClient, {TelemetryActions, TelemetryCategory} from '../../telemetry/telemetryClient'
import {Utils} from '../../utils'
import './shareBoardLoginButton.scss'
@ -15,19 +14,12 @@ const ShareBoardLoginButton = () => {
const match = useRouteMatch<{teamId: string, boardId: string, viewId?: string, cardId?: string}>()
const history = useHistory()
let redirectQueryParam = 'r=' + encodeURIComponent(generatePath('/:boardId?/:viewId?/:cardId?', match.params))
if (Utils.isFocalboardLegacy()) {
redirectQueryParam = 'redirect_to=' + encodeURIComponent(generatePath('/boards/team/:teamId/:boardId?/:viewId?/:cardId?', match.params))
}
const redirectQueryParam = 'r=' + encodeURIComponent(generatePath('/:boardId?/:viewId?/:cardId?', match.params))
const loginPath = '/login?' + redirectQueryParam
const onLoginClick = useCallback(() => {
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.ShareBoardLogin)
if (Utils.isFocalboardLegacy()) {
location.assign(loginPath)
} else {
history.push(loginPath)
}
history.push(loginPath)
}, [])
return (

View File

@ -7,12 +7,10 @@ import thunk from 'redux-thunk'
import React from 'react'
import {MemoryRouter} from 'react-router'
import {mocked} from 'jest-mock'
import {IUser} from '../../user'
import {TestBlockFactory} from '../../test/testBlockFactory'
import {mockStateStore, wrapDNDIntl} from '../../testUtils'
import {Utils} from '../../utils'
import {MemberRole} from '../../blocks/board'
@ -24,8 +22,6 @@ const boardId = '1'
jest.mock('../../utils')
const mockedUtils = mocked(Utils, true)
const board = TestBlockFactory.createBoard()
board.id = boardId
board.teamId = 'team-id'
@ -76,31 +72,8 @@ describe('src/components/shareBoard/teamPermissionsRow', () => {
jest.clearAllMocks()
})
test('should match snapshot', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(false)
const store = mockStateStore([thunk], state)
await act(async () => {
const result = render(
wrapDNDIntl(
<ReduxProvider store={store}>
<TeamPermissionsRow/>
</ReduxProvider>),
{wrapper: MemoryRouter},
)
container = result.container
})
const buttonElement = container?.querySelector('.user-item__button')
expect(buttonElement).toBeDefined()
userEvent.click(buttonElement!)
expect(container).toMatchSnapshot()
})
test('should match snapshot in plugin mode', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const store = mockStateStore([thunk], state)
await act(async () => {
const result = render(
@ -122,7 +95,6 @@ describe('src/components/shareBoard/teamPermissionsRow', () => {
test('should match snapshot in template', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const testState = {
...state,
boards: {

View File

@ -15,7 +15,6 @@ import {useAppSelector} from '../../store/hooks'
import {getCurrentTeam} from '../../store/teams'
import {getCurrentBoard} from '../../store/boards'
import {Permission} from '../../constants'
import {Utils} from '../../utils'
import BoardPermissionGate from '../permissions/boardPermissionGate'
import ConfirmationDialogBox from '../confirmationDialogBox'
@ -90,12 +89,10 @@ const TeamPermissionsRow = (): JSX.Element => {
<div className='user-item'>
{changeRoleConfirmation && confirmationDialog}
<div className='user-item__content'>
{Utils.isFocalboardPlugin() &&
<CompassIcon
icon='mattermost'
className='user-item__img'
/>
}
<CompassIcon
icon='mattermost'
className='user-item__img'
/>
<div className='ml-3'><strong>{intl.formatMessage({id: 'ShareBoard.teamPermissionsText', defaultMessage: 'Everyone at {teamName} Team'}, {teamName: team?.title})}</strong></div>
</div>
<div>

View File

@ -7,14 +7,12 @@ import thunk from 'redux-thunk'
import React from 'react'
import {MemoryRouter} from 'react-router'
import {mocked} from 'jest-mock'
import {BoardMember} from '../../blocks/board'
import {IUser} from '../../user'
import {TestBlockFactory} from '../../test/testBlockFactory'
import {mockStateStore, wrapDNDIntl} from '../../testUtils'
import {Utils} from '../../utils'
import UserPermissionsRow from './userPermissionsRow'
@ -24,8 +22,6 @@ const boardId = '1'
jest.mock('../../utils')
const mockedUtils = mocked(Utils, true)
const board = TestBlockFactory.createBoard()
board.id = boardId
board.teamId = 'team-id'
@ -75,70 +71,8 @@ describe('src/components/shareBoard/userPermissionsRow', () => {
jest.clearAllMocks()
})
test('should match snapshot', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(false)
const store = mockStateStore([thunk], state)
await act(async () => {
const result = render(
wrapDNDIntl(
<ReduxProvider store={store}>
<UserPermissionsRow
user={me}
isMe={true}
member={state.boards.myBoardMemberships[board.id] as BoardMember}
teammateNameDisplay={'test'}
onDeleteBoardMember={() => {}}
onUpdateBoardMember={() => {}}
/>
</ReduxProvider>),
{wrapper: MemoryRouter},
)
container = result.container
})
const buttonElement = container?.querySelector('.user-item__button')
expect(buttonElement).toBeDefined()
userEvent.click(buttonElement!)
expect(container).toMatchSnapshot()
})
test('should match snapshot-admin', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(false)
const store = mockStateStore([thunk], state)
const newMe = Object.assign({}, me)
newMe.permissions = ['manage_system']
await act(async () => {
const result = render(
wrapDNDIntl(
<ReduxProvider store={store}>
<UserPermissionsRow
user={newMe}
isMe={true}
member={state.boards.myBoardMemberships[board.id] as BoardMember}
teammateNameDisplay={'test'}
onDeleteBoardMember={() => {}}
onUpdateBoardMember={() => {}}
/>
</ReduxProvider>),
{wrapper: MemoryRouter},
)
container = result.container
})
const buttonElement = container?.querySelector('.user-item__button')
expect(buttonElement).toBeDefined()
userEvent.click(buttonElement!)
expect(container).toMatchSnapshot()
})
test('should match snapshot in plugin mode', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const store = mockStateStore([thunk], state)
await act(async () => {
const result = render(
@ -167,7 +101,6 @@ describe('src/components/shareBoard/userPermissionsRow', () => {
test('should match snapshot in template', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const testState = {
...state,
boards: {

View File

@ -55,12 +55,10 @@ const UserPermissionsRow = (props: Props): JSX.Element => {
ref={menuWrapperRef}
>
<div className='user-item__content'>
{Utils.isFocalboardPlugin() &&
<img
src={Utils.getProfilePicture(user.id)}
className='user-item__img'
/>
}
<img
src={Utils.getProfilePicture(user.id)}
className='user-item__img'
/>
<div className='ml-3'>
<strong>{Utils.getUserDisplayName(user, teammateNameDisplay)}</strong>
<strong className='ml-2 text-light'>{`@${user.username}`}</strong>

View File

@ -6,62 +6,8 @@ exports[`components/sidebarSidebar dont show hidden boards 1`] = `
class="Sidebar octo-sidebar"
>
<div
class="octo-sidebar-header"
class="WorkspaceTitle"
>
<div
class="heading"
>
<div
class="SidebarUserMenu"
>
<div
class="ModalWrapper"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="logo"
>
<div
class="logo-title"
>
<svg
class="FocalboardLogoIcon Icon"
version="1.1"
viewBox="0 0 52.589677 64"
x="0px"
y="0px"
>
<path
d="m 33.071077,12.069805 c -12.663,-3.4670001 -27.0530002,3.289 -31.6760002,16.943 -4.655,13.75 2.719,28.67 16.4690002,33.325 13.75,4.655 28.67,-2.719 33.326,-16.469 3.804,-11.235 -0.462,-22.701 -8.976,-29.249 l -0.46,4.871 h -0.001 c 4.631,4.896 6.709,11.941 4.325,18.985 -3.362,9.931 -14.447,15.151 -24.76,11.66 -10.313,-3.49 -15.9480002,-14.37 -12.5870002,-24.301 2.9750002,-8.788 11.9980002,-13.715 20.7430002,-12.625 v -10e-4 z m -6.175,16.488 c 3.456,-0.665 6.986,2.754 5.762,6.37 -0.854,2.522 -3.67,3.85 -6.291,2.962 -2.62,-0.887 -4.052,-3.651 -3.197,-6.174 0.573,-1.697 2.034,-2.852 3.726,-3.158 z m -1.285,-4.944 c -1.786,0.323 -3.45,1.104 -4.812,2.258 -1.299,1.101 -2.319,2.545 -2.898,4.258 -0.879,2.597 -0.579,5.323 0.617,7.632 1.206,2.329 3.325,4.234 6.07,5.164 2.744,0.929 5.584,0.701 7.959,-0.417 2.352,-1.107 4.246,-3.091 5.125,-5.688 0.555,-1.639 0.633,-3.254 0.344,-4.761 -0.21,-1.093 -0.615,-2.134 -1.174,-3.091 l 1.019,-5.107 c 0.189,0.187 0.374,0.378 0.552,0.574 1.75,1.919 3.008,4.283 3.508,6.877 0.415,2.154 0.304,4.457 -0.484,6.784 -1.239,3.661 -3.898,6.453 -7.193,8.005 -3.273,1.541 -7.175,1.858 -10.93,0.588 -3.754,-1.271 -6.661,-3.895 -8.326,-7.108 -1.674,-3.233 -2.09,-7.065 -0.851,-10.728 0.819,-2.419 2.26,-4.46 4.097,-6.016 1.88,-1.593 4.181,-2.673 6.656,-3.125 l -0.001,-0.004 c 1.759,-0.339 3.522,-0.313 5.213,0.016 l -3.583,3.761 c -0.294,0.028 -0.588,0.071 -0.883,0.127 h -0.025 z"
/>
<polygon
points="26.057,32.594 37.495,11.658 36.79,8.44 41.066,0.207 43.683,4.611 48.803,4.434 44.185,12.48 40.902,13.697 29.542,34.491 "
transform="translate(7.6780426e-5,-0.21919512)"
/>
</svg>
<span>
Focalboard
</span>
<div
class="versionFrame"
>
<div
class="version"
title="v7.9.0"
>
v7.9.0
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="octo-spacer"
/>
@ -87,9 +33,6 @@ exports[`components/sidebarSidebar dont show hidden boards 1`] = `
</button>
</div>
</div>
<div
class="WorkspaceTitle"
/>
<div
class="BoardsSwitcherWrapper"
>
@ -105,6 +48,20 @@ exports[`components/sidebarSidebar dont show hidden boards 1`] = `
</span>
</div>
</div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="IconButton style--inverted add-board-icon size--small"
type="button"
>
<i
class="CompassIcon icon-plus AddIcon"
/>
</button>
</div>
</div>
<div
class="octo-sidebar-list"
@ -177,26 +134,6 @@ exports[`components/sidebarSidebar dont show hidden boards 1`] = `
<div
class="octo-spacer"
/>
<div
class="add-board"
>
+ Add board
</div>
<div
class="SidebarSettingsMenu"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="menu-entry"
>
Settings
</div>
</div>
</div>
</div>
</div>
`;
@ -207,62 +144,8 @@ exports[`components/sidebarSidebar should assign default category if current boa
class="Sidebar octo-sidebar"
>
<div
class="octo-sidebar-header"
class="WorkspaceTitle"
>
<div
class="heading"
>
<div
class="SidebarUserMenu"
>
<div
class="ModalWrapper"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="logo"
>
<div
class="logo-title"
>
<svg
class="FocalboardLogoIcon Icon"
version="1.1"
viewBox="0 0 52.589677 64"
x="0px"
y="0px"
>
<path
d="m 33.071077,12.069805 c -12.663,-3.4670001 -27.0530002,3.289 -31.6760002,16.943 -4.655,13.75 2.719,28.67 16.4690002,33.325 13.75,4.655 28.67,-2.719 33.326,-16.469 3.804,-11.235 -0.462,-22.701 -8.976,-29.249 l -0.46,4.871 h -0.001 c 4.631,4.896 6.709,11.941 4.325,18.985 -3.362,9.931 -14.447,15.151 -24.76,11.66 -10.313,-3.49 -15.9480002,-14.37 -12.5870002,-24.301 2.9750002,-8.788 11.9980002,-13.715 20.7430002,-12.625 v -10e-4 z m -6.175,16.488 c 3.456,-0.665 6.986,2.754 5.762,6.37 -0.854,2.522 -3.67,3.85 -6.291,2.962 -2.62,-0.887 -4.052,-3.651 -3.197,-6.174 0.573,-1.697 2.034,-2.852 3.726,-3.158 z m -1.285,-4.944 c -1.786,0.323 -3.45,1.104 -4.812,2.258 -1.299,1.101 -2.319,2.545 -2.898,4.258 -0.879,2.597 -0.579,5.323 0.617,7.632 1.206,2.329 3.325,4.234 6.07,5.164 2.744,0.929 5.584,0.701 7.959,-0.417 2.352,-1.107 4.246,-3.091 5.125,-5.688 0.555,-1.639 0.633,-3.254 0.344,-4.761 -0.21,-1.093 -0.615,-2.134 -1.174,-3.091 l 1.019,-5.107 c 0.189,0.187 0.374,0.378 0.552,0.574 1.75,1.919 3.008,4.283 3.508,6.877 0.415,2.154 0.304,4.457 -0.484,6.784 -1.239,3.661 -3.898,6.453 -7.193,8.005 -3.273,1.541 -7.175,1.858 -10.93,0.588 -3.754,-1.271 -6.661,-3.895 -8.326,-7.108 -1.674,-3.233 -2.09,-7.065 -0.851,-10.728 0.819,-2.419 2.26,-4.46 4.097,-6.016 1.88,-1.593 4.181,-2.673 6.656,-3.125 l -0.001,-0.004 c 1.759,-0.339 3.522,-0.313 5.213,0.016 l -3.583,3.761 c -0.294,0.028 -0.588,0.071 -0.883,0.127 h -0.025 z"
/>
<polygon
points="26.057,32.594 37.495,11.658 36.79,8.44 41.066,0.207 43.683,4.611 48.803,4.434 44.185,12.48 40.902,13.697 29.542,34.491 "
transform="translate(7.6780426e-5,-0.21919512)"
/>
</svg>
<span>
Focalboard
</span>
<div
class="versionFrame"
>
<div
class="version"
title="v7.9.0"
>
v7.9.0
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="octo-spacer"
/>
@ -288,9 +171,6 @@ exports[`components/sidebarSidebar should assign default category if current boa
</button>
</div>
</div>
<div
class="WorkspaceTitle"
/>
<div
class="BoardsSwitcherWrapper"
>
@ -306,6 +186,20 @@ exports[`components/sidebarSidebar should assign default category if current boa
</span>
</div>
</div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="IconButton style--inverted add-board-icon size--small"
type="button"
>
<i
class="CompassIcon icon-plus AddIcon"
/>
</button>
</div>
</div>
<div
class="octo-sidebar-list"
@ -433,26 +327,6 @@ exports[`components/sidebarSidebar should assign default category if current boa
<div
class="octo-spacer"
/>
<div
class="add-board"
>
+ Add board
</div>
<div
class="SidebarSettingsMenu"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="menu-entry"
>
Settings
</div>
</div>
</div>
</div>
</div>
`;
@ -463,62 +337,8 @@ exports[`components/sidebarSidebar shouldnt do any category assignment is board
class="Sidebar octo-sidebar"
>
<div
class="octo-sidebar-header"
class="WorkspaceTitle"
>
<div
class="heading"
>
<div
class="SidebarUserMenu"
>
<div
class="ModalWrapper"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="logo"
>
<div
class="logo-title"
>
<svg
class="FocalboardLogoIcon Icon"
version="1.1"
viewBox="0 0 52.589677 64"
x="0px"
y="0px"
>
<path
d="m 33.071077,12.069805 c -12.663,-3.4670001 -27.0530002,3.289 -31.6760002,16.943 -4.655,13.75 2.719,28.67 16.4690002,33.325 13.75,4.655 28.67,-2.719 33.326,-16.469 3.804,-11.235 -0.462,-22.701 -8.976,-29.249 l -0.46,4.871 h -0.001 c 4.631,4.896 6.709,11.941 4.325,18.985 -3.362,9.931 -14.447,15.151 -24.76,11.66 -10.313,-3.49 -15.9480002,-14.37 -12.5870002,-24.301 2.9750002,-8.788 11.9980002,-13.715 20.7430002,-12.625 v -10e-4 z m -6.175,16.488 c 3.456,-0.665 6.986,2.754 5.762,6.37 -0.854,2.522 -3.67,3.85 -6.291,2.962 -2.62,-0.887 -4.052,-3.651 -3.197,-6.174 0.573,-1.697 2.034,-2.852 3.726,-3.158 z m -1.285,-4.944 c -1.786,0.323 -3.45,1.104 -4.812,2.258 -1.299,1.101 -2.319,2.545 -2.898,4.258 -0.879,2.597 -0.579,5.323 0.617,7.632 1.206,2.329 3.325,4.234 6.07,5.164 2.744,0.929 5.584,0.701 7.959,-0.417 2.352,-1.107 4.246,-3.091 5.125,-5.688 0.555,-1.639 0.633,-3.254 0.344,-4.761 -0.21,-1.093 -0.615,-2.134 -1.174,-3.091 l 1.019,-5.107 c 0.189,0.187 0.374,0.378 0.552,0.574 1.75,1.919 3.008,4.283 3.508,6.877 0.415,2.154 0.304,4.457 -0.484,6.784 -1.239,3.661 -3.898,6.453 -7.193,8.005 -3.273,1.541 -7.175,1.858 -10.93,0.588 -3.754,-1.271 -6.661,-3.895 -8.326,-7.108 -1.674,-3.233 -2.09,-7.065 -0.851,-10.728 0.819,-2.419 2.26,-4.46 4.097,-6.016 1.88,-1.593 4.181,-2.673 6.656,-3.125 l -0.001,-0.004 c 1.759,-0.339 3.522,-0.313 5.213,0.016 l -3.583,3.761 c -0.294,0.028 -0.588,0.071 -0.883,0.127 h -0.025 z"
/>
<polygon
points="26.057,32.594 37.495,11.658 36.79,8.44 41.066,0.207 43.683,4.611 48.803,4.434 44.185,12.48 40.902,13.697 29.542,34.491 "
transform="translate(7.6780426e-5,-0.21919512)"
/>
</svg>
<span>
Focalboard
</span>
<div
class="versionFrame"
>
<div
class="version"
title="v7.9.0"
>
v7.9.0
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="octo-spacer"
/>
@ -544,9 +364,6 @@ exports[`components/sidebarSidebar shouldnt do any category assignment is board
</button>
</div>
</div>
<div
class="WorkspaceTitle"
/>
<div
class="BoardsSwitcherWrapper"
>
@ -562,6 +379,20 @@ exports[`components/sidebarSidebar shouldnt do any category assignment is board
</span>
</div>
</div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="IconButton style--inverted add-board-icon size--small"
type="button"
>
<i
class="CompassIcon icon-plus AddIcon"
/>
</button>
</div>
</div>
<div
class="octo-sidebar-list"
@ -786,26 +617,6 @@ exports[`components/sidebarSidebar shouldnt do any category assignment is board
<div
class="octo-spacer"
/>
<div
class="add-board"
>
+ Add board
</div>
<div
class="SidebarSettingsMenu"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="menu-entry"
>
Settings
</div>
</div>
</div>
</div>
</div>
`;
@ -874,62 +685,8 @@ exports[`components/sidebarSidebar sidebar hidden 1`] = `
class="Sidebar octo-sidebar"
>
<div
class="octo-sidebar-header"
class="WorkspaceTitle"
>
<div
class="heading"
>
<div
class="SidebarUserMenu"
>
<div
class="ModalWrapper"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="logo"
>
<div
class="logo-title"
>
<svg
class="FocalboardLogoIcon Icon"
version="1.1"
viewBox="0 0 52.589677 64"
x="0px"
y="0px"
>
<path
d="m 33.071077,12.069805 c -12.663,-3.4670001 -27.0530002,3.289 -31.6760002,16.943 -4.655,13.75 2.719,28.67 16.4690002,33.325 13.75,4.655 28.67,-2.719 33.326,-16.469 3.804,-11.235 -0.462,-22.701 -8.976,-29.249 l -0.46,4.871 h -0.001 c 4.631,4.896 6.709,11.941 4.325,18.985 -3.362,9.931 -14.447,15.151 -24.76,11.66 -10.313,-3.49 -15.9480002,-14.37 -12.5870002,-24.301 2.9750002,-8.788 11.9980002,-13.715 20.7430002,-12.625 v -10e-4 z m -6.175,16.488 c 3.456,-0.665 6.986,2.754 5.762,6.37 -0.854,2.522 -3.67,3.85 -6.291,2.962 -2.62,-0.887 -4.052,-3.651 -3.197,-6.174 0.573,-1.697 2.034,-2.852 3.726,-3.158 z m -1.285,-4.944 c -1.786,0.323 -3.45,1.104 -4.812,2.258 -1.299,1.101 -2.319,2.545 -2.898,4.258 -0.879,2.597 -0.579,5.323 0.617,7.632 1.206,2.329 3.325,4.234 6.07,5.164 2.744,0.929 5.584,0.701 7.959,-0.417 2.352,-1.107 4.246,-3.091 5.125,-5.688 0.555,-1.639 0.633,-3.254 0.344,-4.761 -0.21,-1.093 -0.615,-2.134 -1.174,-3.091 l 1.019,-5.107 c 0.189,0.187 0.374,0.378 0.552,0.574 1.75,1.919 3.008,4.283 3.508,6.877 0.415,2.154 0.304,4.457 -0.484,6.784 -1.239,3.661 -3.898,6.453 -7.193,8.005 -3.273,1.541 -7.175,1.858 -10.93,0.588 -3.754,-1.271 -6.661,-3.895 -8.326,-7.108 -1.674,-3.233 -2.09,-7.065 -0.851,-10.728 0.819,-2.419 2.26,-4.46 4.097,-6.016 1.88,-1.593 4.181,-2.673 6.656,-3.125 l -0.001,-0.004 c 1.759,-0.339 3.522,-0.313 5.213,0.016 l -3.583,3.761 c -0.294,0.028 -0.588,0.071 -0.883,0.127 h -0.025 z"
/>
<polygon
points="26.057,32.594 37.495,11.658 36.79,8.44 41.066,0.207 43.683,4.611 48.803,4.434 44.185,12.48 40.902,13.697 29.542,34.491 "
transform="translate(7.6780426e-5,-0.21919512)"
/>
</svg>
<span>
Focalboard
</span>
<div
class="versionFrame"
>
<div
class="version"
title="v7.9.0"
>
v7.9.0
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="octo-spacer"
/>
@ -955,9 +712,6 @@ exports[`components/sidebarSidebar sidebar hidden 1`] = `
</button>
</div>
</div>
<div
class="WorkspaceTitle"
/>
<div
class="BoardsSwitcherWrapper"
>
@ -973,6 +727,20 @@ exports[`components/sidebarSidebar sidebar hidden 1`] = `
</span>
</div>
</div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="IconButton style--inverted add-board-icon size--small"
type="button"
>
<i
class="CompassIcon icon-plus AddIcon"
/>
</button>
</div>
</div>
<div
class="octo-sidebar-list"
@ -1080,26 +848,6 @@ exports[`components/sidebarSidebar sidebar hidden 1`] = `
<div
class="octo-spacer"
/>
<div
class="add-board"
>
+ Add board
</div>
<div
class="SidebarSettingsMenu"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="menu-entry"
>
Settings
</div>
</div>
</div>
</div>
</div>
`;
@ -1168,62 +916,8 @@ exports[`components/sidebarSidebar some categories hidden 1`] = `
class="Sidebar octo-sidebar"
>
<div
class="octo-sidebar-header"
class="WorkspaceTitle"
>
<div
class="heading"
>
<div
class="SidebarUserMenu"
>
<div
class="ModalWrapper"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="logo"
>
<div
class="logo-title"
>
<svg
class="FocalboardLogoIcon Icon"
version="1.1"
viewBox="0 0 52.589677 64"
x="0px"
y="0px"
>
<path
d="m 33.071077,12.069805 c -12.663,-3.4670001 -27.0530002,3.289 -31.6760002,16.943 -4.655,13.75 2.719,28.67 16.4690002,33.325 13.75,4.655 28.67,-2.719 33.326,-16.469 3.804,-11.235 -0.462,-22.701 -8.976,-29.249 l -0.46,4.871 h -0.001 c 4.631,4.896 6.709,11.941 4.325,18.985 -3.362,9.931 -14.447,15.151 -24.76,11.66 -10.313,-3.49 -15.9480002,-14.37 -12.5870002,-24.301 2.9750002,-8.788 11.9980002,-13.715 20.7430002,-12.625 v -10e-4 z m -6.175,16.488 c 3.456,-0.665 6.986,2.754 5.762,6.37 -0.854,2.522 -3.67,3.85 -6.291,2.962 -2.62,-0.887 -4.052,-3.651 -3.197,-6.174 0.573,-1.697 2.034,-2.852 3.726,-3.158 z m -1.285,-4.944 c -1.786,0.323 -3.45,1.104 -4.812,2.258 -1.299,1.101 -2.319,2.545 -2.898,4.258 -0.879,2.597 -0.579,5.323 0.617,7.632 1.206,2.329 3.325,4.234 6.07,5.164 2.744,0.929 5.584,0.701 7.959,-0.417 2.352,-1.107 4.246,-3.091 5.125,-5.688 0.555,-1.639 0.633,-3.254 0.344,-4.761 -0.21,-1.093 -0.615,-2.134 -1.174,-3.091 l 1.019,-5.107 c 0.189,0.187 0.374,0.378 0.552,0.574 1.75,1.919 3.008,4.283 3.508,6.877 0.415,2.154 0.304,4.457 -0.484,6.784 -1.239,3.661 -3.898,6.453 -7.193,8.005 -3.273,1.541 -7.175,1.858 -10.93,0.588 -3.754,-1.271 -6.661,-3.895 -8.326,-7.108 -1.674,-3.233 -2.09,-7.065 -0.851,-10.728 0.819,-2.419 2.26,-4.46 4.097,-6.016 1.88,-1.593 4.181,-2.673 6.656,-3.125 l -0.001,-0.004 c 1.759,-0.339 3.522,-0.313 5.213,0.016 l -3.583,3.761 c -0.294,0.028 -0.588,0.071 -0.883,0.127 h -0.025 z"
/>
<polygon
points="26.057,32.594 37.495,11.658 36.79,8.44 41.066,0.207 43.683,4.611 48.803,4.434 44.185,12.48 40.902,13.697 29.542,34.491 "
transform="translate(7.6780426e-5,-0.21919512)"
/>
</svg>
<span>
Focalboard
</span>
<div
class="versionFrame"
>
<div
class="version"
title="v7.9.0"
>
v7.9.0
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="octo-spacer"
/>
@ -1249,9 +943,6 @@ exports[`components/sidebarSidebar some categories hidden 1`] = `
</button>
</div>
</div>
<div
class="WorkspaceTitle"
/>
<div
class="BoardsSwitcherWrapper"
>
@ -1267,6 +958,20 @@ exports[`components/sidebarSidebar some categories hidden 1`] = `
</span>
</div>
</div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="IconButton style--inverted add-board-icon size--small"
type="button"
>
<i
class="CompassIcon icon-plus AddIcon"
/>
</button>
</div>
</div>
<div
class="octo-sidebar-list"
@ -1429,26 +1134,6 @@ exports[`components/sidebarSidebar some categories hidden 1`] = `
<div
class="octo-spacer"
/>
<div
class="add-board"
>
+ Add board
</div>
<div
class="SidebarSettingsMenu"
>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<div
class="menu-entry"
>
Settings
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -1,10 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useState} from 'react'
import {FormattedMessage} from 'react-intl'
import {DragDropContext, Droppable, DropResult} from 'react-beautiful-dnd'
import {getActiveThemeName, loadTheme} from '../../theme'
import {loadTheme} from '../../theme'
import IconButton from '../../widgets/buttons/iconButton'
import HamburgerIcon from '../../widgets/icons/hamburger'
import HideSidebarIcon from '../../widgets/icons/hideSidebar'
@ -48,8 +47,6 @@ import mutator from '../../mutator'
import {Board} from '../../blocks/board'
import SidebarCategory from './sidebarCategory'
import SidebarSettingsMenu from './sidebarSettingsMenu'
import SidebarUserMenu from './sidebarUserMenu'
type Props = {
activeBoardId?: string
@ -345,12 +342,8 @@ const Sidebar = (props: Props) => {
return (
<div className='Sidebar octo-sidebar'>
{!Utils.isFocalboardPlugin() &&
<div className='octo-sidebar-header'>
<div className='heading'>
<SidebarUserMenu/>
</div>
{team && team.id !== Constants.globalTeamId &&
<div className='WorkspaceTitle'>
<div className='octo-spacer'/>
<div className='sidebarSwitcher'>
<IconButton
@ -361,24 +354,6 @@ const Sidebar = (props: Props) => {
icon={<HideSidebarIcon/>}
/>
</div>
</div>}
{team && team.id !== Constants.globalTeamId &&
<div className='WorkspaceTitle'>
{Utils.isFocalboardPlugin() &&
<>
<div className='octo-spacer'/>
<div className='sidebarSwitcher'>
<IconButton
onClick={() => {
setUserHidden(true)
setHidden(true)
}}
icon={<HideSidebarIcon/>}
/>
</div>
</>
}
</div>
}
@ -425,22 +400,6 @@ const Sidebar = (props: Props) => {
</DragDropContext>
<div className='octo-spacer'/>
{
(!Utils.isFocalboardPlugin()) &&
<div
className='add-board'
onClick={props.onBoardTemplateSelectorOpen}
>
<FormattedMessage
id='Sidebar.add-board'
defaultMessage='+ Add board'
/>
</div>
}
{!Utils.isFocalboardPlugin() &&
<SidebarSettingsMenu activeTheme={getActiveThemeName()}/>}
</div>
)
}

View File

@ -1,51 +0,0 @@
.SidebarUserMenu {
.logo {
display: flex;
flex-direction: row;
align-items: center;
.logo-title {
font-family: Metropolis, sans-serif;
display: flex;
align-items: center;
font-size: 16px;
margin-right: 5px;
cursor: pointer;
.FocalboardLogoIcon {
fill: rgba(var(--sidebar-text-rgb), 1);
color: rgba(var(--sidebar-text-rgb), 1);
height: 24px;
width: 22px;
margin-right: 3px;
position: relative;
bottom: 2px;
}
span {
height: 32px;
}
}
.versionFrame {
display: flex;
flex-direction: column;
align-items: center;
margin-left: 8px;
}
.version {
font-size: 11px;
line-height: 11px;
font-weight: 500;
color: rgba(var(--sidebar-text-rgb), 0.8);
}
.versionBadge {
font-size: 10px;
line-height: 11px;
font-weight: 500;
color: rgba(var(--sidebar-text-rgb), 0.8);
}
}
}

View File

@ -1,113 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useState} from 'react'
import {useIntl} from 'react-intl'
import {useHistory} from 'react-router-dom'
import {Constants} from '../../constants'
import octoClient from '../../octoClient'
import {IUser} from '../../user'
import FocalboardLogoIcon from '../../widgets/icons/focalboard_logo'
import Menu from '../../widgets/menu'
import MenuWrapper from '../../widgets/menuWrapper'
import {getMe, setMe} from '../../store/users'
import {useAppSelector, useAppDispatch} from '../../store/hooks'
import {Utils} from '../../utils'
import ModalWrapper from '../modalWrapper'
import {IAppWindow} from '../../types'
import RegistrationLink from './registrationLink'
import './sidebarUserMenu.scss'
declare let window: IAppWindow
const SidebarUserMenu = () => {
const dispatch = useAppDispatch()
const history = useHistory()
const [showRegistrationLinkDialog, setShowRegistrationLinkDialog] = useState(false)
const user = useAppSelector<IUser|null>(getMe)
const intl = useIntl()
if (Utils.isFocalboardPlugin()) {
return <></>
}
return (
<div className='SidebarUserMenu'>
<ModalWrapper>
<MenuWrapper>
<div className='logo'>
<div className='logo-title'>
<FocalboardLogoIcon/>
<span>{'Focalboard'}</span>
<div className='versionFrame'>
<div
className='version'
title={`v${Constants.versionString}`}
>
{`v${Constants.versionString}`}
</div>
</div>
</div>
</div>
<Menu>
{user && user.username !== 'single-user' && <>
<Menu.Label><b>{user.username}</b></Menu.Label>
<Menu.Text
id='logout'
name={intl.formatMessage({id: 'Sidebar.logout', defaultMessage: 'Log out'})}
onClick={async () => {
await octoClient.logout()
dispatch(setMe(null))
history.push('/login')
}}
/>
<Menu.Text
id='changePassword'
name={intl.formatMessage({id: 'Sidebar.changePassword', defaultMessage: 'Change password'})}
onClick={async () => {
history.push('/change_password')
}}
/>
<Menu.Text
id='invite'
name={intl.formatMessage({id: 'Sidebar.invite-users', defaultMessage: 'Invite users'})}
onClick={async () => {
setShowRegistrationLinkDialog(true)
}}
/>
<Menu.Separator/>
</>}
<Menu.Text
id='about'
name={intl.formatMessage({id: 'Sidebar.about', defaultMessage: 'About Focalboard'})}
onClick={async () => {
window.open('https://www.focalboard.com?utm_source=webapp', '_blank')
// TODO: Review if this is needed in the future, this is to fix the problem with linux webview links
if (window.openInNewBrowser) {
window.openInNewBrowser('https://www.focalboard.com?utm_source=webapp')
}
}}
/>
</Menu>
</MenuWrapper>
{showRegistrationLinkDialog &&
<RegistrationLink
onClose={() => {
setShowRegistrationLinkDialog(false)
}}
/>
}
</ModalWrapper>
</div>
)
}
export default React.memo(SidebarUserMenu)

View File

@ -2,29 +2,17 @@
// See LICENSE.txt for license information.
import {render} from '@testing-library/react'
import React from 'react'
import {mocked} from 'jest-mock'
import {wrapDNDIntl} from '../testUtils'
import {Constants} from '../constants'
import {Utils} from '../utils'
import TopBar from './topBar'
Object.defineProperty(Constants, 'versionString', {value: '1.0.0'})
jest.mock('../utils')
const mockedUtils = mocked(Utils, true)
describe('src/components/topBar', () => {
beforeEach(jest.resetAllMocks)
test('should match snapshot for focalboardPlugin', () => {
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const {container} = render(wrapDNDIntl(
<TopBar/>,
))
expect(container).toMatchSnapshot()
})
test('should match snapshot for none focalboardPlugin', () => {
mockedUtils.isFocalboardPlugin.mockReturnValue(false)
const {container} = render(wrapDNDIntl(
<TopBar/>,
))

View File

@ -6,48 +6,17 @@ import React from 'react'
import './topBar.scss'
import {FormattedMessage} from 'react-intl'
import HelpIcon from '../widgets/icons/help'
import {Utils} from '../utils'
import {Constants} from '../constants'
const TopBar = (): JSX.Element => {
if (Utils.isFocalboardPlugin()) {
const feedbackUrl = 'https://www.focalboard.com/fwlink/feedback-boards.html?v=' + Constants.versionString
return (
<div
className='TopBar'
>
<a
className='link'
href={feedbackUrl}
target='_blank'
rel='noreferrer'
>
<FormattedMessage
id='TopBar.give-feedback'
defaultMessage='Give feedback'
/>
</a>
<div className='versionFrame'>
<div
className='version'
title={`v${Constants.versionString}`}
>
{`v${Constants.versionString}`}
</div>
</div>
</div>
)
}
const focalboardFeedbackUrl = 'https://www.focalboard.com/fwlink/feedback-focalboard.html?v=' + Constants.versionString
const feedbackUrl = 'https://www.focalboard.com/fwlink/feedback-boards.html?v=' + Constants.versionString
return (
<div
className='TopBar'
>
<a
className='link'
href={focalboardFeedbackUrl}
href={feedbackUrl}
target='_blank'
rel='noreferrer'
>
@ -56,13 +25,14 @@ const TopBar = (): JSX.Element => {
defaultMessage='Give feedback'
/>
</a>
<a
href='https://www.focalboard.com/guide/user?utm_source=webapp'
target='_blank'
rel='noreferrer'
>
<HelpIcon/>
</a>
<div className='versionFrame'>
<div
className='version'
title={`v${Constants.versionString}`}
>
{`v${Constants.versionString}`}
</div>
</div>
</div>
)
}

View File

@ -96,7 +96,7 @@ export const ViewLimitModal = (props: Props): JSX.Element => {
>
<div className='ViewLimitDialog_body'>
<img
src={Utils.buildURL(upgradeImage, true)}
src={upgradeImage}
alt={intl.formatMessage({id: 'ViewLimitDialog.UpgradeImg.AltText', defaultMessage: 'upgrade image'})}
/>
<h2 className='header text-heading5'>

View File

@ -18,30 +18,12 @@ type Props = {
// WithWebSockets component initialises the websocket connection if
// it's not yet running and subscribes to the current team
const WithWebSockets = (props: Props): React.ReactElement => {
const queryString = new URLSearchParams(window.location.search)
useEffect(() => {
// if the websocket client was already connected, do nothing
if (wsClient.state !== 'init') {
return
}
// this is a temporary solution to disable websocket
// connections on legacy routes, as there is no such thing as
// an anonymous websocket connection
if (Utils.isFocalboardLegacy()) {
return
}
if (!Utils.isFocalboardPlugin()) {
const token = localStorage.getItem('focalboardSessionId') || queryString.get('r') || ''
if (token) {
wsClient.authenticate(token)
}
wsClient.open()
return
}
if (!props.webSocketClient) {
Utils.logWarn('Trying to initialise Boards websocket in plugin mode without base connection. Aborting')
return
@ -56,19 +38,6 @@ const WithWebSockets = (props: Props): React.ReactElement => {
wsClient.open()
}, [props.webSocketClient])
useEffect(() => {
// if we're running on a plugin instance or we don't have a
// user yet, do nothing
if (Utils.isFocalboardPlugin() || !props.userId) {
return
}
const token = localStorage.getItem('focalboardSessionId') || queryString.get('r') || ''
if (wsClient.token !== token) {
wsClient.authenticate(token)
}
}, [props.userId])
return (
<>
{props.children}

View File

@ -308,8 +308,6 @@ describe('src/components/workspace', () => {
})
test('show open card tooltip', async () => {
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const welcomeBoard = TestBlockFactory.createBoard()
welcomeBoard.title = 'Welcome to Boards!'
@ -523,8 +521,6 @@ describe('src/components/workspace', () => {
})
test('show copy link tooltip', async () => {
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const welcomeBoard = TestBlockFactory.createBoard()
welcomeBoard.title = 'Welcome to Boards!'

View File

@ -4,7 +4,6 @@
import {useAppSelector} from '../store/hooks'
import {getMyBoardMembership, getCurrentBoardId, getBoard} from '../store/boards'
import {getCurrentTeam} from '../store/teams'
import {Utils} from '../utils'
import {Permission} from '../constants'
import {MemberRole} from '../blocks/board'
@ -24,10 +23,6 @@ export const useHasPermissions = (teamId: string, boardId: string, permissions:
return false
}
if (!Utils.isFocalboardPlugin()) {
return true
}
const adminPermissions = [Permission.ManageBoardType, Permission.DeleteBoard, Permission.ShareBoard, Permission.ManageBoardRoles, Permission.DeleteOthersComments]
const editorPermissions = [Permission.ManageBoardCards, Permission.ManageBoardProperties]
const commenterPermissions = [Permission.CommentBoardCards]

View File

@ -83,22 +83,14 @@ const BoardPage = (props: Props): JSX.Element => {
const [showJoinBoardDialog, setShowJoinBoardDialog] = useState<boolean>(false)
const history = useHistory()
// if we're in a legacy route and not showing a shared board,
// redirect to the new URL schema equivalent
if (Utils.isFocalboardLegacy() && !props.readonly) {
window.location.href = window.location.href.replace('/plugins/focalboard', '/boards')
}
// Load user's block subscriptions when workspace changes
// block subscriptions are relevant only in plugin mode.
if (Utils.isFocalboardPlugin()) {
useEffect(() => {
if (!me) {
return
}
dispatch(fetchUserBlockSubscriptions(me!.id))
}, [me?.id])
}
useEffect(() => {
if (!me) {
return
}
dispatch(fetchUserBlockSubscriptions(me!.id))
}, [me?.id])
// TODO: Make this less brittle. This only works because this is the root render function
useEffect(() => {

View File

@ -2,7 +2,6 @@
// See LICENSE.txt for license information.
import {useEffect} from 'react'
import {Utils} from '../../utils'
import {getCurrentBoard} from '../../store/boards'
import {getCurrentView} from '../../store/views'
import {useAppSelector} from '../../store/hooks'
@ -11,10 +10,6 @@ const SetWindowTitleAndIcon = (): null => {
const board = useAppSelector(getCurrentBoard)
const activeView = useAppSelector(getCurrentView)
useEffect(() => {
Utils.setFavicon(board?.icon)
}, [board?.icon])
useEffect(() => {
if (board) {
let title = `${board.title}`
@ -22,10 +17,8 @@ const SetWindowTitleAndIcon = (): null => {
title += ` | ${activeView.title}`
}
document.title = title
} else if (Utils.isFocalboardPlugin()) {
document.title = 'Boards - Mattermost'
} else {
document.title = 'Focalboard'
document.title = 'Boards - Mattermost'
}
}, [board?.title, activeView?.title])

View File

@ -10,7 +10,6 @@ import Button from '../widgets/buttons/button'
import './errorPage.scss'
import {errorDefFromId, ErrorId} from '../errors'
import {Utils} from '../utils'
const ErrorPage = () => {
const history = useHistory()
@ -46,10 +45,6 @@ const ErrorPage = () => {
)
})
if (!Utils.isFocalboardPlugin() && errid === ErrorId.NotLoggedIn) {
handleButtonClick(errorDef.button1Redirect)
}
return (
<div className='ErrorPage'>
<div>

View File

@ -10,7 +10,6 @@ import BoardWelcomeSmallPNG from '../../../static/boards-welcome-small.png'
import Button from '../../widgets/buttons/button'
import CompassIcon from '../../widgets/icons/compassIcon'
import {Utils} from '../../utils'
import './welcomePage.scss'
import mutator from '../../mutator'
@ -129,14 +128,14 @@ const WelcomePage = () => {
{/* This image will be rendered on large screens over 2000px */}
<img
src={Utils.buildURL(BoardWelcomePNG, true)}
src={BoardWelcomePNG}
className='WelcomePage__image WelcomePage__image--large'
alt='Boards Welcome Image'
/>
{/* This image will be rendered on small screens below 2000px */}
<img
src={Utils.buildURL(BoardWelcomeSmallPNG, true)}
src={BoardWelcomeSmallPNG}
className='WelcomePage__image WelcomePage__image--small'
alt='Boards Welcome Image'
/>

View File

@ -6,7 +6,6 @@ import {
Route,
} from 'react-router-dom'
import {Utils} from './utils'
import {getLoggedIn, getMe, getMyConfig} from './store/users'
import {useAppSelector} from './store/hooks'
import {UserSettingKey} from './userSettings'
@ -36,7 +35,6 @@ function FBRoute(props: RouteProps) {
const disableTour = me?.is_guest || clientConfig?.featureFlags?.disableTour || false
const showWelcomePage = !disableTour &&
Utils.isFocalboardPlugin() &&
(me?.id !== 'single-user') &&
props.path !== '/welcome' &&
loggedIn === true &&
@ -54,7 +52,7 @@ function FBRoute(props: RouteProps) {
if (redirect === null && loggedIn === false && props.loginRequired) {
redirect = ({match}: any) => {
if (props.getOriginalPath) {
let redirectUrl = '/' + Utils.buildURL(props.getOriginalPath!(match))
let redirectUrl = '/' + props.getOriginalPath!(match)
if (redirectUrl.indexOf('//') === 0) {
redirectUrl = redirectUrl.slice(1)
}

View File

@ -14,11 +14,8 @@ import {createBrowserHistory, History} from 'history'
import {IAppWindow} from './types'
import BoardPage from './pages/boardPage/boardPage'
import ChangePasswordPage from './pages/changePasswordPage'
import WelcomePage from './pages/welcome/welcomePage'
import ErrorPage from './pages/errorPage'
import LoginPage from './pages/loginPage'
import RegisterPage from './pages/registerPage'
import {Utils} from './utils'
import octoClient from './octoClient'
import {setGlobalError, getGlobalError} from './store/globalError'
@ -29,8 +26,6 @@ import FBRoute from './route'
declare let window: IAppWindow
const UUID_REGEX = new RegExp(/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/)
function HomeToCurrentTeam(props: {path: string, exact: boolean}) {
return (
<FBRoute
@ -112,8 +107,6 @@ type Props = {
}
const FocalboardRouter = (props: Props): JSX.Element => {
const isPlugin = Utils.isFocalboardPlugin()
let browserHistory: History<unknown>
if (props.history) {
browserHistory = props.history
@ -123,48 +116,29 @@ const FocalboardRouter = (props: Props): JSX.Element => {
}, [])
}
if (isPlugin) {
useEffect(() => {
if (window.frontendBaseURL) {
browserHistory.replace(window.location.pathname.replace(window.frontendBaseURL, ''))
}
}, [])
}
useEffect(() => {
if (window.frontendBaseURL) {
browserHistory.replace(window.location.pathname.replace(window.frontendBaseURL, ''))
}
}, [])
return (
<Router history={browserHistory}>
<GlobalErrorRedirect/>
<Switch>
{isPlugin &&
<HomeToCurrentTeam
path='/'
exact={true}
/>}
{isPlugin &&
<FBRoute
exact={true}
path='/welcome'
>
<WelcomePage/>
</FBRoute>}
<HomeToCurrentTeam
path='/'
exact={true}
/>
<FBRoute
exact={true}
path='/welcome'
>
<WelcomePage/>
</FBRoute>
<FBRoute path='/error'>
<ErrorPage/>
</FBRoute>
{!isPlugin &&
<FBRoute path='/login'>
<LoginPage/>
</FBRoute>}
{!isPlugin &&
<FBRoute path='/register'>
<RegisterPage/>
</FBRoute>}
{!isPlugin &&
<FBRoute path='/change_password'>
<ChangePasswordPage/>
</FBRoute>}
<FBRoute path={['/team/:teamId/new/:channelId']}>
<BoardPage new={true}/>
</FBRoute>
@ -194,21 +168,6 @@ const FocalboardRouter = (props: Props): JSX.Element => {
>
<BoardPage/>
</FBRoute>
{!isPlugin &&
<FBRoute
path='/:boardId?/:viewId?/:cardId?'
loginRequired={true}
getOriginalPath={({params: {boardId, viewId, cardId}}) => {
const boardIdIsValidUUIDV4 = UUID_REGEX.test(boardId || '')
if (boardIdIsValidUUIDV4) {
return `/${Utils.buildOriginalPath('', boardId, viewId, cardId)}`
}
return ''
}}
>
<BoardPage/>
</FBRoute>}
</Switch>
</Router>
)

View File

@ -6,8 +6,6 @@ import {createSlice, createAsyncThunk, PayloadAction, createSelector} from '@red
import {default as client} from '../octoClient'
import {IUser, parseUserProps, UserPreference} from '../user'
import {Utils} from '../utils'
import {Subscription} from '../wsclient'
// TODO: change this whene the initial load is complete
@ -41,7 +39,7 @@ type UsersStatus = {
export const fetchUserBlockSubscriptions = createAsyncThunk(
'user/blockSubscriptions',
async (userId: string) => (Utils.isFocalboardPlugin() ? client.getUserBlockSubscriptions(userId) : []),
async (userId: string) => client.getUserBlockSubscriptions(userId),
)
const initialState = {

View File

@ -5,8 +5,6 @@ import {CSSObject} from '@emotion/serialize'
import isEqual from 'lodash/isEqual'
import color from 'color'
import {Utils} from './utils'
let activeThemeName: string
import {UserSettings} from './userSettings'
@ -124,66 +122,51 @@ export function setTheme(theme: Theme | null): Theme {
setActiveThemeName(consolidatedTheme, theme)
if (Utils.isFocalboardPlugin()) {
// in plugin mode, Focalbaord reuses Mattermost's color pallet, so we don't really need to
// set the color variables here because in the app, Mattermost webapp would have already
// declared them.
// But,
// when testing the plugin mode in Jest unit test,
// since there is no Mattermost webapp, we need to ensure someone declares the variables.
// So here we set the variable if it wasn't already declared.
// In plugins, since Mattermost webapp renders always before the plugin/product,
// the variables are guaranteed to be set there.
//
// Fun fact - in a Jest test suite, if there are some non-plugin tests and a few plugin tests,
// if a non-plugin test ran first, it creates the variables in document, which is somehow
// shared to other tests as well. That's why the tests don't fail unless you run ONLY
// a plugin test.
// Focalboard reuses Mattermost's color pallet, so we don't really need to
// set the color variables here because in the app, Mattermost webapp would have already
// declared them.
// But,
// when testing the plugin mode in Jest unit test,
// since there is no Mattermost webapp, we need to ensure someone declares the variables.
// So here we set the variable if it wasn't already declared.
// In plugins, since Mattermost webapp renders always before the plugin/product,
// the variables are guaranteed to be set there.
//
// Fun fact - in a Jest test suite, if there are some non-plugin tests and a few plugin tests,
// if a non-plugin test ran first, it creates the variables in document, which is somehow
// shared to other tests as well. That's why the tests don't fail unless you run ONLY
// a plugin test.
const style = document.documentElement.style
const style = document.documentElement.style
style.setProperty('--center-channel-bg-rgb', style.getPropertyValue('--center-channel-bg-rgb') || consolidatedTheme.mainBg)
style.setProperty('--center-channel-color-rgb', style.getPropertyValue('--center-channel-color-rgb') || consolidatedTheme.mainBg)
style.setProperty('--button-bg-rgb', style.getPropertyValue('--button-bg-rgb') || consolidatedTheme.mainBg)
style.setProperty('--button-color-rgb', style.getPropertyValue('--button-color-rgb') || consolidatedTheme.mainBg)
style.setProperty('--sidebar-bg-rgb', style.getPropertyValue('--sidebar-bg-rgb') || consolidatedTheme.mainBg)
style.setProperty('--sidebar-text-rgb', style.getPropertyValue('--sidebar-text-rgb') || consolidatedTheme.mainBg)
style.setProperty('--link-color-rgb', style.getPropertyValue('--link-color-rgb') || consolidatedTheme.mainBg)
style.setProperty('--sidebar-text-active-border-rgb', style.getPropertyValue('--sidebar-text-active-border-rgb') || consolidatedTheme.mainBg)
} else {
// for personal server and desktop, Focalboard is responsible for managing the theme,
// so we set all the color variables here.
document.documentElement.style.setProperty('--center-channel-bg-rgb', consolidatedTheme.mainBg)
document.documentElement.style.setProperty('--center-channel-color-rgb', consolidatedTheme.mainFg)
document.documentElement.style.setProperty('--button-bg-rgb', consolidatedTheme.buttonBg)
document.documentElement.style.setProperty('--button-color-rgb', consolidatedTheme.buttonFg)
document.documentElement.style.setProperty('--sidebar-bg-rgb', consolidatedTheme.sidebarBg)
document.documentElement.style.setProperty('--sidebar-text-rgb', consolidatedTheme.sidebarFg)
document.documentElement.style.setProperty('--link-color-rgb', consolidatedTheme.link)
document.documentElement.style.setProperty('--sidebar-text-active-border-rgb', consolidatedTheme.sidebarTextActiveBorder)
}
style.setProperty('--center-channel-bg-rgb', style.getPropertyValue('--center-channel-bg-rgb') || consolidatedTheme.mainBg)
style.setProperty('--center-channel-color-rgb', style.getPropertyValue('--center-channel-color-rgb') || consolidatedTheme.mainBg)
style.setProperty('--button-bg-rgb', style.getPropertyValue('--button-bg-rgb') || consolidatedTheme.mainBg)
style.setProperty('--button-color-rgb', style.getPropertyValue('--button-color-rgb') || consolidatedTheme.mainBg)
style.setProperty('--sidebar-bg-rgb', style.getPropertyValue('--sidebar-bg-rgb') || consolidatedTheme.mainBg)
style.setProperty('--sidebar-text-rgb', style.getPropertyValue('--sidebar-text-rgb') || consolidatedTheme.mainBg)
style.setProperty('--link-color-rgb', style.getPropertyValue('--link-color-rgb') || consolidatedTheme.mainBg)
style.setProperty('--sidebar-text-active-border-rgb', style.getPropertyValue('--sidebar-text-active-border-rgb') || consolidatedTheme.mainBg)
document.documentElement.style.setProperty('--sidebar-white-logo', consolidatedTheme.sidebarWhiteLogo)
document.documentElement.style.setProperty('--link-visited-color-rgb', consolidatedTheme.linkVisited)
const mainBgColor = color(`rgb(${getComputedStyle(document.documentElement).getPropertyValue('--center-channel-bg-rgb')})`)
if (Utils.isFocalboardPlugin()) {
let fixedTheme = lightTheme
if (mainBgColor.isDark()) {
fixedTheme = darkTheme
}
consolidatedTheme.propDefault = fixedTheme.propDefault
consolidatedTheme.propGray = fixedTheme.propGray
consolidatedTheme.propBrown = fixedTheme.propBrown
consolidatedTheme.propOrange = fixedTheme.propOrange
consolidatedTheme.propYellow = fixedTheme.propYellow
consolidatedTheme.propGreen = fixedTheme.propGreen
consolidatedTheme.propBlue = fixedTheme.propBlue
consolidatedTheme.propPurple = fixedTheme.propPurple
consolidatedTheme.propPink = fixedTheme.propPink
consolidatedTheme.propRed = fixedTheme.propRed
let fixedTheme = lightTheme
if (mainBgColor.isDark()) {
fixedTheme = darkTheme
}
consolidatedTheme.propDefault = fixedTheme.propDefault
consolidatedTheme.propGray = fixedTheme.propGray
consolidatedTheme.propBrown = fixedTheme.propBrown
consolidatedTheme.propOrange = fixedTheme.propOrange
consolidatedTheme.propYellow = fixedTheme.propYellow
consolidatedTheme.propGreen = fixedTheme.propGreen
consolidatedTheme.propBlue = fixedTheme.propBlue
consolidatedTheme.propPurple = fixedTheme.propPurple
consolidatedTheme.propPink = fixedTheme.propPink
consolidatedTheme.propRed = fixedTheme.propRed
document.documentElement.style.setProperty('--prop-default', consolidatedTheme.propDefault)
document.documentElement.style.setProperty('--prop-gray', consolidatedTheme.propGray)

View File

@ -7,7 +7,6 @@ type TelemetryProps = {
export interface IAppWindow extends Window {
baseURL?: string
frontendBaseURL?: string
isFocalboardPlugin?: boolean
getCurrentTeamId?: () => string
msCrypto: Crypto
openInNewBrowser?: ((href: string) => void) | null
@ -23,6 +22,5 @@ export type SuiteWindow = Window & {
getCurrentTeamId?: () => string
baseURL?: string
frontendBaseURL?: string
isFocalboardPlugin?: boolean
WebappUtils?: any
}

View File

@ -84,37 +84,6 @@ describe('utils', () => {
})
})
describe('test - buildURL', () => {
test('buildURL, no base', () => {
(global as any).isFocalboardPlugin = true
expect(Utils.buildURL('test', true)).toBe('http://localhost/test')
expect(Utils.buildURL('/test', true)).toBe('http://localhost/test')
expect(Utils.buildURL('test')).toBe('/test')
expect(Utils.buildURL('/test')).toBe('/test')
})
test('buildURL, base no slash', () => {
window.baseURL = 'base'
expect(Utils.buildURL('test', true)).toBe('http://localhost/base/test')
expect(Utils.buildURL('/test', true)).toBe('http://localhost/base/test')
expect(Utils.buildURL('test')).toBe('base/test')
expect(Utils.buildURL('/test')).toBe('base/test')
})
test('buildUrl, base with slash', () => {
window.baseURL = '/base/'
expect(Utils.buildURL('test', true)).toBe('http://localhost/base/test')
expect(Utils.buildURL('/test', true)).toBe('http://localhost/base/test')
expect(Utils.buildURL('test')).toBe('base/test')
expect(Utils.buildURL('/test')).toBe('base/test')
})
})
describe('display date', () => {
const intl = createIntl({locale: 'en-us'})

View File

@ -421,26 +421,6 @@ class Utils {
/// #!endif
}
// favicon
static setFavicon(icon?: string): void {
if (Utils.isFocalboardPlugin()) {
// Do not change the icon from focalboard plugin
return
}
if (!icon) {
document.querySelector("link[rel*='icon']")?.remove()
return
}
const link = document.createElement('link') as HTMLLinkElement
link.type = 'image/x-icon'
link.rel = 'shortcut icon'
link.href = `data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y=".9em" font-size="90">${icon}</text></svg>`
document.querySelectorAll("link[rel*='icon']").forEach((n) => n.remove())
document.getElementsByTagName('head')[0].appendChild(link)
}
// URL
static replaceUrlQueryParam(paramName: string, value?: string): void {
@ -582,41 +562,10 @@ class Utils {
return frontendBaseURL
}
static buildURL(path: string, absolute?: boolean): string {
/* eslint-disable no-process-env */
if (!Utils.isFocalboardPlugin() || process.env.TARGET_IS_PRODUCT) {
return path
}
const baseURL = Utils.getBaseURL()
let finalPath = baseURL + path
if (path.indexOf('/') !== 0) {
finalPath = baseURL + '/' + path
}
if (absolute) {
if (finalPath.indexOf('/') === 0) {
finalPath = finalPath.slice(1)
}
return window.location.origin + '/' + finalPath
}
return finalPath
}
static roundTo(num: number, decimalPlaces: number): number {
return Math.round(num * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPlaces)
}
static isFocalboardPlugin(): boolean {
return Boolean(window.isFocalboardPlugin)
}
// this is a temporary solution while we're using legacy routes
// for shared boards as a way to check if we're accessing the
// legacy routes inside the plugin
static isFocalboardLegacy(): boolean {
return window.location.pathname.includes('/plugins/focalboard')
}
static fixWSData(message: WSMessage): [WSMessagePayloads, ChangeHandlerType] {
if (message.block) {
return [this.fixBlock(message.block), 'block']

View File

@ -106,7 +106,6 @@ type Subscriptions = {
}
class WSClient {
ws: WebSocket|null = null
client: MMWebSocketClient|null = null
onPluginReconnect: null|(() => void) = null
token = ''
@ -180,10 +179,7 @@ class WSClient {
if (this.client !== null) {
const {action, ...data} = command
this.client.sendMessage(this.clientPrefix + action, data)
return
}
this.ws?.send(JSON.stringify(command))
} catch (e) {
Utils.logError(`WSClient failed to send command ${command.action}: ${e}`)
}
@ -386,111 +382,11 @@ class WSClient {
this.client.addErrorListener(onError)
this.client.addCloseListener(onClose)
this.client.addReconnectListener(onReconnect)
return
}
const url = new URL(this.getBaseURL())
const protocol = (url.protocol === 'https:') ? 'wss:' : 'ws:'
const wsServerUrl = `${protocol}//${url.host}${url.pathname.replace(/\/$/, '')}/ws`
Utils.log(`WSClient open: ${wsServerUrl}`)
const ws = new WebSocket(wsServerUrl)
this.ws = ws
ws.onopen = () => {
Utils.log('WSClient webSocket opened.')
this.state = 'open'
// if has a token defined when connecting, authenticate
if (this.token) {
this.sendAuthenticationCommand(this.token)
}
// if there are any subscriptions set by the components,
// send their subscribe messages
this.subscribe()
for (const handler of this.onStateChange) {
handler(this, 'open')
}
}
ws.onerror = (e) => {
Utils.logError(`WSClient websocket onerror. data: ${e}`)
for (const handler of this.onError) {
handler(this, e)
}
}
ws.onclose = (e) => {
Utils.log(`WSClient websocket onclose, code: ${e.code}, reason: ${e.reason}`)
if (ws === this.ws) {
// Unexpected close, re-open
Utils.logError('Unexpected close, re-opening websocket')
for (const handler of this.onStateChange) {
handler(this, 'close')
}
this.state = 'close'
setTimeout(() => {
// ToDo: assert that this actually runs the onopen
// contents (auth + this.subscribe())
this.open()
for (const handler of this.onReconnect) {
handler(this)
}
}, this.reopenDelay)
}
}
ws.onmessage = (e) => {
if (ws !== this.ws) {
Utils.log('Ignoring closed ws')
return
}
try {
const message = JSON.parse(e.data) as WSMessage
if (message.error) {
Utils.logError(`Listener websocket error: ${message.error}`)
return
}
switch (message.action) {
case ACTION_UPDATE_BOARD:
this.updateHandler(message)
break
case ACTION_UPDATE_MEMBER:
this.updateHandler(message)
break
case ACTION_DELETE_MEMBER:
this.updateHandler(message)
break
case ACTION_UPDATE_BLOCK:
this.updateHandler(message)
break
case ACTION_UPDATE_CATEGORY:
this.updateHandler(message)
break
case ACTION_UPDATE_BOARD_CATEGORY:
this.updateHandler(message)
break
case ACTION_UPDATE_SUBSCRIPTION:
this.updateSubscriptionHandler(message)
break
case ACTION_REORDER_CATEGORIES:
this.updateHandler(message)
break
default:
Utils.logError(`Unexpected action: ${message.action}`)
}
} catch (err) {
Utils.log('message is not an object')
}
}
}
hasConn(): boolean {
return this.ws?.readyState === 1 || this.client !== null
return this.client !== null
}
updateHandler(message: WSMessage): void {
@ -761,30 +657,11 @@ class WSClient {
return
}
Utils.log(`WSClient close: ${this.ws?.url}`)
// Use this sequence so the onclose method doesn't try to re-open
const ws = this.ws
this.ws = null
this.onChange = {Block: [], Category: [], BoardCategory: [], Board: [], BoardMember: [], CategoryReorder: []}
this.onReconnect = []
this.onStateChange = []
this.onError = []
// if running in plugin mode, nothing else needs to be done
if (this.client) {
return
}
try {
ws?.close()
} catch {
try {
(ws as any)?.websocket?.close()
} catch {
Utils.log('WSClient unable to close the websocket')
}
}
}
}