metafacture / metafacture-playground

Web application to play around with workflows using Fix and Flux
https://metafacture.org/playground
Apache License 2.0
3 stars 2 forks source link

Make form input persist through page reload #17

Closed acka47 closed 3 years ago

acka47 commented 3 years ago

As a user I want my input into the form to be saved if I accidentally close and reopen the tab or reload the page to not have to do double work.

katauber commented 3 years ago

In order to fulfill our Deinfition of Ready:

Please +1 if you agree.

katauber commented 3 years ago

Deployed to http://test.lobid.org/playground/: Form inputs and collapse status of data editor, flux editor and fix editor will be saved when the page is reloaded.

@acka47 I thought it would be nicer if different tabs could have different persisted data, so that changing the inputs of one tab does not change the inputs of another open tab of metafacture playground when reloading. But if you don't like this behaviour it's easy to change that multiple tabs of metafacture playground use the same saved data.

acka47 commented 3 years ago

I thought it would be nicer if different tabs could have different persisted data, so that changing the inputs of one tab does not change the inputs of another open tab of metafacture playground when reloading.

I agree.

I played around with it a bit. Unfortunately, this does not work consistently. Adjusting the example workflow and then closing and reopening the tab or reloading works (whether I ran the workflow or not). But I also added a workflow from oersi-etl with a bigger input JSON document, a longer flux and a the edusharing fix and it didn't work.

Does the feature currently somehow rely on the share URL for a workflow? If yes, it didn't work because the URL was too long to be loaded. (I assume, we will have to think of another solution for share URLs soon, latest when implementing examples with more input in #25 .

As an aside: I noticed that there are suggestions from a dictionary when typing. I think we should disable it as it is of not much help but rather overwrites the names of flux parameters one has typed in.

katauber commented 3 years ago

I played around with it a bit. Unfortunately, this does not work consistently. Adjusting the example workflow and then closing and reopening the tab or reloading works (whether I ran the workflow or not). But I also added a workflow from oersi-etl with a bigger input JSON document, a longer flux and a the edusharing fix and it didn't work.

Could you please provide the input of the editors @acka47, so I can analyze this behaviour.

Does the feature currently somehow rely on the share URL for a workflow? If yes, it didn't work because the URL was too long to be loaded.

The feature does not rely on the share URL for a workflow, but it's possible that it may have something to do with long editor inputs.

As an aside: I noticed that there are suggestions from a dictionary when typing. I think we should disable it as it is of not much help but rather overwrites the names of flux parameters one has typed in.

I'm sure I can disable this.

acka47 commented 3 years ago

I just repeated the test, using the following input. The workflow does not run but is should work for testing this feature. Result:

Data

