Merge branch 'main' into mobile/bridge-done-stamp
* main: (43 commits) Remove payment/subscription system and card/storage limits Conditionally disable peer verification for ZIP streaming Prevent HTML injection through filenames Revert "Configure Lexxy to add extra spacing between block elements" Configure Lexxy to add extra spacing between block elements SaaS usage reporting (#2690) Update app/models/user/named.rb Prevent line breaks in the middle of familiar_name Tweak the layout Set the list of importable models based on the record sets in the manifest Validate polymorphic types against importable models allowlist Fix that the "maybe" stream wouldn't be replaced after triaging a card Use x_user_agent cookie for platform detection in Hotwire Native Add JSON response format to entropy endpoints (#2673) Fix path traversal vulnerability in ActiveStorage blob key import Enable CORS fetch mode for storage requests Revert CORS fetch mode for Active Storage Use CORS fetch mode for Active Storage to enable `maxEntrySize` checks Only start offline mode when signed in Exclude service worker and edit/pin/watch/new pages from main cache ...
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
json.(@export, :id, :status)
|
||||
json.created_at @export.created_at.utc
|
||||
|
||||
if @export.completed? && @export.file.attached?
|
||||
json.download_url rails_blob_url(@export.file, disposition: "attachment")
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
json.(@join_code, :code, :usage_count, :usage_limit)
|
||||
json.url join_url(code: @join_code.code, script_name: Current.account.slug)
|
||||
json.active !!@join_code.active?
|
||||
@@ -21,5 +21,3 @@
|
||||
<%= render "account/settings/cancellation" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "account/settings/subscription_panel" if Fizzy.saas? %>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
json.(@account, :id, :name, :cards_count)
|
||||
json.created_at @account.created_at.utc
|
||||
json.auto_postpone_period_in_days @account.entropy.auto_postpone_period_in_days
|
||||
@@ -1,6 +1,7 @@
|
||||
json.cache! board do
|
||||
json.(board, :id, :name, :all_access)
|
||||
json.created_at board.created_at.utc
|
||||
json.auto_postpone_period_in_days board.auto_postpone_period_in_days
|
||||
json.url board_url(board)
|
||||
|
||||
json.creator board.creator, partial: "users/user", as: :user
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
json.array! @page.records, partial: "cards/card", as: :card
|
||||
@@ -0,0 +1 @@
|
||||
json.array! @page.records, partial: "cards/card", as: :card
|
||||
@@ -0,0 +1 @@
|
||||
json.array! @page.records, partial: "cards/card", as: :card
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
<div class="cards__list hide-scrollbar" data-drag-drop-item-container>
|
||||
<% if page.used? %>
|
||||
<%= with_automatic_pagination "maybe", @page do %>
|
||||
<%= with_automatic_pagination "maybe", page do %>
|
||||
<%= render "cards/display/previews", cards: page.records, draggable: true %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<% if @source_column %>
|
||||
<%= turbo_stream.replace(dom_id(@source_column), partial: "boards/show/column", method: :morph, locals: { column: @source_column }) %>
|
||||
<% elsif @was_in_stream %>
|
||||
<%= turbo_stream.replace("the-stream", partial: "boards/show/stream", method: :morph, locals: { board: @card.board, page: @page }) %>
|
||||
<%= turbo_stream.replace("maybe", partial: "boards/show/stream", method: :morph, locals: { board: @card.board, page: @page }) %>
|
||||
<% end %>
|
||||
|
||||
<%= turbo_stream.replace([ @card, :card_container ], partial: "cards/container", method: :morph, locals: { card: @card.reload }) %>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<% if @card.column %>
|
||||
<%= turbo_stream.replace(dom_id(@card.column), partial: "boards/show/column", method: :morph, locals: { column: @card.column }) %>
|
||||
<% elsif @card.awaiting_triage? %>
|
||||
<%= turbo_stream.replace("the-stream", partial: "boards/show/stream", method: :morph, locals: { board: @card.board, page: @page }) %>
|
||||
<%= turbo_stream.replace("maybe", partial: "boards/show/stream", method: :morph, locals: { board: @card.board, page: @page }) %>
|
||||
<% end %>
|
||||
|
||||
<%= turbo_stream.replace([ @card, :card_container ], partial: "cards/container", method: :morph, locals: { card: @card.reload }) %>
|
||||
|
||||
@@ -13,7 +13,5 @@
|
||||
<span>Create and add another</span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= render "cards/container/footer/saas/near_notice" if Fizzy.saas? %>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -26,9 +26,5 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if Fizzy.saas? %>
|
||||
<%= render "cards/container/footer/saas/create", card: card %>
|
||||
<% else %>
|
||||
<%= render "cards/container/footer/create", card: card %>
|
||||
<% end %>
|
||||
<%= render "cards/container/footer/create", card: card %>
|
||||
</section>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<% if @source_column %>
|
||||
<%= turbo_stream.replace(dom_id(@source_column), partial: "boards/show/column", method: :morph, locals: { column: @source_column }) %>
|
||||
<% elsif @was_in_stream %>
|
||||
<%= turbo_stream.replace("the-stream", partial: "boards/show/stream", method: :morph, locals: { board: @card.board, page: @page }) %>
|
||||
<%= turbo_stream.replace("maybe", partial: "boards/show/stream", method: :morph, locals: { board: @card.board, page: @page }) %>
|
||||
<% end %>
|
||||
|
||||
<%= turbo_stream.replace([ @card, :card_container ], partial: "cards/container", method: :morph, locals: { card: @card.reload }) %>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
json.array! @card.steps, partial: "cards/steps/step", as: :step
|
||||
@@ -6,8 +6,9 @@
|
||||
<%= form_with model: model, url: url, data: { controller: "form" } do |form| %>
|
||||
<%= render "entropy/knob",
|
||||
form: form,
|
||||
name: :auto_postpone_period,
|
||||
knob_options: entropy_auto_close_options,
|
||||
name: :auto_postpone_period_in_days,
|
||||
current_value: model.auto_postpone_period_in_days,
|
||||
knob_options: Entropy::AUTO_POSTPONE_PERIODS_IN_DAYS,
|
||||
label: "Days until auto-close",
|
||||
disabled: disabled %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<%
|
||||
period = form.object.send(name)
|
||||
current_index = knob_options.index(period.to_i / 1.day)
|
||||
current_index = knob_options.index(current_value) || knob_options.index(Entropy::DEFAULT_AUTO_POSTPONE_PERIOD_IN_DAYS)
|
||||
%>
|
||||
|
||||
<fieldset class="knob" data-controller="knob" data-knob-target="field" style="--knob-options: <%= knob_options.length %>; --knob-index: <%= current_index %>">
|
||||
@@ -8,7 +7,7 @@
|
||||
<% knob_options.each_with_index do |value, index| %>
|
||||
<label class="knob__option" style="--i: <%= index %>">
|
||||
<%= form.radio_button name,
|
||||
value.days,
|
||||
value,
|
||||
data: {
|
||||
action: "change->knob#optionChanged change->form#submit",
|
||||
index: index,
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
<%= render "layouts/theme_preference" %>
|
||||
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
|
||||
<%= stylesheet_link_tag "fizzy/saas", "data-turbo-track": "reload" if Fizzy.saas? %>
|
||||
<%= javascript_importmap_tags %>
|
||||
|
||||
<%= tenanted_action_cable_meta_tag %>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
json.(access_token, :id, :description, :permission)
|
||||
json.created_at access_token.created_at.utc
|
||||
@@ -0,0 +1 @@
|
||||
json.array! @access_tokens, partial: "my/access_tokens/access_token", as: :access_token
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<%= tag.li class: "popup__item", data: { filter_target: "item", navigable_list_target: "item" } do %>
|
||||
<%= icon_tag "logout", class: "popup__icon" %>
|
||||
<%= button_to session_path(script_name: nil), method: :delete, class: "popup__btn btn", data: { turbo: false } do %>
|
||||
<%= button_to session_path(script_name: nil), method: :delete, class: "popup__btn btn", form: { data: { turbo: false, controller: "clear-offline-cache", action: "submit->clear-offline-cache#clearCache" } } do %>
|
||||
<span>Sign out</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
json.bundle_email_frequency Current.user.settings.bundle_email_frequency
|
||||
@@ -1,41 +0,0 @@
|
||||
self.addEventListener('fetch', (event) => {
|
||||
if (event.request.method !== 'GET') return
|
||||
|
||||
if (event.request.destination === 'document') {
|
||||
event.respondWith(
|
||||
fetch(event.request, { cache: 'no-cache' })
|
||||
.catch(() => caches.match(event.request))
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
self.addEventListener("push", (event) => {
|
||||
const data = event.data.json()
|
||||
event.waitUntil(Promise.all([ showNotification(data), updateBadgeCount(data.options) ]))
|
||||
})
|
||||
|
||||
async function showNotification({ title, options }) {
|
||||
return self.registration.showNotification(title, options)
|
||||
}
|
||||
|
||||
async function updateBadgeCount({ data: { badge } }) {
|
||||
return self.navigator.setAppBadge?.(badge || 0)
|
||||
}
|
||||
|
||||
self.addEventListener("notificationclick", (event) => {
|
||||
event.notification.close()
|
||||
|
||||
const url = new URL(event.notification.data.url, self.location.origin).href
|
||||
event.waitUntil(openURL(url))
|
||||
})
|
||||
|
||||
async function openURL(url) {
|
||||
const clients = await self.clients.matchAll({ type: "window" })
|
||||
const focused = clients.find((client) => client.focused)
|
||||
|
||||
if (focused) {
|
||||
await focused.navigate(url)
|
||||
} else {
|
||||
await self.clients.openWindow(url)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
importScripts("<%= javascript_url("turbo-offline-umd.min") %>")
|
||||
|
||||
// Documents - top-level navigation requests only
|
||||
// We need `cache: "no-cache"` here to work around
|
||||
// an annoying Safari PWA bug that predates offline mode
|
||||
TurboOffline.addRule({
|
||||
match: (request) => request.destination === "document",
|
||||
except: /\/(edit|pin|watch|new)$/,
|
||||
handler: TurboOffline.handlers.networkFirst({
|
||||
cacheName: "main",
|
||||
maxAge: 60 * 60 * 24 * 3,
|
||||
networkTimeout: 3,
|
||||
fetchOptions: { cache: "no-cache" },
|
||||
maxEntrySize: 1024 * 1024
|
||||
})
|
||||
})
|
||||
|
||||
TurboOffline.addRule({
|
||||
match: /\/assets\/.+[-\.][0-9a-f]+\.(js|css|svg|png|jpg|webp|woff2?|ico)$/,
|
||||
handler: TurboOffline.handlers.cacheFirst({
|
||||
cacheName: "assets",
|
||||
maxAge: 60 * 60 * 24 * 7,
|
||||
maxEntrySize: 1024 * 1024
|
||||
})
|
||||
})
|
||||
|
||||
TurboOffline.addRule({
|
||||
match: /\/(boards|cards|users)\//,
|
||||
except: /\/(edit|pin|watch|new)$/,
|
||||
handler: TurboOffline.handlers.networkFirst({
|
||||
cacheName: "main",
|
||||
maxAge: 60 * 60 * 24 * 3,
|
||||
networkTimeout: 2,
|
||||
maxEntrySize: 1024 * 1024
|
||||
})
|
||||
})
|
||||
|
||||
TurboOffline.addRule({
|
||||
match: /\/rails\/active_storage\//,
|
||||
handler: TurboOffline.handlers.networkFirst({
|
||||
cacheName: "storage",
|
||||
maxAge: 60 * 60 * 24 * 7,
|
||||
networkTimeout: 2,
|
||||
maxEntrySize: 2 * 1024 * 1024, // 2MB covers about 95% of all Fizzy blobs
|
||||
maxEntries: 500,
|
||||
fetchOptions: { mode: "cors" }
|
||||
})
|
||||
})
|
||||
|
||||
// Everything else
|
||||
TurboOffline.addRule({
|
||||
except: /\/(service-worker\.js|edit|pin|watch|new)$/,
|
||||
handler: TurboOffline.handlers.networkFirst({
|
||||
cacheName: "main",
|
||||
maxAge: 60 * 60 * 24,
|
||||
networkTimeout: 3,
|
||||
maxEntrySize: 1024 * 1024
|
||||
})
|
||||
})
|
||||
|
||||
self.addEventListener("activate", (event) => {
|
||||
event.waitUntil(self.clients.claim())
|
||||
})
|
||||
|
||||
TurboOffline.start()
|
||||
|
||||
|
||||
self.addEventListener("push", (event) => {
|
||||
const data = event.data.json()
|
||||
event.waitUntil(Promise.all([ showNotification(data), updateBadgeCount(data.options) ]))
|
||||
})
|
||||
|
||||
async function showNotification({ title, options }) {
|
||||
return self.registration.showNotification(title, options)
|
||||
}
|
||||
|
||||
async function updateBadgeCount({ data: { badge } }) {
|
||||
return self.navigator.setAppBadge?.(badge || 0)
|
||||
}
|
||||
|
||||
self.addEventListener("notificationclick", (event) => {
|
||||
event.notification.close()
|
||||
|
||||
const url = new URL(event.notification.data.url, self.location.origin).href
|
||||
event.waitUntil(openURL(url))
|
||||
})
|
||||
|
||||
async function openURL(url) {
|
||||
const clients = await self.clients.matchAll({ type: "window" })
|
||||
const focused = clients.find((client) => client.focused)
|
||||
|
||||
if (focused) {
|
||||
await focused.navigate(url)
|
||||
} else {
|
||||
await self.clients.openWindow(url)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
json.partial! "reactions/reaction", reaction: @reaction
|
||||
@@ -0,0 +1 @@
|
||||
json.array! @page.records, partial: "cards/card", as: :card
|
||||
@@ -8,7 +8,7 @@
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<%= form_with url: session_magic_link_path, method: :post, html: { data: { controller: "magic-link" } } do |form| %>
|
||||
<%= form_with url: session_magic_link_path, method: :post, html: { data: { controller: "magic-link clear-offline-cache", action: "submit->clear-offline-cache#clearCache" } } do |form| %>
|
||||
<%= form.text_field :code, required: true, class: "input center txt-align-enter txt-large txt-uppercase",
|
||||
autofocus: true, autocorrect: "off", autocapitalize: "off", spellcheck: "false", "data-1p-ignore": true,
|
||||
autocomplete: "one-time-code", maxlength: "6", placeholder: "••••••", value: params[:code],
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<% if Current.user == @user %>
|
||||
<hr class="separator--horizontal full-width flex-item-grow margin-block-start-double" style="--border-color: var(--color-ink-light);" aria-hidden="true">
|
||||
|
||||
<%= button_to session_path(script_name: nil), method: :delete, class: "btn txt-x-small center", data: { turbo: false } do %>
|
||||
<%= button_to session_path(script_name: nil), method: :delete, class: "btn txt-x-small center", form: { data: { turbo: false, controller: "clear-offline-cache", action: "submit->clear-offline-cache#clearCache" } } do %>
|
||||
<span>Sign out of Fizzy on this device</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
json.cache! [ webhook, webhook.board ] do
|
||||
json.(webhook, :id, :name, :active, :signing_secret, :subscribed_actions)
|
||||
json.payload_url webhook.url
|
||||
json.created_at webhook.created_at.utc
|
||||
json.url board_webhook_url(webhook.board, webhook)
|
||||
|
||||
json.board webhook.board, partial: "boards/board", as: :board
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
json.array! @page.records, partial: "webhooks/webhook", as: :webhook
|
||||
@@ -0,0 +1 @@
|
||||
json.partial! "webhooks/webhook", webhook: @webhook
|
||||
Reference in New Issue
Block a user