Skip to content

Add NewOrgModal #62

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion elm-git.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"git-dependencies": {
"direct": {
"https://github.com/unisonweb/ui-core": "194adc73aceca4e3ae1519206e122419c9985f35"
"https://github.com/unisonweb/ui-core": "78ba490fac82e43146be5653e5a9be2288ac6ad0"
},
"indirect": {}
}
Expand Down
1 change: 1 addition & 0 deletions elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"j-maas/elm-ordered-containers": "1.0.0",
"justinmimbs/time-extra": "1.1.1",
"krisajenkins/remotedata": "6.0.1",
"kuon/elm-string-normalize": "1.0.6",
"mgold/elm-nonempty-list": "4.2.0",
"noahzgordon/elm-color-extra": "1.0.2",
"rtfeldman/elm-iso8601-date-strings": "1.1.4",
Expand Down
7 changes: 5 additions & 2 deletions src/UnisonShare/Account.elm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type alias Account a =
, completedTours : List Tour
, organizationMemberships : List OrganizationMembership
, isSuperAdmin : Bool
, primaryEmail : String
}


Expand Down Expand Up @@ -89,20 +90,22 @@ isProjectOwner projectRef account =
decodeSummary : Decode.Decoder AccountSummary
decodeSummary =
let
makeSummary handle name_ avatarUrl completedTours organizationMemberships isSuperAdmin =
makeSummary handle name_ avatarUrl completedTours organizationMemberships isSuperAdmin primaryEmail =
{ handle = handle
, name = name_
, avatarUrl = avatarUrl
, pronouns = Nothing
, completedTours = Maybe.withDefault [] completedTours
, organizationMemberships = organizationMemberships
, isSuperAdmin = isSuperAdmin
, primaryEmail = primaryEmail
}
in
Decode.map6 makeSummary
Decode.map7 makeSummary
(field "handle" UserHandle.decodeUnprefixed)
(maybe (field "name" string))
(maybe (field "avatarUrl" decodeUrl))
(maybe (field "completedTours" (Decode.list Tour.decode)))
(field "organizationMemberships" (Decode.list (Decode.map OrganizationMembership UserHandle.decodeUnprefixed)))
(field "isSuperadmin" Decode.bool)
(field "primaryEmail" string)
33 changes: 31 additions & 2 deletions src/UnisonShare/Api.elm
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,26 @@ import UnisonShare.Tour as Tour exposing (Tour)
import Url.Builder exposing (QueryParameter, int, string)


profile : UserHandle -> Endpoint
profile handle =
GET { path = [ "users", UserHandle.toUnprefixedString handle ], queryParams = [] }


user : UserHandle -> Endpoint
user handle =
GET { path = [ "users", UserHandle.toUnprefixedString handle ], queryParams = [] }


org : UserHandle -> Endpoint
org handle =
GET { path = [ "users", UserHandle.toUnprefixedString handle ], queryParams = [] }


updateUserProfile : UserHandle -> { bio : String } -> Endpoint
updateUserProfile handle profile =
updateUserProfile handle profile_ =
let
body =
Encode.object [ ( "bio", Encode.string profile.bio ) ]
Encode.object [ ( "bio", Encode.string profile_.bio ) ]
|> Http.jsonBody
in
PATCH
Expand Down Expand Up @@ -178,6 +188,25 @@ session =
-- ORG ROLE ASSIGNMENTS (COLLABORATORS)


createOrg : { a | handle : UserHandle, primaryEmail : String } -> String -> UserHandle -> Bool -> Endpoint
createOrg owner name orgHandle isCommercial =
let
body =
Encode.object
[ ( "name", Encode.string name )
, ( "handle", Encode.string (UserHandle.toUnprefixedString orgHandle) )
, ( "isCommercial", Encode.bool isCommercial )
, ( "owner", Encode.string (UserHandle.toUnprefixedString owner.handle) )
, ( "email", Encode.string owner.primaryEmail )
]
in
POST
{ path = [ "orgs" ]
, queryParams = []
, body = Http.jsonBody body
}


orgRoleAssignments : UserHandle -> Endpoint
orgRoleAssignments orgHandle =
let
Expand Down
34 changes: 34 additions & 0 deletions src/UnisonShare/App.elm
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import UnisonShare.AppDocument as AppDocument
import UnisonShare.AppError as AppError exposing (AppError)
import UnisonShare.AppHeader as AppHeader
import UnisonShare.Link as Link
import UnisonShare.NewOrgModal as NewOrgModal
import UnisonShare.Page.AcceptTermsPage as AcceptTermsPage
import UnisonShare.Page.AccountPage as AccountPage
import UnisonShare.Page.AppErrorPage as AppErrorPage
Expand Down Expand Up @@ -86,6 +87,7 @@ type Page
type AppModal
= NoModal
| KeyboardShortcuts
| NewOrg NewOrgModal.Model


type alias Model =
Expand Down Expand Up @@ -213,6 +215,7 @@ type Msg
| ToggleAccountMenu
| ToggleCreateAccountMenu
| ShowKeyboardShortcuts
| ShowNewOrgModal
| CloseModal
| WhatsNewFetchFinished (HttpResult WhatsNew.LoadedWhatsNew)
| WhatsNewMarkAllAsRead
Expand All @@ -224,6 +227,7 @@ type Msg
| ProjectPageMsg ProjectPage.Msg
| AccountPageMsg AccountPage.Msg
| AcceptTermsPageMsg AcceptTermsPage.Msg
| NewOrgModalMsg NewOrgModal.Msg