{
  "remote":null,
  "content":{
    "url":"https://www.zoerr.de/edu-sharing/components/render/038b8b6a-f51d-49f7-aa40-fd0b6adab60f",
    "hash":null,
    "version":"1.0"
  },
  "license":{
    "icon":"https://www.oerbw.de/edu-sharing/ccimages/licenses/cc-0.svg",
    "url":"https://creativecommons.org/publicdomain/zero/1.0/deed.en"
  },
  "isDirectory":false,
  "commentCount":0,
  "rating":{
    "overall":{
      "sum":0,
      "count":0,
      "rating":0
    },
    "affiliation":{

    },
    "user":0
  },
  "usedInCollections":[

  ],
  "accessOriginal":[
    "Read",
    "ReadAll"
  ],
  "originalRestrictedAccess":false,
  "ref":{
    "repo":"uni-tuebingen.de",
    "id":"038b8b6a-f51d-49f7-aa40-fd0b6adab60f",
    "archived":false,
    "isHomeRepo":true
  },
  "parent":{
    "repo":"uni-tuebingen.de",
    "id":"b24ee9a4-1bc7-4866-8cfe-1450644b031b",
    "archived":false,
    "isHomeRepo":true
  },
  "type":"ccm:io",
  "aspects":[
    "cclom:lifecycle",
    "cclom:technical",
    "cm:versionable",
    "ccm:iometadata",
    "sys:referenceable",
    "ccm:basemetadata",
    "cm:metadataset",
    "ccm:commonlicenses",
    "cclom:rights",
    "cm:thumbnailed",
    "cm:auditable",
    "cclom:meta-metadata",
    "ccm:positionable",
    "ccm:educontext",
    "ccm:eduscope",
    "ccm:usageaspect",
    "ccm:collection_io_reference",
    "sys:localized",
    "cm:thumbnailModification",
    "cclom:schema",
    "ccm:published",
    "ccm:licenses",
    "cm:copiedfrom",
    "ccm:lomreplication",
    "cclom:general"
  ],
  "name":"Funktionsweise eines Seismometers",
  "title":"Funktionsweise eines Seismometers",
  "metadataset":"mds",
  "repositoryType":"ALFRESCO",
  "createdAt":"2018-10-01T13:19:07Z",
  "createdBy":{
    "profile":null,
    "firstName":"Andreas",
    "lastName":"Barth",
    "mailbox":null
  },
  "modifiedAt":"2019-07-19T08:26:57Z",
  "modifiedBy":{
    "profile":null,
    "firstName":"unknown",
    "lastName":"unknown",
    "mailbox":null
  },
  "access":[
    "Read",
    "ReadAll"
  ],
  "downloadUrl":"https://www.oerbw.de/edu-sharing/eduservlet/download?nodeId=038b8b6a-f51d-49f7-aa40-fd0b6adab60f",
  "properties":{
    "ccm:lifecyclecontributer_authorVCARD_ORG":[
      ""
    ],
    "ccm:lifecyclecontributer_authorVCARD_TITLE":[
      ""
    ],
    "ccm:original":[
      "82cee92b-12e6-4666-a908-e50976ca3ca8"
    ],
    "cm:created":[
      "1538399947925"
    ],
    "virtual:commentcount":[
      "0"
    ],
    "ccm:metadatacontributer_creatorVCARD_ORG":[
      ""
    ],
    "cclom:version":[
      "1.0"
    ],
    "cm:original":[
      "82cee92b-12e6-4666-a908-e50976ca3ca8"
    ],
    "ccm:university_DISPLAYNAME":[
      "- Alle -"
    ],
    "cclom:general_language":[
      "en"
    ],
    "virtual:licenseicon":[
      "https://www.oerbw.de/edu-sharing/ccimages/licenses/cc-0.svg"
    ],
    "virtual:usagecount":[
      "0"
    ],
    "sys:node-uuid":[
      "038b8b6a-f51d-49f7-aa40-fd0b6adab60f"
    ],
    "ccm:lifecyclecontributer_authorVCARD_SURNAME":[
      ""
    ],
    "ccm:taxonid_DISPLAYNAME":[
      "Geowissenschaften (ohne Geographie)"
    ],
    "ccm:classification_keyword":[
      "Seismologie (Erdbebenkunde)",
      "Seismometer (Seismograf, Seismograph)",
      "Seismometrie (Erdbebenmessung)"
    ],
    "virtual:licenseurl":[
      "https://creativecommons.org/publicdomain/zero/1.0/deed.de"
    ],
    "ccm:lifecyclecontributer_authorVCARD_URL":[
      ""
    ],
    "virtual:childobjectcount":[
      "0"
    ],
    "cclom:title":[
      "Funktionsweise eines Seismometers"
    ],
    "ccm:lifecyclecontributer_authorVCARD_COUNTRY":[
      ""
    ],
    "ccm:lifecyclecontributer_author":[
      "BEGIN:VCARD\r\nVERSION:3.0\r\nN:;;;;\r\nFN:\r\nEND:VCARD\r\n"
    ],
    "ccm:lifecyclecontributer_authorVCARD_REGION":[
      ""
    ],
    "sys:store-protocol":[
      "workspace"
    ],
    "ccm:lifecyclecontributer_authorVCARD_STREET":[
      ""
    ],
    "ccm:lifecyclecontributer_authorVCARD_PLZ":[
      ""
    ],
    "sys:store-identifier":[
      "SpacesStore"
    ],
    "cclom:general_language_DISPLAYNAME":[
      "Englisch"
    ],
    "ccm:version_comment":[
      "MAIN_FILE_UPLOAD"
    ],
    "ccm:metadatacontributer_creatorVCARD_URL":[
      ""
    ],
    "ccm:educationallearningresourcetype":[
      "https://w3id.org/kim/hcrt/index"
    ],
    "ccm:create_version":[
      "true"
    ],
    "ccm:university":[
      ""
    ],
    "cm:modifiedISO8601":[
      "2019-07-19T08:26:57.317Z"
    ],
    "ccm:author_freetext":[
      "USGS"
    ],
    "ccm:metadatacontributer_creatorVCARD_REGION":[
      ""
    ],
    "sys:node-dbid":[
      "16935"
    ],
    "ccm:wwwurl":[
      "http://earthquake.usgs.gov/learn/glossary/?term=seismograph"
    ],
    "cm:edu_metadataset":[
      "mds"
    ],
    "ccm:metadatacontributer_creatorVCARD_PLZ":[
      ""
    ],
    "cclom:otherplatformrequirements":[
      ""
    ],
    "cm:autoVersion":[
      "false"
    ],
    "cm:creator":[
      "sn4928@kit.edu"
    ],
    "virtual:permalink":[
      "https://www.oerbw.de/edu-sharing/components/render/038b8b6a-f51d-49f7-aa40-fd0b6adab60f/1.0"
    ],
    "ccm:metadatacontributer_creatorVCARD_GIVENNAME":[
      "Mark"
    ],
    "cm:versionLabel":[
      "1.0"
    ],
    "cm:versionable":[
      "true"
    ],
    "ccm:lifecyclecontributer_authorVCARD_GIVENNAME":[
      ""
    ],
    "ccm:published_handle_id":[
      "10900.3/OER_HVLBPPeD"
    ],
    "ccm:metadatacontributer_creatorVCARD_COUNTRY":[
      ""
    ],
    "cm:created_LONG":[
      "1538399947925"
    ],
    "ccm:lifecyclecontributer_authorVCARD_TEL":[
      ""
    ],
    "virtual:primaryparent_nodeid":[
      "b24ee9a4-1bc7-4866-8cfe-1450644b031b"
    ],
    "cm:lastThumbnailModification":[
      "imgpreview:1538399948862"
    ],
    "ccm:metadatacontributer_creator":[
      "BEGIN:VCARD\r\nVERSION:3.0\r\nN:Wienöbst;Mark;;;\r\nFN:Mark Wienöbst\r\nTITLE:\r\nORG:\r\nURL:\r\nADR;TYPE=INTL,POSTAL,PARCEL,WORK:;;;;;;\r\nTEL;TYPE=WORK,VOICE:\r\nEND:VCARD\r\n"
    ],
    "ccm:metadatacontributer_creatorVCARD_TEL":[
      ""
    ],
    "ccm:lifecyclecontributer_authorVCARD_CITY":[
      ""
    ],
    "ccm:metadatacontributer_creatorVCARD_STREET":[
      ""
    ],
    "cm:createdISO8601":[
      "2018-10-01T13:19:07.925Z"
    ],
    "cclom:general_description":[
      "Funktionsweise eines Seismometers mit Abbildung eines Horizontalseismometers"
    ],
    "cm:modified":[
      "1563524817317"
    ],
    "ccm:metadatacontributer_creatorVCARD_CITY":[
      ""
    ],
    "ccm:taxonid":[
      "https://w3id.org/kim/hochschulfaechersystematik/n43"
    ],
    "cm:edu_forcemetadataset":[
      "false"
    ],
    "cm:modifier":[
      "System"
    ],
    "ccm:educationallearningresourcetype_DISPLAYNAME":[
      "Nachschlagewerk"
    ],
    "ccm:published_date":[
      "1535627398060"
    ],
    "cm:autoVersionOnUpdateProps":[
      "false"
    ],
    "cclom:location":[
      "ccrep://uni-tuebingen.de/ce72bc7f-9cfd-492d-9a77-480c5e02a2e9"
    ],
    "ccm:educontextname":[
      "default"
    ],
    "ccm:lifecyclecontributer_authorFN":[
      ""
    ],
    "ccm:metadatacontributer_creatorFN":[
      "Mark Wienöbst"
    ],
    "cm:modified_LONG":[
      "1563524817317"
    ],
    "ccm:metadatacontributer_creatorVCARD_TITLE":[
      ""
    ],
    "ccm:published_dateISO8601":[
      "2018-08-30T11:09:58.060Z"
    ],
    "ccm:questionsallowed":[
      "true"
    ],
    "cm:automaticUpdate":[
      "true"
    ],
    "cm:name":[
      "Funktionsweise eines Seismometers"
    ],
    "ccm:published_date_LONG":[
      "1535627398060"
    ],
    "cm:initialVersion":[
      "false"
    ],
    "ccm:metadatacontributer_creatorVCARD_SURNAME":[
      "Wienöbst"
    ],
    "cclom:general_keyword":[
      "Horizontalseismometer"
    ],
    "ccm:commonlicense_key":[
      "CC_0"
    ]
  },
  "mimetype":null,
  "mediatype":"link",
  "size":null,
  "preview":{
    "isIcon":false,
    "isGenerated":false,
    "type":"TYPE_USERDEFINED",
    "mimetype":null,
    "data":null,
    "url":"https://www.oerbw.de/edu-sharing/preview?nodeId=038b8b6a-f51d-49f7-aa40-fd0b6adab60f&storeProtocol=workspace&storeId=SpacesStore&dontcache=1623846484768",
    "width":null,
    "height":null
  },
  "iconURL":"https://www.zoerr.de/edu-sharing/themes/default/images/common/mime-types/svg/link.svg",
  "collection":null,
  "owner":{
    "profile":null,
    "firstName":"Andreas",
    "lastName":"Barth",
    "mailbox":null
  },
  "originalId":"82cee92b-12e6-4666-a908-e50976ca3ca8"
}

