Merge branch 'master' into boards-playbooks-i18n-sync
Этот коммит содержится в:
12
.github/PULL_REQUEST_TEMPLATE.md
поставляемый
12
.github/PULL_REQUEST_TEMPLATE.md
поставляемый
@@ -19,6 +19,18 @@ If this pull request addresses a Help Wanted ticket, please link the relevant Gi
|
|||||||
Otherwise, link the JIRA ticket.
|
Otherwise, link the JIRA ticket.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
#### Screenshots
|
||||||
|
<!--
|
||||||
|
If the PR includes UI changes, include screenshots/GIFs.
|
||||||
|
|
||||||
|
For an easier comparison of UI changes a table (template below) can be used.
|
||||||
|
|
||||||
|
| before | after |
|
||||||
|
|----|----|
|
||||||
|
| <insert before screenshot here> | <insert after screenshot here> |
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
#### Release Note
|
#### Release Note
|
||||||
<!--
|
<!--
|
||||||
Add a release note for each of the following conditions:
|
Add a release note for each of the following conditions:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('admin console', () => {
|
describe('admin console', {testIsolation: true}, () => {
|
||||||
let testUser;
|
let testUser;
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('api > runs', () => {
|
describe('api > runs', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import {onlyOn} from '@cypress/skip-test';
|
import {onlyOn} from '@cypress/skip-test';
|
||||||
|
|
||||||
describe('channels > App Bar', () => {
|
describe('channels > App Bar', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > broadcast', () => {
|
describe('channels > broadcast', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testAdmin;
|
let testAdmin;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import {onlyOn} from '@cypress/skip-test';
|
import {onlyOn} from '@cypress/skip-test';
|
||||||
|
|
||||||
describe('channels > channel header', () => {
|
describe('channels > channel header', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||||
|
|
||||||
describe('channels > general actions', () => {
|
describe('channels > general actions', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testSysadmin;
|
let testSysadmin;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > actions', () => {
|
describe('channels > actions', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testSysadmin;
|
let testSysadmin;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > post type components', () => {
|
describe('channels > post type components', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testChannel;
|
let testChannel;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('runs > retrospective', () => {
|
describe('runs > retrospective', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybookWithMetrics;
|
let testPlaybookWithMetrics;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > rhs > header', () => {
|
describe('channels > rhs > header', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import {HALF_SEC, ONE_SEC} from '../../../../fixtures/timeouts';
|
import {HALF_SEC, ONE_SEC} from '../../../../fixtures/timeouts';
|
||||||
|
|
||||||
describe('channels > rhs > checklist', () => {
|
describe('channels > rhs > checklist', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
@@ -164,7 +164,7 @@ describe('channels > rhs > checklist', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// * Verify the expected error message.
|
// * Verify the expected error message.
|
||||||
cy.verifyEphemeralMessage('Failed to execute slash command /invalid');
|
cy.verifyEphemeralMessage('Failed to find slash command /invalid');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('successfully runs a valid slash command', () => {
|
it('successfully runs a valid slash command', () => {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > rhs > header', () => {
|
describe('channels > rhs > header', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > rhs > home', () => {
|
describe('channels > rhs > home', {testIsolation: true}, () => {
|
||||||
let testSysadmin;
|
let testSysadmin;
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > rhs > runlist', () => {
|
describe('channels > rhs > runlist', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels rhs > start a run', () => {
|
describe('channels rhs > start a run', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testChannel;
|
let testChannel;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||||
|
|
||||||
describe('channels > rhs > status update', () => {
|
describe('channels > rhs > status update', {testIsolation: true}, () => {
|
||||||
const defaultReminderMessage = '# Default reminder message';
|
const defaultReminderMessage = '# Default reminder message';
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testChannel;
|
let testChannel;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > rhs > template', () => {
|
describe('channels > rhs > template', {testIsolation: true}, () => {
|
||||||
let team1;
|
let team1;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > rhs > title', () => {
|
describe('channels > rhs > title', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||||
|
|
||||||
describe('channels > rhs', () => {
|
describe('channels > rhs', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > run dialog', () => {
|
describe('channels > run dialog', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > run', () => {
|
describe('channels > run', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPrivateChannel;
|
let testPrivateChannel;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import {switchToChannel} from '../../../channels/mark_as_unread/helpers';
|
import {switchToChannel} from '../../../channels/mark_as_unread/helpers';
|
||||||
|
|
||||||
describe('channels > slash command > owner', () => {
|
describe('channels > slash command > owner', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testUser2;
|
let testUser2;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > slash command > info', () => {
|
describe('channels > slash command > info', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testUser2;
|
let testUser2;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > slash command > owner', () => {
|
describe('channels > slash command > owner', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testUser2;
|
let testUser2;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > slash command > test', () => {
|
describe('channels > slash command > test', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testUser2;
|
let testUser2;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('channels > slash command > todo', () => {
|
describe('channels > slash command > todo', {testIsolation: true}, () => {
|
||||||
let team1;
|
let team1;
|
||||||
let team2;
|
let team2;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||||
|
|
||||||
describe('channels > update request post', () => {
|
describe('channels > update request post', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testParticipant;
|
let testParticipant;
|
||||||
let testChannelMemberOnly;
|
let testChannelMemberOnly;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('digest messages', () => {
|
describe('digest messages', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
import {HALF_SEC} from '../../fixtures/timeouts';
|
import {HALF_SEC} from '../../fixtures/timeouts';
|
||||||
import {stubClipboard} from '../../utils';
|
import {stubClipboard} from '../../utils';
|
||||||
|
|
||||||
describe('lhs', () => {
|
describe('lhs', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPublicPlaybook;
|
let testPublicPlaybook;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('navigation', () => {
|
describe('navigation', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('playbooks > edit', () => {
|
describe('playbooks > edit', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testUser2;
|
let testUser2;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('playbooks > creation button', () => {
|
describe('playbooks > creation button', {testIsolation: true}, () => {
|
||||||
let testSysadmin;
|
let testSysadmin;
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
//
|
//
|
||||||
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
import * as TIMEOUTS from '../../../../fixtures/timeouts';
|
||||||
|
|
||||||
describe('playbooks > edit > task actions', () => {
|
describe('playbooks > edit > task actions', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testUser2;
|
let testUser2;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
/* eslint-disable no-only-tests/no-only-tests */
|
/* eslint-disable no-only-tests/no-only-tests */
|
||||||
|
|
||||||
describe('playbooks > edit_metrics', () => {
|
describe('playbooks > edit_metrics', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||||
|
|
||||||
describe('playbooks > edit', () => {
|
describe('playbooks > edit', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testSysadmin;
|
let testSysadmin;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('playbooks > feedback', () => {
|
describe('playbooks > feedback', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('playbooks > list', () => {
|
describe('playbooks > list', {testIsolation: true}, () => {
|
||||||
const playbookTitle = 'The Playbook Name';
|
const playbookTitle = 'The Playbook Name';
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import {stubClipboard} from '../../../utils';
|
import {stubClipboard} from '../../../utils';
|
||||||
|
|
||||||
describe('playbooks > overview', () => {
|
describe('playbooks > overview', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testOtherTeam;
|
let testOtherTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('playbooks > list pagination', () => {
|
describe('playbooks > list pagination', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
const ExtraPlaybooks = 20;
|
const ExtraPlaybooks = 20;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
const RUN_NAME_MAX_LENGTH = 64;
|
const RUN_NAME_MAX_LENGTH = 64;
|
||||||
|
|
||||||
describe('playbooks > start a run', () => {
|
describe('playbooks > start a run', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('playbooks > edit status update', () => {
|
describe('playbooks > edit status update', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('runs > list', () => {
|
describe('runs > list', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testAnotherUser;
|
let testAnotherUser;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import {getRandomId} from '../../../utils';
|
import {getRandomId} from '../../../utils';
|
||||||
|
|
||||||
describe('runs > permissions', () => {
|
describe('runs > permissions', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testOtherTeam;
|
let testOtherTeam;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('runs > run details page', () => {
|
describe('runs > run details page', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testPublicPlaybook;
|
let testPublicPlaybook;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
// Note that this test checks the basic behavior in Run details page as participant / viewer
|
// Note that this test checks the basic behavior in Run details page as participant / viewer
|
||||||
// It relies on the Channel RHS Checklist test to cover the full behavior of the checklists
|
// It relies on the Channel RHS Checklist test to cover the full behavior of the checklists
|
||||||
|
|
||||||
describe('runs > run details page > checklist', () => {
|
describe('runs > run details page > checklist', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testViewerUser;
|
let testViewerUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('runs > run details page > finish', () => {
|
describe('runs > run details page > finish', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testViewerUser;
|
let testViewerUser;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import {stubClipboard} from '../../../utils';
|
import {stubClipboard} from '../../../utils';
|
||||||
|
|
||||||
describe('runs > run details page > header', () => {
|
describe('runs > run details page > header', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testViewerUser;
|
let testViewerUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('runs > run details page > restart run', () => {
|
describe('runs > run details page > restart run', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testViewerUser;
|
let testViewerUser;
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ const verifyMetricInput = (index, title, target, description, placeholder) => {
|
|||||||
|
|
||||||
const getRetro = () => cy.findByTestId('run-retrospective-section');
|
const getRetro = () => cy.findByTestId('run-retrospective-section');
|
||||||
|
|
||||||
describe('runs > run details page', () => {
|
describe('runs > run details page', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testViewerUser;
|
let testViewerUser;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
/* eslint-disable no-only-tests/no-only-tests */
|
/* eslint-disable no-only-tests/no-only-tests */
|
||||||
|
|
||||||
describe('runs > run details page > status update', () => {
|
describe('runs > run details page > status update', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testViewerUser;
|
let testViewerUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('runs > run details page > summary', () => {
|
describe('runs > run details page > summary', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testRun;
|
let testRun;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||||
|
|
||||||
describe('runs > task actions', () => {
|
describe('runs > task actions', {testIsolation: true}, () => {
|
||||||
let testPlaybook;
|
let testPlaybook;
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('runs > run details page > rhs > participants', () => {
|
describe('runs > run details page > rhs > participants', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testUser2;
|
let testUser2;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('runs > run details page > run info', () => {
|
describe('runs > run details page > run info', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testViewerUser;
|
let testViewerUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('runs > run details page > RHS', () => {
|
describe('runs > run details page > RHS', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testViewerUser;
|
let testViewerUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('runs > run details page > status update', () => {
|
describe('runs > run details page > status update', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testViewerUser;
|
let testViewerUser;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('Task Inbox >', () => {
|
describe('Task Inbox >', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
// Stage: @prod
|
// Stage: @prod
|
||||||
// Group: @playbooks
|
// Group: @playbooks
|
||||||
|
|
||||||
describe('playbook tour points', () => {
|
describe('playbook tour points', {testIsolation: true}, () => {
|
||||||
let testTeam;
|
let testTeam;
|
||||||
let testUser;
|
let testUser;
|
||||||
let testSysadmin;
|
let testSysadmin;
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ Cypress.Commands.add('updateStatus', (message, reminderQuery) => {
|
|||||||
|
|
||||||
if (reminderQuery) {
|
if (reminderQuery) {
|
||||||
cy.get('#reminder_timer_datetime').within(() => {
|
cy.get('#reminder_timer_datetime').within(() => {
|
||||||
cy.get('input').type(reminderQuery, {delay: TIMEOUTS.TWO_HUNDRED_MILLIS, force: true}).type('{enter}', {force: true});
|
cy.get('input').type(reminderQuery, {delay: TIMEOUTS.TWO_HUNDRED_MILLIS, force: true}).wait(TIMEOUTS.ONE_SEC).type('{enter}');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,10 +77,13 @@ func TestSetConfiguration(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("test enable shared boards", func(t *testing.T) {
|
t.Run("test enable shared boards", func(t *testing.T) {
|
||||||
|
baseProductSettings := &model.ProductSettings{
|
||||||
|
EnablePublicSharedBoards: &falseRef,
|
||||||
|
}
|
||||||
|
|
||||||
mmConfig := baseConfig
|
mmConfig := baseConfig
|
||||||
mmConfig.PluginSettings.Plugins = make(map[string]map[string]interface{})
|
mmConfig.ProductSettings = *baseProductSettings
|
||||||
mmConfig.PluginSettings.Plugins[server.PluginName] = make(map[string]interface{})
|
mmConfig.ProductSettings.EnablePublicSharedBoards = &boolTrue
|
||||||
mmConfig.PluginSettings.Plugins[server.PluginName][server.SharedBoardsName] = true
|
|
||||||
config := server.CreateBoardsConfig(*mmConfig, "", "")
|
config := server.CreateBoardsConfig(*mmConfig, "", "")
|
||||||
assert.Equal(t, true, config.EnablePublicSharedBoards)
|
assert.Equal(t, true, config.EnablePublicSharedBoards)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ func CreateBoardsConfig(mmconfig mm_model.Config, baseURL string, serverID strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
enablePublicSharedBoards := false
|
enablePublicSharedBoards := false
|
||||||
if mmconfig.PluginSettings.Plugins[PluginName][SharedBoardsName] == true {
|
if mmconfig.ProductSettings.EnablePublicSharedBoards != nil {
|
||||||
enablePublicSharedBoards = true
|
enablePublicSharedBoards = *mmconfig.ProductSettings.EnablePublicSharedBoards
|
||||||
}
|
}
|
||||||
|
|
||||||
enableBoardsDeletion := false
|
enableBoardsDeletion := false
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
save-exact=true
|
save-exact=true
|
||||||
legacy-peer-deps=true
|
legacy-peer-deps=true
|
||||||
global-style=true
|
global-style=true
|
||||||
|
|||||||
@@ -102,12 +102,11 @@
|
|||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"@types/react-transition-group": "4.4.4",
|
"@types/react-transition-group": "4.4.4",
|
||||||
"@types/redux-mock-store": "1.0.3",
|
"@types/redux-mock-store": "1.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "5.16.0",
|
"@typescript-eslint/eslint-plugin": "5.57.1",
|
||||||
"@typescript-eslint/parser": "5.16.0",
|
"@typescript-eslint/parser": "5.57.1",
|
||||||
"babel-eslint": "10.1.0",
|
"babel-eslint": "10.1.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"css-loader": "6.7.1",
|
"css-loader": "6.7.1",
|
||||||
"eslint": "^8.11.0",
|
|
||||||
"eslint-import-resolver-webpack": "0.13.2",
|
"eslint-import-resolver-webpack": "0.13.2",
|
||||||
"eslint-plugin-babel": "^5.3.1",
|
"eslint-plugin-babel": "^5.3.1",
|
||||||
"eslint-plugin-formatjs": "4.9.0",
|
"eslint-plugin-formatjs": "4.9.0",
|
||||||
|
|||||||
@@ -873,7 +873,7 @@ exports[`src/components/workspace return workspace readonly and showcard 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="octo-board-header-cell KanbanColumnHeader"
|
class="octo-board-header-cell KanbanColumnHeader"
|
||||||
draggable="true"
|
draggable="false"
|
||||||
style="opacity: 1;"
|
style="opacity: 1;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -901,7 +901,7 @@ exports[`src/components/workspace return workspace readonly and showcard 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="octo-board-header-cell KanbanColumnHeader"
|
class="octo-board-header-cell KanbanColumnHeader"
|
||||||
draggable="true"
|
draggable="false"
|
||||||
style="opacity: 1;"
|
style="opacity: 1;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -1927,7 +1927,7 @@ exports[`src/components/workspace should match snapshot with readonly 1`] = `
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="octo-board-header-cell KanbanColumnHeader"
|
class="octo-board-header-cell KanbanColumnHeader"
|
||||||
draggable="true"
|
draggable="false"
|
||||||
style="opacity: 1;"
|
style="opacity: 1;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -1955,7 +1955,7 @@ exports[`src/components/workspace should match snapshot with readonly 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="octo-board-header-cell KanbanColumnHeader"
|
class="octo-board-header-cell KanbanColumnHeader"
|
||||||
draggable="true"
|
draggable="false"
|
||||||
style="opacity: 1;"
|
style="opacity: 1;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -29,7 +29,14 @@ jest.mock('react-router-dom', () => {
|
|||||||
return {
|
return {
|
||||||
...originalModule,
|
...originalModule,
|
||||||
useRouteMatch: jest.fn(() => {
|
useRouteMatch: jest.fn(() => {
|
||||||
return {url: '/board/view'}
|
return {
|
||||||
|
params: {
|
||||||
|
teamId: 'team1',
|
||||||
|
boardId: 'boardId1',
|
||||||
|
viewId: 'viewId1',
|
||||||
|
cardId: 'cardId1',
|
||||||
|
},
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -469,7 +469,7 @@ exports[`src/components/kanban/kanbanColumnHeader should match snapshot readonly
|
|||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="octo-board-header-cell KanbanColumnHeader"
|
class="octo-board-header-cell KanbanColumnHeader"
|
||||||
draggable="true"
|
draggable="false"
|
||||||
style="opacity: 1;"
|
style="opacity: 1;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -52,8 +52,12 @@ const defaultProperty: IPropertyTemplate = {
|
|||||||
export default function KanbanColumnHeader(props: Props): JSX.Element {
|
export default function KanbanColumnHeader(props: Props): JSX.Element {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const {board, activeView, group, groupByProperty} = props
|
const {board, activeView, group, groupByProperty} = props
|
||||||
|
let readonly = props.readonly
|
||||||
|
if(!readonly){
|
||||||
|
readonly = !useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
|
||||||
|
}
|
||||||
|
|
||||||
const [groupTitle, setGroupTitle] = useState(group.option.value)
|
const [groupTitle, setGroupTitle] = useState(group.option.value)
|
||||||
const canEditBoardProperties = useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
|
|
||||||
const canEditOption = groupByProperty?.type !== 'person' && group.option.id
|
const canEditOption = groupByProperty?.type !== 'person' && group.option.id
|
||||||
|
|
||||||
const headerRef = useRef<HTMLDivElement>(null)
|
const headerRef = useRef<HTMLDivElement>(null)
|
||||||
@@ -79,7 +83,7 @@ export default function KanbanColumnHeader(props: Props): JSX.Element {
|
|||||||
setGroupTitle(group.option.value)
|
setGroupTitle(group.option.value)
|
||||||
}, [group.option.value])
|
}, [group.option.value])
|
||||||
|
|
||||||
if (canEditBoardProperties) {
|
if (!readonly) {
|
||||||
drop(drag(headerRef))
|
drop(drag(headerRef))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +101,7 @@ export default function KanbanColumnHeader(props: Props): JSX.Element {
|
|||||||
ref={headerRef}
|
ref={headerRef}
|
||||||
style={{opacity: isDragging ? 0.5 : 1}}
|
style={{opacity: isDragging ? 0.5 : 1}}
|
||||||
className={className}
|
className={className}
|
||||||
draggable={!props.readonly && canEditBoardProperties}
|
draggable={!readonly}
|
||||||
>
|
>
|
||||||
{!group.option.id &&
|
{!group.option.id &&
|
||||||
<Label
|
<Label
|
||||||
@@ -133,7 +137,7 @@ export default function KanbanColumnHeader(props: Props): JSX.Element {
|
|||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
setGroupTitle(group.option.value)
|
setGroupTitle(group.option.value)
|
||||||
}}
|
}}
|
||||||
readonly={props.readonly || !canEditBoardProperties}
|
readonly={readonly}
|
||||||
spellCheck={true}
|
spellCheck={true}
|
||||||
/>
|
/>
|
||||||
</Label>}
|
</Label>}
|
||||||
@@ -145,7 +149,7 @@ export default function KanbanColumnHeader(props: Props): JSX.Element {
|
|||||||
onMenuClose={props.onCalculationMenuClose}
|
onMenuClose={props.onCalculationMenuClose}
|
||||||
onMenuOpen={props.onCalculationMenuOpen}
|
onMenuOpen={props.onCalculationMenuOpen}
|
||||||
cardProperties={board.cardProperties}
|
cardProperties={board.cardProperties}
|
||||||
readonly={props.readonly || !canEditBoardProperties}
|
readonly={readonly}
|
||||||
onChange={(data: {calculation: string, propertyId: string}) => {
|
onChange={(data: {calculation: string, propertyId: string}) => {
|
||||||
if (data.calculation === calculationValue && data.propertyId === calculationProperty.id) {
|
if (data.calculation === calculationValue && data.propertyId === calculationProperty.id) {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -983,11 +983,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Regene
|
|||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="shareUrl"
|
class="shareUrl"
|
||||||
href="http://localhost:8065/team/team-id/shared/1/1?r=anotherToken"
|
href="http://localhost:8065/boards/public/team/team-id/shared/1/1?r=anotherToken"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
http://localhost:8065/team/team-id/shared/1/1?r=anotherToken
|
http://localhost:8065/boards/public/team/team-id/shared/1/1?r=anotherToken
|
||||||
</a>
|
</a>
|
||||||
<div
|
<div
|
||||||
class="octo-tooltip tooltip-top"
|
class="octo-tooltip tooltip-top"
|
||||||
@@ -3188,11 +3188,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoard, and click switc
|
|||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="shareUrl"
|
class="shareUrl"
|
||||||
href="http://localhost:8065/team/team-id/shared/1/1?r=oneToken"
|
href="http://localhost:8065/boards/public/team/team-id/shared/1/1?r=oneToken"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
http://localhost:8065/team/team-id/shared/1/1?r=oneToken
|
http://localhost:8065/boards/public/team/team-id/shared/1/1?r=oneToken
|
||||||
</a>
|
</a>
|
||||||
<div
|
<div
|
||||||
class="octo-tooltip tooltip-top"
|
class="octo-tooltip tooltip-top"
|
||||||
@@ -3461,11 +3461,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoardComponent and cli
|
|||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="shareUrl"
|
class="shareUrl"
|
||||||
href="http://localhost:8065/team/team-id/shared/1/1?r=aToken"
|
href="http://localhost:8065/boards/public/team/team-id/shared/1/1?r=aToken"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
http://localhost:8065/team/team-id/shared/1/1?r=aToken
|
http://localhost:8065/boards/public/team/team-id/shared/1/1?r=aToken
|
||||||
</a>
|
</a>
|
||||||
<div
|
<div
|
||||||
class="octo-tooltip tooltip-top"
|
class="octo-tooltip tooltip-top"
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element {
|
|||||||
viewId: match.params.viewId,
|
viewId: match.params.viewId,
|
||||||
teamId: match.params.teamId,
|
teamId: match.params.teamId,
|
||||||
})
|
})
|
||||||
shareUrl.pathname = newPath
|
shareUrl.pathname = `/boards/public${newPath}`
|
||||||
|
|
||||||
const boardPath = generatePath('/team/:teamId/:boardId/:viewId', {
|
const boardPath = generatePath('/team/:teamId/:boardId/:viewId', {
|
||||||
boardId: match.params.boardId,
|
boardId: match.params.boardId,
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ jest.mock('react-router-dom', () => {
|
|||||||
...originalModule,
|
...originalModule,
|
||||||
useRouteMatch: jest.fn(() => {
|
useRouteMatch: jest.fn(() => {
|
||||||
return {
|
return {
|
||||||
teamId: 'team1',
|
params: {
|
||||||
boardId: 'boardId1',
|
teamId: 'team1',
|
||||||
viewId: 'viewId1',
|
boardId: 'boardId1',
|
||||||
cardId: 'cardId1',
|
viewId: 'viewId1',
|
||||||
|
cardId: 'cardId1',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import React, {useCallback} from 'react'
|
import React, {useCallback} from 'react'
|
||||||
import {FormattedMessage} from 'react-intl'
|
import {FormattedMessage} from 'react-intl'
|
||||||
import {generatePath, useRouteMatch, useHistory} from 'react-router-dom'
|
import {generatePath, useRouteMatch} from 'react-router-dom'
|
||||||
|
|
||||||
import Button from 'src/widgets/buttons/button'
|
import Button from 'src/widgets/buttons/button'
|
||||||
import TelemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetry/telemetryClient'
|
import TelemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetry/telemetryClient'
|
||||||
@@ -12,14 +12,17 @@ import './shareBoardLoginButton.scss'
|
|||||||
|
|
||||||
const ShareBoardLoginButton = () => {
|
const ShareBoardLoginButton = () => {
|
||||||
const match = useRouteMatch<{teamId: string, boardId: string, viewId?: string, cardId?: string}>()
|
const match = useRouteMatch<{teamId: string, boardId: string, viewId?: string, cardId?: string}>()
|
||||||
const history = useHistory()
|
|
||||||
|
|
||||||
const redirectQueryParam = 'r=' + encodeURIComponent(generatePath('/:boardId?/:viewId?/:cardId?', match.params))
|
// Mattermost login doesn't respect the redirect query parameter
|
||||||
const loginPath = '/login?' + redirectQueryParam
|
// if the user is already logged in, so we send the user to the
|
||||||
|
// board and if they are not logged in, the webapp will take care
|
||||||
|
// of the redirection
|
||||||
|
const baseURL = window.location.href.split('/boards/public')[0]
|
||||||
|
const loginPath = `${baseURL}/${generatePath('/boards/team/:teamId/:boardId?/:viewId?/:cardId?', match.params)}`
|
||||||
|
|
||||||
const onLoginClick = useCallback(() => {
|
const onLoginClick = useCallback(() => {
|
||||||
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.ShareBoardLogin)
|
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.ShareBoardLogin)
|
||||||
history.push(loginPath)
|
location.assign(loginPath)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -52,19 +52,22 @@ const TeamPermissionsRow = (): JSX.Element => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentRoleName = intl.formatMessage({id: 'BoardMember.schemeNone', defaultMessage: 'None'})
|
let currentRoleName = intl.formatMessage({id: 'BoardMember.schemeAdmin', defaultMessage: 'Admin'})
|
||||||
if (board.type === BoardTypeOpen && board.minimumRole === MemberRole.Admin) {
|
if (board.type === BoardTypeOpen) {
|
||||||
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeAdmin', defaultMessage: 'Admin'})
|
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})
|
||||||
} else if (board.type === BoardTypeOpen && board.minimumRole === MemberRole.Editor) {
|
if (board.minimumRole === MemberRole.Editor) {
|
||||||
if (board.isTemplate) {
|
if (board.isTemplate) {
|
||||||
|
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})
|
||||||
|
} else {
|
||||||
|
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})
|
||||||
|
}
|
||||||
|
} else if (board.minimumRole === MemberRole.Commenter) {
|
||||||
|
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeCommenter', defaultMessage: 'Commenter'})
|
||||||
|
} else if (board.minimumRole === MemberRole.Viewer) {
|
||||||
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})
|
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})
|
||||||
} else {
|
|
||||||
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})
|
|
||||||
}
|
}
|
||||||
} else if (board.type === BoardTypeOpen && board.minimumRole === MemberRole.Commenter) {
|
} else {
|
||||||
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeCommenter', defaultMessage: 'Commenter'})
|
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeNone', defaultMessage: 'None'})
|
||||||
} else if (board.type === BoardTypeOpen && board.minimumRole === MemberRole.Viewer) {
|
|
||||||
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmationDialog = (
|
const confirmationDialog = (
|
||||||
|
|||||||
@@ -59,9 +59,12 @@ const ViewHeader = (props: Props) => {
|
|||||||
const [showFilter, setShowFilter] = useState(false)
|
const [showFilter, setShowFilter] = useState(false)
|
||||||
const [lockFilterOnClose, setLockFilterOnClose] = useState(false)
|
const [lockFilterOnClose, setLockFilterOnClose] = useState(false)
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const canEditBoardProperties = useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
|
|
||||||
|
|
||||||
const {board, activeView, views, groupByProperty, cards, dateDisplayProperty} = props
|
const {board, activeView, views, groupByProperty, cards, dateDisplayProperty} = props
|
||||||
|
let readonly = props.readonly
|
||||||
|
if(!readonly){
|
||||||
|
readonly = !useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
|
||||||
|
}
|
||||||
|
|
||||||
const withGroupBy = activeView.fields.viewType === 'board' || activeView.fields.viewType === 'table'
|
const withGroupBy = activeView.fields.viewType === 'board' || activeView.fields.viewType === 'table'
|
||||||
const withDisplayBy = activeView.fields.viewType === 'calendar'
|
const withDisplayBy = activeView.fields.viewType === 'calendar'
|
||||||
@@ -137,7 +140,7 @@ const ViewHeader = (props: Props) => {
|
|||||||
}}
|
}}
|
||||||
onChange={setViewTitle}
|
onChange={setViewTitle}
|
||||||
saveOnEsc={true}
|
saveOnEsc={true}
|
||||||
readonly={props.readonly || !canEditBoardProperties}
|
readonly={readonly}
|
||||||
spellCheck={true}
|
spellCheck={true}
|
||||||
autoExpand={false}
|
autoExpand={false}
|
||||||
/>
|
/>
|
||||||
@@ -148,7 +151,7 @@ const ViewHeader = (props: Props) => {
|
|||||||
board={board}
|
board={board}
|
||||||
activeView={activeView}
|
activeView={activeView}
|
||||||
views={views}
|
views={views}
|
||||||
readonly={props.readonly || !canEditBoardProperties}
|
readonly={readonly}
|
||||||
allowCreateView={allowCreateView}
|
allowCreateView={allowCreateView}
|
||||||
/>
|
/>
|
||||||
</MenuWrapper>
|
</MenuWrapper>
|
||||||
@@ -159,7 +162,7 @@ const ViewHeader = (props: Props) => {
|
|||||||
|
|
||||||
<div className='octo-spacer'/>
|
<div className='octo-spacer'/>
|
||||||
|
|
||||||
{!props.readonly && canEditBoardProperties &&
|
{!readonly &&
|
||||||
<>
|
<>
|
||||||
{/* Card properties */}
|
{/* Card properties */}
|
||||||
|
|
||||||
|
|||||||
@@ -34,9 +34,11 @@ const ViewTitle = (props: Props) => {
|
|||||||
}, [board.id, board.icon])
|
}, [board.id, board.icon])
|
||||||
const onShowDescription = useCallback(() => mutator.showBoardDescription(board.id, Boolean(board.showDescription), true), [board.id, board.showDescription])
|
const onShowDescription = useCallback(() => mutator.showBoardDescription(board.id, Boolean(board.showDescription), true), [board.id, board.showDescription])
|
||||||
const onHideDescription = useCallback(() => mutator.showBoardDescription(board.id, Boolean(board.showDescription), false), [board.id, board.showDescription])
|
const onHideDescription = useCallback(() => mutator.showBoardDescription(board.id, Boolean(board.showDescription), false), [board.id, board.showDescription])
|
||||||
const canEditBoardProperties = useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
|
|
||||||
|
|
||||||
const readonly = props.readonly || !canEditBoardProperties
|
let readonly = props.readonly
|
||||||
|
if(!readonly){
|
||||||
|
readonly = !useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
|
||||||
|
}
|
||||||
|
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ jest.mock('react-router-dom', () => {
|
|||||||
useRouteMatch: jest.fn(() => {
|
useRouteMatch: jest.fn(() => {
|
||||||
return {
|
return {
|
||||||
params: {
|
params: {
|
||||||
|
teamId: board.teamId,
|
||||||
boardId: board.id,
|
boardId: board.id,
|
||||||
viewId: activeView.id,
|
viewId: activeView.id,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,13 +12,12 @@ export const useHasPermissions = (teamId: string, boardId: string, permissions:
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const member = useAppSelector(getMyBoardMembership(boardId))
|
|
||||||
const board = useAppSelector(getBoard(boardId))
|
const board = useAppSelector(getBoard(boardId))
|
||||||
|
|
||||||
if (!board) {
|
if (!board) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const member = useAppSelector(getMyBoardMembership(boardId))
|
||||||
if (!member) {
|
if (!member) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ windowAny.baseURL = '/plugins/boards'
|
|||||||
windowAny.frontendBaseURL = '/boards'
|
windowAny.frontendBaseURL = '/boards'
|
||||||
|
|
||||||
import App from 'src/app'
|
import App from 'src/app'
|
||||||
|
import PublicApp, {publicBaseURL} from 'src/public/app'
|
||||||
|
|
||||||
import store from 'src/store'
|
import store from 'src/store'
|
||||||
import WithWebSockets from 'src/components/withWebSockets'
|
import WithWebSockets from 'src/components/withWebSockets'
|
||||||
@@ -175,10 +176,44 @@ const MainApp = (props: Props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PublicMainApp = () => {
|
||||||
|
useEffect(() => {
|
||||||
|
document.body.classList.add('focalboard-body')
|
||||||
|
const root = document.getElementById('root')
|
||||||
|
if (root) {
|
||||||
|
while (root.firstElementChild) {
|
||||||
|
if( root.firstElementChild.id === 'focalboard-app'){
|
||||||
|
break
|
||||||
|
}
|
||||||
|
root.removeChild(root.firstElementChild)
|
||||||
|
}
|
||||||
|
root.classList.add('focalboard-plugin-root')
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.body.classList.remove('focalboard-body')
|
||||||
|
if (root) {
|
||||||
|
root.classList.remove('focalboard-plugin-root')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ErrorBoundary>
|
||||||
|
<ReduxProvider store={store}>
|
||||||
|
<div id='focalboard-app'>
|
||||||
|
<PublicApp />
|
||||||
|
</div>
|
||||||
|
<div id='focalboard-root-portal' />
|
||||||
|
</ReduxProvider>
|
||||||
|
</ErrorBoundary>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const HeaderComponent = () => {
|
const HeaderComponent = () => {
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<GlobalHeader history={browserHistory}/>
|
<GlobalHeader history={browserHistory} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -243,8 +278,6 @@ export default class Plugin {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const initCurrentChannelId = mmStore.getState().entities.channels.currentChannelId
|
const initCurrentChannelId = mmStore.getState().entities.channels.currentChannelId
|
||||||
const initCurrentChannel = mmStore.getState().entities.channels.channels[initCurrentChannelId]
|
const initCurrentChannel = mmStore.getState().entities.channels.channels[initCurrentChannelId]
|
||||||
let lastViewedChannelId = initCurrentChannelId
|
let lastViewedChannelId = initCurrentChannelId
|
||||||
@@ -274,7 +307,9 @@ export default class Plugin {
|
|||||||
prevTeamId = currentTeamId
|
prevTeamId = currentTeamId
|
||||||
store.dispatch(setTeam(currentTeamId))
|
store.dispatch(setTeam(currentTeamId))
|
||||||
octoClient.teamId = currentTeamId
|
octoClient.teamId = currentTeamId
|
||||||
store.dispatch(initialLoad())
|
if(!window.location.pathname.includes(publicBaseURL())){
|
||||||
|
store.dispatch(initialLoad())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTeamId && currentTeamId !== prevTeamId) {
|
if (currentTeamId && currentTeamId !== prevTeamId) {
|
||||||
@@ -336,6 +371,9 @@ export default class Plugin {
|
|||||||
HeaderComponent,
|
HeaderComponent,
|
||||||
() => null,
|
() => null,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
PublicMainApp,
|
||||||
)
|
)
|
||||||
|
|
||||||
const goToFocalboardTemplate = () => {
|
const goToFocalboardTemplate = () => {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`properties/number should match snapshot for number with empty value 1`] = `
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
class="Editable octo-propertyvalue"
|
||||||
|
placeholder=""
|
||||||
|
style="width: 100%;"
|
||||||
|
title=""
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
70
webapp/boards/src/properties/number/number.test.tsx
Обычный файл
70
webapp/boards/src/properties/number/number.test.tsx
Обычный файл
@@ -0,0 +1,70 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import React, {ComponentProps} from 'react'
|
||||||
|
import {screen} from '@testing-library/react'
|
||||||
|
import {mocked} from 'jest-mock'
|
||||||
|
|
||||||
|
import {setup, wrapIntl} from 'src/testUtils'
|
||||||
|
import {TestBlockFactory} from 'src/test/testBlockFactory'
|
||||||
|
import mutator from 'src/mutator'
|
||||||
|
|
||||||
|
import {Board, IPropertyTemplate} from 'src/blocks/board'
|
||||||
|
import {Card} from 'src/blocks/card'
|
||||||
|
|
||||||
|
import NumberProperty from './property'
|
||||||
|
import NumberEditor from './number'
|
||||||
|
|
||||||
|
jest.mock('src/components/flashMessages')
|
||||||
|
jest.mock('src/mutator')
|
||||||
|
|
||||||
|
const mockedMutator = mocked(mutator)
|
||||||
|
|
||||||
|
describe('properties/number', () => {
|
||||||
|
let board: Board
|
||||||
|
let card: Card
|
||||||
|
let propertyTemplate: IPropertyTemplate
|
||||||
|
let baseProps: ComponentProps<typeof NumberEditor>
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
board = TestBlockFactory.createBoard()
|
||||||
|
card = TestBlockFactory.createCard()
|
||||||
|
propertyTemplate = board.cardProperties[0]
|
||||||
|
|
||||||
|
baseProps = {
|
||||||
|
property: new NumberProperty(),
|
||||||
|
card,
|
||||||
|
board,
|
||||||
|
propertyTemplate,
|
||||||
|
propertyValue: '',
|
||||||
|
readOnly: false,
|
||||||
|
showEmptyPlaceholder: false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should match snapshot for number with empty value', () => {
|
||||||
|
const {container} = setup(
|
||||||
|
wrapIntl((
|
||||||
|
<NumberEditor
|
||||||
|
{...baseProps}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
)
|
||||||
|
expect(container).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should fire change event when valid number value is entered', async () => {
|
||||||
|
const {user} = setup(
|
||||||
|
wrapIntl(
|
||||||
|
<NumberEditor
|
||||||
|
{...baseProps}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
const value = '42'
|
||||||
|
const input = screen.getByRole('textbox')
|
||||||
|
await user.type(input, `${value}{Enter}`)
|
||||||
|
|
||||||
|
expect(mockedMutator.changePropertyValue).toHaveBeenCalledWith(board.id, card, propertyTemplate.id, `${value}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -10,7 +10,7 @@ const Number = (props: PropertyProps): JSX.Element => {
|
|||||||
return (
|
return (
|
||||||
<BaseTextEditor
|
<BaseTextEditor
|
||||||
{...props}
|
{...props}
|
||||||
validator={() => !isNaN(parseInt(props.propertyValue as string, 10))}
|
validator={() => props.propertyValue === '' || !isNaN(parseInt(props.propertyValue as string, 10))}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
61
webapp/boards/src/public/app.tsx
Обычный файл
61
webapp/boards/src/public/app.tsx
Обычный файл
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
import React from 'react'
|
||||||
|
import {Router, Switch} from 'react-router-dom'
|
||||||
|
|
||||||
|
import {IntlProvider} from 'react-intl'
|
||||||
|
import {DndProvider} from 'react-dnd'
|
||||||
|
import {HTML5Backend} from 'react-dnd-html5-backend'
|
||||||
|
import {TouchBackend} from 'react-dnd-touch-backend'
|
||||||
|
import {createBrowserHistory} from 'history'
|
||||||
|
|
||||||
|
import BoardPage from 'src/pages/boardPage/boardPage'
|
||||||
|
import FBRoute from 'src/route'
|
||||||
|
|
||||||
|
import {getMessages} from 'src/i18n'
|
||||||
|
import FlashMessages from 'src/components/flashMessages'
|
||||||
|
import NewVersionBanner from 'src/components/newVersionBanner'
|
||||||
|
import {Utils} from 'src/utils'
|
||||||
|
import {getLanguage} from 'src/store/language'
|
||||||
|
import {useAppSelector} from 'src/store/hooks'
|
||||||
|
|
||||||
|
export const publicBaseURL = () => {
|
||||||
|
return Utils.getFrontendBaseURL() + '/public'
|
||||||
|
}
|
||||||
|
|
||||||
|
const PublicRouter = () => {
|
||||||
|
const history = createBrowserHistory({basename: publicBaseURL()})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Router history={history}>
|
||||||
|
<Switch>
|
||||||
|
<FBRoute path={['/team/:teamId/shared/:boardId?/:viewId?/:cardId?', '/shared/:boardId?/:viewId?/:cardId?']}>
|
||||||
|
<BoardPage readonly={true}/>
|
||||||
|
</FBRoute>
|
||||||
|
</Switch>
|
||||||
|
</Router>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const PublicApp = (): JSX.Element => {
|
||||||
|
const language = useAppSelector<string>(getLanguage)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IntlProvider
|
||||||
|
locale={language.split(/[_]/)[0]}
|
||||||
|
messages={getMessages(language)}
|
||||||
|
>
|
||||||
|
<DndProvider backend={Utils.isMobile() ? TouchBackend : HTML5Backend}>
|
||||||
|
<FlashMessages milliseconds={2000}/>
|
||||||
|
<div id='frame'>
|
||||||
|
<div id='main'>
|
||||||
|
<NewVersionBanner/>
|
||||||
|
<PublicRouter/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DndProvider>
|
||||||
|
</IntlProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(PublicApp)
|
||||||
4
webapp/boards/src/types/mattermost-webapp/index.d.ts
поставляемый
4
webapp/boards/src/types/mattermost-webapp/index.d.ts
поставляемый
@@ -14,7 +14,9 @@ export interface PluginRegistry {
|
|||||||
registerCustomRoute(route: string, component: ReactResolvable): any
|
registerCustomRoute(route: string, component: ReactResolvable): any
|
||||||
registerProductRoute(route: string, component: ReactResolvable): any
|
registerProductRoute(route: string, component: ReactResolvable): any
|
||||||
unregisterComponent(componentId: string): any
|
unregisterComponent(componentId: string): any
|
||||||
registerProduct(baseURL: string, switcherIcon: string, switcherText: string, switcherLinkURL: string, mainComponent: ReactResolvable, headerCentreComponent: ReactResolvable, headerRightComponent: ReactResolvable, showTeamSidebar: boolean): any
|
registerProduct(baseURL: string, switcherIcon: string, switcherText: string, switcherLinkURL: string,
|
||||||
|
mainComponent: ReactResolvable, headerCentreComponent: ReactResolvable, headerRightComponent: ReactResolvable,
|
||||||
|
showTeamSidebar: boolean, showAppBar: boolean, wrapped: boolean, publicComponent: ReactResolvable | null): any
|
||||||
registerPostWillRenderEmbedComponent(match: (embed: {type: string, data: any}) => void, component: any, toggleable: boolean): any
|
registerPostWillRenderEmbedComponent(match: (embed: {type: string, data: any}) => void, component: any, toggleable: boolean): any
|
||||||
registerWebSocketEventHandler(event: string, handler: (e: any) => void): any
|
registerWebSocketEventHandler(event: string, handler: (e: any) => void): any
|
||||||
unregisterWebSocketEventHandler(event: string): any
|
unregisterWebSocketEventHandler(event: string): any
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"plugin:react-hooks/recommended"
|
"plugin:react-hooks/recommended"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@babel/eslint-plugin",
|
"@babel",
|
||||||
"mattermost",
|
"mattermost",
|
||||||
"import",
|
"import",
|
||||||
"no-only-tests",
|
"no-only-tests",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"npm": ">=7.0.0",
|
"npm": ">=7.0.0",
|
||||||
"node": ">=16.4.0"
|
"node": ">=16.10.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/react-dom": "1.0.0",
|
"@floating-ui/react-dom": "1.0.0",
|
||||||
@@ -153,8 +153,8 @@
|
|||||||
"@types/styled-components": "5.1.24",
|
"@types/styled-components": "5.1.24",
|
||||||
"@types/tinycolor2": "1.4.3",
|
"@types/tinycolor2": "1.4.3",
|
||||||
"@types/webpack-env": "1.18.0",
|
"@types/webpack-env": "1.18.0",
|
||||||
"@typescript-eslint/eslint-plugin": "5.41.0",
|
"@typescript-eslint/eslint-plugin": "5.57.1",
|
||||||
"@typescript-eslint/parser": "5.41.0",
|
"@typescript-eslint/parser": "5.57.1",
|
||||||
"babel-loader": "8.2.3",
|
"babel-loader": "8.2.3",
|
||||||
"babel-plugin-lodash": "3.3.4",
|
"babel-plugin-lodash": "3.3.4",
|
||||||
"babel-plugin-styled-components": "1.12.0",
|
"babel-plugin-styled-components": "1.12.0",
|
||||||
@@ -167,14 +167,13 @@
|
|||||||
"enzyme": "3.11.0",
|
"enzyme": "3.11.0",
|
||||||
"enzyme-adapter-react-17-updated": "1.0.2",
|
"enzyme-adapter-react-17-updated": "1.0.2",
|
||||||
"enzyme-to-json": "3.6.2",
|
"enzyme-to-json": "3.6.2",
|
||||||
"eslint": "7.32.0",
|
|
||||||
"eslint-import-resolver-webpack": "0.13.2",
|
"eslint-import-resolver-webpack": "0.13.2",
|
||||||
"eslint-plugin-formatjs": "4.3.4",
|
"eslint-plugin-formatjs": "4.9.1",
|
||||||
"eslint-plugin-header": "3.1.1",
|
"eslint-plugin-header": "3.1.1",
|
||||||
"eslint-plugin-import": "2.23.4",
|
"eslint-plugin-import": "2.27.5",
|
||||||
"eslint-plugin-mattermost": "github:mattermost/eslint-plugin-mattermost#5b0c972eacf19286e4c66221b39113bf8728a99e",
|
"eslint-plugin-mattermost": "github:mattermost/eslint-plugin-mattermost#5b0c972eacf19286e4c66221b39113bf8728a99e",
|
||||||
"eslint-plugin-no-only-tests": "2.6.0",
|
"eslint-plugin-no-only-tests": "3.1.0",
|
||||||
"eslint-plugin-react": "7.31.10",
|
"eslint-plugin-react": "7.32.2",
|
||||||
"eslint-plugin-react-hooks": "4.6.0",
|
"eslint-plugin-react-hooks": "4.6.0",
|
||||||
"external-remotes-plugin": "1.0.0",
|
"external-remotes-plugin": "1.0.0",
|
||||||
"file-loader": "6.2.0",
|
"file-loader": "6.2.0",
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export default class AboutBuildModal extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
doHide = () => {
|
doHide = () => {
|
||||||
this.setState({show: false});
|
this.setState({show: false});
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const config = this.props.config;
|
const config = this.props.config;
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ export default class AccessHistoryModal extends React.PureComponent<Props, State
|
|||||||
|
|
||||||
public onShow = () => { // public for testing
|
public onShow = () => { // public for testing
|
||||||
this.props.actions.getUserAudits(this.props.currentUserId, 0, 200);
|
this.props.actions.getUserAudits(this.props.currentUserId, 0, 200);
|
||||||
}
|
};
|
||||||
|
|
||||||
public onHide = () => { // public for testing
|
public onHide = () => { // public for testing
|
||||||
this.setState({show: false});
|
this.setState({show: false});
|
||||||
}
|
};
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
this.onShow();
|
this.onShow();
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export default class Accordion extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
setExpanded = (expandedKey: string) => {
|
setExpanded = (expandedKey: string) => {
|
||||||
this.setState({expandedKey});
|
this.setState({expandedKey});
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
|
|||||||
appBindings: [],
|
appBindings: [],
|
||||||
location: Locations.CENTER,
|
location: Locations.CENTER,
|
||||||
pluginMenuItems: [],
|
pluginMenuItems: [],
|
||||||
}
|
};
|
||||||
private buttonRef: React.RefObject<HTMLButtonElement>;
|
private buttonRef: React.RefObject<HTMLButtonElement>;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
@@ -115,7 +115,7 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
|
|||||||
defaultMessage='Message actions'
|
defaultMessage='Message actions'
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
);
|
||||||
|
|
||||||
componentDidUpdate(prevProps: Props) {
|
componentDidUpdate(prevProps: Props) {
|
||||||
if (this.props.isMenuOpen && !prevProps.isMenuOpen) {
|
if (this.props.isMenuOpen && !prevProps.isMenuOpen) {
|
||||||
@@ -137,7 +137,7 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
|
|||||||
this.setState({appBindings: data});
|
this.setState({appBindings: data});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
handleOpenMarketplace = (): void => {
|
handleOpenMarketplace = (): void => {
|
||||||
const openedFrom: OpenedFromType = 'actions_menu';
|
const openedFrom: OpenedFromType = 'actions_menu';
|
||||||
@@ -197,7 +197,7 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
|
|||||||
this.props.actions.postEphemeralCallResponseForPost(callResp, errorMessage, post);
|
this.props.actions.postEphemeralCallResponseForPost(callResp, errorMessage, post);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
visitMarketplaceTip(): React.ReactElement {
|
visitMarketplaceTip(): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
@@ -263,7 +263,7 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
|
|||||||
this.setState({
|
this.setState({
|
||||||
openUp: (spaceOnTop > spaceOnBottom),
|
openUp: (spaceOnTop > spaceOnBottom),
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
render(): React.ReactNode {
|
render(): React.ReactNode {
|
||||||
const isSystemMessage = PostUtils.isSystemMessage(this.props.post);
|
const isSystemMessage = PostUtils.isSystemMessage(this.props.post);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ type State = {
|
|||||||
export default class ActivityLogModal extends React.PureComponent<Props, State> {
|
export default class ActivityLogModal extends React.PureComponent<Props, State> {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -73,15 +73,15 @@ export default class ActivityLogModal extends React.PureComponent<Props, State>
|
|||||||
this.props.actions.revokeSession(this.props.currentUserId, altId).then(() => {
|
this.props.actions.revokeSession(this.props.currentUserId, altId).then(() => {
|
||||||
this.props.actions.getSessions(this.props.currentUserId);
|
this.props.actions.getSessions(this.props.currentUserId);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
onShow = () => {
|
onShow = () => {
|
||||||
this.props.actions.getSessions(this.props.currentUserId);
|
this.props.actions.getSessions(this.props.currentUserId);
|
||||||
}
|
};
|
||||||
|
|
||||||
onHide = () => {
|
onHide = () => {
|
||||||
this.setState({show: false});
|
this.setState({show: false});
|
||||||
}
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.onShow();
|
this.onShow();
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ export default class ActivityLog extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
handleMoreInfo = (): void => {
|
handleMoreInfo = (): void => {
|
||||||
this.setState({moreInfo: true});
|
this.setState({moreInfo: true});
|
||||||
}
|
};
|
||||||
|
|
||||||
submitRevoke = (e: React.MouseEvent): void => {
|
submitRevoke = (e: React.MouseEvent): void => {
|
||||||
this.props.submitRevoke(this.props.currentSession.id, e);
|
this.props.submitRevoke(this.props.currentSession.id, e);
|
||||||
}
|
};
|
||||||
|
|
||||||
isMobileSession = (session: Session): boolean => {
|
isMobileSession = (session: Session): boolean => {
|
||||||
return Boolean(session.device_id && (session.device_id.includes('apple') || session.device_id.includes('android')));
|
return Boolean(session.device_id && (session.device_id.includes('apple') || session.device_id.includes('android')));
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
|
|||||||
handleHide = () => {
|
handleHide = () => {
|
||||||
this.props.actions.setModalSearchTerm('');
|
this.props.actions.setModalSearchTerm('');
|
||||||
this.setState({show: false});
|
this.setState({show: false});
|
||||||
}
|
};
|
||||||
|
|
||||||
handleResponse = (err?: ServerError) => {
|
handleResponse = (err?: ServerError) => {
|
||||||
let addError = null;
|
let addError = null;
|
||||||
@@ -122,7 +122,7 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
|
|||||||
saving: false,
|
saving: false,
|
||||||
addError,
|
addError,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
handleSubmit = async () => {
|
handleSubmit = async () => {
|
||||||
const groupIDs = this.state.values.map((v) => v.id);
|
const groupIDs = this.state.values.map((v) => v.id);
|
||||||
@@ -147,7 +147,7 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
|
|||||||
this.handleHide();
|
this.handleHide();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
};
|
||||||
|
|
||||||
addValue = (value: GroupValue) => {
|
addValue = (value: GroupValue) => {
|
||||||
const values = Object.assign([], this.state.values);
|
const values = Object.assign([], this.state.values);
|
||||||
@@ -157,13 +157,13 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.setState({values});
|
this.setState({values});
|
||||||
}
|
};
|
||||||
|
|
||||||
setGroupsLoadingState = (loadingState: boolean) => {
|
setGroupsLoadingState = (loadingState: boolean) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
loadingGroups: loadingState,
|
loadingGroups: loadingState,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
handlePageChange = (page: number, prevPage: number) => {
|
handlePageChange = (page: number, prevPage: number) => {
|
||||||
if (page > prevPage) {
|
if (page > prevPage) {
|
||||||
@@ -172,15 +172,15 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
|
|||||||
this.setGroupsLoadingState(false);
|
this.setGroupsLoadingState(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
handleDelete = (values: GroupValue[]) => {
|
handleDelete = (values: GroupValue[]) => {
|
||||||
this.setState({values});
|
this.setState({values});
|
||||||
}
|
};
|
||||||
|
|
||||||
search = (term: string) => {
|
search = (term: string) => {
|
||||||
this.props.actions.setModalSearchTerm(term);
|
this.props.actions.setModalSearchTerm(term);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderOption = (option: GroupValue, isSelected: boolean, onAdd: (value: GroupValue) => void, onMouseMove?: (value: GroupValue) => void) => {
|
renderOption = (option: GroupValue, isSelected: boolean, onAdd: (value: GroupValue) => void, onMouseMove?: (value: GroupValue) => void) => {
|
||||||
const rowSelected = isSelected ? 'more-modal__row--selected' : '';
|
const rowSelected = isSelected ? 'more-modal__row--selected' : '';
|
||||||
@@ -222,7 +222,7 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderValue(props: { data: Partial<Value> }) {
|
renderValue(props: { data: Partial<Value> }) {
|
||||||
return props.data.display_name;
|
return props.data.display_name;
|
||||||
|
|||||||
@@ -105,12 +105,12 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
|
|||||||
public handleHide = () => {
|
public handleHide = () => {
|
||||||
this.props.actions.setModalSearchTerm('');
|
this.props.actions.setModalSearchTerm('');
|
||||||
this.setState({show: false});
|
this.setState({show: false});
|
||||||
}
|
};
|
||||||
|
|
||||||
// public for tests
|
// public for tests
|
||||||
public handleExit = (): void => {
|
public handleExit = (): void => {
|
||||||
this.props.onExited();
|
this.props.onExited();
|
||||||
}
|
};
|
||||||
|
|
||||||
// public for tests
|
// public for tests
|
||||||
public handleResponse = (err?: Error): void => {
|
public handleResponse = (err?: Error): void => {
|
||||||
@@ -123,7 +123,7 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
|
|||||||
saving: false,
|
saving: false,
|
||||||
addError,
|
addError,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// public for tests
|
// public for tests
|
||||||
public handleSubmit = async () => {
|
public handleSubmit = async () => {
|
||||||
@@ -148,7 +148,7 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
|
|||||||
this.handleHide();
|
this.handleHide();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
};
|
||||||
|
|
||||||
// public for tests
|
// public for tests
|
||||||
public addValue = (value: GroupValue): void => {
|
public addValue = (value: GroupValue): void => {
|
||||||
@@ -159,13 +159,13 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.setState({values});
|
this.setState({values});
|
||||||
}
|
};
|
||||||
|
|
||||||
private setGroupsLoadingState = (loadingState: boolean) => {
|
private setGroupsLoadingState = (loadingState: boolean) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
loadingGroups: loadingState,
|
loadingGroups: loadingState,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// public for tests
|
// public for tests
|
||||||
public handlePageChange = (page: number, prevPage: number): void => {
|
public handlePageChange = (page: number, prevPage: number): void => {
|
||||||
@@ -175,7 +175,7 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
|
|||||||
this.setGroupsLoadingState(false);
|
this.setGroupsLoadingState(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// public for tests
|
// public for tests
|
||||||
public handleDelete = (values: GroupValue[]): void => this.setState({values});
|
public handleDelete = (values: GroupValue[]): void => this.setState({values});
|
||||||
@@ -224,7 +224,7 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
// public for tests
|
// public for tests
|
||||||
public renderValue = (props: { data: Value }): string | undefined => props.data.display_name;
|
public renderValue = (props: { data: Value }): string | undefined => props.data.display_name;
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
|
|||||||
|
|
||||||
enableChannelProvider = () => {
|
enableChannelProvider = () => {
|
||||||
this.suggestionProviders[0].disableDispatches = false;
|
this.suggestionProviders[0].disableDispatches = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
focusTextbox = () => {
|
focusTextbox = () => {
|
||||||
if (this.channelSearchBox == null) {
|
if (this.channelSearchBox == null) {
|
||||||
@@ -126,30 +126,30 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
|
|||||||
textbox.focus();
|
textbox.focus();
|
||||||
placeCaretAtEnd(textbox);
|
placeCaretAtEnd(textbox);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({text: e.target.value, selectedChannelId: null});
|
this.setState({text: e.target.value, selectedChannelId: null});
|
||||||
}
|
};
|
||||||
|
|
||||||
onHide = () => {
|
onHide = () => {
|
||||||
this.setState({show: false});
|
this.setState({show: false});
|
||||||
}
|
};
|
||||||
|
|
||||||
onExited = () => {
|
onExited = () => {
|
||||||
this.props.onExited();
|
this.props.onExited();
|
||||||
}
|
};
|
||||||
|
|
||||||
setSearchBoxRef = (input: SuggestionBoxComponent) => {
|
setSearchBoxRef = (input: SuggestionBoxComponent) => {
|
||||||
this.channelSearchBox = input;
|
this.channelSearchBox = input;
|
||||||
this.focusTextbox();
|
this.focusTextbox();
|
||||||
}
|
};
|
||||||
|
|
||||||
handleSubmitError = (error: {message: string}) => {
|
handleSubmitError = (error: {message: string}) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
this.setState({submitError: error.message, saving: false});
|
this.setState({submitError: error.message, saving: false});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
didSelectChannel = (selection: {channel: Channel}) => {
|
didSelectChannel = (selection: {channel: Channel}) => {
|
||||||
const channel = selection.channel;
|
const channel = selection.channel;
|
||||||
@@ -165,7 +165,7 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
|
|||||||
this.props.actions.getChannelMember(channel.id, userId).then(() => {
|
this.props.actions.getChannelMember(channel.id, userId).then(() => {
|
||||||
this.setState({checkingForMembership: false});
|
this.setState({checkingForMembership: false});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
handleSubmit = (e: FormEvent) => {
|
handleSubmit = (e: FormEvent) => {
|
||||||
if (e && e.preventDefault) {
|
if (e && e.preventDefault) {
|
||||||
@@ -192,7 +192,7 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
|
|||||||
this.onHide();
|
this.onHide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
isUserMemberOfChannel = (channelId: string | null) => {
|
isUserMemberOfChannel = (channelId: string | null) => {
|
||||||
const user = this.props.user;
|
const user = this.props.user;
|
||||||
@@ -207,7 +207,7 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Boolean(memberships[channelId][user.id]);
|
return Boolean(memberships[channelId][user.id]);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const user = this.props.user;
|
const user = this.props.user;
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ export default class AddUserToGroupMultiSelect extends React.PureComponent<Props
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return option.username;
|
return option.username;
|
||||||
}
|
};
|
||||||
|
|
||||||
renderOption = (option: UserProfileValue, isSelected: boolean, onAdd: (user: UserProfileValue) => void, onMouseMove: (user: UserProfileValue) => void) => {
|
renderOption = (option: UserProfileValue, isSelected: boolean, onAdd: (user: UserProfileValue) => void, onMouseMove: (user: UserProfileValue) => void) => {
|
||||||
return (
|
return (
|
||||||
@@ -241,5 +241,5 @@ export default class AddUserToGroupMultiSelect extends React.PureComponent<Props
|
|||||||
numRemainingText={numRemainingText}
|
numRemainingText={numRemainingText}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,11 +78,11 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
|
|||||||
public componentDidMount = async () => {
|
public componentDidMount = async () => {
|
||||||
await this.props.actions.getProfilesNotInTeam(this.props.team.id, false, 0, USERS_PER_PAGE * 2);
|
await this.props.actions.getProfilesNotInTeam(this.props.team.id, false, 0, USERS_PER_PAGE * 2);
|
||||||
this.setUsersLoadingState(false);
|
this.setUsersLoadingState(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
private setUsersLoadingState = (loading: boolean) => {
|
private setUsersLoadingState = (loading: boolean) => {
|
||||||
this.setState({loading});
|
this.setState({loading});
|
||||||
}
|
};
|
||||||
|
|
||||||
public search = async (term: string) => {
|
public search = async (term: string) => {
|
||||||
this.setUsersLoadingState(true);
|
this.setUsersLoadingState(true);
|
||||||
@@ -95,17 +95,17 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
|
|||||||
await this.props.actions.getProfilesNotInTeam(this.props.team.id, false, 0, USERS_PER_PAGE * 2);
|
await this.props.actions.getProfilesNotInTeam(this.props.team.id, false, 0, USERS_PER_PAGE * 2);
|
||||||
}
|
}
|
||||||
this.setState({loading: false, searchResults, search});
|
this.setState({loading: false, searchResults, search});
|
||||||
}
|
};
|
||||||
|
|
||||||
public handleHide = () => {
|
public handleHide = () => {
|
||||||
this.setState({show: false});
|
this.setState({show: false});
|
||||||
}
|
};
|
||||||
|
|
||||||
private handleExit = () => {
|
private handleExit = () => {
|
||||||
if (this.props.onExited) {
|
if (this.props.onExited) {
|
||||||
this.props.onExited();
|
this.props.onExited();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
private renderOption = (option: UserProfileValue, isSelected: boolean, onAdd: (user: UserProfileValue) => void, onMouseMove: (user: UserProfileValue) => void) => {
|
private renderOption = (option: UserProfileValue, isSelected: boolean, onAdd: (user: UserProfileValue) => void, onMouseMove: (user: UserProfileValue) => void) => {
|
||||||
let rowSelected = '';
|
let rowSelected = '';
|
||||||
@@ -139,15 +139,15 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
private renderValue = (value: { data: UserProfileValue }): string => {
|
private renderValue = (value: { data: UserProfileValue }): string => {
|
||||||
return value.data?.username || '';
|
return value.data?.username || '';
|
||||||
}
|
};
|
||||||
|
|
||||||
private renderAriaLabel = (option: UserProfileValue): string => {
|
private renderAriaLabel = (option: UserProfileValue): string => {
|
||||||
return option?.username || '';
|
return option?.username || '';
|
||||||
}
|
};
|
||||||
|
|
||||||
private handleAdd = (value: UserProfileValue) => {
|
private handleAdd = (value: UserProfileValue) => {
|
||||||
const values: UserProfileValue[] = [...this.state.values];
|
const values: UserProfileValue[] = [...this.state.values];
|
||||||
@@ -155,11 +155,11 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
|
|||||||
values.push(value);
|
values.push(value);
|
||||||
}
|
}
|
||||||
this.setState({values});
|
this.setState({values});
|
||||||
}
|
};
|
||||||
|
|
||||||
private handleDelete = (values: UserProfileValue[]) => {
|
private handleDelete = (values: UserProfileValue[]) => {
|
||||||
this.setState({values});
|
this.setState({values});
|
||||||
}
|
};
|
||||||
|
|
||||||
private handlePageChange = (page: number, prevPage: number) => {
|
private handlePageChange = (page: number, prevPage: number) => {
|
||||||
if (page > prevPage) {
|
if (page > prevPage) {
|
||||||
@@ -173,7 +173,7 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
|
|||||||
private handleSubmit = () => {
|
private handleSubmit = () => {
|
||||||
this.props.onAddCallback(this.state.values);
|
this.props.onAddCallback(this.state.values);
|
||||||
this.handleHide();
|
this.handleHide();
|
||||||
}
|
};
|
||||||
|
|
||||||
public render = (): JSX.Element => {
|
public render = (): JSX.Element => {
|
||||||
const numRemainingText = (
|
const numRemainingText = (
|
||||||
@@ -259,5 +259,5 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
|
|||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export default class AdminConsole extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
private onFilterChange = (filter: string) => {
|
private onFilterChange = (filter: string) => {
|
||||||
this.setState({filter});
|
this.setState({filter});
|
||||||
}
|
};
|
||||||
|
|
||||||
private mainRolesLoaded(roles: Record<string, Role>) {
|
private mainRolesLoaded(roles: Record<string, Role>) {
|
||||||
return (
|
return (
|
||||||
@@ -186,7 +186,7 @@ export default class AdminConsole extends React.PureComponent<Props, State> {
|
|||||||
{<Redirect to={`${this.props.match.url}/${defaultUrl}`}/>}
|
{<Redirect to={`${this.props.match.url}/${defaultUrl}`}/>}
|
||||||
</Switch>
|
</Switch>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
public render(): JSX.Element | null {
|
public render(): JSX.Element | null {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -5746,7 +5746,6 @@ const AdminDefinition = {
|
|||||||
sectionTitle: t('admin.sidebar.products'),
|
sectionTitle: t('admin.sidebar.products'),
|
||||||
sectionTitleDefault: 'Products',
|
sectionTitleDefault: 'Products',
|
||||||
isHidden: it.any(
|
isHidden: it.any(
|
||||||
it.configIsFalse('FeatureFlags', 'BoardsProduct'),
|
|
||||||
it.not(it.userHasReadPermissionOnSomeResources(RESOURCE_KEYS.PRODUCTS)),
|
it.not(it.userHasReadPermissionOnSomeResources(RESOURCE_KEYS.PRODUCTS)),
|
||||||
),
|
),
|
||||||
boards: {
|
boards: {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export default abstract class AdminSettings <Props extends BaseProps, State exte
|
|||||||
|
|
||||||
private closeTooltip = () => {
|
private closeTooltip = () => {
|
||||||
this.setState({errorTooltip: false});
|
this.setState({errorTooltip: false});
|
||||||
}
|
};
|
||||||
|
|
||||||
private openTooltip = (e: React.MouseEvent) => {
|
private openTooltip = (e: React.MouseEvent) => {
|
||||||
const elm: HTMLElement|null = e.currentTarget.querySelector('.control-label');
|
const elm: HTMLElement|null = e.currentTarget.querySelector('.control-label');
|
||||||
@@ -77,7 +77,7 @@ export default abstract class AdminSettings <Props extends BaseProps, State exte
|
|||||||
const isElipsis = elm.offsetWidth < elm.scrollWidth;
|
const isElipsis = elm.offsetWidth < elm.scrollWidth;
|
||||||
this.setState({errorTooltip: isElipsis});
|
this.setState({errorTooltip: isElipsis});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
protected handleChange = (id: string, value: boolean) => {
|
protected handleChange = (id: string, value: boolean) => {
|
||||||
this.setState((prevState) => ({
|
this.setState((prevState) => ({
|
||||||
@@ -95,7 +95,7 @@ export default abstract class AdminSettings <Props extends BaseProps, State exte
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
this.doSubmit();
|
this.doSubmit();
|
||||||
}
|
};
|
||||||
|
|
||||||
protected doSubmit = async (callback?: () => void) => {
|
protected doSubmit = async (callback?: () => void) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|||||||
@@ -1072,6 +1072,37 @@ exports[`components/AdminSidebar should match snapshot 1`] = `
|
|||||||
title="Plugin 0"
|
title="Plugin 0"
|
||||||
/>
|
/>
|
||||||
</AdminSidebarCategory>
|
</AdminSidebarCategory>
|
||||||
|
<AdminSidebarCategory
|
||||||
|
definitionKey="products"
|
||||||
|
icon={
|
||||||
|
<ProductsIcon
|
||||||
|
className="category-icon fa"
|
||||||
|
color="currentColor"
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
key="products"
|
||||||
|
parentLink="/admin_console"
|
||||||
|
sectionClass=""
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Products"
|
||||||
|
id="admin.sidebar.products"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AdminSidebarSection
|
||||||
|
definitionKey="products.boards"
|
||||||
|
key="products.boards"
|
||||||
|
name="products/boards"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Boards"
|
||||||
|
id="admin.sidebar.boards"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AdminSidebarCategory>
|
||||||
<AdminSidebarCategory
|
<AdminSidebarCategory
|
||||||
definitionKey="integrations"
|
definitionKey="integrations"
|
||||||
icon={
|
icon={
|
||||||
@@ -1775,6 +1806,37 @@ exports[`components/AdminSidebar should match snapshot with workspace optimizati
|
|||||||
title="Plugin 0"
|
title="Plugin 0"
|
||||||
/>
|
/>
|
||||||
</AdminSidebarCategory>
|
</AdminSidebarCategory>
|
||||||
|
<AdminSidebarCategory
|
||||||
|
definitionKey="products"
|
||||||
|
icon={
|
||||||
|
<ProductsIcon
|
||||||
|
className="category-icon fa"
|
||||||
|
color="currentColor"
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
key="products"
|
||||||
|
parentLink="/admin_console"
|
||||||
|
sectionClass=""
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Products"
|
||||||
|
id="admin.sidebar.products"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AdminSidebarSection
|
||||||
|
definitionKey="products.boards"
|
||||||
|
key="products.boards"
|
||||||
|
name="products/boards"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Boards"
|
||||||
|
id="admin.sidebar.boards"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AdminSidebarCategory>
|
||||||
<AdminSidebarCategory
|
<AdminSidebarCategory
|
||||||
definitionKey="integrations"
|
definitionKey="integrations"
|
||||||
icon={
|
icon={
|
||||||
@@ -2533,6 +2595,37 @@ exports[`components/AdminSidebar should match snapshot, not prevent the console
|
|||||||
title="Plugin 0"
|
title="Plugin 0"
|
||||||
/>
|
/>
|
||||||
</AdminSidebarCategory>
|
</AdminSidebarCategory>
|
||||||
|
<AdminSidebarCategory
|
||||||
|
definitionKey="products"
|
||||||
|
icon={
|
||||||
|
<ProductsIcon
|
||||||
|
className="category-icon fa"
|
||||||
|
color="currentColor"
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
key="products"
|
||||||
|
parentLink="/admin_console"
|
||||||
|
sectionClass=""
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Products"
|
||||||
|
id="admin.sidebar.products"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AdminSidebarSection
|
||||||
|
definitionKey="products.boards"
|
||||||
|
key="products.boards"
|
||||||
|
name="products/boards"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Boards"
|
||||||
|
id="admin.sidebar.boards"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AdminSidebarCategory>
|
||||||
<AdminSidebarCategory
|
<AdminSidebarCategory
|
||||||
definitionKey="integrations"
|
definitionKey="integrations"
|
||||||
icon={
|
icon={
|
||||||
@@ -3236,6 +3329,37 @@ exports[`components/AdminSidebar should match snapshot, render plugins without a
|
|||||||
title="Plugin 0"
|
title="Plugin 0"
|
||||||
/>
|
/>
|
||||||
</AdminSidebarCategory>
|
</AdminSidebarCategory>
|
||||||
|
<AdminSidebarCategory
|
||||||
|
definitionKey="products"
|
||||||
|
icon={
|
||||||
|
<ProductsIcon
|
||||||
|
className="category-icon fa"
|
||||||
|
color="currentColor"
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
key="products"
|
||||||
|
parentLink="/admin_console"
|
||||||
|
sectionClass=""
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Products"
|
||||||
|
id="admin.sidebar.products"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AdminSidebarSection
|
||||||
|
definitionKey="products.boards"
|
||||||
|
key="products.boards"
|
||||||
|
name="products/boards"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Boards"
|
||||||
|
id="admin.sidebar.boards"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AdminSidebarCategory>
|
||||||
<AdminSidebarCategory
|
<AdminSidebarCategory
|
||||||
definitionKey="integrations"
|
definitionKey="integrations"
|
||||||
icon={
|
icon={
|
||||||
@@ -4038,6 +4162,37 @@ exports[`components/AdminSidebar should match snapshot, with license (with all f
|
|||||||
title="Plugin 0"
|
title="Plugin 0"
|
||||||
/>
|
/>
|
||||||
</AdminSidebarCategory>
|
</AdminSidebarCategory>
|
||||||
|
<AdminSidebarCategory
|
||||||
|
definitionKey="products"
|
||||||
|
icon={
|
||||||
|
<ProductsIcon
|
||||||
|
className="category-icon fa"
|
||||||
|
color="currentColor"
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
key="products"
|
||||||
|
parentLink="/admin_console"
|
||||||
|
sectionClass=""
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Products"
|
||||||
|
id="admin.sidebar.products"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AdminSidebarSection
|
||||||
|
definitionKey="products.boards"
|
||||||
|
key="products.boards"
|
||||||
|
name="products/boards"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Boards"
|
||||||
|
id="admin.sidebar.boards"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AdminSidebarCategory>
|
||||||
<AdminSidebarCategory
|
<AdminSidebarCategory
|
||||||
definitionKey="integrations"
|
definitionKey="integrations"
|
||||||
icon={
|
icon={
|
||||||
@@ -4973,6 +5128,37 @@ exports[`components/AdminSidebar should match snapshot, with license (without an
|
|||||||
title="Plugin 0"
|
title="Plugin 0"
|
||||||
/>
|
/>
|
||||||
</AdminSidebarCategory>
|
</AdminSidebarCategory>
|
||||||
|
<AdminSidebarCategory
|
||||||
|
definitionKey="products"
|
||||||
|
icon={
|
||||||
|
<ProductsIcon
|
||||||
|
className="category-icon fa"
|
||||||
|
color="currentColor"
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
key="products"
|
||||||
|
parentLink="/admin_console"
|
||||||
|
sectionClass=""
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Products"
|
||||||
|
id="admin.sidebar.products"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<AdminSidebarSection
|
||||||
|
definitionKey="products.boards"
|
||||||
|
key="products.boards"
|
||||||
|
name="products/boards"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Boards"
|
||||||
|
id="admin.sidebar.boards"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AdminSidebarCategory>
|
||||||
<AdminSidebarCategory
|
<AdminSidebarCategory
|
||||||
definitionKey="integrations"
|
definitionKey="integrations"
|
||||||
icon={
|
icon={
|
||||||
|
|||||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user