<%= render "bubbles/bubble", bubble: @bubble, editing: params[:editing] %>
diff --git a/app/views/notifications/_tray.html.erb b/app/views/notifications/_tray.html.erb
index 9b9d91c40..af1c2d452 100644
--- a/app/views/notifications/_tray.html.erb
+++ b/app/views/notifications/_tray.html.erb
@@ -1,5 +1,5 @@
<%= turbo_stream_from Current.user, :notifications %>
-<%= tag.div id: "notification-tray", class: "notification-tray", data: { turbo_permanent: true, controller: "notifications--readings" } do %>
+<%= tag.div id: "notification-tray", class: "notification-tray", data: { turbo_permanent: true } do %>
<%= turbo_frame_tag("notifications", src: notifications_path) %>
<% end %>
diff --git a/app/views/readings/create.turbo_stream.erb b/app/views/readings/create.turbo_stream.erb
new file mode 100644
index 000000000..5d7fe7801
--- /dev/null
+++ b/app/views/readings/create.turbo_stream.erb
@@ -0,0 +1,3 @@
+<% @notifications.each do |notification| %>
+ <%= turbo_stream.remove notification %>
+<% end %>
diff --git a/config/importmap.rb b/config/importmap.rb
index bf42e394c..87974cc7f 100644
--- a/config/importmap.rb
+++ b/config/importmap.rb
@@ -4,6 +4,7 @@ pin "application"
pin "@hotwired/turbo-rails", to: "turbo.min.js"
pin "@hotwired/stimulus", to: "stimulus.min.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
+pin "@rails/request.js", to: "@rails--request.js" # @0.0.11
pin "house", to: "house.min.js"
pin_all_from "app/javascript/controllers", under: "controllers"
diff --git a/config/routes.rb b/config/routes.rb
index 329e8fc7f..ad0d9a2cf 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -18,16 +18,13 @@ Rails.application.routes.draw do
end
resources :bubbles
- resources :notifications do
- scope module: :notifications do
- resource :readings, only: :create
- end
- end
+ resources :notifications
resources :buckets do
resources :bubbles do
resources :boosts
resources :comments
+ resource :readings, only: :create
scope module: :bubbles do
resource :image
diff --git a/test/controllers/notifications/readings_controller_test.rb b/test/controllers/notifications/readings_controller_test.rb
deleted file mode 100644
index cce305a3d..000000000
--- a/test/controllers/notifications/readings_controller_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require "test_helper"
-
-class Notifications::ReadingsControllerTest < ActionDispatch::IntegrationTest
- # test "the truth" do
- # assert true
- # end
-end
diff --git a/test/fixtures/notifications.yml b/test/fixtures/notifications.yml
index bb0035b95..802dcf68b 100644
--- a/test/fixtures/notifications.yml
+++ b/test/fixtures/notifications.yml
@@ -10,7 +10,7 @@ logo_created_kevin:
layout_created_kevin:
user: kevin
creator: david
- bubble: logo
+ bubble: layout
resource: layout_overflowing_david (Comment)
read: false
body: "re: Layout is broken"
diff --git a/vendor/javascript/@rails--request.js b/vendor/javascript/@rails--request.js
new file mode 100644
index 000000000..b85d5c78a
--- /dev/null
+++ b/vendor/javascript/@rails--request.js
@@ -0,0 +1,4 @@
+// @rails/request.js@0.0.11 downloaded from https://ga.jspm.io/npm:@rails/request.js@0.0.11/src/index.js
+
+class FetchResponse{constructor(t){this.response=t}get statusCode(){return this.response.status}get redirected(){return this.response.redirected}get ok(){return this.response.ok}get unauthenticated(){return this.statusCode===401}get unprocessableEntity(){return this.statusCode===422}get authenticationURL(){return this.response.headers.get("WWW-Authenticate")}get contentType(){const t=this.response.headers.get("Content-Type")||"";return t.replace(/;.*$/,"")}get headers(){return this.response.headers}get html(){return this.contentType.match(/^(application|text)\/(html|xhtml\+xml)$/)?this.text:Promise.reject(new Error(`Expected an HTML response but got "${this.contentType}" instead`))}get json(){return this.contentType.match(/^application\/.*json$/)?this.responseJson||(this.responseJson=this.response.json()):Promise.reject(new Error(`Expected a JSON response but got "${this.contentType}" instead`))}get text(){return this.responseText||(this.responseText=this.response.text())}get isTurboStream(){return this.contentType.match(/^text\/vnd\.turbo-stream\.html/)}get isScript(){return this.contentType.match(/\b(?:java|ecma)script\b/)}async renderTurboStream(){if(!this.isTurboStream)return Promise.reject(new Error(`Expected a Turbo Stream response but got "${this.contentType}" instead`));window.Turbo?await window.Turbo.renderStreamMessage(await this.text):console.warn("You must set `window.Turbo = Turbo` to automatically process Turbo Stream events with request.js")}async activeScript(){if(!this.isScript)return Promise.reject(new Error(`Expected a Script response but got "${this.contentType}" instead`));{const t=document.createElement("script");const e=document.querySelector("meta[name=csp-nonce]");const n=e&&e.content;n&&t.setAttribute("nonce",n);t.innerHTML=await this.text;document.body.appendChild(t)}}}class RequestInterceptor{static register(t){this.interceptor=t}static get(){return this.interceptor}static reset(){this.interceptor=void 0}}function getCookie(t){const e=document.cookie?document.cookie.split("; "):[];const n=`${encodeURIComponent(t)}=`;const s=e.find((t=>t.startsWith(n)));if(s){const t=s.split("=").slice(1).join("=");if(t)return decodeURIComponent(t)}}function compact(t){const e={};for(const n in t){const s=t[n];s!==void 0&&(e[n]=s)}return e}function metaContent(t){const e=document.head.querySelector(`meta[name="${t}"]`);return e&&e.content}function stringEntriesFromFormData(t){return[...t].reduce(((t,[e,n])=>t.concat(typeof n==="string"?[[e,n]]:[])),[])}function mergeEntries(t,e){for(const[n,s]of e)if(!(s instanceof window.File))if(t.has(n)&&!n.includes("[]")){t.delete(n);t.set(n,s)}else t.append(n,s)}class FetchRequest{constructor(t,e,n={}){this.method=t;this.options=n;this.originalUrl=e.toString()}async perform(){try{const t=RequestInterceptor.get();t&&await t(this)}catch(t){console.error(t)}const t=this.responseKind==="turbo-stream"&&window.Turbo?window.Turbo.fetch:window.fetch;const e=new FetchResponse(await t(this.url,this.fetchOptions));if(e.unauthenticated&&e.authenticationURL)return Promise.reject(window.location.href=e.authenticationURL);e.isScript&&await e.activeScript();const n=e.ok||e.unprocessableEntity;n&&e.isTurboStream&&await e.renderTurboStream();return e}addHeader(t,e){const n=this.additionalHeaders;n[t]=e;this.options.headers=n}sameHostname(){if(!this.originalUrl.startsWith("http:"))return true;try{return new URL(this.originalUrl).hostname===window.location.hostname}catch(t){return true}}get fetchOptions(){return{method:this.method.toUpperCase(),headers:this.headers,body:this.formattedBody,signal:this.signal,credentials:this.credentials,redirect:this.redirect}}get headers(){const t={"X-Requested-With":"XMLHttpRequest","Content-Type":this.contentType,Accept:this.accept};this.sameHostname()&&(t["X-CSRF-Token"]=this.csrfToken);return compact(Object.assign(t,this.additionalHeaders))}get csrfToken(){return getCookie(metaContent("csrf-param"))||metaContent("csrf-token")}get contentType(){return this.options.contentType?this.options.contentType:this.body==null||this.body instanceof window.FormData?void 0:this.body instanceof window.File?this.body.type:"application/json"}get accept(){switch(this.responseKind){case"html":return"text/html, application/xhtml+xml";case"turbo-stream":return"text/vnd.turbo-stream.html, text/html, application/xhtml+xml";case"json":return"application/json, application/vnd.api+json";case"script":return"text/javascript, application/javascript";default:return"*/*"}}get body(){return this.options.body}get query(){const t=(this.originalUrl.split("?")[1]||"").split("#")[0];const e=new URLSearchParams(t);let n=this.options.query;n=n instanceof window.FormData?stringEntriesFromFormData(n):n instanceof window.URLSearchParams?n.entries():Object.entries(n||{});mergeEntries(e,n);const s=e.toString();return s.length>0?`?${s}`:""}get url(){return this.originalUrl.split("?")[0].split("#")[0]+this.query}get responseKind(){return this.options.responseKind||"html"}get signal(){return this.options.signal}get redirect(){return this.options.redirect||"follow"}get credentials(){return this.options.credentials||"same-origin"}get additionalHeaders(){return this.options.headers||{}}get formattedBody(){const t=Object.prototype.toString.call(this.body)==="[object String]";const e=this.headers["Content-Type"]==="application/json";return e&&!t?JSON.stringify(this.body):this.body}}async function get(t,e){const n=new FetchRequest("get",t,e);return n.perform()}async function post(t,e){const n=new FetchRequest("post",t,e);return n.perform()}async function put(t,e){const n=new FetchRequest("put",t,e);return n.perform()}async function patch(t,e){const n=new FetchRequest("patch",t,e);return n.perform()}async function destroy(t,e){const n=new FetchRequest("delete",t,e);return n.perform()}export{FetchRequest,FetchResponse,RequestInterceptor,destroy,get,patch,post,put};
+