Flux

as-lines
| decode-json
| fix(FLUX_DIR + "edu-sharing-6_0.fix", *) // '*': pass all flux variables to the fix
| encode-json

Fix

/* Set up the context */
do array('@context')
 add_field('','https://w3id.org/kim/lrmi-profile/draft/context.jsonld')
 do entity('')
  add_field('@language', 'de')
 end
end

map(node.title, name)
map(node.preview.url, image)

/* Default ID: */
do map('node.ref.id', id)
  compose(prefix: 'https://$[service_domain]/edu-sharing/components/render/')
end

/* Replace default ID if we have a ccm:wwwurl */
do map('node.properties.ccm:wwwurl[].1', id)
  trim()
  replace_all(pattern: '\\u00a0', with: '') /* %A0 /   */
end

do array('mainEntityOfPage')
  do entity('')
    do map('node.ref.id', id)
      compose(prefix: 'https://$[service_domain]/edu-sharing/components/render/')
    end
    /* Add creation/modification date, converting dateTime (e.g. 2019-07-23T09:26:00Z) to date (2019-07-23) */
    do map('node.modifiedAt', 'dateModified')
      replace_all(pattern: 'T.+Z', with: '')
    end
    do map('node.createdAt', 'dateCreated')
      replace_all(pattern: 'T.+Z', with: '')
    end
    /* Add provider/source information to each resource description */
    do entity('provider')
      add_field('id','$[service_id]')
      add_field('type','Service')
      add_field('name','$[service_name]')
    end
  end
