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
Adding wireframe contract setup workflow. #2773
Conversation
_templates = prop (SProxy :: SProxy "templates") | ||
|
||
_subState :: Lens' State (Either PickupState WalletState) | ||
_subState = prop (SProxy :: SProxy "subState") | ||
|
||
-- This isn't a Traversal' in any meaningful sense (that I can see), but a Traversal' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out it is an affine traversal. 🤓 So I'm removing this comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, I wrote one type design issue and then it is just lints
initialState :: Slot -> Contract -> State | ||
initialState slot contract = | ||
defaultState :: State | ||
defaultState = mkInitialState zero Close |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Close
and zero
as default for when there is no contract is a smell for me (is a bit like using null
in Java). I think this should be wrapped in some kind of Maybe
type or custom data type with a NotStarted
constructor or something like that. It is a bit more work, but I think that will make things much easier in the long run, especially when debugging later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we have a general problem here. David and I have been experimenting with different options, and so far have found having a default state (that we know will never be used) is the least awkward. Otherwise you have to handle the Nothing
cases in the view functions, even though the view functions will never be called in that case. But I agree it is "wrong". Going to leave it for now if you don't mind, and we can revisit it as we go along...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's nice that this is a separate function from mkInitialState
as well as it indicates the situation somewhat.
@@ -69,6 +71,8 @@ mkWalletState pubKeyHash = | |||
, menuOpen: false | |||
, screen: ContractsScreen Running | |||
, card: Nothing | |||
, templateState: Template.defaultState | |||
, contractState: Contract.defaultState |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could wrap both of these in a subtype in a Maybe
or something like that, because we only have templateState
and contractState
either both at the same time or none
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above.
case mCurrentTemplate of | ||
Just currentTemplate | ||
| currentTemplate == template -> pure unit | ||
_ -> assign (_walletState <<< _templateState) $ Template.mkInitialState template |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think 187-190 can be written as:
when (mCurrentTemplate /= Just template) $ assign (_walletState <<< _templateState) $ Template.mkInitialState template
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it can, thank you.
let | ||
templateContent = view _templateContent templateState | ||
let | ||
mContract = toCore $ fillTemplate templateContent extendedContract |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think 198-205 can be written as:
let
extendedContract = view (_template <<< _extendedContract) templateState
templateContent = view _templateContent templateState
mContract = toCore $ fillTemplate templateContent extendedContract
in
Without do
or pure unit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, don't know how that pure unit
got in there. Must have been during a rewrite when I wasn't paying full attention. Thanks. 👍
web-common/src/Halogen/Extra.purs
Outdated
|
||
mainToSub mainState = case preview traversal mainState of | ||
Just submoduleState -> submoduleState | ||
_ -> submoduleDefaultState |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think 91-93 could also be written:
mainToSub mainState = fromMaybe submoduleDefaultState $ preview traversal mainState
or even:
mainToSub = fromMaybe submoduleDefaultState <<< preview traversal
Not sure about parenthesis in last one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So it can. Nice.
getParties (Scale _ val) = getParties val | ||
getParties (ChoiceValue choId) = getParties choId | ||
getParties (Cond obs lhs rhs) = getParties obs <> getParties lhs <> getParties rhs | ||
getParties _ = Set.empty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to specify all the clauses (not using catch-all underscores) because that way if we modify Marlowe types we will get an error here. As it is now, we will get a default behaviour of no parties which is harder to notice. But this is just my opinion, we can leave it as is, no big deal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I don't have strong feelings on this so I'll go with your preference.
getParties :: a -> Set S.Party | ||
|
||
instance arrayHasParties :: HasParties a => HasParties (Array a) where | ||
getParties as = foldMap (\a -> getParties a) as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(\a -> getParties a)
is equivalent to getParties
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry one more thing...
mkRoleWallets contract = fromFoldable $ Set.map (\name -> Tuple name "") (getRoleNames contract) | ||
|
||
getRoleNames :: Contract -> Set String | ||
getRoleNames contract = Set.delete "" $ Set.map roleName (getParties contract) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This delete
here removes also Role ""
which I don't think is right. We can just use mapMaybe
and have roleName
return a Maybe String
. Using ""
, again, is a smell to me, like using null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that was bugging me too. Good idea with mapMaybe
. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a few suggestions but can be in next PR
initialState :: Slot -> Contract -> State | ||
initialState slot contract = | ||
defaultState :: State | ||
defaultState = mkInitialState zero Close |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's nice that this is a separate function from mkInitialState
as well as it indicates the situation somewhat.
handleAction (ContractAction contractAction) = handleSubAction (_walletState <<< _contractState) ContractAction Contract.defaultState (Contract.handleAction contractAction) | ||
|
||
-- there must be a nicer way to get the current state than by manually | ||
-- piecing together each of its properties, but I haven't found it :( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given that we are using row types, can't you just use the current state?
state <- get
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well that is exactly the function I wanted. And did not know existed. 😄
Just (ContractCard contract) -> [ ContractAction <$> contractDetailsCard contract ] | ||
Just NewContractForRoleCard -> [] | ||
Just ContractSetupConfirmationCard -> [ contractSetupConfirmationCard ] | ||
Just ContractCard -> [ ContractAction <$> contractDetailsCard contractState ] | ||
Nothing -> [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is
(flip foldMap card) \cardType -> case cardType of
CreateWalletCard -> [ newContactCard newWalletNicknameKey wallets ]
...
Not sure if it's nicer or not, I just didn't like the Just x
so many times and I spotted that we have Nothing -> []
i.e. Nothing -> mempty
i.e. Foldable f => Monoid m => f a -> m
which is foldMap :: forall m a. Monoid m => (a -> m) -> f a -> m
where the (a -> m)
is the pattern match without the Just
s everywhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
slick
mkRoleWallets contract = fromFoldable $ Set.map (\name -> Tuple name "") (getRoleNames contract) | ||
|
||
getRoleNames :: Contract -> Set String | ||
getRoleNames contract = Set.mapMaybe roleName (getParties contract) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not combine these 2 functions, it doesn't seem like they are doing that much
fromFoldable $ Set.mapMaybe getRoleEntry (getParties contract)
where
getRoleEntry (PK _) = Nothing
getRoleEntry (Role tokenName) = Just (Tuple tokenName "")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, I though getRoleNames
might be useful somewhere else, but probably not
templateContent = view _templateContent state | ||
in | ||
div | ||
[] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we've generally agreed on using div_
where possible these days (though I'm not that bothered)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but I'm expecting most of these divs will need classes when we start styling, so I've not been that fussed about this for now.
contractSetupScreenHeader setupScreen contractNickname = | ||
div_ | ||
[ div | ||
[] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
[ onClick $ const $ Just $ ToggleCard TemplateLibraryCard ] | ||
[ text "< Library quick access" ] | ||
, button | ||
[ onClick $ const $ Just $ SetScreen $ ContractSetupScreen ContractParametersScreen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should really define onClick <<< const <<< Just
somewhere (although I don't know a good name)
[ text "< Library quick access" ] | ||
, button | ||
[ onClick $ const $ Just $ SetScreen $ ContractSetupScreen ContractParametersScreen | ||
, disabled $ not $ roleWalletsAreValid roleWallets wallets |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
didn't know that existed - thanks
getParties :: a -> Set S.Party | ||
|
||
instance arrayHasParties :: HasParties a => HasParties (Array a) where | ||
getParties = foldMap (\a -> getParties a) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
foldMap getParties
Work in progress, but this seems as good a moment as any to open a PR... A few comments:
Template.State
submodule, but there isn't. I've just separated out some template-relatedMainFrame.State
code into a separate module for readability. Compare withContract.State
. Not sure which way is better. 🤷♂️@palas, I've changed
Marlowe.Extended
slightly: added agetParties
function and changed the default timeout value from zero to one.UPDATE: While I was responding to Pablo's comments, I thought I might as well include the changes to template metadata as well. Sorry that makes this PR a bit larger.
Also I forgot to mention: Although we are not including contract drafts in the prototype, this PR does give you one draft for free. I.e. while you are setting up a contract you can go away and do something else - the roles and template parameters will still be around if you go back to setting up a contract from that same template later. (In concrete terms: the template state is only overwritten if you start setting up a different template.)