[MM-51854] Onboarding Role selection screen (#23121)
Co-authored-by: Mattermost Build <build@mattermost.com>
@@ -10,3 +10,25 @@
|
||||
border: 2px solid var(--button-bg);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin sideIllustrationKeyframe($name, $rightPx) {
|
||||
@keyframes #{$name}SlideInRight {
|
||||
from {
|
||||
right: -#{$rightPx}px;
|
||||
}
|
||||
|
||||
to {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes #{$name}SlideOutRight {
|
||||
from {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
right: -#{$rightPx}px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@import 'utils/variables';
|
||||
@import 'utils/mixins';
|
||||
@import 'mixins';
|
||||
|
||||
.PreparingWorkspace {
|
||||
width: 100vw;
|
||||
@@ -93,34 +94,35 @@
|
||||
animation-duration: 0.3s;
|
||||
animation-fill-mode: forwards;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.enter {
|
||||
animation-name: slideInRight;
|
||||
}
|
||||
@include sideIllustrationKeyframe(invitation, 651);
|
||||
|
||||
.exit {
|
||||
animation-name: slideOutRight;
|
||||
}
|
||||
&.enter {
|
||||
animation-name: invitationSlideInRight;
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
right: -651px;
|
||||
&.exit {
|
||||
animation-name: invitationSlideOutRight;
|
||||
}
|
||||
}
|
||||
|
||||
to {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
&__roles-illustration {
|
||||
position: absolute;
|
||||
right: -295px;
|
||||
bottom: 0;
|
||||
animation-duration: 0.3s;
|
||||
animation-fill-mode: forwards;
|
||||
animation-timing-function: ease-in-out;
|
||||
|
||||
@keyframes slideOutRight {
|
||||
from {
|
||||
right: 0;
|
||||
}
|
||||
@include sideIllustrationKeyframe(roles, 295);
|
||||
|
||||
to {
|
||||
right: -651px;
|
||||
&.enter {
|
||||
animation-name: rolesSlideInRight;
|
||||
}
|
||||
|
||||
&.exit {
|
||||
animation-name: rolesSlideOutRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,3 +148,10 @@
|
||||
overflow-y: visible;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1199px) {
|
||||
.PreparingWorkspace__roles-illustration,
|
||||
.PreparingWorkspace__invite-members-illustration {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ import {getCurrentTeam, getMyTeams} from 'mattermost-redux/selectors/entities/te
|
||||
import {getFirstAdminSetupComplete, getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
|
||||
import {CategoryOther} from '@mattermost/types/work_templates';
|
||||
|
||||
import Constants from 'utils/constants';
|
||||
import {getSiteURL, teamNameToUrl} from 'utils/url';
|
||||
import {makeNewTeam} from 'utils/team_utils';
|
||||
@@ -42,6 +44,8 @@ import {
|
||||
} from './steps';
|
||||
|
||||
import Organization from './organization';
|
||||
import Roles from './roles';
|
||||
import RolesIllustration from './roles_illustration';
|
||||
import Plugins from './plugins';
|
||||
import Progress from './progress';
|
||||
import InviteMembers from './invite_members';
|
||||
@@ -90,6 +94,7 @@ function makeSubmitFail(step: WizardStep) {
|
||||
|
||||
const trackSubmitFail = {
|
||||
[WizardSteps.Organization]: makeSubmitFail(WizardSteps.Organization),
|
||||
[WizardSteps.Roles]: makeSubmitFail(WizardSteps.Roles),
|
||||
[WizardSteps.Plugins]: makeSubmitFail(WizardSteps.Plugins),
|
||||
[WizardSteps.InviteMembers]: makeSubmitFail(WizardSteps.InviteMembers),
|
||||
[WizardSteps.LaunchingWorkspace]: makeSubmitFail(WizardSteps.LaunchingWorkspace),
|
||||
@@ -97,6 +102,7 @@ const trackSubmitFail = {
|
||||
|
||||
const onPageViews = {
|
||||
[WizardSteps.Organization]: makeOnPageView(WizardSteps.Organization),
|
||||
[WizardSteps.Roles]: makeOnPageView(WizardSteps.Roles),
|
||||
[WizardSteps.Plugins]: makeOnPageView(WizardSteps.Plugins),
|
||||
[WizardSteps.InviteMembers]: makeOnPageView(WizardSteps.InviteMembers),
|
||||
[WizardSteps.LaunchingWorkspace]: makeOnPageView(WizardSteps.LaunchingWorkspace),
|
||||
@@ -128,6 +134,7 @@ const PreparingWorkspace = (props: Props) => {
|
||||
|
||||
const stepOrder = [
|
||||
isSelfHosted && WizardSteps.Organization,
|
||||
WizardSteps.Roles,
|
||||
pluginsEnabled && WizardSteps.Plugins,
|
||||
WizardSteps.InviteMembers,
|
||||
WizardSteps.LaunchingWorkspace,
|
||||
@@ -256,6 +263,7 @@ const PreparingWorkspace = (props: Props) => {
|
||||
// even if admin skipped submitting plugins.
|
||||
const completeSetupRequest = {
|
||||
organization: form.organization,
|
||||
role: form.role === CategoryOther ? form.roleOther : form.role,
|
||||
install_plugins: pluginsToSetup,
|
||||
};
|
||||
|
||||
@@ -365,6 +373,15 @@ const PreparingWorkspace = (props: Props) => {
|
||||
return '';
|
||||
}, [currentStep]);
|
||||
|
||||
const getRolesAnimationClass = useCallback(() => {
|
||||
if (currentStep === WizardSteps.Roles) {
|
||||
return 'enter';
|
||||
} else if (mostRecentStep === WizardSteps.Roles) {
|
||||
return 'exit';
|
||||
}
|
||||
return '';
|
||||
}, [currentStep]);
|
||||
|
||||
let previous: React.ReactNode = (
|
||||
<div
|
||||
onClick={goPrevious}
|
||||
@@ -431,6 +448,48 @@ const PreparingWorkspace = (props: Props) => {
|
||||
updateTeam={updateTeam}
|
||||
/>
|
||||
|
||||
<Roles
|
||||
onPageView={onPageViews[WizardSteps.Roles]}
|
||||
previous={previous}
|
||||
next={() => {
|
||||
makeNext(WizardSteps.Roles)({
|
||||
role: form.role,
|
||||
roleOther: form.roleOther,
|
||||
});
|
||||
}}
|
||||
quickNext={(role: string) => {
|
||||
setForm({
|
||||
...form,
|
||||
role,
|
||||
roleOther: '',
|
||||
});
|
||||
makeNext(WizardSteps.Roles)({
|
||||
role,
|
||||
roleOther: '',
|
||||
});
|
||||
}}
|
||||
skip={() => {
|
||||
setForm({
|
||||
...form,
|
||||
role: '',
|
||||
roleOther: '',
|
||||
});
|
||||
makeNext(WizardSteps.Roles, true)();
|
||||
}}
|
||||
transitionDirection={getTransitionDirection(WizardSteps.Roles)}
|
||||
show={shouldShowPage(WizardSteps.Roles)}
|
||||
role={form.role}
|
||||
roleOther={form.roleOther}
|
||||
setRole={(role: Form['role'], roleOther: Form['roleOther']) => {
|
||||
setForm({
|
||||
...form,
|
||||
role,
|
||||
roleOther,
|
||||
});
|
||||
}}
|
||||
className='child-page'
|
||||
/>
|
||||
|
||||
<Plugins
|
||||
isSelfHosted={isSelfHosted}
|
||||
onPageView={onPageViews[WizardSteps.Plugins]}
|
||||
@@ -508,6 +567,9 @@ const PreparingWorkspace = (props: Props) => {
|
||||
<div className={`PreparingWorkspace__invite-members-illustration ${getInviteMembersAnimationClass()}`}>
|
||||
<InviteMembersIllustration/>
|
||||
</div>
|
||||
<div className={`PreparingWorkspace__roles-illustration ${getRolesAnimationClass()}`}>
|
||||
<RolesIllustration/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
47
webapp/channels/src/components/preparing_workspace/roles.scss
Обычный файл
@@ -0,0 +1,47 @@
|
||||
@import 'utils/mixins';
|
||||
|
||||
$btn-margin-right: 24px;
|
||||
|
||||
.plugins-skip-btn {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.Roles__input {
|
||||
width: calc(100% - $btn-margin-right);
|
||||
padding: 10px 16px;
|
||||
border: 2px solid rgba(var(--center-channel-color-rgb), 0.16);
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
|
||||
&:active,
|
||||
&:focus {
|
||||
border: 2px solid var(--button-bg);
|
||||
}
|
||||
}
|
||||
|
||||
.Roles-body {
|
||||
.PreparingWorkspacePageBody {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.Roles-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.role-button {
|
||||
@include secondary-button;
|
||||
@include button-large;
|
||||
|
||||
border-color: rgba(63, 67, 80, 0.16);
|
||||
margin-right: $btn-margin-right;
|
||||
margin-bottom: 24px;
|
||||
color: #3f4350;
|
||||
|
||||
&.active {
|
||||
background: rgba(var(--denim-button-bg-rgb), 0.16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include simple-in-and-out("Roles");
|
||||
158
webapp/channels/src/components/preparing_workspace/roles.tsx
Обычный файл
@@ -0,0 +1,158 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useEffect} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {CSSTransition} from 'react-transition-group';
|
||||
|
||||
import {Animations, mapAnimationReasonToClass, Form, PreparingWorkspacePageProps} from './steps';
|
||||
|
||||
import Title from './title';
|
||||
import Description from './description';
|
||||
import PageBody from './page_body';
|
||||
import SingleColumnLayout from './single_column_layout';
|
||||
|
||||
import PageLine from './page_line';
|
||||
import './roles.scss';
|
||||
import {useDispatch, useSelector} from 'react-redux';
|
||||
import {getWorkTemplateCategories as fetchCategories} from 'mattermost-redux/actions/work_templates';
|
||||
import {getWorkTemplateCategories} from 'selectors/work_template';
|
||||
import classNames from 'classnames';
|
||||
import QuickInput from 'components/quick_input';
|
||||
import {CategoryOther} from '@mattermost/types/work_templates';
|
||||
|
||||
type Props = PreparingWorkspacePageProps & {
|
||||
role: Form['role'];
|
||||
roleOther: Form['roleOther'];
|
||||
setRole: (role: string, roleOther: string) => void;
|
||||
className?: string;
|
||||
quickNext(role: string): void;
|
||||
}
|
||||
const Roles = ({role, next, ...props}: Props) => {
|
||||
const {formatMessage} = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const categories = useSelector(getWorkTemplateCategories);
|
||||
|
||||
let className = 'Roles-body';
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchCategories());
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.show) {
|
||||
props.onPageView();
|
||||
}
|
||||
}, [props.show]);
|
||||
|
||||
if (props.className) {
|
||||
className += ' ' + props.className;
|
||||
}
|
||||
|
||||
const title = (
|
||||
<FormattedMessage
|
||||
id={'onboarding_wizard.roles.title'}
|
||||
defaultMessage='What is your primary function?'
|
||||
/>
|
||||
);
|
||||
const description = (
|
||||
<FormattedMessage
|
||||
id={'onboarding_wizard.roles.description'}
|
||||
defaultMessage={'We’ll use this to suggest templates to help get you started.'}
|
||||
/>
|
||||
);
|
||||
|
||||
const selectRole = (role: string) => {
|
||||
if (role !== CategoryOther) {
|
||||
props.quickNext(role);
|
||||
}
|
||||
props.setRole(role, '');
|
||||
};
|
||||
|
||||
const roleIsSet = Boolean(role);
|
||||
const roleOtherIsSet = Boolean(props.roleOther);
|
||||
const canContinue = (roleIsSet && role !== CategoryOther) || (role === CategoryOther && roleOtherIsSet);
|
||||
|
||||
return (
|
||||
<CSSTransition
|
||||
in={props.show}
|
||||
timeout={Animations.PAGE_SLIDE}
|
||||
classNames={mapAnimationReasonToClass('Roles', props.transitionDirection)}
|
||||
mountOnEnter={true}
|
||||
unmountOnExit={true}
|
||||
>
|
||||
<div className={className}>
|
||||
<SingleColumnLayout>
|
||||
<PageLine
|
||||
style={{
|
||||
marginBottom: '50px',
|
||||
marginLeft: '50px',
|
||||
height: 'calc(25vh)',
|
||||
}}
|
||||
noLeft={true}
|
||||
/>
|
||||
{props.previous}
|
||||
<Title>
|
||||
{title}
|
||||
</Title>
|
||||
<Description>{description}</Description>
|
||||
<PageBody>
|
||||
<div className='Roles-list'>
|
||||
{categories.map((category) => (
|
||||
<button
|
||||
key={category.id}
|
||||
className={classNames('role-button', {active: category.id === role})}
|
||||
onClick={() => selectRole(category.id)}
|
||||
>
|
||||
{category.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{role === CategoryOther && (
|
||||
<QuickInput
|
||||
value={props.roleOther || ''}
|
||||
className='Roles__input'
|
||||
onChange={(e) => props.setRole(CategoryOther, e.target.value)}
|
||||
placeholder={formatMessage({
|
||||
id: 'onboarding_wizard.roles.other_input_placeholder',
|
||||
defaultMessage: 'Please share your primary function',
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</PageBody>
|
||||
<div>
|
||||
<button
|
||||
className='primary-button'
|
||||
onClick={next}
|
||||
disabled={!canContinue}
|
||||
>
|
||||
<FormattedMessage
|
||||
id={'onboarding_wizard.next'}
|
||||
defaultMessage='Continue'
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
className='link-style plugins-skip-btn'
|
||||
onClick={props.skip}
|
||||
>
|
||||
<FormattedMessage
|
||||
id={'onboarding_wizard.skip-button'}
|
||||
defaultMessage='Skip'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<PageLine
|
||||
style={{
|
||||
marginTop: '50px',
|
||||
marginLeft: '50px',
|
||||
height: 'calc(30vh)',
|
||||
}}
|
||||
noLeft={true}
|
||||
/>
|
||||
</SingleColumnLayout>
|
||||
</div>
|
||||
</CSSTransition>
|
||||
);
|
||||
};
|
||||
|
||||
export default Roles;
|
||||
@@ -5,6 +5,7 @@ import deepFreeze from 'mattermost-redux/utils/deep_freeze';
|
||||
|
||||
export const WizardSteps = {
|
||||
Organization: 'Organization',
|
||||
Roles: 'Roles',
|
||||
Plugins: 'Plugins',
|
||||
InviteMembers: 'InviteMembers',
|
||||
LaunchingWorkspace: 'LaunchingWorkspace',
|
||||
@@ -24,6 +25,8 @@ export function mapStepToNextName(step: WizardStep): string {
|
||||
switch (step) {
|
||||
case WizardSteps.Organization:
|
||||
return 'admin_onboarding_next_organization';
|
||||
case WizardSteps.Roles:
|
||||
return 'admin_onboarding_next_roles';
|
||||
case WizardSteps.Plugins:
|
||||
return 'admin_onboarding_next_plugins';
|
||||
case WizardSteps.InviteMembers:
|
||||
@@ -39,6 +42,8 @@ export function mapStepToPrevious(step: WizardStep): string {
|
||||
switch (step) {
|
||||
case WizardSteps.Organization:
|
||||
return 'admin_onboarding_previous_organization';
|
||||
case WizardSteps.Roles:
|
||||
return 'admin_onboarding_previous_roles';
|
||||
case WizardSteps.Plugins:
|
||||
return 'admin_onboarding_previous_plugins';
|
||||
case WizardSteps.InviteMembers:
|
||||
@@ -54,6 +59,8 @@ export function mapStepToPageView(step: WizardStep): string {
|
||||
switch (step) {
|
||||
case WizardSteps.Organization:
|
||||
return 'pageview_admin_onboarding_organization';
|
||||
case WizardSteps.Roles:
|
||||
return 'pageview_admin_onboarding_roles';
|
||||
case WizardSteps.Plugins:
|
||||
return 'pageview_admin_onboarding_plugins';
|
||||
case WizardSteps.InviteMembers:
|
||||
@@ -69,6 +76,8 @@ export function mapStepToSubmitFail(step: WizardStep): string {
|
||||
switch (step) {
|
||||
case WizardSteps.Organization:
|
||||
return 'admin_onboarding_organization_submit_fail';
|
||||
case WizardSteps.Roles:
|
||||
return 'admin_onboarding_roles_submit_fail';
|
||||
case WizardSteps.Plugins:
|
||||
return 'admin_onboarding_plugins_submit_fail';
|
||||
case WizardSteps.InviteMembers:
|
||||
@@ -84,6 +93,8 @@ export function mapStepToSkipName(step: WizardStep): string {
|
||||
switch (step) {
|
||||
case WizardSteps.Organization:
|
||||
return 'admin_onboarding_skip_organization';
|
||||
case WizardSteps.Roles:
|
||||
return 'admin_onboarding_skip_roles';
|
||||
case WizardSteps.Plugins:
|
||||
return 'admin_onboarding_skip_plugins';
|
||||
case WizardSteps.InviteMembers:
|
||||
@@ -127,6 +138,8 @@ export const PLUGIN_NAME_TO_ID_MAP: PluginNameMap = {
|
||||
|
||||
export type Form = {
|
||||
organization?: string;
|
||||
role?: string;
|
||||
roleOther?: string;
|
||||
url?: string;
|
||||
urlSkipped: boolean;
|
||||
inferredProtocol: 'http' | 'https' | null;
|
||||
@@ -184,6 +197,8 @@ export const emptyForm = deepFreeze({
|
||||
invites: [],
|
||||
skipped: false,
|
||||
},
|
||||
role: '',
|
||||
roleOther: '',
|
||||
});
|
||||
|
||||
export type PreparingWorkspacePageProps = {
|
||||
|
||||
@@ -37,6 +37,11 @@ const CategoryButton = styled.button`
|
||||
background: none;
|
||||
text-align: left;
|
||||
|
||||
&:hover {
|
||||
background: rgba(var(--denim-button-bg-rgb), 0.04);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background: rgba(var(--denim-button-bg-rgb), 0.04);
|
||||
font-weight: 600;
|
||||
|
||||
@@ -4236,6 +4236,9 @@
|
||||
"onboarding_wizard.plugins.zoom": "Zoom",
|
||||
"onboarding_wizard.plugins.zoom.tooltip": "Start Zoom audio and video conferencing calls in Mattermost with a single click",
|
||||
"onboarding_wizard.previous": "Previous",
|
||||
"onboarding_wizard.roles.description": "We’ll use this to suggest templates to help get you started.",
|
||||
"onboarding_wizard.roles.other_input_placeholder": "Please share your primary function",
|
||||
"onboarding_wizard.roles.title": "What is your primary function?",
|
||||
"onboarding_wizard.self_hosted_plugins.description": "Choose the tools you work with, and we'll add them to your workspace. Additional set up may be needed later.",
|
||||
"onboarding_wizard.self_hosted_plugins.title": "What tools do you use?",
|
||||
"onboarding_wizard.skip-button": "Skip",
|
||||
|
||||
Двоичные данные
webapp/channels/src/images/worktemplates/boards/content_calendar.png
Обычный файл
|
После Ширина: | Высота: | Размер: 53 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/design/content_calendar/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 80 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/design/content_calendar/content_calendar.png
Обычный файл
|
После Ширина: | Высота: | Размер: 22 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/design/create_project/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/design/create_project/create_project.png
Обычный файл
|
После Ширина: | Высота: | Размер: 119 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/design/feature_release/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/design/feature_release/feature_release.png
Обычный файл
|
После Ширина: | Высота: | Размер: 98 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/design/product_release/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/design/product_release/product_release.png
Обычный файл
|
После Ширина: | Высота: | Размер: 113 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/design/sprint_planning/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/design/sprint_planning/sprint_planning.png
Обычный файл
|
После Ширина: | Высота: | Размер: 68 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/devops/bug_bash/bug_bash.png
Обычный файл
|
После Ширина: | Высота: | Размер: 109 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/devops/bug_bash/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 565 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/devops/create_project/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/devops/create_project/create_project.png
Обычный файл
|
После Ширина: | Высота: | Размер: 119 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/devops/sprint_planning/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/devops/sprint_planning/sprint_planning.png
Обычный файл
|
После Ширина: | Высота: | Размер: 68 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/engineering/bug_bash/bug_bash.png
Обычный файл
|
После Ширина: | Высота: | Размер: 109 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/engineering/bug_bash/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 565 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/engineering/create_project/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/engineering/create_project/create_project.png
Обычный файл
|
После Ширина: | Высота: | Размер: 119 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/engineering/feature_release/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/engineering/feature_release/feature_release.png
Обычный файл
|
После Ширина: | Высота: | Размер: 98 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/engineering/goals_and_okrs/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/engineering/goals_and_okrs/goals_and_okrs.png
Обычный файл
|
После Ширина: | Высота: | Размер: 182 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/engineering/sprint_planning/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/engineering/sprint_planning/sprint_planning.png
Обычный файл
|
После Ширина: | Высота: | Размер: 68 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/leadership/content_calendar/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 80 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/leadership/content_calendar/content_calendar.png
Обычный файл
|
После Ширина: | Высота: | Размер: 22 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/leadership/create_project/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/leadership/create_project/create_project.png
Обычный файл
|
После Ширина: | Высота: | Размер: 119 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/leadership/incident_resolution/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/leadership/incident_resolution/incident_resolution.png
Обычный файл
|
После Ширина: | Высота: | Размер: 88 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/marketing/content_calendar/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 80 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/marketing/content_calendar/content_calendar.png
Обычный файл
|
После Ширина: | Высота: | Размер: 22 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/marketing/create_project/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/marketing/create_project/create_project.png
Обычный файл
|
После Ширина: | Высота: | Размер: 119 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/marketing/goals_and_okrs/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/marketing/goals_and_okrs/goals_and_okrs.png
Обычный файл
|
После Ширина: | Высота: | Размер: 182 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/marketing/product_release/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/marketing/product_release/product_release.png
Обычный файл
|
После Ширина: | Высота: | Размер: 113 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/other/create_project/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/other/create_project/create_project.png
Обычный файл
|
После Ширина: | Высота: | Размер: 119 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/other/feature_release/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/other/feature_release/feature_release.png
Обычный файл
|
После Ширина: | Высота: | Размер: 98 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/other/goals_and_okrs/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/other/goals_and_okrs/goals_and_okrs.png
Обычный файл
|
После Ширина: | Высота: | Размер: 182 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/other/incident_resolution/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/other/incident_resolution/incident_resolution.png
Обычный файл
|
После Ширина: | Высота: | Размер: 88 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/other/product_release/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/other/product_release/product_release.png
Обычный файл
|
После Ширина: | Высота: | Размер: 113 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/project_management/create_project/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/project_management/create_project/create_project.png
Обычный файл
|
После Ширина: | Высота: | Размер: 119 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/project_management/feature_release/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/project_management/feature_release/feature_release.png
Обычный файл
|
После Ширина: | Высота: | Размер: 98 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/project_management/goals_and_okrs/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/project_management/goals_and_okrs/goals_and_okrs.png
Обычный файл
|
После Ширина: | Высота: | Размер: 182 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/project_management/product_release/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/project_management/product_release/product_release.png
Обычный файл
|
После Ширина: | Высота: | Размер: 113 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/project_management/product_roadmap/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/project_management/product_roadmap/product_roadmap.png
Обычный файл
|
После Ширина: | Высота: | Размер: 112 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/qa/bug_bash/bug_bash.png
Обычный файл
|
После Ширина: | Высота: | Размер: 109 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/qa/bug_bash/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 565 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/qa/create_project/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 568 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/qa/create_project/create_project.png
Обычный файл
|
После Ширина: | Высота: | Размер: 119 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/qa/incident_resolution/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/qa/incident_resolution/incident_resolution.png
Обычный файл
|
После Ширина: | Высота: | Размер: 88 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/qa/product_release/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/qa/product_release/product_release.png
Обычный файл
|
После Ширина: | Высота: | Размер: 113 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/qa/sprint_planning/channel.png
Обычный файл
|
После Ширина: | Высота: | Размер: 567 KiB |
Двоичные данные
webapp/channels/src/images/worktemplates/qa/sprint_planning/sprint_planning.png
Обычный файл
|
После Ширина: | Высота: | Размер: 68 KiB |
@@ -23,3 +23,4 @@ export const areWorkTemplatesEnabled = createSelector(
|
||||
},
|
||||
);
|
||||
|
||||
export const getWorkTemplateCategories = (state: GlobalState) => state.entities.worktemplates.categories;
|
||||
|
||||