Skip to content

Make Specify a Progressive Web App #2791

@grantfitzsimmons

Description

@grantfitzsimmons

We need to finish the process of making Specify a PWA. The initial work was started with #2752 with the color scheme and other info laid out in the manifest.json file in the static directory.

We need to make it install-able and do some testing on this process. Need to add the service worker and test this. On my to-do list but time is hard to come by.

@grantfitzsimmons:

https://web.dev/codelab-make-installable/

There is some more work to be done to make this installable from what I understand.

We need to add a service worker to this branch to enable installing the app.

https://glitch.com/edit/#!/make-it-installable?path=service-worker.js%3A1%3A0

See this example service-worker.js:

const CACHE_NAME = 'offline';
const OFFLINE_URL = 'offline.html';

self.addEventListener('install', function(event) {
  console.log('[ServiceWorker] Install');
  
  event.waitUntil((async () => {
    const cache = await caches.open(CACHE_NAME);
    // Setting {cache: 'reload'} in the new request will ensure that the response
    // isn't fulfilled from the HTTP cache; i.e., it will be from the network.
    await cache.add(new Request(OFFLINE_URL, {cache: 'reload'}));
  })());
  
  self.skipWaiting();
});

self.addEventListener('activate', (event) => {
  console.log('[ServiceWorker] Activate');
  event.waitUntil((async () => {
    // Enable navigation preload if it's supported.
    // See https://developers.google.com/web/updates/2017/02/navigation-preload
    if ('navigationPreload' in self.registration) {
      await self.registration.navigationPreload.enable();
    }
  })());

  // Tell the active service worker to take control of the page immediately.
  self.clients.claim();
});

self.addEventListener('fetch', function(event) {
  // console.log('[Service Worker] Fetch', event.request.url);
  if (event.request.mode === 'navigate') {
    event.respondWith((async () => {
      try {
        const preloadResponse = await event.preloadResponse;
        if (preloadResponse) {
          return preloadResponse;
        }

        const networkResponse = await fetch(event.request);
        return networkResponse;
      } catch (error) {
        console.log('[Service Worker] Fetch failed; returning offline page instead.', error);

        const cache = await caches.open(CACHE_NAME);
        const cachedResponse = await cache.match(OFFLINE_URL);
        return cachedResponse;
      }
    })());
  }
});

Potential refactoring to consider down the road:

# Add web app manifest
WEBPACK_LOADER = {
'MANIFEST_FILE': os.path.join(SPECIFY_CONFIG_DIR, "/static/manifest.json"),
}

@maxpatiiuk:
Is this required? You might be able to achieve the same by defining a view that would serve the manifest.json page:

View:

url(r'^opensearch.xml$', search_view),

it's imported here:

from .frontend.views import open_search as search_view

the view itself is defined like this: (https://specifydev.slack.com/archives/D02LXH9PEUU/p1672952503649319)

def open_search(request):
return HttpResponse(f"""<?xml version="1.0"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
<ShortName>Specify 7</ShortName>
<Description>Biological Collections Data Management Platform</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image height="16" width="16" type="image/png">/static/img/fav_icon.png</Image>
<Url type="text/html" method="get" template="{request.build_absolute_uri('/specify/express-search/?q=')}{'{searchTerms}'}" />
<moz:SearchForm>{request.build_absolute_uri('/specify/express-search/')}</moz:SearchForm>
</OpenSearchDescription>""",content_type='text/xml')

Metadata

Metadata

Assignees

Labels

1 - RequestA request made by a member of the community2 - User InterfaceIssues that are related to the user interface or user experience.

Type

No type

Projects

Status

✅ Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions