Packages
phoenix_kit
1.7.145
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps β SaaS, social networks, ERP systems, marketplaces, and more
Current section
221 Versions
Jump to
Current section
221 Versions
Compare versions
15
files changed
+924
additions
-262
deletions
unknownCHANGELOG.md
File is too large to be displayed (100 KB limit).
| @@ -1,6 +1,6 @@ | |
| 1 1 | {<<"links">>,[{<<"GitHub">>,<<"https://github.com/BeamLabEU/phoenix_kit">>}]}. |
| 2 2 | {<<"name">>,<<"phoenix_kit">>}. |
| 3 | - {<<"version">>,<<"1.7.144">>}. |
| 3 | + {<<"version">>,<<"1.7.145">>}. |
| 4 4 | {<<"description">>, |
| 5 5 | <<65,32,102,111,117,110,100,97,116,105,111,110,32,102,111,114,32,98,117,105, |
| 6 6 | 108,100,105,110,103,32,69,108,105,120,105,114,32,80,104,111,101,110,105, |
| @@ -549,6 +549,7 @@ | |
| 549 549 | <<"lib/phoenix_kit/migrations/postgres/v124.ex">>, |
| 550 550 | <<"lib/phoenix_kit/migrations/postgres/v64.ex">>, |
| 551 551 | <<"lib/phoenix_kit/migrations/postgres/v93.ex">>, |
| 552 | + <<"lib/phoenix_kit/migrations/postgres/v133.ex">>, |
| 552 553 | <<"lib/phoenix_kit/migrations/postgres/v84.ex">>, |
| 553 554 | <<"lib/phoenix_kit/migrations/postgres/v73.ex">>, |
| 554 555 | <<"lib/phoenix_kit/migrations/postgres/v03.ex">>, |
| @@ -591,6 +592,7 @@ | |
| 591 592 | <<"lib/phoenix_kit/migrations/postgres/v123.ex">>, |
| 592 593 | <<"lib/phoenix_kit/migrations/postgres/v94.ex">>, |
| 593 594 | <<"lib/phoenix_kit/migrations/postgres/v63.ex">>, |
| 595 | + <<"lib/phoenix_kit/migrations/postgres/v134.ex">>, |
| 594 596 | <<"lib/phoenix_kit/migrations/postgres/v74.ex">>, |
| 595 597 | <<"lib/phoenix_kit/migrations/postgres/v83.ex">>, |
| 596 598 | <<"lib/phoenix_kit/migrations/postgres/v04.ex">>, |
| @@ -19,6 +19,20 @@ defmodule PhoenixKit.Modules.Storage.Folder do | |
| 19 19 | field :description, :string |
| 20 20 | field :color, :string, default: "default" |
| 21 21 | field :trashed_at, :utc_datetime |
| 22 | + # Folder hero-header customization. The cover (background) and logo (icon) |
| 23 | + # are media files living in the folder, excluded from its visible listing. |
| 24 | + # `header_size` is small/medium/large; the `header_show_*` flags toggle each |
| 25 | + # header element. All defaulted so existing folders render as before. |
| 26 | + field :cover_file_uuid, UUIDv7 |
| 27 | + field :logo_file_uuid, UUIDv7 |
| 28 | + field :header_size, :string, default: "medium" |
| 29 | + field :header_show_title, :boolean, default: true |
| 30 | + field :header_show_icon, :boolean, default: true |
| 31 | + field :header_show_creator, :boolean, default: true |
| 32 | + field :header_show_date, :boolean, default: true |
| 33 | + field :header_show_file_count, :boolean, default: true |
| 34 | + field :header_show_description, :boolean, default: true |
| 35 | + field :header_show_background, :boolean, default: true |
| 22 36 | |
| 23 37 | belongs_to :parent, __MODULE__, |
| 24 38 | foreign_key: :parent_uuid, |
| @@ -47,9 +61,27 @@ defmodule PhoenixKit.Modules.Storage.Folder do | |
| 47 61 | |
| 48 62 | def changeset(folder, attrs) do |
| 49 63 | folder |
| 50 | - |> cast(attrs, [:name, :description, :parent_uuid, :user_uuid, :color, :trashed_at]) |
| 64 | + |> cast(attrs, [ |
| 65 | + :name, |
| 66 | + :description, |
| 67 | + :parent_uuid, |
| 68 | + :user_uuid, |
| 69 | + :color, |
| 70 | + :trashed_at, |
| 71 | + :cover_file_uuid, |
| 72 | + :logo_file_uuid, |
| 73 | + :header_size, |
| 74 | + :header_show_title, |
| 75 | + :header_show_icon, |
| 76 | + :header_show_creator, |
| 77 | + :header_show_date, |
| 78 | + :header_show_file_count, |
| 79 | + :header_show_description, |
| 80 | + :header_show_background |
| 81 | + ]) |
| 51 82 | |> validate_required([:name]) |
| 52 83 | |> validate_inclusion(:color, @folder_colors) |
| 84 | + |> validate_inclusion(:header_size, ~w(small medium large)) |
| 53 85 | |> validate_length(:name, min: 1, max: 255) |
| 54 86 | |> validate_length(:description, max: 2000) |
| 55 87 | |> foreign_key_constraint(:parent_uuid) |
unknownlib/modules/storage/storage.ex
File is too large to be displayed (100 KB limit).
| @@ -12,50 +12,11 @@ | |
| 12 12 | title={gettext("Media Settings")} |
| 13 13 | subtitle={ |
| 14 14 | gettext( |
| 15 | - "Configure media storage buckets and file processing settings for your application" |
| 15 | + "Media is a core system module that is always enabled and cannot be disabled β it provides essential file management functionality across PhoenixKit. Configure its storage buckets and file processing settings here." |
| 16 16 | ) |
| 17 17 | } |
| 18 18 | /> |
| 19 19 | |
| 20 | - <%!-- Module Status Alert --%> |
| 21 | - <div class="alert alert-info mb-6"> |
| 22 | - <.icon name="hero-information-circle" class="w-5 h-5" /> |
| 23 | - <div> |
| 24 | - <h3 class="font-bold">{gettext("Core System Module")}</h3> |
| 25 | - <p class="text-sm"> |
| 26 | - {gettext("Media is a core system module that is always enabled and cannot be disabled.")} |
| 27 | - {gettext("It provides essential file management functionality across PhoenixKit.")} |
| 28 | - </p> |
| 29 | - </div> |
| 30 | - </div> |
| 31 | - |
| 32 | - <%!-- Repair Media Module Section --%> |
| 33 | - <div class="alert alert-warning mb-6"> |
| 34 | - <.icon name="hero-wrench-screwdriver" class="w-5 h-5" /> |
| 35 | - <div class="flex-1"> |
| 36 | - <h3 class="font-bold">{gettext("Media Module Repair")}</h3> |
| 37 | - <p class="text-sm"> |
| 38 | - {gettext( |
| 39 | - "If your media module isn't working correctly, use this to reset configuration to defaults." |
| 40 | - )} |
| 41 | - {gettext("This will NOT delete any uploaded files.")} |
| 42 | - </p> |
| 43 | - </div> |
| 44 | - <button |
| 45 | - phx-click="repair_storage_module" |
| 46 | - data-confirm={ |
| 47 | - gettext( |
| 48 | - "This will reset dimensions and settings to defaults, and create a local bucket if none exist. Your uploaded files will NOT be deleted. Continue?" |
| 49 | - ) |
| 50 | - } |
| 51 | - class="btn btn-warning btn-sm" |
| 52 | - > |
| 53 | - <.icon name="hero-wrench-screwdriver" class="w-4 h-4 mr-1" /> {gettext( |
| 54 | - "Repair Media Module" |
| 55 | - )} |
| 56 | - </button> |
| 57 | - </div> |
| 58 | - |
| 59 20 | <%!-- System Dependencies Check --%> |
| 60 21 | <%= if match?({:error, :not_installed}, @imagemagick_status) do %> |
| 61 22 | <div class="alert alert-error mb-6"> |
| @@ -503,122 +464,109 @@ | |
| 503 464 | <%!-- Quick Actions --%> |
| 504 465 | <div class="divider">{gettext("Quick Actions")}</div> |
| 505 466 | |
| 467 | + <%!-- |
| 468 | + Each action is wrapped in a daisyUI tooltip (rather than putting the |
| 469 | + tooltip on the button) so the hover description also works on the |
| 470 | + disabled "Media Stats" button β a disabled button has |
| 471 | + `pointer-events: none` and would otherwise swallow hover. Each button |
| 472 | + also carries a trailing info icon as the visible "what does this do?" |
| 473 | + affordance. |
| 474 | + --%> |
| 506 475 | <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> |
| 507 | - <.link |
| 508 | - navigate={PhoenixKit.Utils.Routes.path("/admin/settings/media/dimensions")} |
| 509 | - class="btn btn-outline" |
| 476 | + <%!-- Manage Dimensions --%> |
| 477 | + <div |
| 478 | + class="tooltip tooltip-bottom" |
| 479 | + data-tip={ |
| 480 | + gettext( |
| 481 | + "Create and edit the image/video size presets used to generate variants of uploaded media." |
| 482 | + ) |
| 483 | + } |
| 510 484 | > |
| 511 | - <.icon name="hero-photo" class="w-4 h-4 mr-2" /> {gettext("Manage Dimensions")} |
| 512 | - </.link> |
| 485 | + <.link |
| 486 | + navigate={PhoenixKit.Utils.Routes.path("/admin/settings/media/dimensions")} |
| 487 | + class="btn btn-outline w-full" |
| 488 | + > |
| 489 | + <.icon name="hero-photo" class="w-4 h-4 mr-2" /> {gettext("Manage Dimensions")} |
| 490 | + <.icon name="hero-information-circle" class="w-4 h-4 ml-1 opacity-50" /> |
| 491 | + </.link> |
| 492 | + </div> |
| 513 493 | |
| 514 | - <button class="btn btn-outline" disabled> |
| 515 | - <.icon name="hero-chart-bar" class="w-4 h-4 mr-2" /> {gettext("Media Stats")} |
| 516 | - <span class="badge badge-xs ml-1">{gettext("Soon")}</span> |
| 517 | - </button> |
| 518 | - |
| 519 | - <.link |
| 520 | - navigate={PhoenixKit.Utils.Routes.path("/admin/settings/media/health")} |
| 521 | - class="btn btn-outline" |
| 494 | + <%!-- Media Stats (coming soon) --%> |
| 495 | + <div |
| 496 | + class="tooltip tooltip-bottom" |
| 497 | + data-tip={gettext("View storage usage and media statistics. Coming soon.")} |
| 522 498 | > |
| 523 | - <.icon name="hero-arrow-path" class="w-4 h-4 mr-2" /> {gettext("Sync Files")} |
| 524 | - </.link> |
| 525 | - </div> |
| 526 | - </div> |
| 527 | - </div> |
| 528 | - |
| 529 | - <%!-- Coming Soon Features --%> |
| 530 | - <div class="card bg-base-100 shadow-xl border-2 border-dashed border-base-300"> |
| 531 | - <div class="card-body"> |
| 532 | - <h2 class="card-title text-2xl mb-4"> |
| 533 | - <.icon name="hero-rocket-launch" class="w-6 h-6 mr-2" /> {gettext( |
| 534 | - "Advanced Features Coming Soon" |
| 535 | - )} |
| 536 | - </h2> |
| 537 | - |
| 538 | - <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
| 539 | - <%!-- Multi-Location Media Storage --%> |
| 540 | - <div class="border border-base-300 rounded-lg p-4"> |
| 541 | - <div class="flex items-start gap-3"> |
| 542 | - <div class="text-3xl">ποΈ</div> |
| 543 | - <div> |
| 544 | - <h3 class="font-bold mb-1">{gettext("Multi-Location Media Storage")}</h3> |
| 545 | - <p class="text-sm text-base-content/70"> |
| 546 | - {gettext("Store files across 1-5 redundant locations with automatic failover")} |
| 547 | - </p> |
| 548 | - </div> |
| 549 | - </div> |
| 499 | + <button class="btn btn-outline w-full" disabled> |
| 500 | + <.icon name="hero-chart-bar" class="w-4 h-4 mr-2" /> {gettext("Media Stats")} |
| 501 | + <span class="badge badge-xs ml-1">{gettext("Soon")}</span> |
| 502 | + <.icon name="hero-information-circle" class="w-4 h-4 ml-1 opacity-50" /> |
| 503 | + </button> |
| 550 504 | </div> |
| 551 505 | |
| 552 | - <%!-- S3 Integration --%> |
| 553 | - <div class="border border-base-300 rounded-lg p-4"> |
| 554 | - <div class="flex items-start gap-3"> |
| 555 | - <div class="text-3xl">βοΈ</div> |
| 556 | - <div> |
| 557 | - <h3 class="font-bold mb-1">{gettext("AWS S3 Integration")}</h3> |
| 558 | - <p class="text-sm text-base-content/70"> |
| 559 | - {gettext("Store files in Amazon S3 buckets for cloud redundancy")} |
| 560 | - </p> |
| 561 | - </div> |
| 562 | - </div> |
| 506 | + <%!-- Sync Files / Health dashboard --%> |
| 507 | + <div |
| 508 | + class="tooltip tooltip-bottom" |
| 509 | + data-tip={ |
| 510 | + gettext( |
| 511 | + "Open the media health dashboard to check file redundancy and re-sync files across storage locations." |
| 512 | + ) |
| 513 | + } |
| 514 | + > |
| 515 | + <.link |
| 516 | + navigate={PhoenixKit.Utils.Routes.path("/admin/settings/media/health")} |
| 517 | + class="btn btn-outline w-full" |
| 518 | + > |
| 519 | + <.icon name="hero-arrow-path" class="w-4 h-4 mr-2" /> {gettext("Sync Files")} |
| 520 | + <.icon name="hero-information-circle" class="w-4 h-4 ml-1 opacity-50" /> |
| 521 | + </.link> |
| 563 522 | </div> |
| 564 523 | |
| 565 | - <%!-- Remote Servers --%> |
| 566 | - <div class="border border-base-300 rounded-lg p-4"> |
| 567 | - <div class="flex items-start gap-3"> |
| 568 | - <div class="text-3xl">π₯οΈ</div> |
| 569 | - <div> |
| 570 | - <h3 class="font-bold mb-1">{gettext("Remote Servers")}</h3> |
| 571 | - <p class="text-sm text-base-content/70"> |
| 572 | - {gettext("Distribute files across multiple remote servers and datacenters")} |
| 573 | - </p> |
| 574 | - </div> |
| 575 | - </div> |
| 524 | + <%!-- Find Orphaned Files --%> |
| 525 | + <div |
| 526 | + class="tooltip tooltip-bottom" |
| 527 | + data-tip={ |
| 528 | + gettext( |
| 529 | + "Browse files no longer attached to any record (orphaned media) so you can review or delete them." |
| 530 | + ) |
| 531 | + } |
| 532 | + > |
| 533 | + <.link |
| 534 | + navigate={PhoenixKit.Utils.Routes.path("/admin/media") <> "?orphaned=1"} |
| 535 | + class="btn btn-outline w-full" |
| 536 | + > |
| 537 | + <.icon name="hero-funnel" class="w-4 h-4 mr-2" /> {gettext("Find Orphaned Files")} |
| 538 | + <.icon name="hero-information-circle" class="w-4 h-4 ml-1 opacity-50" /> |
| 539 | + </.link> |
| 576 540 | </div> |
| 577 541 | |
| 578 | - <%!-- Admin Dashboard --%> |
| 579 | - <div class="border border-base-300 rounded-lg p-4"> |
| 580 | - <div class="flex items-start gap-3"> |
| 581 | - <div class="text-3xl">π</div> |
| 582 | - <div> |
| 583 | - <h3 class="font-bold mb-1">{gettext("Admin Dashboard")}</h3> |
| 584 | - <p class="text-sm text-base-content/70"> |
| 585 | - {gettext("Monitor media health, locations, and file distribution")} |
| 586 | - </p> |
| 587 | - </div> |
| 588 | - </div> |
| 589 | - </div> |
| 590 | - |
| 591 | - <%!-- File Tracking --%> |
| 592 | - <div class="border border-base-300 rounded-lg p-4"> |
| 593 | - <div class="flex items-start gap-3"> |
| 594 | - <div class="text-3xl">π</div> |
| 595 | - <div> |
| 596 | - <h3 class="font-bold mb-1">{gettext("File Tracking")}</h3> |
| 597 | - <p class="text-sm text-base-content/70"> |
| 598 | - {gettext("PostgreSQL-based file registry with location tracking")} |
| 599 | - </p> |
| 600 | - </div> |
| 601 | - </div> |
| 602 | - </div> |
| 603 | - |
| 604 | - <%!-- Automatic Failover --%> |
| 605 | - <div class="border border-base-300 rounded-lg p-4"> |
| 606 | - <div class="flex items-start gap-3"> |
| 607 | - <div class="text-3xl">π</div> |
| 608 | - <div> |
| 609 | - <h3 class="font-bold mb-1">{gettext("Automatic Failover")}</h3> |
| 610 | - <p class="text-sm text-base-content/70"> |
| 611 | - {gettext("Seamless file retrieval even when media locations fail")} |
| 612 | - </p> |
| 613 | - </div> |
| 614 | - </div> |
| 542 | + <%!-- Repair Media Module --%> |
| 543 | + <div |
| 544 | + class="tooltip tooltip-bottom" |
| 545 | + data-tip={ |
| 546 | + gettext( |
| 547 | + "Reset dimensions and settings to defaults and create a local bucket if none exist. Does not delete uploaded files." |
| 548 | + ) |
| 549 | + } |
| 550 | + > |
| 551 | + <button |
| 552 | + phx-click="repair_storage_module" |
| 553 | + data-confirm={ |
| 554 | + gettext( |
| 555 | + "This will reset dimensions and settings to defaults, and create a local bucket if none exist. Your uploaded files will NOT be deleted. Continue?" |
| 556 | + ) |
| 557 | + } |
| 558 | + class="btn btn-outline btn-warning w-full" |
| 559 | + > |
| 560 | + <.icon name="hero-wrench-screwdriver" class="w-4 h-4 mr-2" /> {gettext( |
| 561 | + "Repair Media Module" |
| 562 | + )} |
| 563 | + <.icon name="hero-information-circle" class="w-4 h-4 ml-1 opacity-50" /> |
| 564 | + </button> |
| 615 565 | </div> |
| 616 566 | </div> |
| 617 567 | </div> |
| 618 568 | </div> |
| 619 569 | |
| 620 | - <%!-- Upload Test Section --%> |
| 621 | - |
| 622 570 | <%!-- Help Section --%> |
| 623 571 | <div class="alert mt-6"> |
| 624 572 | <.icon name="hero-light-bulb" class="w-5 h-5" /> |
Loading more filesβ¦