Giter Site home page Giter Site logo

atomicdata-dev / atomic-data-browser Goto Github PK

View Code? Open in Web Editor NEW
56.0 4.0 9.0 208.71 MB

This repo is no longer used! Code is moved to Atomic-Server

Home Page: https://github.com/atomicdata-dev/atomic-server/issues

License: MIT License

CSS 0.89% HTML 1.33% JavaScript 1.27% TypeScript 96.31% Shell 0.07% MDX 0.14%
linked-data react atomic-data typescript

atomic-data-browser's Introduction

Atomic Data Browser

THIS REPO IS NO LONGER USED, ATOMIC-DATA-BROWSER IS NOW PART OF ATOMIC-SERVER.

atomic-data-browser's People

Contributors

adileo avatar dsabanin avatar joepio avatar polleps avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

atomic-data-browser's Issues

Consider removing the Value abstraction (for Get operations)

In the Rust implementation of Atomic Data, the store is always fully aware of the datatype of some value. However, in this TS implementation, that is not the case. I simply use the incoming JSON-AD object and put that directly in the store. There is no datatype validation on incoming data, because it seemed unnecessary. When writing data, however, we do check validity, but that only happens when using a form at this moment.

Anyway. The Value abstraction was added because I thought it would be useful to have a predictable set of methods for every single value in the store (e.g. toArray, toDate, toNestedResource, etc.). But now, I'm not so sure. We could simply store the native JS(ON) values of the incoming JSON-AD, and still keep the type-specific hooks. That way, views still get predictable types, but we don't have to instantiate Values when parsing.

I'll just keep this open until I feel like I know of the best way to move forward.

Consider passing subject to hooks instead of objects

I've implemented useString(resource) to accept resource as an argument.
This was done with performance in mind, as it would mean less calls to the database.
Unfortunately, React does not perform re-renders when content of passed objects change.
The effect of this is that if I use a hook to set some property in a component, some child components will not update.
For example, I can't programmatically update the parent field in the ResourceForm component. The value is properly updated, but the child does not re-render.

Solutions:

  • Pass subjects instead of resources

Input field for Resources and ResourceArrays

Most forms will feature fields in which users can set one or multiple resources, depending of the datatype of its Property is a ResourceArray or an AtomicURL. These fields will probably be highly similar. I'm currently trying to write the Array one, but I'm having a hard time deciding on how to share code between the two. So let's look at some differences, similarities and usecases.

Usecases

  • I want to easily select data by searching through it
  • I want to select some resource by typing / pasting its URL
  • I want to create a new resource (inline, if possible)
  • I want to see existing data if it's an edit field

Differences

  • For arrays, I want to be able to add and remove items
  • For arrays, I want to change the order of items

Component properties

Now... The InputResource component (which renders the form for a single resource) might be able to work for InputResourceArray, too, but it needs some changes. For starters, it currently uses the useString hook.

Maybe I can pass the index from the parent form field to the child, and use that to set it's value using the useArray hook instead.

But... This means I have to keep it in sync with all other values. Keeping multiple instances of the same Values in sync might require the same solution as for keeping Resources in sync: having a big Subscriber object where listeners subscribe. But this might be a bit overkill for keeping state in sync. It seems like it's preferable to explicitly pass props to children, and keep state more locally.

Pagination and sorting in Collections

Currently, collections only show the first page, and offer no sort options. To fix this, we need to change the subject of the page and add / remove query params.

Number input resulting in strings in JSON, causing invalid commits

Here's the incorrectly sent one:

{
  "https://atomicdata.dev/properties/createdAt": 1614461419486,
  "https://atomicdata.dev/properties/isA": [
    "https://atomicdata.dev/classes/Commit"
  ],
  "https://atomicdata.dev/properties/set": {
    "https://atomicdata.dev/properties/collection/currentPage": "124124124",
    "https://atomicdata.dev/properties/collection/pageSize": "111",
    "https://atomicdata.dev/properties/collection/totalPages": "124",
    "https://atomicdata.dev/properties/isA": [
      "https://atomicdata.dev/classes/Collection"
    ]
  },
  "https://atomicdata.dev/properties/signature": "RYICLjwCIebTRi2Z+MzCBugn9vtgT55NdnSTdY91zFnIFADpsmIClyJW37uYUbO0Q3evFb9w09MdUP0CvzJJBA==",
  "https://atomicdata.dev/properties/signer": "https://atomicdata.dev/agents/PLwTOXVvQdHYpaLEq5IozLNeUBdXMVchKjFwFfamBlo=",
  "https://atomicdata.dev/properties/subject": "http://localhost/things/c4rmpk7krcq"
}