end

do map(node.description, description)
  not_equals(string: '')
end

do array('creator', flushWith: record)
 do entity('')
  add_field('type', 'Person')
  do map('node.properties.ccm:lifecyclecontributer_authorFN[].*', 'name')
    trim()
    not_equals(string: '')
    not_equals(string: 'null null')
  end
 end
end

do array('sourceOrganization')
 do entity('')
  add_field('type', 'Organization')
  do map('node.properties.ccm:university_DISPLAYNAME[].1', 'name')
    not_equals(string: '')
    not_equals(string: '- Alle -')
  end
 end
end

do map('node.properties.virtual:licenseurl[].1', license)
  replace_all(pattern: '/deed.*$', with: '')
end

do array("inLanguage")
  do map('node.properties.cclom:general_language[].1')
    replace_all(pattern: '_..$', with: '') /* remove country suffixes eg. _DE */
    replace_all(pattern: '^$', with: 'de') /* empty strings default to 'de' */
    replace_all(pattern: 'unknown', with: 'de')
  end
end

do array('type')
  add_field('','LearningResource')
end

do array('keywords')
  map('node.properties.cclom:general_keyword[].*')
end

/* Enable to see what else is coming in from the source: */
/* map(_else) */
katauber commented 3 years ago

I just repeated the test, using the following input. The workflow does not run but is should work for testing this feature. Result:

  • Input persists through reload (Strg+r)
  • Input does not persist when closing and reopening (strg+shift+t) the tab.

Thank you for the providing the inputs @acka47 I tested with these inputs and it shows a different bahaviour. Input persists through reload (Strg+r) and when closing and reopening (strg+shift+t) the tab 🤔 Maybe we can test this together so I can see what happens in the developer console?

katauber commented 3 years ago

Which browser do you use @acka47? I have observed the same behaviour with firefox, in Chrome everything works as expected. Since sharing workflows with long inputs does not work anymore and persisting input not in firefox I will move this issue to 'working' again.

acka47 commented 3 years ago

Which browser do you use @acka47? I have observed the same behaviour with firefox

Yes, I am using Firefox.

katauber commented 3 years ago

Unfortunately, it seems to be a firefox problem that session storage is not properly saved when restore a tab and the storage data is big. This should work as described in the API reference and does work in Chrome and Edge (tested by myself) and in Safari (according to the internet 🤓). I am not sure how to handle this. Should we implement a workaround?

acka47 commented 3 years ago

I am not sure how to handle this. Should we implement a workaround?

I am not sure as well. I tested some other web apps I use how they do this:

So, only GitHub reaches the high bar I have set. If you can easily find out how GitHub (or the JSON Formatter) achieve persistence over closing/reopening a tab in FF I'd be happy if you implemented it here as well. If it takes too much effort, I think we can deploy it as is.

katauber commented 3 years ago

It seems like that Github uses cookies instead of webstorage. Since I believe in our case webstorage is the right solution and it works for shorter examples, I would like to deploy it as is.