[MM-51854] Onboarding Role selection screen (#23121)
Co-authored-by: Mattermost Build <build@mattermost.com>
@@ -11,6 +11,8 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/server/v8/model"
|
"github.com/mattermost/mattermost-server/server/v8/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const WorkTemplateContextOnboarding = "onboarding"
|
||||||
|
|
||||||
func (api *API) InitWorkTemplate() {
|
func (api *API) InitWorkTemplate() {
|
||||||
api.BaseRoutes.WorkTemplates.Handle("/categories", api.APISessionRequired(getWorkTemplateCategories)).Methods("GET")
|
api.BaseRoutes.WorkTemplates.Handle("/categories", api.APISessionRequired(getWorkTemplateCategories)).Methods("GET")
|
||||||
api.BaseRoutes.WorkTemplates.Handle("/categories/{category}/templates", api.APISessionRequired(getWorkTemplates)).Methods("GET")
|
api.BaseRoutes.WorkTemplates.Handle("/categories/{category}/templates", api.APISessionRequired(getWorkTemplates)).Methods("GET")
|
||||||
@@ -62,7 +64,13 @@ func getWorkTemplates(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
t := c.AppContext.GetT()
|
t := c.AppContext.GetT()
|
||||||
|
|
||||||
workTemplates, appErr := c.App.GetWorkTemplates(c.Params.Category, c.App.Config().FeatureFlags.ToMap(), t)
|
context := r.URL.Query().Get("context")
|
||||||
|
isOnboarding := false
|
||||||
|
if context == WorkTemplateContextOnboarding {
|
||||||
|
isOnboarding = true
|
||||||
|
}
|
||||||
|
|
||||||
|
workTemplates, appErr := c.App.GetWorkTemplates(c.Params.Category, c.App.Config().FeatureFlags.ToMap(), isOnboarding, t)
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
c.Err = appErr
|
c.Err = appErr
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -861,7 +861,7 @@ type AppIface interface {
|
|||||||
GetWarnMetricsBot() (*model.Bot, *model.AppError)
|
GetWarnMetricsBot() (*model.Bot, *model.AppError)
|
||||||
GetWarnMetricsStatus() (map[string]*model.WarnMetricStatus, *model.AppError)
|
GetWarnMetricsStatus() (map[string]*model.WarnMetricStatus, *model.AppError)
|
||||||
GetWorkTemplateCategories(t i18n.TranslateFunc) ([]*model.WorkTemplateCategory, *model.AppError)
|
GetWorkTemplateCategories(t i18n.TranslateFunc) ([]*model.WorkTemplateCategory, *model.AppError)
|
||||||
GetWorkTemplates(category string, featureFlags map[string]string, t i18n.TranslateFunc) ([]*model.WorkTemplate, *model.AppError)
|
GetWorkTemplates(category string, featureFlags map[string]string, includeOnboardingTemplates bool, t i18n.TranslateFunc) ([]*model.WorkTemplate, *model.AppError)
|
||||||
HTTPService() httpservice.HTTPService
|
HTTPService() httpservice.HTTPService
|
||||||
Handle404(w http.ResponseWriter, r *http.Request)
|
Handle404(w http.ResponseWriter, r *http.Request)
|
||||||
HandleCommandResponse(c request.CTX, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.CommandResponse, *model.AppError)
|
HandleCommandResponse(c request.CTX, command *model.Command, args *model.CommandArgs, response *model.CommandResponse, builtIn bool) (*model.CommandResponse, *model.AppError)
|
||||||
|
|||||||
@@ -41,11 +41,20 @@ func (a *App) CompleteOnboarding(c *request.Context, request *model.CompleteOnbo
|
|||||||
Value: request.Organization,
|
Value: request.Organization,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// don't block onboarding because of that.
|
|
||||||
a.Log().Error("failed to save organization name", mlog.Err(err))
|
a.Log().Error("failed to save organization name", mlog.Err(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if request.Role != "" {
|
||||||
|
err := a.Srv().Store().System().SaveOrUpdate(&model.System{
|
||||||
|
Name: model.SystemFirstAdminRole,
|
||||||
|
Value: request.Role,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
a.Log().Error("failed to save first admin role", mlog.Err(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pluginsEnvironment := a.Channels().GetPluginsEnvironment()
|
pluginsEnvironment := a.Channels().GetPluginsEnvironment()
|
||||||
if pluginsEnvironment == nil {
|
if pluginsEnvironment == nil {
|
||||||
return a.markAdminOnboardingComplete(c)
|
return a.markAdminOnboardingComplete(c)
|
||||||
@@ -54,7 +63,6 @@ func (a *App) CompleteOnboarding(c *request.Context, request *model.CompleteOnbo
|
|||||||
pluginContext := pluginContext(c)
|
pluginContext := pluginContext(c)
|
||||||
|
|
||||||
for _, pluginID := range request.InstallPlugins {
|
for _, pluginID := range request.InstallPlugins {
|
||||||
|
|
||||||
go func(id string) {
|
go func(id string) {
|
||||||
installRequest := &model.InstallMarketplacePluginRequest{
|
installRequest := &model.InstallMarketplacePluginRequest{
|
||||||
Id: id,
|
Id: id,
|
||||||
|
|||||||
@@ -28,3 +28,21 @@ func TestOnboardingSavesOrganizationName(t *testing.T) {
|
|||||||
require.NoError(t, storeErr)
|
require.NoError(t, storeErr)
|
||||||
require.Equal(t, "Mattermost In Tests", sys.Value)
|
require.Equal(t, "Mattermost In Tests", sys.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOnboardingFirstAdminRole(t *testing.T) {
|
||||||
|
th := Setup(t)
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
err := th.App.CompleteOnboarding(&request.Context{}, &mm_model.CompleteOnboardingRequest{
|
||||||
|
Organization: "myorg",
|
||||||
|
Role: "engineering",
|
||||||
|
})
|
||||||
|
require.Nil(t, err)
|
||||||
|
defer func() {
|
||||||
|
th.App.Srv().Store().System().PermanentDeleteByName(mm_model.SystemFirstAdminRole)
|
||||||
|
}()
|
||||||
|
|
||||||
|
sys, storeErr := th.App.Srv().Store().System().GetByName(mm_model.SystemFirstAdminRole)
|
||||||
|
require.NoError(t, storeErr)
|
||||||
|
require.Equal(t, "engineering", sys.Value)
|
||||||
|
}
|
||||||
|
|||||||
@@ -11382,7 +11382,7 @@ func (a *OpenTracingAppLayer) GetWorkTemplateCategories(t i18n.TranslateFunc) ([
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) GetWorkTemplates(category string, featureFlags map[string]string, t i18n.TranslateFunc) ([]*model.WorkTemplate, *model.AppError) {
|
func (a *OpenTracingAppLayer) GetWorkTemplates(category string, featureFlags map[string]string, includeOnboardingTemplates bool, t i18n.TranslateFunc) ([]*model.WorkTemplate, *model.AppError) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetWorkTemplates")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetWorkTemplates")
|
||||||
|
|
||||||
@@ -11394,7 +11394,7 @@ func (a *OpenTracingAppLayer) GetWorkTemplates(category string, featureFlags map
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
resultVar0, resultVar1 := a.app.GetWorkTemplates(category, featureFlags, t)
|
resultVar0, resultVar1 := a.app.GetWorkTemplates(category, featureFlags, includeOnboardingTemplates, t)
|
||||||
|
|
||||||
if resultVar1 != nil {
|
if resultVar1 != nil {
|
||||||
span.LogFields(spanlog.Error(resultVar1))
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
pbclient "github.com/mattermost/mattermost-server/server/v8/playbooks/client"
|
pbclient "github.com/mattermost/mattermost-server/server/v8/playbooks/client"
|
||||||
|
"github.com/mattermost/mattermost-server/server/v8/plugin"
|
||||||
|
|
||||||
fb_model "github.com/mattermost/mattermost-server/server/v8/boards/model"
|
fb_model "github.com/mattermost/mattermost-server/server/v8/boards/model"
|
||||||
|
|
||||||
@@ -250,6 +251,26 @@ func (e *appWorkTemplateExecutor) InstallPlugin(
|
|||||||
if err := e.app.EnablePlugin(pluginID); err != nil {
|
if err := e.app.EnablePlugin(pluginID); err != nil {
|
||||||
return fmt.Errorf("unable to enable plugin: %w", err)
|
return fmt.Errorf("unable to enable plugin: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hooks, err := e.app.ch.HooksForPluginOrProduct(pluginID)
|
||||||
|
if err != nil {
|
||||||
|
mlog.Warn("Getting hooks for plugin failed", mlog.String("plugin_id", pluginID), mlog.Err(err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
event := model.OnInstallEvent{
|
||||||
|
UserId: c.Session().UserId,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = hooks.OnInstall(&plugin.Context{
|
||||||
|
RequestId: c.RequestId(),
|
||||||
|
SessionId: c.Session().Id,
|
||||||
|
IPAddress: c.IPAddress(),
|
||||||
|
AcceptLanguage: c.AcceptLanguage(),
|
||||||
|
UserAgent: c.UserAgent(),
|
||||||
|
}, event); err != nil {
|
||||||
|
mlog.Error("Plugin OnInstall hook failed", mlog.String("plugin_id", pluginID), mlog.Err(err))
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ func (a *App) GetWorkTemplateCategories(t i18n.TranslateFunc) ([]*model.WorkTemp
|
|||||||
return modelCategories, nil
|
return modelCategories, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) GetWorkTemplates(category string, featureFlags map[string]string, t i18n.TranslateFunc) ([]*model.WorkTemplate, *model.AppError) {
|
func (a *App) GetWorkTemplates(category string, featureFlags map[string]string, includeOnboardingTemplates bool, t i18n.TranslateFunc) ([]*model.WorkTemplate, *model.AppError) {
|
||||||
templates, err := worktemplates.ListByCategory(category)
|
templates, err := worktemplates.ListByCategory(category, includeOnboardingTemplates)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, model.NewAppError("GetWorkTemplates", "app.worktemplates.get_templates.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
return nil, model.NewAppError("GetWorkTemplates", "app.worktemplates.get_templates.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,12 @@ func TestGetWorkTemplatesByCategory(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ID: "test-template-4",
|
||||||
|
Category: firstCat.ID,
|
||||||
|
UseCase: "test use case 4",
|
||||||
|
OnboardingOnly: true,
|
||||||
|
},
|
||||||
{ // this one should not be returned because of the category
|
{ // this one should not be returned because of the category
|
||||||
ID: "test-template-4",
|
ID: "test-template-4",
|
||||||
Category: "cat-test2",
|
Category: "cat-test2",
|
||||||
@@ -97,18 +103,30 @@ func TestGetWorkTemplatesByCategory(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Act
|
t.Run("not onboarding", func(t *testing.T) {
|
||||||
worktemplates, appErr := th.App.GetWorkTemplates(firstCat.ID, ff, wtTranslationFunc)
|
// Act
|
||||||
|
worktemplates, appErr := th.App.GetWorkTemplates(firstCat.ID, ff, false, wtTranslationFunc)
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
assert.Nil(appErr)
|
assert.Nil(appErr)
|
||||||
assert.Len(worktemplates, 2)
|
assert.Len(worktemplates, 2)
|
||||||
// assert the correct work templates have been returned
|
// assert the correct work templates have been returned
|
||||||
assert.Equal("test-template", worktemplates[0].ID)
|
assert.Equal("test-template", worktemplates[0].ID)
|
||||||
assert.Equal("test-template-3", worktemplates[1].ID)
|
assert.Equal("test-template-3", worktemplates[1].ID)
|
||||||
// assert the descriptions have been translated
|
// assert the descriptions have been translated
|
||||||
assert.Equal("Translated test-template-channel-description", worktemplates[0].Description.Channel.Message)
|
assert.Equal("Translated test-template-channel-description", worktemplates[0].Description.Channel.Message)
|
||||||
assert.Equal("default message picked for unknown", worktemplates[1].Description.Channel.Message)
|
assert.Equal("default message picked for unknown", worktemplates[1].Description.Channel.Message)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("onboarding", func(t *testing.T) {
|
||||||
|
// Act
|
||||||
|
worktemplates, appErr := th.App.GetWorkTemplates(firstCat.ID, ff, true, wtTranslationFunc)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assert.Nil(appErr)
|
||||||
|
assert.Len(worktemplates, 3)
|
||||||
|
assert.Equal("test-template-4", worktemplates[2].ID)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
|
|||||||
@@ -2,7 +2,17 @@
|
|||||||
name: worktemplate.category.product_teams
|
name: worktemplate.category.product_teams
|
||||||
- id: devops
|
- id: devops
|
||||||
name: worktemplate.category.devops
|
name: worktemplate.category.devops
|
||||||
- id: companywide
|
|
||||||
name: worktemplate.category.companywide
|
|
||||||
- id: leadership
|
- id: leadership
|
||||||
name: worktemplate.category.leadership
|
name: worktemplate.category.leadership
|
||||||
|
- id: engineering
|
||||||
|
name: worktemplate.category.engineering
|
||||||
|
- id: project_management
|
||||||
|
name: worktemplate.category.project_management
|
||||||
|
- id: marketing
|
||||||
|
name: worktemplate.category.marketing
|
||||||
|
- id: design
|
||||||
|
name: worktemplate.category.design
|
||||||
|
- id: qa
|
||||||
|
name: worktemplate.category.qa
|
||||||
|
- id: other
|
||||||
|
name: worktemplate.category.other
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ func main() {
|
|||||||
log.Fatal(errors.Wrap(err, "failed to read categories.yaml"))
|
log.Fatal(errors.Wrap(err, "failed to read categories.yaml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
illustrations := []string{}
|
||||||
|
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
|
|
||||||
cats := []WorkTemplateCategoryWithMD5{} // meow
|
cats := []WorkTemplateCategoryWithMD5{} // meow
|
||||||
@@ -53,6 +55,7 @@ func main() {
|
|||||||
|
|
||||||
// validate categories
|
// validate categories
|
||||||
categoryIds := map[string]struct{}{}
|
categoryIds := map[string]struct{}{}
|
||||||
|
lastCategory := ""
|
||||||
for id := range cats {
|
for id := range cats {
|
||||||
cat := cats[id]
|
cat := cats[id]
|
||||||
|
|
||||||
@@ -67,12 +70,16 @@ func main() {
|
|||||||
if cat.Name == "" {
|
if cat.Name == "" {
|
||||||
log.Fatal(errors.New("category name cannot be empty"))
|
log.Fatal(errors.New("category name cannot be empty"))
|
||||||
}
|
}
|
||||||
|
lastCategory = cat.ID
|
||||||
categoryIds[cat.ID] = struct{}{}
|
categoryIds[cat.ID] = struct{}{}
|
||||||
|
|
||||||
h.Write([]byte(cat.ID))
|
h.Write([]byte(cat.ID))
|
||||||
cats[id].MD5 = fmt.Sprintf("%x", h.Sum(nil))
|
cats[id].MD5 = fmt.Sprintf("%x", h.Sum(nil))
|
||||||
h.Reset()
|
h.Reset()
|
||||||
}
|
}
|
||||||
|
if lastCategory != "other" {
|
||||||
|
log.Fatal(errors.New("category 'other' must exist AND be the last category"))
|
||||||
|
}
|
||||||
|
|
||||||
dat, err = getFileContent("templates.yaml")
|
dat, err = getFileContent("templates.yaml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -105,6 +112,33 @@ func main() {
|
|||||||
MD5: fmt.Sprintf("%x", h.Sum(nil)),
|
MD5: fmt.Sprintf("%x", h.Sum(nil)),
|
||||||
})
|
})
|
||||||
h.Reset()
|
h.Reset()
|
||||||
|
|
||||||
|
// add illustrations to the list
|
||||||
|
illustrations = append(illustrations, t.Illustration)
|
||||||
|
if t.Description.Channel != nil && t.Description.Channel.Illustration != "" {
|
||||||
|
illustrations = append(illustrations, t.Description.Channel.Illustration)
|
||||||
|
}
|
||||||
|
if t.Description.Board != nil && t.Description.Board.Illustration != "" {
|
||||||
|
illustrations = append(illustrations, t.Description.Board.Illustration)
|
||||||
|
}
|
||||||
|
if t.Description.Integration != nil && t.Description.Integration.Illustration != "" {
|
||||||
|
illustrations = append(illustrations, t.Description.Integration.Illustration)
|
||||||
|
}
|
||||||
|
if t.Description.Playbook != nil && t.Description.Playbook.Illustration != "" {
|
||||||
|
illustrations = append(illustrations, t.Description.Playbook.Illustration)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range t.Content {
|
||||||
|
if t.Content[i].Channel != nil && t.Content[i].Channel.Illustration != "" {
|
||||||
|
illustrations = append(illustrations, t.Content[i].Channel.Illustration)
|
||||||
|
}
|
||||||
|
if t.Content[i].Board != nil && t.Content[i].Board.Illustration != "" {
|
||||||
|
illustrations = append(illustrations, t.Content[i].Board.Illustration)
|
||||||
|
}
|
||||||
|
if t.Content[i].Playbook != nil && t.Content[i].Playbook.Illustration != "" {
|
||||||
|
illustrations = append(illustrations, t.Content[i].Playbook.Illustration)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
code := bytes.NewBuffer(nil)
|
code := bytes.NewBuffer(nil)
|
||||||
@@ -146,6 +180,15 @@ func main() {
|
|||||||
translationHelper(t.Description.Integration)
|
translationHelper(t.Description.Integration)
|
||||||
translationHelper(t.Description.Playbook)
|
translationHelper(t.Description.Playbook)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("Missing illustrations:")
|
||||||
|
for _, illustration := range illustrations {
|
||||||
|
// check if file exists
|
||||||
|
illusPath := path.Join("../../../../webapp/channels/src/images", illustration[8:])
|
||||||
|
if _, err := os.Stat(illusPath); os.IsNotExist(err) {
|
||||||
|
fmt.Println("\t" + illusPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var translationHelperTemplate = `{
|
var translationHelperTemplate = `{
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ var wt{{.MD5}} = &WorkTemplate{
|
|||||||
UseCase: "{{.UseCase}}",
|
UseCase: "{{.UseCase}}",
|
||||||
Illustration: "{{.Illustration}}",
|
Illustration: "{{.Illustration}}",
|
||||||
Visibility: "{{.Visibility}}",
|
Visibility: "{{.Visibility}}",
|
||||||
|
OnboardingOnly: {{.OnboardingOnly}},
|
||||||
{{if .FeatureFlag}}FeatureFlag: &FeatureFlag{
|
{{if .FeatureFlag}}FeatureFlag: &FeatureFlag{
|
||||||
Name: "{{.FeatureFlag.Name}}",
|
Name: "{{.FeatureFlag.Name}}",
|
||||||
Value: "{{.FeatureFlag.Value}}",
|
Value: "{{.FeatureFlag.Value}}",
|
||||||
|
|||||||
@@ -18,14 +18,15 @@ type WorkTemplateCategory struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WorkTemplate struct {
|
type WorkTemplate struct {
|
||||||
ID string `yaml:"id"`
|
ID string `yaml:"id"`
|
||||||
Category string `yaml:"category"`
|
Category string `yaml:"category"`
|
||||||
UseCase string `yaml:"useCase"`
|
UseCase string `yaml:"useCase"`
|
||||||
Illustration string `yaml:"illustration"`
|
Illustration string `yaml:"illustration"`
|
||||||
Visibility string `yaml:"visibility"`
|
Visibility string `yaml:"visibility"`
|
||||||
FeatureFlag *FeatureFlag `yaml:"featureFlag,omitempty"`
|
OnboardingOnly bool `yaml:"onboardingOnly"`
|
||||||
Description Description `yaml:"description"`
|
FeatureFlag *FeatureFlag `yaml:"featureFlag,omitempty"`
|
||||||
Content []Content `yaml:"content"`
|
Description Description `yaml:"description"`
|
||||||
|
Content []Content `yaml:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wt WorkTemplate) ToModelWorkTemplate(t i18n.TranslateFunc) *model.WorkTemplate {
|
func (wt WorkTemplate) ToModelWorkTemplate(t i18n.TranslateFunc) *model.WorkTemplate {
|
||||||
@@ -201,17 +202,19 @@ func (wt WorkTemplate) Validate(categoryIds map[string]struct{}) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasChannel && wt.Description.Channel == nil {
|
if !wt.OnboardingOnly {
|
||||||
return errors.New("description.channel is required")
|
if hasChannel && wt.Description.Channel == nil {
|
||||||
}
|
return errors.New("description.channel is required")
|
||||||
if hasBoard && wt.Description.Board == nil {
|
}
|
||||||
return errors.New("description.board is required")
|
if hasBoard && wt.Description.Board == nil {
|
||||||
}
|
return errors.New("description.board is required")
|
||||||
if hasPlaybook && wt.Description.Playbook == nil {
|
}
|
||||||
return errors.New("description.playbook is required")
|
if hasPlaybook && wt.Description.Playbook == nil {
|
||||||
}
|
return errors.New("description.playbook is required")
|
||||||
if hasIntegration && wt.Description.Integration == nil {
|
}
|
||||||
return errors.New("description.integration is required")
|
if hasIntegration && wt.Description.Integration == nil {
|
||||||
|
return errors.New("description.integration is required")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, channel := range mustHaveChannels {
|
for _, channel := range mustHaveChannels {
|
||||||
|
|||||||
@@ -25,10 +25,14 @@ func ListCategories() ([]*WorkTemplateCategory, error) {
|
|||||||
return OrderedWorkTemplateCategories, nil
|
return OrderedWorkTemplateCategories, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListByCategory(category string) ([]*WorkTemplate, error) {
|
func ListByCategory(category string, includeOnboardingTemplate bool) ([]*WorkTemplate, error) {
|
||||||
wts := []*WorkTemplate{}
|
wts := []*WorkTemplate{}
|
||||||
for i := range OrderedWorkTemplates {
|
for i := range OrderedWorkTemplates {
|
||||||
if OrderedWorkTemplates[i].Category == category {
|
if OrderedWorkTemplates[i].Category == category {
|
||||||
|
// do not include work template with onboarding only flag if includeOnboardingTemplate is false
|
||||||
|
if !includeOnboardingTemplate && OrderedWorkTemplates[i].OnboardingOnly {
|
||||||
|
continue
|
||||||
|
}
|
||||||
wts = append(wts, OrderedWorkTemplates[i])
|
wts = append(wts, OrderedWorkTemplates[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10060,44 +10060,124 @@
|
|||||||
"translation": "Couldn't find the user."
|
"translation": "Couldn't find the user."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.category.companywide",
|
"id": "worktemplate.category.design",
|
||||||
"translation": "Company-wide"
|
"translation": "Design"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.category.devops",
|
"id": "worktemplate.category.devops",
|
||||||
"translation": "DevOps"
|
"translation": "DevOps"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.category.engineering",
|
||||||
|
"translation": "Engineering"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.category.leadership",
|
"id": "worktemplate.category.leadership",
|
||||||
"translation": "Leadership"
|
"translation": "Leadership"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.category.marketing",
|
||||||
|
"translation": "Marketing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.category.other",
|
||||||
|
"translation": "Other"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.category.product_teams",
|
"id": "worktemplate.category.product_teams",
|
||||||
"translation": "Product"
|
"translation": "Product"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.companywide.create_project.board",
|
"id": "worktemplate.category.project_management",
|
||||||
|
"translation": "Project Management"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.category.qa",
|
||||||
|
"translation": "QA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.design.content_calendar.board",
|
||||||
|
"translation": "Use the Content Calendar boad to track ideas, plan your content themes, manage the creation process, and set milestones."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.design.content_calendar.channel",
|
||||||
|
"translation": "Share content ideas, trending posts, blog links, and mentions in a dedicated channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.design.create_project.board",
|
||||||
"translation": "Use a Kanban board to define and track your project tasks and progress."
|
"translation": "Use a Kanban board to define and track your project tasks and progress."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.companywide.create_project.channel",
|
"id": "worktemplate.design.create_project.channel",
|
||||||
"translation": "Chat with your team about your new project and decide how you’re going to structure it, in a collaborative channel."
|
"translation": "Chat with your team about your new project and decide how you’re going to structure it, in a collaborative channel."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.companywide.create_project.integration",
|
"id": "worktemplate.design.create_project.integration",
|
||||||
"translation": "Increase productivity in your channel by integrating your most commonly used tools. These will be downloaded for you."
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools. These will be downloaded for you."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.companywide.goals_and_okrs.board",
|
"id": "worktemplate.design.feature_release.description.board",
|
||||||
"translation": "Track your team's progress toward organizational goals with the Goals and OKR board. Keep meetings on track with the Meeting Agenda board."
|
"translation": "Keep meetings on track with the Meeting Agenda board. Manage your workload with the Project Tasks board."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.companywide.goals_and_okrs.channel",
|
"id": "worktemplate.design.feature_release.description.channel",
|
||||||
"translation": "Chat about your goals and progress with your team, async or real-time, and stay up to date with changes in a single channel."
|
"translation": "Chat with your team about any release blockers and changes in a channel that connects easily with your boards, playbooks and other integrations."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.companywide.goals_and_okrs.integration",
|
"id": "worktemplate.design.feature_release.description.integration",
|
||||||
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom, to facilitate easy collaboration. These will be downloaded for you."
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools to support your feature release, such as GitHub. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.design.feature_release.description.playbook",
|
||||||
|
"translation": "Boost cross-functional team collaboration with task checklists and automation that support your feature development process. When you’re done, run a retrospective and make improvements for your next release."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.design.product_release.board",
|
||||||
|
"translation": "Use the Product Release board to support your release timeframe and process, ensuring everyone knows which tasks are due."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.design.product_release.channel",
|
||||||
|
"translation": "Chat with your team about daily milestones, any blockers, and changes to deliverables, easily and quickly."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.design.product_release.playbook",
|
||||||
|
"translation": "Create repeatable workflows that are easy to follow and implement so product releases are reliable and on time."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.design.sprint_planning.board",
|
||||||
|
"translation": "Track your team's progress toward weekly goals with sprint breakdowns, prioritization, owner assignment, and comments."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.design.sprint_planning.channel",
|
||||||
|
"translation": "Chat with your team in a channel that connects easily with your boards and integrations."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.design.sprint_planning.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.devops.bug_bash.channel",
|
||||||
|
"translation": "Plan and manage bug reports and resolutions in a single channel, that’s easily accessible to your team and organization."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.devops.bug_bash.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Jira, to track your bug bash progress. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.devops.bug_bash.playbook",
|
||||||
|
"translation": "Use checklists to assign testing areas and automated tasks to run a comprehensive bug bash process. Use a retrospective to review your process and improve it for next time."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.devops.create_project.board",
|
||||||
|
"translation": "Use a Kanban board to define and track your project tasks and progress."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.devops.create_project.channel",
|
||||||
|
"translation": "Chat with your team about your new project and decide how you’re going to structure it, in a collaborative channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.devops.create_project.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools. These will be downloaded for you."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.devops.incident_resolution.description.board",
|
"id": "worktemplate.devops.incident_resolution.description.board",
|
||||||
@@ -10123,6 +10203,102 @@
|
|||||||
"id": "worktemplate.devops.product_release.playbook",
|
"id": "worktemplate.devops.product_release.playbook",
|
||||||
"translation": "Create repeatable workflows that are easy to follow and implement so product releases are reliable and on time."
|
"translation": "Create repeatable workflows that are easy to follow and implement so product releases are reliable and on time."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.devops.sprint_planning.board",
|
||||||
|
"translation": "Track your team's progress toward weekly goals with sprint breakdowns, prioritization, owner assignment, and comments."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.devops.sprint_planning.channel",
|
||||||
|
"translation": "Chat with your team in a channel that connects easily with your boards and integrations."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.devops.sprint_planning.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.bug_bash.channel",
|
||||||
|
"translation": "Plan and manage bug reports and resolutions in a single channel, that’s easily accessible to your team and organization."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.bug_bash.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Jira, to track your bug bash progress. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.bug_bash.playbook",
|
||||||
|
"translation": "Use checklists to assign testing areas and automated tasks to run a comprehensive bug bash process. Use a retrospective to review your process and improve it for next time."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.create_project.board",
|
||||||
|
"translation": "Use a Kanban board to define and track your project tasks and progress."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.create_project.channel",
|
||||||
|
"translation": "Chat with your team about your new project and decide how you’re going to structure it, in a collaborative channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.create_project.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.feature_release.description.board",
|
||||||
|
"translation": "Keep meetings on track with the Meeting Agenda board. Manage your workload with the Project Tasks board."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.feature_release.description.channel",
|
||||||
|
"translation": "Chat with your team about any release blockers and changes in a channel that connects easily with your boards, playbooks and other integrations."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.feature_release.description.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools to support your feature release, such as GitHub. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.feature_release.description.playbook",
|
||||||
|
"translation": "Boost cross-functional team collaboration with task checklists and automation that support your feature development process. When you’re done, run a retrospective and make improvements for your next release."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.goals_and_okrs.board",
|
||||||
|
"translation": "Track your team's progress toward organizational goals with the Goals and OKR board. Keep meetings on track with the Meeting Agenda board."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.goals_and_okrs.channel",
|
||||||
|
"translation": "Chat about your goals and progress with your team, async or real-time, and stay up to date with changes in a single channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.goals_and_okrs.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom, to facilitate easy collaboration. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.sprint_planning.board",
|
||||||
|
"translation": "Track your team's progress toward weekly goals with sprint breakdowns, prioritization, owner assignment, and comments."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.sprint_planning.channel",
|
||||||
|
"translation": "Chat with your team in a channel that connects easily with your boards and integrations."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.engineering.sprint_planning.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.leadership.content_calendar.board",
|
||||||
|
"translation": "Use the Content Calendar boad to track ideas, plan your content themes, manage the creation process, and set milestones."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.leadership.content_calendar.channel",
|
||||||
|
"translation": "Share content ideas, trending posts, blog links, and mentions in a dedicated channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.leadership.create_project.board",
|
||||||
|
"translation": "Use a Kanban board to define and track your project tasks and progress."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.leadership.create_project.channel",
|
||||||
|
"translation": "Chat with your team about your new project and decide how you’re going to structure it, in a collaborative channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.leadership.create_project.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools. These will be downloaded for you."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.leadership.goals_and_okrs.board",
|
"id": "worktemplate.leadership.goals_and_okrs.board",
|
||||||
"translation": "Track your team's progress toward organizational goals with the Goals and OKR board. Keep meetings on track with the Meeting Agenda board."
|
"translation": "Track your team's progress toward organizational goals with the Goals and OKR board. Keep meetings on track with the Meeting Agenda board."
|
||||||
@@ -10135,6 +10311,126 @@
|
|||||||
"id": "worktemplate.leadership.goals_and_okrs.integration",
|
"id": "worktemplate.leadership.goals_and_okrs.integration",
|
||||||
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom, to facilitate easy collaboration. These will be downloaded for you."
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom, to facilitate easy collaboration. These will be downloaded for you."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.leadership.incident_resolution.description.board",
|
||||||
|
"translation": "Use the Incident Resolution board to support repeatable processes and assign defined tasks across the team."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.leadership.incident_resolution.description.channel",
|
||||||
|
"translation": "Chat with your team about priorities, add stakeholders, provide updates, and work toward a resolution in a single channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.leadership.incident_resolution.description.playbook",
|
||||||
|
"translation": "Use checklists and automation to bring in key team members, and share how your incident is tracking toward resolution."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.content_calendar.board",
|
||||||
|
"translation": "Use the Content Calendar boad to track ideas, plan your content themes, manage the creation process, and set milestones."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.content_calendar.channel",
|
||||||
|
"translation": "Share content ideas, trending posts, blog links, and mentions in a dedicated channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.create_project.board",
|
||||||
|
"translation": "Use a Kanban board to define and track your project tasks and progress."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.create_project.channel",
|
||||||
|
"translation": "Chat with your team about your new project and decide how you’re going to structure it, in a collaborative channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.create_project.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.goals_and_okrs.board",
|
||||||
|
"translation": "Track your team's progress toward organizational goals with the Goals and OKR board. Keep meetings on track with the Meeting Agenda board."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.goals_and_okrs.channel",
|
||||||
|
"translation": "Chat about your goals and progress with your team, async or real-time, and stay up to date with changes in a single channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.goals_and_okrs.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom, to facilitate easy collaboration. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.product_release.board",
|
||||||
|
"translation": "Use the Product Release board to support your release timeframe and process, ensuring everyone knows which tasks are due."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.product_release.channel",
|
||||||
|
"translation": "Chat with your team about daily milestones, any blockers, and changes to deliverables, easily and quickly."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.marketing.product_release.playbook",
|
||||||
|
"translation": "Create repeatable workflows that are easy to follow and implement so product releases are reliable and on time."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.create_project.board",
|
||||||
|
"translation": "Use a Kanban board to define and track your project tasks and progress."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.create_project.channel",
|
||||||
|
"translation": "Chat with your team about your new project and decide how you’re going to structure it, in a collaborative channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.create_project.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.feature_release.description.board",
|
||||||
|
"translation": "Keep meetings on track with the Meeting Agenda board. Manage your workload with the Project Tasks board."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.feature_release.description.channel",
|
||||||
|
"translation": "Chat with your team about any release blockers and changes in a channel that connects easily with your boards, playbooks and other integrations."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.feature_release.description.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools to support your feature release, such as GitHub. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.feature_release.description.playbook",
|
||||||
|
"translation": "Boost cross-functional team collaboration with task checklists and automation that support your feature development process. When you’re done, run a retrospective and make improvements for your next release."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.goals_and_okrs.board",
|
||||||
|
"translation": "Track your team's progress toward organizational goals with the Goals and OKR board. Keep meetings on track with the Meeting Agenda board."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.goals_and_okrs.channel",
|
||||||
|
"translation": "Chat about your goals and progress with your team, async or real-time, and stay up to date with changes in a single channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.goals_and_okrs.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom, to facilitate easy collaboration. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.incident_resolution.description.board",
|
||||||
|
"translation": "Use the Incident Resolution board to support repeatable processes and assign defined tasks across the team."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.incident_resolution.description.channel",
|
||||||
|
"translation": "Chat with your team about priorities, add stakeholders, provide updates, and work toward a resolution in a single channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.incident_resolution.description.playbook",
|
||||||
|
"translation": "Use checklists and automation to bring in key team members, and share how your incident is tracking toward resolution."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.product_release.board",
|
||||||
|
"translation": "Use the Product Release board to support your release timeframe and process, ensuring everyone knows which tasks are due."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.product_release.channel",
|
||||||
|
"translation": "Chat with your team about daily milestones, any blockers, and changes to deliverables, easily and quickly."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.other.product_release.playbook",
|
||||||
|
"translation": "Create repeatable workflows that are easy to follow and implement so product releases are reliable and on time."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.product_teams.bug_bash.channel",
|
"id": "worktemplate.product_teams.bug_bash.channel",
|
||||||
"translation": "Plan and manage bug reports and resolutions in a single channel, that’s easily accessible to your team and organization."
|
"translation": "Plan and manage bug reports and resolutions in a single channel, that’s easily accessible to your team and organization."
|
||||||
@@ -10161,7 +10457,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.product_teams.feature_release.description.playbook",
|
"id": "worktemplate.product_teams.feature_release.description.playbook",
|
||||||
"translation": "Boost cross-functional team collaboration with task checklists and automation that support your feature development process. When you're done, run a retrospective and make improvements for your next release."
|
"translation": "Boost cross-functional team collaboration with task checklists and automation that support your feature development process. When you’re done, run a retrospective and make improvements for your next release."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "worktemplate.product_teams.goals_and_okrs.board",
|
"id": "worktemplate.product_teams.goals_and_okrs.board",
|
||||||
@@ -10194,5 +10490,125 @@
|
|||||||
{
|
{
|
||||||
"id": "worktemplate.product_teams.sprint_planning.integration",
|
"id": "worktemplate.product_teams.sprint_planning.integration",
|
||||||
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom. These will be downloaded for you."
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.create_project.board",
|
||||||
|
"translation": "Use a Kanban board to define and track your project tasks and progress."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.create_project.channel",
|
||||||
|
"translation": "Chat with your team about your new project and decide how you’re going to structure it, in a collaborative channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.create_project.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.feature_release.description.board",
|
||||||
|
"translation": "Keep meetings on track with the Meeting Agenda board. Manage your workload with the Project Tasks board."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.feature_release.description.channel",
|
||||||
|
"translation": "Chat with your team about any release blockers and changes in a channel that connects easily with your boards, playbooks and other integrations."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.feature_release.description.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools to support your feature release, such as GitHub. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.feature_release.description.playbook",
|
||||||
|
"translation": "Boost cross-functional team collaboration with task checklists and automation that support your feature development process. When you’re done, run a retrospective and make improvements for your next release."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.goals_and_okrs.board",
|
||||||
|
"translation": "Track your team's progress toward organizational goals with the Goals and OKR board. Keep meetings on track with the Meeting Agenda board."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.goals_and_okrs.channel",
|
||||||
|
"translation": "Chat about your goals and progress with your team, async or real-time, and stay up to date with changes in a single channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.goals_and_okrs.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom, to facilitate easy collaboration. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.product_release.board",
|
||||||
|
"translation": "Use the Product Release board to support your release timeframe and process, ensuring everyone knows which tasks are due."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.product_release.channel",
|
||||||
|
"translation": "Chat with your team about daily milestones, any blockers, and changes to deliverables, easily and quickly."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.product_release.playbook",
|
||||||
|
"translation": "Create repeatable workflows that are easy to follow and implement so product releases are reliable and on time."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.product_roadmap.board",
|
||||||
|
"translation": "Use the Product Roadmap board to manage user feedback, assign resources, view deliverables in a calendar view, and prioritize issues."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.project_management.product_roadmap.channel",
|
||||||
|
"translation": "Chat with your team about your customers' feedback, prioritization, and get aligned on progress together."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.bug_bash.channel",
|
||||||
|
"translation": "Plan and manage bug reports and resolutions in a single channel, that’s easily accessible to your team and organization."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.bug_bash.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Jira, to track your bug bash progress. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.bug_bash.playbook",
|
||||||
|
"translation": "Use checklists to assign testing areas and automated tasks to run a comprehensive bug bash process. Use a retrospective to review your process and improve it for next time."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.create_project.board",
|
||||||
|
"translation": "Use a Kanban board to define and track your project tasks and progress."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.create_project.channel",
|
||||||
|
"translation": "Chat with your team about your new project and decide how you’re going to structure it, in a collaborative channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.create_project.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools. These will be downloaded for you."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.incident_resolution.description.board",
|
||||||
|
"translation": "Use the Incident Resolution board to support repeatable processes and assign defined tasks across the team."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.incident_resolution.description.channel",
|
||||||
|
"translation": "Chat with your team about priorities, add stakeholders, provide updates, and work toward a resolution in a single channel."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.incident_resolution.description.playbook",
|
||||||
|
"translation": "Use checklists and automation to bring in key team members, and share how your incident is tracking toward resolution."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.product_release.board",
|
||||||
|
"translation": "Use the Product Release board to support your release timeframe and process, ensuring everyone knows which tasks are due."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.product_release.channel",
|
||||||
|
"translation": "Chat with your team about daily milestones, any blockers, and changes to deliverables, easily and quickly."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.product_release.playbook",
|
||||||
|
"translation": "Create repeatable workflows that are easy to follow and implement so product releases are reliable and on time."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.sprint_planning.board",
|
||||||
|
"translation": "Track your team's progress toward weekly goals with sprint breakdowns, prioritization, owner assignment, and comments."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.sprint_planning.channel",
|
||||||
|
"translation": "Chat with your team in a channel that connects easily with your boards and integrations."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "worktemplate.qa.sprint_planning.integration",
|
||||||
|
"translation": "Increase productivity in your channel by integrating your most commonly used tools, such as Zoom. These will be downloaded for you."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
// CompleteOnboardingRequest describes parameters of the requested plugin.
|
// CompleteOnboardingRequest describes parameters of the requested plugin.
|
||||||
type CompleteOnboardingRequest struct {
|
type CompleteOnboardingRequest struct {
|
||||||
Organization string `json:"organization"` // Organization is the name of the organization
|
Organization string `json:"organization"` // Organization is the name of the organization
|
||||||
|
Role string `json:"role"` // Role is the role selected by first admin
|
||||||
InstallPlugins []string `json:"install_plugins"` // InstallPlugins is a list of plugins to be installed
|
InstallPlugins []string `json:"install_plugins"` // InstallPlugins is a list of plugins to be installed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const (
|
|||||||
SystemPostActionCookieSecretKey = "PostActionCookieSecret"
|
SystemPostActionCookieSecretKey = "PostActionCookieSecret"
|
||||||
SystemInstallationDateKey = "InstallationDate"
|
SystemInstallationDateKey = "InstallationDate"
|
||||||
SystemOrganizationName = "OrganizationName"
|
SystemOrganizationName = "OrganizationName"
|
||||||
|
SystemFirstAdminRole = "FirstAdminRole"
|
||||||
SystemFirstServerRunTimestampKey = "FirstServerRunTimestamp"
|
SystemFirstServerRunTimestampKey = "FirstServerRunTimestamp"
|
||||||
SystemClusterEncryptionKey = "ClusterEncryptionKey"
|
SystemClusterEncryptionKey = "ClusterEncryptionKey"
|
||||||
SystemUpgradedFromTeId = "UpgradedFromTE"
|
SystemUpgradedFromTeId = "UpgradedFromTE"
|
||||||
|
|||||||
@@ -10,3 +10,25 @@
|
|||||||
border: 2px solid var(--button-bg);
|
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/variables';
|
||||||
@import 'utils/mixins';
|
@import 'utils/mixins';
|
||||||
|
@import 'mixins';
|
||||||
|
|
||||||
.PreparingWorkspace {
|
.PreparingWorkspace {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
@@ -93,34 +94,35 @@
|
|||||||
animation-duration: 0.3s;
|
animation-duration: 0.3s;
|
||||||
animation-fill-mode: forwards;
|
animation-fill-mode: forwards;
|
||||||
animation-timing-function: ease-in-out;
|
animation-timing-function: ease-in-out;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.enter {
|
@include sideIllustrationKeyframe(invitation, 651);
|
||||||
animation-name: slideInRight;
|
|
||||||
}
|
|
||||||
|
|
||||||
.exit {
|
&.enter {
|
||||||
animation-name: slideOutRight;
|
animation-name: invitationSlideInRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slideInRight {
|
&.exit {
|
||||||
from {
|
animation-name: invitationSlideOutRight;
|
||||||
right: -651px;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
&__roles-illustration {
|
||||||
right: 0;
|
position: absolute;
|
||||||
}
|
right: -295px;
|
||||||
}
|
bottom: 0;
|
||||||
|
animation-duration: 0.3s;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
animation-timing-function: ease-in-out;
|
||||||
|
|
||||||
@keyframes slideOutRight {
|
@include sideIllustrationKeyframe(roles, 295);
|
||||||
from {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
&.enter {
|
||||||
right: -651px;
|
animation-name: rolesSlideInRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.exit {
|
||||||
|
animation-name: rolesSlideOutRight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,3 +148,10 @@
|
|||||||
overflow-y: visible;
|
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 {getFirstAdminSetupComplete, getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||||
import {Client4} from 'mattermost-redux/client';
|
import {Client4} from 'mattermost-redux/client';
|
||||||
|
|
||||||
|
import {CategoryOther} from '@mattermost/types/work_templates';
|
||||||
|
|
||||||
import Constants from 'utils/constants';
|
import Constants from 'utils/constants';
|
||||||
import {getSiteURL, teamNameToUrl} from 'utils/url';
|
import {getSiteURL, teamNameToUrl} from 'utils/url';
|
||||||
import {makeNewTeam} from 'utils/team_utils';
|
import {makeNewTeam} from 'utils/team_utils';
|
||||||
@@ -42,6 +44,8 @@ import {
|
|||||||
} from './steps';
|
} from './steps';
|
||||||
|
|
||||||
import Organization from './organization';
|
import Organization from './organization';
|
||||||
|
import Roles from './roles';
|
||||||
|
import RolesIllustration from './roles_illustration';
|
||||||
import Plugins from './plugins';
|
import Plugins from './plugins';
|
||||||
import Progress from './progress';
|
import Progress from './progress';
|
||||||
import InviteMembers from './invite_members';
|
import InviteMembers from './invite_members';
|
||||||
@@ -90,6 +94,7 @@ function makeSubmitFail(step: WizardStep) {
|
|||||||
|
|
||||||
const trackSubmitFail = {
|
const trackSubmitFail = {
|
||||||
[WizardSteps.Organization]: makeSubmitFail(WizardSteps.Organization),
|
[WizardSteps.Organization]: makeSubmitFail(WizardSteps.Organization),
|
||||||
|
[WizardSteps.Roles]: makeSubmitFail(WizardSteps.Roles),
|
||||||
[WizardSteps.Plugins]: makeSubmitFail(WizardSteps.Plugins),
|
[WizardSteps.Plugins]: makeSubmitFail(WizardSteps.Plugins),
|
||||||
[WizardSteps.InviteMembers]: makeSubmitFail(WizardSteps.InviteMembers),
|
[WizardSteps.InviteMembers]: makeSubmitFail(WizardSteps.InviteMembers),
|
||||||
[WizardSteps.LaunchingWorkspace]: makeSubmitFail(WizardSteps.LaunchingWorkspace),
|
[WizardSteps.LaunchingWorkspace]: makeSubmitFail(WizardSteps.LaunchingWorkspace),
|
||||||
@@ -97,6 +102,7 @@ const trackSubmitFail = {
|
|||||||
|
|
||||||
const onPageViews = {
|
const onPageViews = {
|
||||||
[WizardSteps.Organization]: makeOnPageView(WizardSteps.Organization),
|
[WizardSteps.Organization]: makeOnPageView(WizardSteps.Organization),
|
||||||
|
[WizardSteps.Roles]: makeOnPageView(WizardSteps.Roles),
|
||||||
[WizardSteps.Plugins]: makeOnPageView(WizardSteps.Plugins),
|
[WizardSteps.Plugins]: makeOnPageView(WizardSteps.Plugins),
|
||||||
[WizardSteps.InviteMembers]: makeOnPageView(WizardSteps.InviteMembers),
|
[WizardSteps.InviteMembers]: makeOnPageView(WizardSteps.InviteMembers),
|
||||||
[WizardSteps.LaunchingWorkspace]: makeOnPageView(WizardSteps.LaunchingWorkspace),
|
[WizardSteps.LaunchingWorkspace]: makeOnPageView(WizardSteps.LaunchingWorkspace),
|
||||||
@@ -128,6 +134,7 @@ const PreparingWorkspace = (props: Props) => {
|
|||||||
|
|
||||||
const stepOrder = [
|
const stepOrder = [
|
||||||
isSelfHosted && WizardSteps.Organization,
|
isSelfHosted && WizardSteps.Organization,
|
||||||
|
WizardSteps.Roles,
|
||||||
pluginsEnabled && WizardSteps.Plugins,
|
pluginsEnabled && WizardSteps.Plugins,
|
||||||
WizardSteps.InviteMembers,
|
WizardSteps.InviteMembers,
|
||||||
WizardSteps.LaunchingWorkspace,
|
WizardSteps.LaunchingWorkspace,
|
||||||
@@ -256,6 +263,7 @@ const PreparingWorkspace = (props: Props) => {
|
|||||||
// even if admin skipped submitting plugins.
|
// even if admin skipped submitting plugins.
|
||||||
const completeSetupRequest = {
|
const completeSetupRequest = {
|
||||||
organization: form.organization,
|
organization: form.organization,
|
||||||
|
role: form.role === CategoryOther ? form.roleOther : form.role,
|
||||||
install_plugins: pluginsToSetup,
|
install_plugins: pluginsToSetup,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -365,6 +373,15 @@ const PreparingWorkspace = (props: Props) => {
|
|||||||
return '';
|
return '';
|
||||||
}, [currentStep]);
|
}, [currentStep]);
|
||||||
|
|
||||||
|
const getRolesAnimationClass = useCallback(() => {
|
||||||
|
if (currentStep === WizardSteps.Roles) {
|
||||||
|
return 'enter';
|
||||||
|
} else if (mostRecentStep === WizardSteps.Roles) {
|
||||||
|
return 'exit';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}, [currentStep]);
|
||||||
|
|
||||||
let previous: React.ReactNode = (
|
let previous: React.ReactNode = (
|
||||||
<div
|
<div
|
||||||
onClick={goPrevious}
|
onClick={goPrevious}
|
||||||
@@ -431,6 +448,48 @@ const PreparingWorkspace = (props: Props) => {
|
|||||||
updateTeam={updateTeam}
|
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
|
<Plugins
|
||||||
isSelfHosted={isSelfHosted}
|
isSelfHosted={isSelfHosted}
|
||||||
onPageView={onPageViews[WizardSteps.Plugins]}
|
onPageView={onPageViews[WizardSteps.Plugins]}
|
||||||
@@ -508,6 +567,9 @@ const PreparingWorkspace = (props: Props) => {
|
|||||||
<div className={`PreparingWorkspace__invite-members-illustration ${getInviteMembersAnimationClass()}`}>
|
<div className={`PreparingWorkspace__invite-members-illustration ${getInviteMembersAnimationClass()}`}>
|
||||||
<InviteMembersIllustration/>
|
<InviteMembersIllustration/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={`PreparingWorkspace__roles-illustration ${getRolesAnimationClass()}`}>
|
||||||
|
<RolesIllustration/>
|
||||||
|
</div>
|
||||||
</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 = {
|
export const WizardSteps = {
|
||||||
Organization: 'Organization',
|
Organization: 'Organization',
|
||||||
|
Roles: 'Roles',
|
||||||
Plugins: 'Plugins',
|
Plugins: 'Plugins',
|
||||||
InviteMembers: 'InviteMembers',
|
InviteMembers: 'InviteMembers',
|
||||||
LaunchingWorkspace: 'LaunchingWorkspace',
|
LaunchingWorkspace: 'LaunchingWorkspace',
|
||||||
@@ -24,6 +25,8 @@ export function mapStepToNextName(step: WizardStep): string {
|
|||||||
switch (step) {
|
switch (step) {
|
||||||
case WizardSteps.Organization:
|
case WizardSteps.Organization:
|
||||||
return 'admin_onboarding_next_organization';
|
return 'admin_onboarding_next_organization';
|
||||||
|
case WizardSteps.Roles:
|
||||||
|
return 'admin_onboarding_next_roles';
|
||||||
case WizardSteps.Plugins:
|
case WizardSteps.Plugins:
|
||||||
return 'admin_onboarding_next_plugins';
|
return 'admin_onboarding_next_plugins';
|
||||||
case WizardSteps.InviteMembers:
|
case WizardSteps.InviteMembers:
|
||||||
@@ -39,6 +42,8 @@ export function mapStepToPrevious(step: WizardStep): string {
|
|||||||
switch (step) {
|
switch (step) {
|
||||||
case WizardSteps.Organization:
|
case WizardSteps.Organization:
|
||||||
return 'admin_onboarding_previous_organization';
|
return 'admin_onboarding_previous_organization';
|
||||||
|
case WizardSteps.Roles:
|
||||||
|
return 'admin_onboarding_previous_roles';
|
||||||
case WizardSteps.Plugins:
|
case WizardSteps.Plugins:
|
||||||
return 'admin_onboarding_previous_plugins';
|
return 'admin_onboarding_previous_plugins';
|
||||||
case WizardSteps.InviteMembers:
|
case WizardSteps.InviteMembers:
|
||||||
@@ -54,6 +59,8 @@ export function mapStepToPageView(step: WizardStep): string {
|
|||||||
switch (step) {
|
switch (step) {
|
||||||
case WizardSteps.Organization:
|
case WizardSteps.Organization:
|
||||||
return 'pageview_admin_onboarding_organization';
|
return 'pageview_admin_onboarding_organization';
|
||||||
|
case WizardSteps.Roles:
|
||||||
|
return 'pageview_admin_onboarding_roles';
|
||||||
case WizardSteps.Plugins:
|
case WizardSteps.Plugins:
|
||||||
return 'pageview_admin_onboarding_plugins';
|
return 'pageview_admin_onboarding_plugins';
|
||||||
case WizardSteps.InviteMembers:
|
case WizardSteps.InviteMembers:
|
||||||
@@ -69,6 +76,8 @@ export function mapStepToSubmitFail(step: WizardStep): string {
|
|||||||
switch (step) {
|
switch (step) {
|
||||||
case WizardSteps.Organization:
|
case WizardSteps.Organization:
|
||||||
return 'admin_onboarding_organization_submit_fail';
|
return 'admin_onboarding_organization_submit_fail';
|
||||||
|
case WizardSteps.Roles:
|
||||||
|
return 'admin_onboarding_roles_submit_fail';
|
||||||
case WizardSteps.Plugins:
|
case WizardSteps.Plugins:
|
||||||
return 'admin_onboarding_plugins_submit_fail';
|
return 'admin_onboarding_plugins_submit_fail';
|
||||||
case WizardSteps.InviteMembers:
|
case WizardSteps.InviteMembers:
|
||||||
@@ -84,6 +93,8 @@ export function mapStepToSkipName(step: WizardStep): string {
|
|||||||
switch (step) {
|
switch (step) {
|
||||||
case WizardSteps.Organization:
|
case WizardSteps.Organization:
|
||||||
return 'admin_onboarding_skip_organization';
|
return 'admin_onboarding_skip_organization';
|
||||||
|
case WizardSteps.Roles:
|
||||||
|
return 'admin_onboarding_skip_roles';
|
||||||
case WizardSteps.Plugins:
|
case WizardSteps.Plugins:
|
||||||
return 'admin_onboarding_skip_plugins';
|
return 'admin_onboarding_skip_plugins';
|
||||||
case WizardSteps.InviteMembers:
|
case WizardSteps.InviteMembers:
|
||||||
@@ -127,6 +138,8 @@ export const PLUGIN_NAME_TO_ID_MAP: PluginNameMap = {
|
|||||||
|
|
||||||
export type Form = {
|
export type Form = {
|
||||||
organization?: string;
|
organization?: string;
|
||||||
|
role?: string;
|
||||||
|
roleOther?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
urlSkipped: boolean;
|
urlSkipped: boolean;
|
||||||
inferredProtocol: 'http' | 'https' | null;
|
inferredProtocol: 'http' | 'https' | null;
|
||||||
@@ -184,6 +197,8 @@ export const emptyForm = deepFreeze({
|
|||||||
invites: [],
|
invites: [],
|
||||||
skipped: false,
|
skipped: false,
|
||||||
},
|
},
|
||||||
|
role: '',
|
||||||
|
roleOther: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
export type PreparingWorkspacePageProps = {
|
export type PreparingWorkspacePageProps = {
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ const CategoryButton = styled.button`
|
|||||||
background: none;
|
background: none;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(var(--denim-button-bg-rgb), 0.04);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background: rgba(var(--denim-button-bg-rgb), 0.04);
|
background: rgba(var(--denim-button-bg-rgb), 0.04);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
@@ -4236,6 +4236,9 @@
|
|||||||
"onboarding_wizard.plugins.zoom": "Zoom",
|
"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.plugins.zoom.tooltip": "Start Zoom audio and video conferencing calls in Mattermost with a single click",
|
||||||
"onboarding_wizard.previous": "Previous",
|
"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.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.self_hosted_plugins.title": "What tools do you use?",
|
||||||
"onboarding_wizard.skip-button": "Skip",
|
"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;
|
||||||
|
|||||||
@@ -3,5 +3,6 @@
|
|||||||
|
|
||||||
export type CompleteOnboardingRequest = {
|
export type CompleteOnboardingRequest = {
|
||||||
organization: string;
|
organization: string;
|
||||||
|
role?: string;
|
||||||
install_plugins: string[];
|
install_plugins: string[];
|
||||||
}
|
}
|
||||||
|
|||||||