* Resolved D0020: Add exclusion filter for entries.
* Refactored ``timeline`` fields of several objects in ``ts.js`` to be
``timelineModel`` to be explicit.
* Added support for exclusions in ``EntryListView.renderOne`` and
``EntryListView.render``.
* Added route back for PUT /ts_api/user/<username>
* Fixed typo in ``ts_api:put_user/2``.
* Fixed incorrect expected return from ``ts_ext_data:set_property/3``.
* Added missing assignment for ``ts_user.email`` in the appropriate
``ts_json:construct_record/3`` clause.
* Fixed model attribute assignment in ``ts.js``.
* Many calls to ``ts_ext_data:get_properties/1`` from ``ts_api`` were passing
the record reference, not the record itself. Fixed.
* Created ``ts_api:put_user/2`` which updates a ``ts_user`` record. This is
needed specifically for updating the ``liat_timeline`` extended data property.
* Removed unreachable code in ``ts_api:post_entry/3``
* Fixed return value of some ``ts_user`` functions to use the
``{Status, Value}`` convention. TODO: make sure all calls are using the same
convention.
* Fixed error message formatting in ``ts_ext_data:set_property/3``.
* Added clauses to ``ts_json:ejson_to_record/2``,
``ts_json:ejson_to_record_strict/2`` and ``ts_json:construct_record/3`` to
handle the ``ts_user`` record type.
* Added code to ``AppView.loadInitialData`` and ``AppView.selectTimeline`` to
support the ``last_timeline`` extended data property.
* Transformed the test database to match the new data model. Added
``ts_ext_data`` table and moved ``ts_user.ext_data`` values to it.
* Added D0022: cascade delete ``ts_ext_data`` when ``ts_entry`` record is
deleted.
* Completed refactor of ``ts_api`` functions to account for extended data:
* ``post_entry/3``
* ``put_entry/3``
* Created ``ts_entry:write/2`` to write extended data atomically with the entry.
* Fixed copy/paste bug in ``ts_ext_data:create_table/1``.
* Fixed implementation of ``ts_ext_data:set_property/3`` to be explicit about
taking a record, not a reference. It then extracts the reference and passes it
to the underlying implementation in ``ts_ext_data:do_set_property/3``.
* Refactored ``ts_ext_data:do_set_property/3`` to take a record *reference*, not
the record itself.
* Refactored the ``ts_ext_data:get_property/2`` and
``ts_ext_data:get_properties/1`` functions to return key value tuple pairs,
not ``ts_ext_data{}`` records.
* Refactored ``ts_json:ext_data_to_ejson{1,2}`` from a function that iterates
over a list of extended data properties and returns a transformed list to
``ts_json:ext_data_to_ejson/1``, a function that transforms one extended data
property. The iteration behavior is acheived using ``lists:map/2``.
* Refactored ``ts_json:ejson_to_ext_data{1,2}`` in a similar fashion to
``ts_json:ext_data_to_ejson{1,2}``.
* Fixed ``ts_json:construct_record/3`` to use ``ts_json:ejson_to_ext_data/1``.
------------------
* Created the extended data table. This is a more generic version of the
extended data field that was on ``ts_user``. Instead of arbitrary key-value
pairs going in a list on the user record we will have an additional table, a
one to many relationship between existing tables and the ``ts_ext_data``
table, each row being an extended value of the corresponding record.
* Added support to the ``timestamper:create_tables/1`` and
``timestamper_dev:create_table/1`` functions for the new ``ts_ext_data`` table.
Documentation
-------------
* Added some general docs about the DB layer code.
* Added two new issues, *D0020*: Entry exclusion filters and *D0021*: notes width.
API Changes
-----------
Necessitated by the change to the data model.
* Updated ``ts_api`` data-retrieval functions to use extended data:
* ``get_user_summary/2``
* ``list_timelines/2``
* ``list_entries/3``
* Updated ``ts_api:put_timeline/3`` to parse the extended data supplied by the
caller. *FIXME* it is not actually saving this data.
* TODO: Started updating ``ts_api:post_entry/3`` to handle extended data, need
to finish.
Database Layer
--------------
Changes necessitated by the change to the model.
* Added ``ts_common:do_set_ext_data/2`` which iterates through the extended data
key-value pairs calling ``ts_ext_data:set_property/3``. It does not provide a
transaction context.
* Split ``ts_common:new/1`` and ``ts_common:update/1`` functions into multiple
functions to prevent code-duplication:
* ``do_{new,update}`` contains the code that performs integrity checks and
the actual database write function. It does this assuming that it is being
called from within the context of an mnesia transaction (uses
``mnesia:read`` and ``mnesia:write``).
* ``{new,update}/1`` performs the same function as previously. The
implementation changed from using mnesia ``dirty_*`` calls to prociding a
transaction and calling ``do_{new,update}/1``.
* ``{new,update}/2`` expect the record to update/create and the extended
data to write atomically with the record. They provide a transaction
context, call ``do_{new,update}/1``, then call ``do_set_ext_data/2``.
* Similar to the refactoring of ``ts_common:{new,update}/1``,
``ts_entry:{new,update}/1`` have been refactored into multiple methods each to
support extended data properties:
* ``do_{new,update}/1`` perform the actual update assuming we have already
established an mnesia transaction.
* ``{new,update}/1`` behave the same as they used to, but now do so by
creating an mnesia transaction and calling ``do_{new,update}/1``.
* ``{new,update}/2`` create an mnesia transaction, call
``do_{new,update}/1``, and then call ``ts_common:do_set_ext_data/2``.
* Again similar to the refactoring of ``ts_common:{new,update}/1``,
``ts_user:{new,update}/1`` have been refactored into multiple methods each to
support extended data properties:
* ``do_{new,update}/1`` perform the actual update assuming we have already
established an mnesia transaction.
* ``{new,update}/1`` behave the same as they used to, but now do so by
creating an mnesia transaction and calling ``do_{new,update}/1``.
* ``{new,update}/2`` create an mnesia transaction, call
``do_{new,update}/1``, and then call ``ts_common:do_set_ext_data/2``.
* Created the ``ts_ext_data`` module as the interface to the extended data
properties introduced in the data model:
* ``create_table/1`` performs the same function as it does in the other db
layer modules, creates the table with the appropriate structure given the
more general table options desired (location, storage type, etc.).
* ``set_property/3`` takes a record, a property key, and a property value as
input and sets the property described by the property key on the record to
the given value, assuming this is a valid property for the record to have.
For example, currently the ``ts_user`` record can have an associated
property, ``last_timeline``, which represents the last timeline the user
was working with. Trying to pass this property with a ``ts_entry`` record
would result in an exception. This function uses
``ts_ext_data:do_set_property/3`` as its underlying implementation.
* ``get_property/2`` takes a record and a property key and returns the value
of that property for the given record, or ``not_set`` if the property has
not been set on that record. This method creates its own mnesia
transaction.
* ``get_properties/1`` takes a record and returns a list of key-value tuples
representing all of the extended data properties set for the given record.
This method creates its own mnesia transaction.
* ``do_set_property/3`` takes a record reference (not the whole record), a
a property key, and adds the property assignment to the ``ts_ext_data``
table. It creates its own mnesia transaction.
* Added ``new/2`` and ``update/2`` to the ``ts_timeline`` module to support
extended data properties. They delegate implementation to
``ts_common:{new,update}/2``.
JSON Encoding/Decoding
----------------------
Changes necessitated by the change to the data model.
The JSON objects now contain a potentially unlimited number of fields, as each
extended data property is encoded as a seperate field, and looks no different
from any of the required fields on the object. The intended explanation in API
documentation is that each object type (``user``, ``timeline``, or ``entry``)
now has both *required* fields that *MUST* be present in every message in either
direction and *optional* fields that may or may not be present in any
communication with the API. There should be a clear distinction between which
fields are required and which are optional. It might also be a good idea to
provide a suggested default for optional values when they are not present.
* Updated documentation about JSON record structures to reflect the fact that
there are now potentially many optional attributes in addition to the required
attributes for each record.
* ``record_to_ejson/1`` refactored to ``record_to_ejson/2`` which also takes
the extended data attributes and appends them as additional attributes to
the end of the record structure.
* Created ``ext_data_to_ejson/{1,2}`` to provide a mechanism for reformatting
extended data properties whose internal representations are not immediately
translatable into JSON. Currently only the ``entry_exclusions`` property,
which is a list of strings, needs to be treated this way (changing from
``[val, val]`` to ``{array, [val, val]}`` as needed by ``json:encode/1``.
``ext_data_to_ejson/1`` acts as a more user-friendly facade to
``ext_data_to_ejson/2``.
* Rewrote ``ejson_to_record/{2,3}`` and ``ejson_to_record_strict/{2,3}`` to
handle extended data. They now use a common method, ``construct_record/3`` to
create the actual record object and extended data key-value list.
``ejson_to_record_strict/{2,3}`` only differs in that it checks for the
presence of each required field of the record after the record is constructed.
The three-parameter versions of these functions also take in the intended
reference for the constructed record, replacing anything that is in the EJSON
body as the record reference (useful when the body does not have the record
ids). These methods now return a tuple: ``{Record, ExtData}`` instead of just
the record.
* Created ``construct_record/3`` takes a record and the EJSON fields from the
input object. The third parameter is an accumulator for the extended data
properties found when constructing the record. This method works by iterating
over the list of input fields. It recognizes any required fields and updates
the record being built with the value. Any fields it does not recognize it
assumes are extended data properties and adds to its list. When all input
fields have been visited it returns the record and list it has constructed.
* ``ejson_to_ext_data/{1,2}`` is the inverse of ``ext_data_to_ejson/{1,2}``.
*TODO*: this method is not actually being used by the ``ejson_to_record*``
methods.
* Added personal VIM ide extension.
* Implemented timeline selection (resolves D0007)
* Slightly restyled the new timeline button and timeline list menu.
* Resolved issues:
* #0006: Fix timeline menu UI.
* #0015: Create new timeline button in timeline menu.
* #0017: Implement timeline creation.
* Removed ts_api:post_timeline/3, corresponded to `POST` to
`/ts_api/timelines/<user-id>`, which makes no sense as there is no way to
auto-generate new timeline-ids.
* Changed ts_api:put_timeline/3 to use ts_timeline:write. This resolved#0017.
* Changed ts_api:put_entry/4 to use ts_entry:write.
* Implemented ts_entry:write/1 and ts_timeline:write/1. These functions are
simple passthroughs to mnesia:dirty_write/1.
* Added clarifing documentation for ts_json:record_to_ejson JSON formats.
* Renamed ts_json:ejson_to_record/2 to ts_json:ejson_to_record_strict/2 and
added ts_json:ejson_to_record/2 as a lax version of the same.
* Updated all ts_api functions to use updated ts_json methods.
* Fixed returned information in ts_api:put_timeline/3
* Added UI for new timeline button.
* Added client-side implementation of new timeline creation. There is a problem
on the server-side, PUT should support creating new items and updating
existing items.
- Switched from a global reset in www/css/ts-screen.scss to a selected
top-level elements reset to allow default formatting for user notes.
- Restructured the #entry-list and entry displays.
- Restructured notes div, now has a sub-div for text and a textarea
element for input.
- Added Showdown.js, a JavaScript Markdown library for formatting comments.
- Moved EntryView blur events to the View events map.
- Added images for expansion of notes.
- Added the ability to edit notes.
- Split EntryListView.addOne into renderOne and addOne so that renderOne
can be called with a new entry (fixes duration glitch)
Client Behaviour (ts.js)
========================
- Created EntryView.getViewModel: translates model data to view data,
specifically synthesizes the start time and duration from the timestamp.
- Added nextModel option to EntryView, needed for calculating the entry
duration.
- Created EntryView.formatStart: given the timestamp, return the start time,
in HH:MM format. Code is written for both 24hr and 12hr format, still need
to write a selector mechanism. For now, uses 12hr format.
- Created EntryView.formatDuration: Get the duration of the entry based on
this entry's timestamp and and the next entry's timestamp in a display-able
form. If nextModel is `null` or `undefined` it is assumed that `model`
is the most recent model and duration is calculated against the current time.
- Changed EntryView.render to use getViewModel.
- Added 'blur' listeners to the mark and timestamp input fields to close them
without persisting the changes.
- Created EntryView.update: Refresh the display based on the model using the
existing DOM elements.
- EntryView.save() now uses EntryView.update() instead of EntryView.render()
and no longer includes an implicit close()
- EntryView.close() has been split into seperate save() and close() functions,
to persist the changes and hide the input dialogs, respectively.
- EntryListView.addOne now passes the nextModel to EntryViews is creates.
- EntryListView.createNewEntryOnEnter() now clear the new intry input after
creating a new entry.
- EntryListView.render() now uses a for-structure to traverse the entry
collection and passes the nextModel (if there is one) to EntryListView.addOne.
Client UI (ts-screen.scss)
==========================
- Font size, family, and color adjusted on timeline and user input fields.
- Day seperator secondary header colors adjusted.
- Mark column width shortened, timestamp and duration columns widened.
- Styles added for notes UI
Client UI (index.yaws)
======================
- Markup changes needed for getViewModel chanes.
- Expanded day seperator.
Client Behaviour (ts.js)
========================
- Created EntryView.getViewModel: translates model data to view data,
specifically synthesizes the start time and duration from the timestamp.
- Added nextModel option to EntryView, needed for calculating the entry
duration.
- Created EntryView.formatStart: given the timestamp, return the start time,
in HH:MM format. Code is written for both 24hr and 12hr format, still need
to write a selector mechanism. For now, uses 12hr format.
- Created EntryView.formatDuration: Get the duration of the entry based on
this entry's timestamp and and the next entry's timestamp in a display-able
form. If nextModel is `null` or `undefined` it is assumed that `model`
is the most recent model and duration is calculated against the current time.
- Changed EntryView.render to use getViewModel.
- Added 'blur' listeners to the mark and timestamp input fields to close them
without persisting the changes.
- Created EntryView.update: Refresh the display based on the model using the
existing DOM elements.
- EntryView.save() now uses EntryView.update() instead of EntryView.render()
and no longer includes an implicit close()
- EntryView.close() has been split into seperate save() and close() functions,
to persist the changes and hide the input dialogs, respectively.
- EntryListView.addOne now passes the nextModel to EntryViews is creates.
- EntryListView.createNewEntryOnEnter() now clear the new intry input after
creating a new entry.
- EntryListView.render() now uses a for-structure to traverse the entry
collection and passes the nextModel (if there is one) to EntryListView.addOne.
Client UI (ts-screen.scss)
==========================
- Font size, family, and color adjusted on timeline and user input fields.
- Day seperator secondary header colors adjusted.
- Mark column width shortened, timestamp and duration columns widened.
- Styles added for notes UI
Client UI (index.yaws)
======================
- Markup changes needed for getViewModel chanes.
- Expanded day seperator.
- Added 'start' and 'duration' headers to day seperators.
- Right-aligned start and duration columns.
- Changed duration to 'Xhr Ym' instead of 'HH:MM:SS'.
- Added a section using 12hr time format instead of 24hr for comparison.
Using atoms will not scale in the large. Also, using atoms as keys forced the
API to convert arbitrary end-user input to atoms, adding another potential
drain of the finite atom-space available.
- ts_api: url paths are now treated and matched as lists, not atoms.
Usernames and API calls all use lists now.
- ts_json: key items (username, timeline ids) are now expected to be lists,
not atoms.
- POST and PUT were being used counter to typical usage, POST updating existing
records and PUT creating new ones. Changed to PUT updating existing records
and POST creating records.
- Instead of returning Meta-Data (status) in the header and the body, we now
only return the content in the body, except in error when we return the error
message.
- JSON entries use the 'id' name for entity ids (instead of 'username',
'timeline_id', and 'entry_id')
Added 'default' make target to only compile.
Reset development configuration.
Commented out starts of tests.
Added sign-up GUI to login panel.
Moved application from /ts/ to /
- Added ts_entry:delete/1 to delete an entry from the database.
- Implemented ts_api:delete_entry/3.
- Added a form to facilitate editing individual entries.
- Moved the small show/hide functions directly into the HTML.
- Wired up the update timeline form.
- Wired up the edit and update entry form.
- Bug fix in ts_api:list_entries/3. Case statement matching on atoms but
input is a list (string).
- Bug fix in ts_api:put_entry/3. Was expecting the wrong result from
ts_entry:new/1.
- Bug fix in ts_entry:list/4. Code crashed when the starting offset was
greater than the total number of elements. Now returns [].
- Fixed ts_json:encode_datetime/1 and ts_json:decode_datetime/1 to handle
millisecond values in the datetime string (per ISO standard).
- Broke out ``control-links`` style to a top-level class.
- Added showdown.js, a JS Markdown processor. Not hooked up to anything
yet but intend to display entry notes with Markdown.
- Added code for entry pagination. Loads the most recent 20 entries and
loads more upon demand in batches of 20.
- Fixed bug in login routine that kept the user edit fields from being
pre-populated.
- Rewrote the loadEntries function to double for new entries and loading
more existing entries.
- Commented displayEntries. Also refactored into displayNewerEntries,
which pushed new entries on to the top of the stack, and
displayOlderEntries, which tags them onto the bottom.
- Implemented hidden notes field for new entry input.
- Implemented new entry creation.
- Created a helper function to ISO format a Date object.
- Expanded entry template to show control links (edit, show notes, del).
- Activated the 'load more entries' button.