morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
shell.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2#pragma once
3
4#include <cstddef>
5#include <expected>
6#include <filesystem>
7#include <functional>
8#include <memory>
9#include <optional>
10#include <string>
11#include <vector>
12
13#include "../ui/backend.hpp"
14#include "../ui/frontend.hpp"
15#include "../ui/host.hpp"
16#include "../ui/interpreter.hpp"
18#include "../ui/value.hpp"
19#include "source.hpp"
20
21/// @file
22/// @brief What the generic client mounts once its source is open: the library's `ShellFrame` (the sidebar with the
23/// navigator, the top bar, the page) with a `Workspace` of tabs in its page, each a screen mounted through the
24/// library's `DocumentScreenHost`; and the application host a shell of an application's own mounts with.
25///
26/// Specified in `docs/spec/client/client.md`.
27
28namespace morph::client {
29
30/// @brief What a sign-in installs: the principal, and the session token its server needs (empty for none).
31struct SignedIn {
32 /// @brief The principal.
33 std::string principal;
34 /// @brief The session token; empty when the server needs none, as in process.
35 std::string token;
36};
37
38/// @brief Maps a sign-in mutation's reply to the principal and token to install; `std::nullopt` refuses the sign-in.
39using SignInMapper = std::function<std::optional<SignedIn>(ui::Value const& reply)>;
40
41/// @brief The default sign-in mapping: a reply `{ok, principal, token}`, refused when `ok` is `false` or there is no
42/// principal; `token` may be absent.
43/// @param reply The sign-in mutation's reply.
44/// @return The principal and token, or `std::nullopt`.
45[[nodiscard]] std::optional<SignedIn> defaultSignIn(ui::Value const& reply);
46
47/// @brief The application's side of the commands a document host does not answer itself (spec 6): sign-in and
48/// sign-out, which install a principal into the source, and the file commands, which read a picked file from
49/// disk and save a downloaded one, moving the bytes over the source's file side channel or inline.
50///
51/// A shell of an application's own builds one and passes it as `DocumentScreenHostOptions::application`;
52/// `mountShell` builds its own.
54public:
55 /// @brief A host over @p source.
56 /// @param source The source sign-ins are installed into and files move through. Borrowed: it outlives the
57 /// host.
58 /// @param signIn Maps a sign-in reply to what is installed. Required.
59 /// @param downloads Where a `download` saves a file; the working directory when empty.
60 /// @param signedIn Called with what a sign-in installs, for the shell to install it and reload.
61 /// @param signedOut Called on a `signOut`.
62 /// @param onProblem Called with a refused sign-in's reason; may be empty.
63 /// @throws std::invalid_argument when @p signIn is empty.
64 ApplicationHost(Source& source, SignInMapper signIn, std::filesystem::path downloads,
65 std::function<void(SignedIn)> signedIn, std::function<void()> signedOut,
66 std::function<void(std::string const&)> onProblem = {});
67
68 /// @brief Maps the reply and hands a principal to `signedIn`.
69 /// @param reply The sign-in mutation's reply.
70 /// @return Whether it signed in: the mapper answered a principal.
71 bool signIn(ui::Value const& reply) override;
72
73 /// @brief Calls `signedOut`.
74 void signOut() override;
75
76 /// @brief Reads the picked file from disk and sends it through the source's file store.
77 /// @param request The file and the mutation it is for.
78 /// @param progress Called with the progress, as an exact fraction.
79 /// @param done Called with the file's reference, or the failure.
80 /// @return Whether it can: the source has a file side channel and the file is a path.
81 bool uploadFor(ui::UploadRequest const& request, std::function<void(ui::Value)> progress,
82 std::function<void(std::expected<ui::Value, std::string>)> done) override;
83
84 /// @brief Fetches a file by reference and saves it in the downloads directory. A preview is not supported.
85 /// @param file The reference.
86 /// @param option `dialog`; `preview` answers not supported.
87 /// @param name The suggested name; `null` keeps the file's own.
88 /// @param done Called with the saved path, or the failure.
89 /// @return Whether it can.
90 bool download(ui::Value const& file, std::string const& option, ui::Value const& name,
91 std::function<void(std::expected<ui::Value, std::string>)> done) override;
92
93 /// @brief Reads a picked file whose bytes a document moves inline; its size is read first, and one over the cap
94 /// is refused without reading it.
95 /// @param file The picked path.
96 /// @param maxBytes The session's inline cap.
97 /// @param done Called with the file, or the failure.
98 /// @return Whether it can: the file is a path.
99 bool readFile(ui::Value const& file, std::size_t maxBytes,
100 std::function<void(std::expected<ui::InlineFile, std::string>)> done) override;
101
102 /// @brief Saves a file a document holds the bytes of in the downloads directory. A preview is not supported.
103 /// @param file The file.
104 /// @param option `dialog`; `preview` answers not supported.
105 /// @param done Called with the saved path, or the failure.
106 /// @return Whether it can.
107 bool saveFile(ui::InlineFile const& file, std::string const& option,
108 std::function<void(std::expected<ui::Value, std::string>)> done) override;
109
110 /// @brief Sets what `notify` calls to show a transient message; empty falls through to the base class's `false`.
111 /// @param sink Given the text and the role; returns whether it showed it.
112 void setNotifySink(std::function<bool(std::string const&, std::string const&)> sink);
113
114 /// @brief Calls the notify sink if one is set.
115 /// @param text The message.
116 /// @param role `info`, `success`, `warning` or `error`; empty for the default.
117 /// @return Whether the sink showed it; `false` when none is set.
118 bool notify(std::string const& text, std::string const& role) override;
119
120private:
121 Source* _source;
122 SignInMapper _signIn;
123 std::filesystem::path _downloads;
124 std::function<void(SignedIn)> _signedIn;
125 std::function<void()> _signedOut;
126 std::function<void(std::string const&)> _onProblem;
127 std::function<bool(std::string const&, std::string const&)> _notifySink;
128};
129
130/// @brief What a client shell reports, and how it starts.
132 /// @brief The screen mounted first; empty for the first the source lists.
133 std::string startScreen;
134 /// @brief The start screen's params.
136 /// @brief Called with each problem: why the source did not open, a document that did not load, a refused mount,
137 /// an interpreter diagnostic. Empty ignores them; the shell shows the first three either way.
138 std::function<void(std::string const& problem)> onProblem;
139 /// @brief Called with the id of each screen once it is mounted.
140 std::function<void(std::string const& screenId)> onMounted;
141 /// @brief Where a screen's `download` saves a file, under the name the screen suggests; the working directory
142 /// when empty.
143 std::filesystem::path downloads;
144 /// @brief The history the shown screen's route is kept in (spec 3 §10), such as the browser's: back and forward
145 /// open the route of the entry moved to, and the route it holds at start is opened once the session has
146 /// the screen. Borrowed: it outlives the shell; null keeps no history.
148 /// @brief Development mode (spec 5 §12): every second the shell polls the source's `ui-hello` digest, and when it
149 /// changed, remounts every open tab whose document changed, keeping its state. A shell built without
150 /// the development tools never polls. A production client leaves it off: the digest is then read once.
151 bool dev = false;
152 /// @brief Called after each development reload with the ids of the screens it remounted; empty ignores it.
153 std::function<void(std::vector<std::string> const& remounted)> onReloaded;
154 /// @brief Maps a sign-in mutation's reply to the principal and token the shell installs. Required.
156};
157
158/// @brief Mounts the client's shell for what @p source delivered.
159///
160/// On a bundle: loads each screen of `source.screens()` with the source's catalog facts, opens the start screen as a
161/// tab, and on a document's `navigate` or a navigator choice opens the screen asked for as a tab (or focuses the tab
162/// that shows it), from a task posted to the owner, never from inside the handler that asked. A sign-in or sign-out
163/// closes every tab and rebuilds the frame for the new catalog. On a `ConnectError`, or when no screen can be mounted,
164/// shows why as text.
165/// @param context The frontend's context.
166/// @param backend The view backend the screens mount on. Borrowed: it outlives the shell.
167/// @param opened What the source delivered.
168/// @param source The source; it outlives the shell.
169/// @param options The start screen and the observers.
170/// @return The shell; destroying it unmounts everything.
171/// @throws std::invalid_argument when `options.signIn` is empty.
172[[nodiscard]] std::unique_ptr<ui::MountedShell> mountShell(ui::AppContext& context, ui::IViewBackend& backend,
173 std::expected<ui::Bundle, ui::ConnectError> opened,
174 Source& source, ShellOptions options);
175
176} // namespace morph::client
bool notify(std::string const &text, std::string const &role) override
Calls the notify sink if one is set.
void setNotifySink(std::function< bool(std::string const &, std::string const &)> sink)
Sets what notify calls to show a transient message; empty falls through to the base class's false.
void signOut() override
Calls signedOut.
ApplicationHost(Source &source, SignInMapper signIn, std::filesystem::path downloads, std::function< void(SignedIn)> signedIn, std::function< void()> signedOut, std::function< void(std::string const &)> onProblem={})
A host over source.
bool saveFile(ui::InlineFile const &file, std::string const &option, std::function< void(std::expected< ui::Value, std::string >)> done) override
Saves a file a document holds the bytes of in the downloads directory. A preview is not supported.
bool signIn(ui::Value const &reply) override
Maps the reply and hands a principal to signedIn.
bool uploadFor(ui::UploadRequest const &request, std::function< void(ui::Value)> progress, std::function< void(std::expected< ui::Value, std::string >)> done) override
Reads the picked file from disk and sends it through the source's file store.
bool download(ui::Value const &file, std::string const &option, ui::Value const &name, std::function< void(std::expected< ui::Value, std::string >)> done) override
Fetches a file by reference and saves it in the downloads directory. A preview is not supported.
bool readFile(ui::Value const &file, std::size_t maxBytes, std::function< void(std::expected< ui::InlineFile, std::string >)> done) override
Reads a picked file whose bytes a document moves inline; its size is read first, and one over the cap...
An AppSource that also hands the shell what it mounts screens with, once it delivered a bundle.
Definition source.hpp:72
What a frontend lends the source it opens and the screens it mounts.
Definition frontend.hpp:50
A history of routes: a browser's session history, or a test's.
Makes widgets. Each factory appends the new widget to parent, or makes a root when it is null,...
Definition backend.hpp:810
What the application answers for the commands a document cannot carry out alone (spec 6)....
The document's typed value (spec 5 §3): what every expression evaluates to.
Definition value.hpp:157
The host contract (spec 6 §4): how a host mounts UI documents and closes them, whether it owns its ow...
ValueRecord ParamMap
A screen's params, by name.
Definition host.hpp:38
The UI document interpreter: Interpreter::mount turns a loaded Document into reactive state and a vie...
Route history (spec 3 §10, spec 6 §20): the route of the screen a shell shows, kept in a history the ...
std::unique_ptr< ui::MountedShell > mountShell(ui::AppContext &context, ui::IViewBackend &backend, std::expected< ui::Bundle, ui::ConnectError > opened, Source &source, ShellOptions options)
Mounts the client's shell for what source delivered.
std::optional< SignedIn > defaultSignIn(ui::Value const &reply)
The default sign-in mapping: a reply {ok, principal, token}, refused when ok is false or there is no ...
std::function< std::optional< SignedIn >(ui::Value const &reply)> SignInMapper
Maps a sign-in mutation's reply to the principal and token to install; std::nullopt refuses the sign-...
Definition shell.hpp:39
Where the generic client's screens and models come from: a server (remote) or an application linked i...
What a client shell reports, and how it starts.
Definition shell.hpp:131
bool dev
Development mode (spec 5 §12): every second the shell polls the source's ui-hello digest,...
Definition shell.hpp:151
std::function< void(std::vector< std::string > const &remounted)> onReloaded
Called after each development reload with the ids of the screens it remounted; empty ignores it.
Definition shell.hpp:153
std::string startScreen
The screen mounted first; empty for the first the source lists.
Definition shell.hpp:133
std::function< void(std::string const &problem)> onProblem
Called with each problem: why the source did not open, a document that did not load,...
Definition shell.hpp:138
std::filesystem::path downloads
Where a screen's download saves a file, under the name the screen suggests; the working directory whe...
Definition shell.hpp:143
std::function< void(std::string const &screenId)> onMounted
Called with the id of each screen once it is mounted.
Definition shell.hpp:140
ui::ParamMap startParams
The start screen's params.
Definition shell.hpp:135
ui::IHistory * history
The history the shown screen's route is kept in (spec 3 §10), such as the browser's: back and forward...
Definition shell.hpp:147
SignInMapper signIn
Maps a sign-in mutation's reply to the principal and token the shell installs. Required.
Definition shell.hpp:155
What a sign-in installs: the principal, and the session token its server needs (empty for none).
Definition shell.hpp:31
std::string token
The session token; empty when the server needs none, as in process.
Definition shell.hpp:35
std::string principal
The principal.
Definition shell.hpp:33
A file whose bytes a document moves inline: download from bytes, upload into bytes.
What an upload command asks the host to send, and the mutation that will reference the file,...
The backend contract: the retained widgets a mount drives, and the factory that makes them.
The frontend seam: main picks a frontend at runtime, and the frontend runs whatever an AppSource open...
The UI document's typed values (ui::Value), its types (ui::Type), their JSON form,...