Skip to content

Commit

Permalink
[Enhancement] Add history table to homepage (And TZ support) (#229)
Browse files Browse the repository at this point in the history
* Added basic history table to homepage

* Improved homepage history query

* Set table to use 24h time

* Added timezone support

* Updated README to reflect new TZ stuff
  • Loading branch information
kieraneglin authored May 7, 2024
1 parent 1b7fb6d commit a1a568b
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 7 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ version: '3'
services:
pinchflat:
image: keglin/pinchflat:latest
environment:
# Set the timezone to your local timezone
- TZ=America/New_York
ports:
- '8945:8945'
volumes:
Expand All @@ -110,7 +113,9 @@ services:
```bash
# Be sure to replace /host/path/to/config and /host/path/to/downloads below with
# the paths to the directories you created in step 1
# Be sure to replace America/New_York with your local timezone
docker run \
-e TZ=America/New_York \
-p 8945:8945 \
-v /host/path/to/config:/config \
-v /host/path/to/downloads:/downloads \
Expand Down
3 changes: 2 additions & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ config :pinchflat,
basic_auth_username: "",
basic_auth_password: "",
expose_feed_endpoints: false,
file_watcher_poll_interval: 1000
file_watcher_poll_interval: 1000,
timezone: "UTC"

config :pinchflat, Pinchflat.Repo,
journal_mode: :wal,
Expand Down
3 changes: 2 additions & 1 deletion config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ if config_env() == :prod do
extras_directory: extras_path,
tmpfile_directory: Path.join([System.tmp_dir!(), "pinchflat", "data"]),
dns_cluster_query: System.get_env("DNS_CLUSTER_QUERY"),
expose_feed_endpoints: expose_feed_endpoints
expose_feed_endpoints: expose_feed_endpoints,
timezone: System.get_env("TIMEZONE") || System.get_env("TZ") || "UTC"

config :pinchflat, Pinchflat.Repo,
database: db_path,
Expand Down
8 changes: 8 additions & 0 deletions lib/pinchflat/media/media_query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ defmodule Pinchflat.Media.MediaQuery do
# Suffixes:
# - _for - the arg passed is an association record

# NOTE: that dyanmic query approach kinda rocked - should refactor in future

def new do
MediaItem
end
Expand Down Expand Up @@ -172,6 +174,12 @@ defmodule Pinchflat.Media.MediaQuery do
|> matching_source_title_regex()
end

def where_pending_or_downloaded(query) do
query
|> where_pending_download()
|> or_where([mi], not is_nil(mi.media_downloaded_at))
end

defp require_assoc(query, identifier) do
if has_named_binding?(query, identifier) do
query
Expand Down
13 changes: 13 additions & 0 deletions lib/pinchflat_web/components/custom_components/text_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,17 @@ defmodule PinchflatWeb.CustomComponents.TextComponents do
<span><%= @text %></span>
"""
end

@doc """
Renders a UTC datetime in the specified format and timezone
"""
attr :datetime, :any, required: true
attr :format, :string, default: "%Y-%m-%d %H:%M:%S"
attr :timezone, :string, default: Application.compile_env(:pinchflat, :timezone)

def datetime_in_zone(assigns) do
~H"""
<time><%= Calendar.strftime(Timex.Timezone.convert(@datetime, @timezone), @format) %></time>
"""
end
end
8 changes: 5 additions & 3 deletions lib/pinchflat_web/controllers/pages/page_controller.ex
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
defmodule PinchflatWeb.Pages.PageController do
alias Pinchflat.Media.MediaItem
use PinchflatWeb, :controller

alias Pinchflat.Repo
alias Pinchflat.Sources.Source
alias Pinchflat.Media.MediaItem
alias Pinchflat.Media.MediaQuery
alias Pinchflat.Profiles.MediaProfile

def home(conn, params) do
Expand All @@ -25,7 +24,10 @@ defmodule PinchflatWeb.Pages.PageController do
|> render(:home,
media_profile_count: Repo.aggregate(MediaProfile, :count, :id),
source_count: Repo.aggregate(Source, :count, :id),
media_item_count: Repo.aggregate(MediaItem, :count, :id)
media_item_count:
MediaQuery.new()
|> MediaQuery.with_media_downloaded_at()
|> Repo.aggregate(:count, :id)
)
end

Expand Down
110 changes: 110 additions & 0 deletions lib/pinchflat_web/controllers/pages/page_html/history_table_live.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
defmodule Pinchflat.Pages.HistoryTableLive do
use PinchflatWeb, :live_view
import Ecto.Query, warn: false

alias Pinchflat.Repo
alias Pinchflat.Media.MediaQuery
alias Pinchflat.Utils.NumberUtils
alias PinchflatWeb.CustomComponents.TextComponents

@limit 10

def render(%{records: []} = assigns) do
~H"""
<div class="mb-4 flex items-center">
<.icon_button icon_name="hero-arrow-path" class="h-10 w-10" phx-click="reload_page" />
<p class="ml-2">Nothing Here!</p>
</div>
"""
end

def render(assigns) do
~H"""
<div>
<span class="mb-4 flex items-center">
<.icon_button icon_name="hero-arrow-path" class="h-10 w-10" phx-click="reload_page" tooltip="Refresh" />
<span class="ml-2">Showing <%= length(@records) %> of <%= @total_record_count %></span>
</span>
<div class="max-w-full overflow-x-auto">
<.table rows={@records} table_class="text-white">
<:col :let={media_item} label="Title">
<.subtle_link href={~p"/sources/#{media_item.source_id}/media/#{media_item}"}>
<%= StringUtils.truncate(media_item.title, 35) %>
</.subtle_link>
</:col>
<:col :let={media_item} label="Upload Date">
<%= media_item.upload_date %>
</:col>
<:col :let={media_item} label="Indexed At">
<%= format_datetime(media_item.inserted_at) %>
</:col>
<:col :let={media_item} label="Downloaded At">
<%= format_datetime(media_item.media_downloaded_at) %>
</:col>
<:col :let={media_item} label="Source">
<.subtle_link href={~p"/sources/#{media_item.source_id}"}>
<%= StringUtils.truncate(media_item.source.custom_name, 35) %>
</.subtle_link>
</:col>
</.table>
</div>
<section class="flex justify-center mt-5">
<.live_pagination_controls page_number={@page} total_pages={@total_pages} />
</section>
</div>
"""
end

def mount(_params, _session, socket) do
page = 1
base_query = generate_base_query()
pagination_attrs = fetch_pagination_attributes(base_query, page)

{:ok, assign(socket, Map.merge(pagination_attrs, %{base_query: base_query}))}
end

def handle_event("page_change", %{"direction" => direction}, %{assigns: assigns} = socket) do
direction = if direction == "inc", do: 1, else: -1
new_page = assigns.page + direction
new_assigns = fetch_pagination_attributes(assigns.base_query, new_page)

{:noreply, assign(socket, new_assigns)}
end

def handle_event("reload_page", _params, %{assigns: assigns} = socket) do
new_assigns = fetch_pagination_attributes(assigns.base_query, assigns.page)

{:noreply, assign(socket, new_assigns)}
end

defp fetch_pagination_attributes(base_query, page) do
total_record_count = Repo.aggregate(base_query, :count, :id)
total_pages = max(ceil(total_record_count / @limit), 1)
page = NumberUtils.clamp(page, 1, total_pages)
records = fetch_records(base_query, page)

%{page: page, total_pages: total_pages, records: records, total_record_count: total_record_count}
end

defp fetch_records(base_query, page) do
offset = (page - 1) * @limit

base_query
|> limit(^@limit)
|> offset(^offset)
|> Repo.all()
|> Repo.preload(:source)
end

defp generate_base_query do
MediaQuery.new()
|> MediaQuery.where_pending_or_downloaded()
|> order_by(desc: :id)
end

defp format_datetime(nil), do: ""

defp format_datetime(datetime) do
TextComponents.datetime_in_zone(%{datetime: datetime, format: "%Y-%m-%d %H:%M"})
end
end
10 changes: 8 additions & 2 deletions lib/pinchflat_web/controllers/pages/page_html/home.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,17 @@
</div>
<div class="rounded-sm border px-7.5 py-6 shadow-default border-strokedark bg-boxdark">
<span class="mt-4 flex flex-col items-center justify-center">
<span class="text-md font-medium">Media Item(s)</span>
<span class="text-md font-medium">Downloaded Media</span>
<h4 class="text-title-md font-bold text-white">
<%= @media_item_count %>
</h4>
</span>
</div>
<span class="text-strokedark">I know this page isn't super useful yet, but give it time :&rpar;</span>
</div>

<div class="rounded-sm border shadow-default border-strokedark bg-boxdark mt-4 p-5">
<span class="text-2xl font-medium mb-4">History</span>
<section class="mt-6">
<%= live_render(@conn, Pinchflat.Pages.HistoryTableLive) %>
</section>
</div>
1 change: 1 addition & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ defmodule Pinchflat.MixProject do
{:plug_cowboy, "~> 2.5"},
{:oban, "~> 2.16"},
{:nimble_parsec, "~> 1.4"},
{:timex, "~> 3.0"},
{:mox, "~> 1.0", only: :test},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:credo_naming, "~> 2.1", only: [:dev, :test], runtime: false},
Expand Down
Loading

0 comments on commit a1a568b

Please sign in to comment.