update : Msg -> Model -> ( Model, Cmd Msg )
Expand Down Expand Up @@ -465,6 +469,9 @@ update msg ({ appContext } as model) =
( _, ShowKeyboardShortcuts ) ->
( { model | openedAppHeaderMenu = AppHeader.NoneOpened, appModal = KeyboardShortcuts }, Cmd.none )

( _, ShowNewOrgModal ) ->
( { model | openedAppHeaderMenu = AppHeader.NoneOpened, appModal = NewOrg NewOrgModal.init }, Cmd.none )

( _, CloseModal ) ->
( { model | appModal = NoModal }, Cmd.none )

Expand Down Expand Up @@ -523,6 +530,29 @@ update msg ({ appContext } as model) =
in
( { model | page = AcceptTerms continueUrl acceptTerms_ }, Cmd.map AcceptTermsPageMsg acceptTermsCmd )

( _, NewOrgModalMsg newOrgMsg ) ->
case ( model.appModal, appContext.session ) of
( NewOrg newOrg, Session.SignedIn account ) ->
let
( newOrg_, cmd, out ) =
NewOrgModal.update appContext account newOrgMsg newOrg

appModal =
case out of
NewOrgModal.NoOutMsg ->
NewOrg newOrg_

NewOrgModal.RequestCloseModal ->
NoModal

NewOrgModal.AddedOrg _ ->
NoModal
in
( { model | appModal = appModal }, Cmd.map NewOrgModalMsg cmd )

_ ->
( model, Cmd.none )

_ ->
( model, Cmd.none )

Expand Down Expand Up @@ -720,6 +750,7 @@ view model =
, toggleAccountMenuMsg = ToggleAccountMenu
, toggleCreateAccountMenuMsg = ToggleCreateAccountMenu
, showKeyboardShortcutsModalMsg = ShowKeyboardShortcuts
, showNewOrgModal = ShowNewOrgModal
}

appDocument =
Expand Down Expand Up @@ -784,6 +815,9 @@ view model =
KeyboardShortcuts ->
{ appDocument | modal = Just (viewKeyboardShortcutsModal appContext.operatingSystem) }

NewOrg m ->
{ appDocument | modal = Just (Html.map NewOrgModalMsg (NewOrgModal.view m)) }

appDocumentWithWelcomeTermsModal =
-- We link to TermsOfService and PrivacyPolicy from the welcome
-- terms modal and the AcceptTerms page is used during UCM signup,
Expand Down
24 changes: 18 additions & 6 deletions src/UnisonShare/AppHeader.elm
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Html.Attributes exposing (class, classList)
import Lib.HttpApi exposing (HttpApi)
import Lib.UserHandle as UserHandle exposing (UserHandle)
import Time
import UI
import UI.ActionMenu as ActionMenu
import UI.AnchoredOverlay as AnchoredOverlay
import UI.AppHeader exposing (AppHeader, AppTitle(..))
Expand Down Expand Up @@ -120,6 +121,7 @@ type alias AppHeaderContext msg =
, toggleHelpAndResourcesMenuMsg : msg
, toggleAccountMenuMsg : msg
, toggleCreateAccountMenuMsg : msg
, showNewOrgModal : msg
, showKeyboardShortcutsModalMsg : msg
}

Expand Down Expand Up @@ -277,21 +279,21 @@ view ctx appHeader_ =
]
)

SignedIn sesh ->
SignedIn account ->
let
nav =
case activeNavItem of
Catalog ->
Navigation.empty |> Navigation.withItems [] navItems.catalog [ navItems.profile sesh.handle ]
Navigation.empty |> Navigation.withItems [] navItems.catalog [ navItems.profile account.handle ]

Profile ->
Navigation.empty |> Navigation.withItems [ navItems.catalog ] (navItems.profile sesh.handle) []
Navigation.empty |> Navigation.withItems [ navItems.catalog ] (navItems.profile account.handle) []

_ ->
Navigation.empty |> Navigation.withNoSelectedItems [ navItems.catalog, navItems.profile sesh.handle ]
Navigation.empty |> Navigation.withNoSelectedItems [ navItems.catalog, navItems.profile account.handle ]

avatar =
Avatar.avatar sesh.avatarUrl (Maybe.map (String.left 1) sesh.name)
Avatar.avatar account.avatarUrl (Maybe.map (String.left 1) account.name)
|> Avatar.view

viewAccountMenuTrigger isOpen =
Expand All @@ -306,6 +308,16 @@ view ctx appHeader_ =
div [ classList [ ( "account-menu-trigger", True ), ( "account-menu_is-open", isOpen ) ] ]
[ avatar, Icon.view chevron ]

newOrgButton =
if account.isSuperAdmin then
Button.iconThenLabel ctx.showNewOrgModal Icon.largePlus "New Org"
|> Button.small
|> Button.positive
|> Button.view

else
UI.nothing

accountMenu =
ActionMenu.items
(ActionMenu.optionItem Icon.cog "Account Settings" Link.account)
Expand All @@ -315,7 +327,7 @@ view ctx appHeader_ =
|> ActionMenu.view
|> (\a -> div [ class "account-menu" ] [ a ])
in
( nav, [ helpAndResources, accountMenu ] )
( nav, [ newOrgButton, helpAndResources, accountMenu ] )
in
UI.AppHeader.appHeader (appTitle (Click.href "/"))
|> UI.AppHeader.withNavigation navigation
Expand Down
Loading
Loading