@@ -32,9 +32,10 @@ tracker command line interface (CLI) that allows users to:
32
32
33
33
- Register themselves with email and password.
34
34
- Sign in to their account with their email and password.
35
- - View, create, modify, and delete tasks.
36
- - Watch for changes to the Task collection and get notified in the terminal
37
- window when a change occurs.
35
+ - View a list of projects they are a member of.
36
+ - View, create, modify, and delete tasks in projects.
37
+ - View a list of team members in their project.
38
+ - Add and remove team members to their project.
38
39
39
40
This tutorial should take around 30 minutes to complete.
40
41
@@ -111,10 +112,10 @@ multiple platforms. The project root for this tutorial is located in the
111
112
files.
112
113
113
114
This application has a flat project structure: all of the files are in the root
114
- directory. In this tutorial, we'll be focusing on 4 files: ``config.js``,
115
- ``users.js``, ``tasks.js``, and ``watch .js``. The other files provide the
115
+ directory. In this tutorial, we'll be focusing on 5 files: ``config.js``,
116
+ ``users.js``, ``tasks.js``, ``team.js``, ``projects .js``. The other files provide the
116
117
underlying structure for the CLI. The following table describes the role of
117
- each file in this project:
118
+ important files in this project:
118
119
119
120
.. cssclass:: config-table
120
121
.. list-table::
@@ -133,7 +134,8 @@ each file in this project:
133
134
throughout its lifecycle and displays the initial logon screen.
134
135
135
136
* - main.js
136
- - Displays the main menu of choices.
137
+ - Displays the main menu of choices. Users can view a list of projects
138
+ they are a member of or select a project.
137
139
138
140
* - output.js
139
141
- Responsible for displaying text in the terminal window.
@@ -149,9 +151,13 @@ each file in this project:
149
151
- Handles Realm user authentication, including logging in, registering a
150
152
new user, and logging out.
151
153
152
- * - watch.js
153
- - Adds a listener to a Realm collection to notify the user when a change
154
- occurs.
154
+ * - team.js
155
+ - Handles the team member related communication between the CLI and Realm.
156
+ The methods for listing, adding, and removing team members are contained in
157
+ this file.
158
+
159
+ * - projects.js
160
+ - Handles project retrieval and listing.
155
161
156
162
D. Connect to Your MongoDB Realm App
157
163
------------------------------------
@@ -160,9 +166,7 @@ To get the app working with your backend, you first need to add your Realm App I
160
166
to the ``config.js`` file. The ``config.js`` module exports a single property,
161
167
``realmAppId``, which is currently set to "TODO":
162
168
163
- .. code-block:: js
164
-
165
- exports.realmAppId = "TODO";
169
+ .. literalinclude:: /tutorial/node-cli/bluehawk-gen/code/start/config.codeblock.realmAppID.js
166
170
167
171
Change this value to your Realm App ID.
168
172
@@ -172,31 +176,22 @@ Change this value to your Realm App ID.
172
176
Your App Id </get-started/find-your-app-id>` doc.
173
177
174
178
Once you have made that change, you now need to complete the code needed to
175
- open a {+realm+}. In ``index.js``, find the ``openRealm`` function. It will look
176
- like this:
177
-
178
- .. code-block:: js
179
-
180
- async function openRealm() {
181
- const config = {
182
- schema: [schemas.TaskSchema, schemas.UserSchema, schemas.ProjectSchema],
183
- sync: {
184
- user: users.getAuthedUser(),
185
- partitionValue: "My Project",
186
- },
187
- };
188
- // TODO: open a realm with these configuration settings.
189
- }
179
+ open a {+realm+}. In ``index.js``, find the ``openRealm`` function. Replace the ``TODO``
180
+ line with a line of code that opens a {+realm+} and assigns it to the ``realm``
181
+ property. It will look like this:
190
182
191
- Replace the ``TODO`` line with a line of code that opens a {+realm+} and assigns
192
- it to the ``realm`` property:
183
+ .. literalinclude:: /tutorial/node-cli/bluehawk-gen/ code/final/index.codeblock.openRealm.js
184
+ :emphasize-lines: 9
193
185
194
- .. code-block:: js
186
+ Now that you have implemented the ``openRealm`` function, you will now need to
187
+ complete the code that retrieves the {+realm+}. In ``index.js``, find the
188
+ ``getRealm`` function. It will look like this:
195
189
196
- realm = new Realm(config);
190
+ .. literalinclude:: /tutorial/node-cli/bluehawk-gen/code/final/index.codeblock.getRealm.js
191
+ :emphasize-lines: 3
197
192
198
193
At this point, your app is pointing to your backend and opens a connection
199
- to it when you start the app. However, users cannot yet log in, so let's update
194
+ to it when you start the app. However, users cannot log in yet , so let's update
200
195
that code next.
201
196
202
197
E. Enable authentication
@@ -208,47 +203,31 @@ an email address and password, and then, within a try-catch block, creates an
208
203
credential and passes it to the Realm
209
204
:js-sdk:`logIn() <Realm.App.html#logIn>` method.
210
205
211
- Find the following comment:
212
-
213
- .. code-block:: js
214
-
215
- // TODO: create new emailPassword credentials and call app.logIn(...)
216
-
217
- And add the following code to create a ``emailPassword`` credential:
218
-
219
- .. code-block:: js
220
-
221
- const credentials = Realm.Credentials.emailPassword(
222
- input.email,
223
- input.password
224
- );
225
-
226
- Immediately below this, add the following code to call the
227
- ``logIn()`` method:
228
-
229
- .. code-block:: js
230
-
231
- const user = await app.logIn(credentials);
206
+ Find the the ``logIn`` function and add the following code to create a
207
+ ``emailPassword`` credential and call the ``logIn()`` method.
232
208
209
+ .. literalinclude:: tutorial/bluehawk-gen/code/final/users.codeblock.userLogin.js
210
+ :emphasize-lines: 17, 18, 19, 22
233
211
234
212
F. Implement the CRUD methods
235
213
-----------------------------
236
214
237
- In the ``tasks.js`` file , there are a number of functions to handle typical
215
+ In the ``tasks.js`` and ``projects.js`` files , there are a number of functions to handle typical
238
216
CRUD functionality: ``getTasks``, ``getTask``, ``createTask``, ``deleteTask``,
239
- ``editTask``, and ``changeStatus``. Each of these functions (except ``getTasks``)
240
- prompts the user for input and then makes the appropriate call to Realm. Your
241
- job is to implement the calls to {+service-short+}. The following list provides
242
- guidance on how to complete this task for each function:
217
+ ``editTask``, ``changeStatus``, and ``getProjects``. Each of these functions
218
+ (except ``getTasks`` and ``getProjects``) prompts the user for input and then makes
219
+ the appropriate call to Realm. Your job is to implement the calls to {+service-short+}.
220
+ The following list provides guidance on how to complete this task for each function.
221
+
222
+ In ``tasks.js``:
243
223
244
224
* ``getTasks``
245
225
246
226
To get all objects, call the :js-sdk:`objects() <Realm.html#objects>` method
247
227
and pass in the name of the collection:
248
228
249
- .. code-block:: js
250
-
251
- const tasks = realm.objects("Task");
229
+ .. literalinclude:: tutorial/bluehawk-gen/final/tasks.codeblock.getTasks.js
230
+ :emphasize-lines: 3
252
231
253
232
254
233
* ``getTask``
@@ -257,12 +236,8 @@ guidance on how to complete this task for each function:
257
236
we call the :js-sdk:`objectForPrimaryKey() <Realm.html#objectForPrimaryKey>`
258
237
function to get a task by its Id.
259
238
260
- .. code-block:: js
261
-
262
- let result = realm.objectForPrimaryKey(
263
- "Task",
264
- new bson.ObjectID(task.id)
265
- );
239
+ .. literalinclude:: tutorial/bluehawk-gen/final/tasks.codeblock.getTask.js
240
+ :emphasize-lines: 11
266
241
267
242
268
243
* ``createTask``
@@ -274,16 +249,9 @@ guidance on how to complete this task for each function:
274
249
the :js-sdk:`create() <Realm.html#create>` function, passing in all of the
275
250
required properties:
276
251
277
- .. code-block:: js
278
-
279
- realm.write(() => {
280
- result = realm.create("Task", {
281
- _id: new bson.ObjectID(),
282
- _partition: "My Project",
283
- name: task.name,
284
- status: task.status,
285
- });
286
- });
252
+ .. literalinclude:: tutorial/bluehawk-gen/final/tasks.codeblock.createTask.js
253
+ :emphasize-lines: 23, 24, 25, 26, 27, 28
254
+
287
255
288
256
.. note::
289
257
@@ -297,16 +265,12 @@ guidance on how to complete this task for each function:
297
265
* ``deleteTask``
298
266
299
267
Deleting objects must also take place within a transaction. As with modifying
300
- an object, we'll use the write() function to handle the transaction for us,
301
- and then call the the :js-sdk:`delete() <Realm.html#delete>` function within
302
- it:
303
-
304
- .. code-block:: js
268
+ an object, we'll use the write() function to handle the transaction for us.
269
+ We'll first call the ``objectForPrimaryKey`` method to get the specific we want
270
+ to delete and then the :js-sdk:`delete() <Realm.html#delete>` function on that task:
305
271
306
- realm.write(() => {
307
- realm.delete(task);
308
- output.result("Task deleted.");
309
- });
272
+ .. literalinclude:: tutorial/bluehawk-gen/code/final/tasks.codeblock.deleteTask.js
273
+ :emphasize-lines: 18, 20
310
274
311
275
312
276
* ``modifyTask``
@@ -317,19 +281,62 @@ guidance on how to complete this task for each function:
317
281
call to a Realm API to change an object. Rather, you change the *local* object
318
282
and Sync ensures the object is updated on the server.
319
283
320
- .. code-block:: js
321
-
322
- realm.write(() => {
323
- task = realm.objectForPrimaryKey("Task", new bson.ObjectID(answers.id));
324
- task[answers.key] = answers.value;
325
- });
284
+ .. literalinclude:: /tutorial/node-cli/bluehawk-gen/code/final/tasks.codeblock.modifyTask.js
285
+ :emphasize-lines: 6, 7
286
+
326
287
327
288
.. note::
328
289
329
290
To learn more about Realm Sync, see :doc:`Sync Overview </sync/overview>`.
330
291
292
+ In ``projects.js``:
293
+
294
+ * ``getProjects``
295
+
296
+ As defined by our data model, ``projects`` are an embedded object of the ``users`` object.
297
+ To get all projects the user is a part of, we'll have to use the ``objectForPrimaryKey``
298
+ method to get the current user and then access the current user's ``memberOf`` property.
299
+
300
+ .. literalinclude:: /tutorial/node-cli/bluehawk-gen/final/projects.codeblock.getProjects.js
301
+ :emphasize-lines: 4, 5
302
+
303
+ G. Use Realm Functions
304
+ ----------------------
305
+
306
+ In the ``team.js`` file, there are functions that rely on :ref:`{+service-short+}
307
+ functions </functions>`. {+service-short+} functions allow you to execute server-side
308
+ logic for your client applications. Each of the following functions require you to
309
+ implement the calls to {+service-short+}.
310
+
311
+ * ``getTeamMembers``
312
+
313
+ To get all team members, call the ``getMyTeamMembers`` {+service-short+} function
314
+ using the ``User.functions`` method.
315
+
316
+ .. literalinclude:: /tutorial/node-cli/bluehawk-gen/final/team.codeblock.getTeamMembers.js
317
+ :emphasize-lines: 4
331
318
332
- G. Run and Test
319
+ * ``addTeamMember``
320
+
321
+ This function prompts the user for the email of the new team member. You will need
322
+ to call the ``addTeamMember`` {+service-short+} function and pass it the ``email``
323
+ parameter.
324
+
325
+ .. literalinclude:: /tutorial/node-cli/bluehawk-gen/final/team.codeblock.addTeamMember.js
326
+ :emphasize-lines: 12
327
+
328
+ * ``removeTeamMember``
329
+
330
+ This functions prompts the user for the email of the team member they would like to
331
+ remove from their project. You will need to call the ``removeTeamMember``
332
+ {+service-short+} function and pass it the ``email`` parameter.
333
+
334
+ .. literalinclude:: /tutorial/node-cli/bluehawk-gen/final/team.codeblock.removeTeamMember.js
335
+ :emphasize-lines: 15
336
+
337
+
338
+
339
+ H. Run and Test
333
340
---------------
334
341
335
342
Once you have completed the code, you should run the app and check functionality.
@@ -357,56 +364,9 @@ Once you have completed the code, you should run the app and check functionality
357
364
358
365
.. admonition:: Reminder
359
366
360
- If something isn't working for you, you can check out the ``main `` branch of
367
+ If something isn't working for you, you can check out the ``final `` branch of
361
368
this repo to compare your code with our finished solution.
362
369
363
- H. Implement the Collection Listener
364
- ------------------------------------
365
-
366
- A very handy feature in Realm is the ability to add a listener to a collection.
367
- The listener notifies your app when a change occurs in the collection. For our
368
- CLI, we want to listen for changes on the ``Tasks`` collection, and when one
369
- occurs, display a notification in the console window. To do this:
370
-
371
- 1. In your text editor, open the ``watch.js`` file.
372
-
373
- #. Our internal ``listener`` function is a callback function that takes two
374
- parameters: the collection of tasks and a ``changes`` object that is sent
375
- from Realm. The ``changes`` object has the following properties:
376
-
377
- * ``changes.deletions`` returns the index of the deleted item *before*
378
- the deletion.
379
-
380
- * ``changes.insertions`` returns the index of the new object.
381
-
382
- * ``changes.modifications`` returns the index of the modified object.
383
-
384
- #. In the ``watchForChanges`` function, you will get all of the objects in
385
- the **Tasks** collection (just as we did in the ``getTasks`` function),
386
- and then call the :js-sdk:`addListener() <Realm.Collection.html#addListener>`
387
- method. Under the ``TODO`` comment, add the following code:
388
-
389
- .. code-block:: js
390
-
391
- const tasks = realm.objects("Task");
392
- tasks.addListener(listener);
393
-
394
- With this code update, you can now re-run the app and watch for changes.
395
-
396
- 1. In the main menu, choose "Watch for changes". You will see that the UI
397
- stays in a "waiting" state.
398
-
399
- 2. Open a second terminal window and run the app again. In this second window,
400
- try creating, modifying, and deleting tasks. Each time you perform an action,
401
- the first terminal window will update with a notification.
402
-
403
- .. note::
404
-
405
- If you want to continue to work in the same process and have the change
406
- notifications appear inline, you can modify the code
407
- in ``main.js``, within the ``case Choices.WatchForChanges`` handler. The
408
- inline code comment explains the change you can make.
409
-
410
370
What's Next?
411
371
------------
412
372
0 commit comments