Here's the expected one (note the lack of quotes surrounding the number in set):

{
  "https://atomicdata.dev/properties/createdAt": 1614461419486,
  "https://atomicdata.dev/properties/isA": [
    "https://atomicdata.dev/classes/Commit"
  ],
  "https://atomicdata.dev/properties/set": {
    "https://atomicdata.dev/properties/collection/currentPage": 124124124,
    "https://atomicdata.dev/properties/collection/pageSize": 111,
    "https://atomicdata.dev/properties/collection/totalPages": 124,
    "https://atomicdata.dev/properties/isA": [
      "https://atomicdata.dev/classes/Collection"
    ]
  },
  "https://atomicdata.dev/properties/signer": "https://atomicdata.dev/agents/PLwTOXVvQdHYpaLEq5IozLNeUBdXMVchKjFwFfamBlo=",
  "https://atomicdata.dev/properties/subject": "http://localhost/things/c4rmpk7krcq"
}

Prevent clearing resourceinput form on blur

The Downshift component might need something like this:

function preventResetOnBlur(state, changes) {
  if (changes.type === Downshift.stateChangeTypes.blurInput) {
    return {} // no-changes
  }
  return changes
}

export default () => (
  <Downshift
    stateReducer={preventResetOnBlur}
  >

Endpoint view

Endpoints are dynamic resources that accept query parameters. I want a standardized view for this.

Mutli-class form support

Currently, the is-a attribute of a Resource is used to render the recommended and required properties in a form. However, Atomic Data supports multi-class models. This means that in a naive implementation, the ResourceForm should use multiple useArray hooks, which is not possible in react. So we need a different way of constructing the list of all required properties.

Usecase for the js library: Atomic-VSCode

A way to edit resources directly in VSCode. Very useful when editing HTML files stored in your atomic server.

Some ideas:

  • Use the file explorer to navigate files on an atomic server.
  • Render resources as text files (kind of difficult to do well). When it is changed, construct a Commit.
  • Render values as text files, and commit when save. (easier to implement)

todo: design UX, implementation

Get rid of on-hover + keyboard shortcuts

Currently, you can hover over any resource and press e to edit it and d to open the data view. It's useful for debugging, and useful for powerusers, but it leads to confusion too often.

The fallback, of editing the currently shown resource, is good enough.

Keyboard support in dropdown menu

let's add some a11y (accessibility). Maybe this could even be the first step in getting rid of the Downshift library, which doesn't seem that great of a fit for this project.

Improve UX and labeling of changing base URL / drive URL / environment

In the settings page, users can set a Base URL. Changing the Base URL changes the URL of new resources, and it changes the used Proxy. It also changes the root of the sidebar.

I think the sidebar is where this setting should be changed, like how in notion you set a Workspace.

I also think the terms Base URL and Drive might be confusing and cryptic. Maybe just use Drive for both.

Internal Value model

All Atomic Data is currently structured as follows:

store =(subject)> resource =(property)> value, where subject and property are URL strings serving as keys.

The final step, the value, is where I'm currently having some issues. In the rust implementation, I used an enum, since rust supports enums with options that have their own datatypes:

pub enum Value {
    AtomicUrl(String),
    Date(String),
    Integer(isize),
    Markdown(String),
    ResourceArray(Vec<String>),
    Slug(String),
    String(String),
    Timestamp(i64),
    NestedResource(PropVals),
    Boolean(bool),
    Unsupported(UnsupportedValue),
}

JS / TS doesn't have such a feature, as far as I know.
And besides, the JS version is designed as a Client, used primarily in browsers.
It should be lightweight and fast, especially when parsing and rendering data.

Approaches:

Value Superclass + many SubClasses

We could have a Value class and many StringValue / DateValue classes that extend from it.

  • The SuperClass allows things like toString() and getDatatype(), whilst Subclasses can do things like toJSDate() or something.
  • Each Value subclass stores a different kind of internal value.

Downsides:

  • Requires setting the datatype when parsing data (which means some extra parsing time + potentially some requests).
  • Lots of Classes to write / maintain

One value, no datatype

We could simply take the JSON value from JSON-AD resources, without converting it.
This also means we don't need to retrieve the Datatype of the value when we parse it, so parsing becomes as fast as possible.
We do need a bunch of conversion methods, for different hooks for example: createdAtDate = usePropDate().

Downsides:

  • Serializing to a different format will take longer
  • Only works with JSON-AD, which limits the flexibility of the store.
  • Will accept invalid Atomic Data coming from the server (e.g. strings where we should expect numbers).

IndexedDB for Store

Currently, all data resides in memory. The browser IndexedDB API enables persistent cross session storage, which means that the app can be even faster. If we want to do things like client side search, this will also make search more powerful, as it will result in a big index.

Safer key storage in the browser

The decentralized architecture of Atomic Data dictates that changes to information (Commits) are signed using the private key of an Agent (user). This means that, if we want to edit things from the browser, the browser app needs to sign commits using that private key.

Attack risks of current implementation:

  • Thief could wait until user leaves desk, go to agent settings, copy the secret / mail it / send it / photograph it. This could be preventable by making the secret only copy-able on creating the Agent, and locking it afterwards.
  • Thief could check localStorage on same browser, even after the session.
  • Thief could navigate the JS state / the react tree and find the private key value

Possible solutions

I want both a good UX, and a safe solution. Some thoughts:

  • Storing the key anywhere where JS has access (localstorage, indexedDB), means that all libraries of Atomic Data Browser have to be trusted.
  • The CryptoKey browser API seems interesting. It saves to indexedDB, but in a way that the key itself cannot be retrieved - it can only be used for signing things. I don't think it supports ed25519 signatures, which kind of sucks, because that's what I'm using in this project and the rust implementation of atomic data.

Some resources to check out::

Class view template

Classes are special resources. They represent one of the core features of Atomic Data: reusable models that are available on line in machine readable and human readable formats. That second one is kind of true at this moment, but could be improved.

Wants

  • Don't just show the props in some random order. Start with the title, make it big. Then: the description.
  • Show more information about properties, not just their shortname.
  • Show some tips for getting started with this model. Maybe a atomic-cli new %{class_subject} cli command to get people started, or a link to the docs with code examples in various programming languages (and libraries!).

Installable as PWA - service worker & manifest

  • start_url should match (currently does not, as the front-end fetches from github pages instead of /
  • Icon images should resolve (currenlty uses relative paths which doesn't work)
  • Add service worker. No matching service worker detected. You may need to reload the page, or check that the scope of the service worker for the current page encloses the scope and start URL from the manifest.
  • Make sure the service worker caches the correct things

Document / Data editor

The Document is perhaps the most used and versatile concept in sharing information. It contains text, it's flexible, it's linear. It's designed for humans, it reads naturally. Combined with Atomic Data, it could benefit from using externally defined sections and type safe data.

Considerations

  • Results in a UX similar to notion
  • Can be serialized to HTML and Markdown
  • Plays nicely with Atomic Commits and versioning
  • Allows for inline / block specific comments
  • Extensible (add arbitrary types of resources)
  • Copy / paste from and to word / google docs / plaintext would be nice

Inspiration

  • notion.clone tutorial
  • [editorjs.io)(https://editorjs.io/), a block-style editor. Each header / paragraph / thing is a 'block' with its own ID.

Approaches

So how to model and implement it?

Markdown

I love markdown. It's simple, elegant, easy to read, and easy to edit.
But... It's not designed to be extensible.
And it's also kind of costly to parse and render.
And it's un-structured and line based, which means that Atomic Commits will be kind of useless.
So no, I don't think markdown is the way to go.

Using something

Recursive Sections

A Section is a recursive model. Sections can have Sections as children, which can be used for things like chapters or paragraphs. Every time a user presses enter, a new sections

  • Title
  • Plaintext
  • Sections (resourcearray => Section / Image / Resource?)

Documents and Sections

Document:

  • Title
  • Sections (resourcearray => TextBlock / Image / Resouce)

Retrieving options for Resource fields in forms

When creating a new Resource, we use the Class and its Properties to construct the form fields. These provide information about data validation and some semantic information (such as a description). If a Property with an AtomicURL datatype also has a classtype property, it specifies which kinds of Resources can be used. For example, a hasFriend property might require Person instances.

I'm currenlty working on a form for creating new things, and I kind of have to descide where this information will come from.

Approaches:

TPF query to atomic server

This query will fetch all instances of some particular class.

Dynamic collection

Collections are a bit more high level as TPF queries (although under the hood, they also use TPF queries).

Paths to collections

  • Get the base URL
  • Follow some path, specified in the form field (e.g. https://atomicdata.dev/prefferedcollections)
  • Get the resulting Collection

Storing formstate in something else than resource fields

We don't store form state seperately from the resource state. Editing a value using useValue will update the Resource everywhere in the app, even if the user does not save.

Problems with the current form state approach:

  • If form state is not posted or even saved, it will still reflect on the current state as if it was edited correctly. This can lead to data loss, because the user might incorrectly assume that the state is saved.
  • When a new Commit comes in, the current CommitBuilder might be lost (not entirely sure if this is what happens right now, though - maybe the CommitBuilder is transferred to the new resource?).
  • When we update a value, we can't revert the changes without requesting the data again. I'd like to revert to the old value in a form if a user edits something, and then presses cancel.

Also, currently we use the useResource hook to validate fields, since it returns errors if the value isn't OK. That's a pretty nice feature, sometimes, but now it makes things harder.

Approaches:

Show that a resource has unsaved edits

Maybe add a warning icon with some text to indicate that the changes haven't been saved.

EDIT: This is my current implementation.

Re-fetch the resource when user presses 'cancel'.

Quick & dirty. Works, but seems inefficient. Will lead a bit of janky performance - takes a while to replace old resource.

Read form state from the CommitBuilder.set map

When rendering a field, first try the CommitBuilder.set. If that is undefined, render the existing value. When the user changes the value, the CommitBuilder.set is set, and we can render that value instead.

It might not make sense to use this in places where values are rendered in a non-editable way - that would be unnecessarily costly.

  • Introduce a new useResourceForm hook, which also deals with the complicated setting / validation stuff. But this would mean we need 1 new hook for every new datatype.
  • Add an option to useValue, such as formValue: true. If true, we check the CommitBuilder instead of the Resource's value.

Store form state in the component only, instead of in the resource

Seems simple and clean, but it might present a few problems:

  • This would make it harder to have live previews.
  • You'd lose the changes when the component unmounts.
  • Form validations will need to be implemented in a different way. Not sure where.

Fetching from /path proxy instead of source

Atomic Servers tend to cache a lot of data. With the /path endoint, a client can ask for external resources. Most of the times, this will probably just make things slower, but it could also help in a few cases:

  • If the resource will go offline / change for whatever reason, and you still need the original
  • If the resource server is very slow, and you'd prefer to use your own
  • If you don't want the server to know how often you're using / requesting the resource

So I've added an option to the fetchResource function to enable this. The question that remains, though, is when and how to trigger this different behavior.

Some ideas:

  • When an external resource returns a non-200 response, automatically retry with /path
  • Manually retry with a button press in the error component.

Some relevant thoughts and considerations:

  • Show a warning in the resource: this is cached version
  • How should you 'refresh' or 'update' this version? Usually you just... refresh the page, but that doesn't really work if it's cached by the server.

User (current Agent) Management UX / page

  • Create a new User
  • Remove / reset the current User (currently done from settings page)
  • Export / save user info (user + private key to single string, maybe QR code?)
  • Basic profile settings (name, bio)

Context-aware navigation (with arrow keys)

I'd like to quickly navigate array-like structures with my keyboard, also after I've opened one item. I think its behavior depends on context.

  • When I open an item from the search page, I want to quickly go to the next result
  • When I open an item from a collection, I want to quickly go to the next member
  • When I open an item from some non-array like structure, I want to open the next item from the parent.

Simplify default form

Some fields are (almost) always visible, yet often not relevant for end-users

  • Subject (is automatically generated)
  • is-a (is set when opening the form through some button)
  • Parent (is set when opening the form through some button)
  • Add other prop (not required)
  • Class text (should be collapsible)

I think we could simplify forms by moving these to a collapsible 'advanced' box. Or maybe the 'add other prop' should have its own minimal button

Client-side full text search

Atomic data browser should make it as simple and fast as possible to open any resource and do things with it. Client-side search can be incredibly fast and responsive, could index multiple sources, and does not require a server. It could be useful for form autocompletion (e.g. when any type or resouce can be entered), or when using the address bar to go to some specific resource.

So. How to implement it? There's a couple of libraries.

Things to consider:

  • Bundle size
  • Speed
  • Ease of use
  • Compatibility with atomic data model
  • Possibility / ease of persistent storage (e.g. indexedDB #11 )

The contenders:

QuickScore

https://fwextensions.github.io/quick-score-demo/

  • only 2kb
  • fast! impressive compared to fuse
  • great sorting engine
  • build index by creating a new instance - seems like a memory hog in our usecase, where there are items added to the store all the time

Fuse

Build issue webpack / snowpack

npm run build is failing (since.. upgrading most dependencies).

throwing errors like this:

Module parse failed: Unexpected token (1:935)
File was processed with these loaders:
 * ../node_modules/babel-loader/lib/index.js
 * ../node_modules/@snowpack/plugin-webpack/plugins/import-meta-fix.js
 * ../node_modules/@snowpack/plugin-webpack/plugins/proxy-import-resolve.js
You may need an additional loader to handle the result of these loaders.
> import React,{useState}from"../../pkg/react.js";import{useArray}from"../../atomic-react/hooks.js";import{ButtonMargin}from"../Button.js";import{ErrMessage}from"./InputStyles.js";import{ResourceSelector}from"./ResourceSelector.js";export default function InputResourceArray({resource,property,required}){const[array,setArray]=useArray(resource,property.subject);const[err,setErr]=useState(null);function handleAdd(){array.push(null);const newArray=array;setArray(newArray);}function handleRemove(index){array.splice(index,1);const newArray=array;setArray(newArray);}function handleSetSubject(value,handleErr,index){array[index]=value;setArray(array,handleErr);}return/* @__PURE__ */React.createElement(React.Fragment,null,array.map((subject,index)=>/* @__PURE__ */React.createElement(ResourceSelector,{key:`${property.subject}${index}${subject}`,value:subject,setSubject:(set,handleErr)=>handleSetSubject(set,handleErr,index),error:err?.index==index&&err,setError:setErr,classType:property.classType,required,handleRemove:()=>handleRemove(index)})),/* @__PURE__ */React.createElement(ButtonMargin,{subtle:true,type:"button",onClick:handleAdd},"add"),err?.index==void 0&&/* @__PURE__ */React.createElement(ErrMessage,null,err?.message),array==[]&&/* @__PURE__ */React.createElement(ErrMessage,null,"Required"));}

If we look at the unexpected token at 1:935, we get a question mark ?. operator for optional chaining, which is an ES2020 feature. So, I've tried setting the compilation target in compilerOptions in tsconfig.json from es2020 to es6, but to no avail. Also tried setting tsconfig's jsx: "preserve", to react. Also tried this suggested fix. Whenever I use snowpack builder (so disabling @snowpack/plugin-webpack), things work fine. That would mean having a bigger bundle size, but maybe that's the best solution as of now.

Nested forms - create new resource from within a ResourceSelector

When creating a new Resource, one of the possible fields can be an AtomicURL or a ResourceArray. If the user doesn't want to select an extisting resource from these inputs, they're currently out of luck. Ideally, creating a nested resource happens right from within this form - without leaving the page, and keeping all existing fields intact. How can we achieve this?

Opening the nested form

Maybe add a plus icon in the resourceselector input, right next to the 'clear' and 'remove' buttons?

Screenshot 2021-03-03 at 21 30 32

Or always show the 'new instance' option in the dropdown:

Screenshot 2021-03-03 at 21 31 19

Or maybe both...

Rendering the nested form

Maybe show it in a modal? Or as a nested form with some border? Maybe make it collapsible? What if the user creates a nested form inside a nested form?

What to include in the view

Should it include the class title and description?

What happens on save

If the resource has errors, is it shown in the nested form? How can we fill in the URL of the newly created resource in the parent resource?

Parent-child relationship

If the nested resource has a relationship to the parent resource, it will probably need to exist and have a URL, which it does not in a non-saved form. Also, how does the form know that this relationship exists?

Getting the same signatures as in atomic-rust

For some reason, I can't get the commit signatures to match with the rust implementation. The deteministic serialization works like it should, but something is going wrong with the signatures. I think the interfaces of Ring (for rust) and noble (js) are subtly different and I fail to see some important detail in which they are.

Edit nested resources / anonymous resources

A nested JSON object, in Atomic Data, represents a nested resource. It might not have its own @id. However, it does have its own unique path.

In the store, these nested resources live inside a propVal, inside resources. So... how should we deal with these, when users edit them? What should we even show?

Regarding UI, I think these nested resources should just be resources. They should render in a form with their own fields, same as regular resources.

The logic, however, might work a bit... different. How do we store the changes? We should probably update the entire object in the CommitBuilder whenever the nested resource changes, since Commits don't really support nested change descriptions.

How should useValue work? Well, it already returns an entire resource. Perhaps we need to make a useNestedResource hook, which returns a new kind of class with its own methods for updating...

And how about rendering these form fields? Do we need a useNestedResourceValue hook, or can we use the existing useValue? Maybe we can pass a path to useResource, to the nested resource... yeah... That seems right, I think. When we start with the useResource hook, we can check if the subject is actually the path (i.e. if it contains a spacebar). If true, we can split it up, get the first resource, and get the corresponding nested resource, and return that.

Splitting repo into library and browser

From the get-go, the goal of this project was two folded: 1) provide a UI for Atomic-Server, and 2) build a JS (+ react) library for others to build apps and components with. The first goal is mostly achieved, but the second one not at all. The project structure has been designed to keep both worlds separate, though.

So the next steps are to:

  • Have a separate package.json for atomic-data-lib
  • Maybe also a separate package.json for atomic-data-react?
  • Publish packages to NPM
  • Maybe move it to separate repo?

Extending views - adding custom components

A crucial part of making this project a success, is developer adoption. I'm trying to provide developers various layers in which they should be able to do something nice with (serialization format, server, library, etc.). Perhaps the most important missing abstraction, at this moment, is the view layer. This repo aims to provide two libraries: one for react, and one for js in general.

But... I think it might make sense to also provide a different type of abstraction. Being able to extend views dynamically.

Usecase

User is using their Atomic Data server for storing various types of personal data. One day, they want to store calendar data on it. They can already create Calendars and Events by instantiating these Classes, but the default views that Atomic-Data-Browser provides aren't very fitting - the user needs a custom View.

Ideally, this custom view can be added during the browser session. Perhaps the user opens a View resource, and an 'install' button appears. If this is done, the view is saved to their Atomic Data server (or in their session only?).

This requires way more thoughts.

Improve UX for switching Base URL / Drive

Notion has a Workspace switcher, like so:

Screenshot 2021-06-28 at 15 52 40

I'd like something similar.

Considerations

  • We have 'base URL' and 'drive' concepts, perhaps these should be merged / renamed (Workspace?)
  • When a user is created, it might make sense to provide that user with their own drive
  • Maybe add a button for creating a Drive.
  • The current Base URL setting does not update views. I think the state needs to reside in the Settings context object
  • When opening a Drive, perhaps show a button 'set as current drive'
  • Being able to switch between drives, means storing mutliple. Maybe store an array to localstorage?

Versioning / history views and UX

  • Have a way to open a list of 'versions' from any view
  • Browse through versions (e.g. through pressing an arrow or something)
  • Improved version view
  • Set as 'current version'?

Server side: atomicdata-dev/atomic-server#135

Some thoughts on the history viewer:

History scratcher

At the bottom of the screen, show a fixed bar. This bar has a line. The user can click anywhere in the line to move their current version to that version. They could even 'scratch' history and see their resource changing as they move the 'current' icon in the timeline.

If we want to achieve this, we'll need seriously awesome performance. So how do we do this?

  • Fetch all constructed versions. This means asking the server for 1) a list of all commits and 2) /versions for all these commits. This could be slow, as every version plays back all commits up until the selected version.
  • Fetch all commits, build on client. Get all the commits, then let the client create a bunch of versions from these commits. We'd have to modify parseAndApplyCommit a little, as the default behaviour is that it replaces the resource in the store.

Event sidebar

How google docs does it. Show a sidebar on the right of the screen containing changes. However, google Docs doesn't create new versions nearly as often as Atomic does, so the versions are far more sparse, which makes showing a list like this useable. Sometimes even these versions are grouped, which shows a dropdown toggle icon.

The complexity of this approach is creating the 'grouped' resources. Instead of creating a new version for every single commit, we create a new version if the next commit is more than 1 hour in the future.

Keep form state for new resources after visiting other page

Currently creates a random resource every time you open a new form.

Approaches

  • Store temporary identifier in the URL as a query parameter.
  • Skip the 'new' form - create a new empty resource when opening the form, then open an Edit form.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.