Skip to content

Commit

Permalink
:entity/admission-policy, hookless persisted-attr view
Browse files Browse the repository at this point in the history
 - :entity/admission-policy for teams and boards (replaces :board/registration-open?)
 - use a view for entity.ui/persisted-attr instead of a hook, more flexible
  • Loading branch information
mhuebert committed Jan 18, 2024
1 parent 30b35c8 commit fcf7a1c
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 105 deletions.
49 changes: 28 additions & 21 deletions src/sb/app.cljc
Expand Up @@ -29,24 +29,31 @@
(def client-endpoints (t/read (shadow.resource/inline "public/js/sparkboard.views.transit.json"))))

(def global-field-meta
{:string {:view field.ui/text-field}
:http/url {:view field.ui/text-field}
:boolean {:view field.ui/checkbox-field}
:project/badges {:view field.ui/badges-field}
:prose/as-map {:view field.ui/prose-field}
:entity/tags {:view field.ui/tags-field}
:account/email {:props {:type "email"
:placeholder (t :tr/email)}
:validators [form.ui/email-validator]}
:account/password {:view field.ui/text-field
:props {:type "password"
:placeholder (t :tr/password)}
:validators [(io/min-length 8)]}
:entity/title {:validators [(io/min-length 3)]}
:field/options {:view field.admin-ui/options-editor}
:entity/domain-name {:view domain.ui/domain-field}
:entity/video {:view field.ui/video-field}
:entity/fields {:view field.admin-ui/fields-editor}
:entity/member-tags {:view field.admin-ui/tags-editor}
:entity/field-entries {:view field.ui/entries-field}
:asset/as-map {:view field.ui/image-field}})
{:string {:view field.ui/text-field}
:http/url {:view field.ui/text-field}
:boolean {:view field.ui/checkbox-field}
:project/badges {:view field.ui/badges-field}
:prose/as-map {:view field.ui/prose-field}
:entity/tags {:view field.ui/tags-field}
:account/email {:props {:type "email"
:placeholder (t :tr/email)}
:validators [form.ui/email-validator]}
:account/password {:view field.ui/text-field
:props {:type "password"
:placeholder (t :tr/password)}
:validators [(io/min-length 8)]}
:entity/title {:validators [(io/min-length 3)]}
:field/options {:view field.admin-ui/options-editor}
:entity/domain-name {:view domain.ui/domain-field}
:entity/video {:view field.ui/video-field}
:entity/fields {:view field.admin-ui/fields-editor}
:entity/member-tags {:view field.admin-ui/tags-editor}
:entity/field-entries {:view field.ui/entries-field}
:entity/admission-policy {:view field.ui/select-field
:props {:field/wrap keyword
:field/unwrap #(subs (str %) 1)
:field/options [{:field-option/value :admission-policy/open
:field-option/label (t :tr/anyone-may-join)}
{:field-option/value :admission-policy/invite-only
:field-option/label (t :tr/invite-only)}]}}
:asset/as-map {:view field.ui/image-field}})
9 changes: 4 additions & 5 deletions src/sb/app/board/admin_ui.cljc
@@ -1,7 +1,7 @@
(ns sb.app.board.admin-ui
(:require [inside-out.forms :as io]
[sb.app.board.data :as data]
[sb.app.entity.ui :as entity.ui :refer [use-persisted-attr]]
[sb.app.entity.ui :as entity.ui :refer [persisted-attr]]
[sb.app.views.header :as header]
[sb.app.views.radix :as radix]
[sb.app.views.ui :as ui]
Expand All @@ -24,8 +24,8 @@
(apply concat)
(into #{}))
use-persisted (fn [attr & [props]]
(use-persisted-attr board attr (merge {:field/can-edit? true
:field/color-list colors} props)))]
(persisted-attr board attr (merge {:field/can-edit? true
:field/color-list colors} props)))]

[:<>
(header/entity board nil)
Expand Down Expand Up @@ -54,7 +54,7 @@

[:div.field-label (t :tr/registration)]
[:div.flex-v.gap-4
(use-persisted :board/registration-open?)
(use-persisted :entity/admission-policy)
(use-persisted :board/registration-url-override)
(use-persisted :board/registration-page-message)
(use-persisted :board/invite-email-text)]
Expand All @@ -69,7 +69,6 @@
;; Registration
;; - :board/registration-invitation-email-text
;; - :board/registration-newsletter-field?
;; - :board/registration-open?
;; - :board/registration-message
;; - :board/registration-url-override
;; - :board/registration-codes
Expand Down
9 changes: 4 additions & 5 deletions src/sb/app/board/data.cljc
Expand Up @@ -33,9 +33,7 @@
:board/invite-email-text {:hint "Text of email sent when inviting a user to a board."
s- :string},
:board/registration-newsletter-field? {:hint "During registration, request permission to send the user an email newsletter"
s- :boolean},
:board/registration-open? {:hint "Allows new registrations via the registration page. Does not affect invitations."
s- :boolean},
s- :boolean},,
:board/registration-page-message {:hint "Content displayed on registration screen (before user chooses provider / enters email)"
s- :prose/as-map},
:board/registration-url-override {:hint "URL to redirect user for registration (replaces the Sparkboard registration page, admins are expected to invite users)",
Expand All @@ -52,7 +50,7 @@
:entity/kind
:entity/parent

:board/registration-open?
:entity/admission-policy

(? :image/avatar)
(? :image/logo-large)
Expand Down Expand Up @@ -111,7 +109,7 @@
:entity/member-tags
:entity/member-fields
:entity/project-fields
:board/registration-open?
:entity/admission-policy
{:entity/parent [~@entity.data/listing-fields :org/show-org-tab?]}]
board-id)]
(merge board {:membership/roles roles})
Expand Down Expand Up @@ -195,6 +193,7 @@
(u/timed `settings
(some->
(q/pull `[~@entity.data/listing-fields
:entity/admission-policy
{:image/background [:entity/id]}
{:entity/domain-name [:domain-name/name]}
:entity/member-tags
Expand Down
30 changes: 16 additions & 14 deletions src/sb/app/entity/ui.cljc
Expand Up @@ -42,20 +42,22 @@
(when-some [init (:init m)] (reset! ?field init))
?field)

(defn use-persisted-attr [e a & {:as props}]
#?(:cljs
(let [persisted-value (get e a)
view (or (:view props) (-> a io/global-meta :view))
make-field (or (:make-?field (meta view))
(fn [init _props] (io/field :init init)))
?field (h/use-memo #(doto (make-field persisted-value props)
(add-meta! {:attribute a
:db/id (sch/wrap-id e)
:field/label (:field/label props)
:field/persisted? true}))
;; create a new field when the persisted value changes
(h/use-deps persisted-value))]
(view-field ?field (assoc props :view view)))))
(ui/defview persisted-attr [e a props]
(let [persisted-value (get e a)
view (or (:view props) (-> a io/global-meta :view))
make-field (or (:make-?field (meta view))
(fn [init _props] (io/field :init init)))
?field (h/use-memo #(doto (make-field persisted-value props)
(add-meta! {:attribute a
:db/id (sch/wrap-id e)
:field/label (:field/label props)
:field/persisted? true}))
;; create a new field when the persisted value changes
;; TODO - instead of creating a new field, reset :init if possible.
;; this will break one place where we currently rely on recognizing a new field
;; (image-field)
(h/use-deps persisted-value))]
(view-field ?field (assoc props :view view))))

#?(:cljs
(defn href [{:as e :entity/keys [kind id]} key]
Expand Down
39 changes: 23 additions & 16 deletions src/sb/app/field/ui.cljc
Expand Up @@ -289,25 +289,31 @@
{:style (color/color-pair color)}
label]))

(ui/defview select-field [?field {:as props :field/keys [label
(ui/defview select-field [?field {:as props :field/keys [wrap
unwrap
label
options
can-edit?]}]
can-edit?]
:or {unwrap identity
wrap identity}}]
[:div.field-wrapper
(form.ui/show-label ?field label)
(if can-edit?
[radix/select-menu (-> (form.ui/?field-props ?field (merge {:field/event->value identity}
props))
(set/rename-keys {:on-change :on-value-change})
(assoc :on-value-change (fn [v]
(reset! ?field v)
(entity.data/maybe-save-field ?field))
:field/can-edit? (:field/can-edit? props)
:field/options (->> options
(map (fn [{:field-option/keys [label value color]}]
{:text label
:value value}))
doall)))]
(with-messages-popover ?field
[radix/select-menu (-> (form.ui/?field-props ?field (merge {:field/event->value identity}
props))
(set/rename-keys {:on-change :on-value-change})
(assoc :on-value-change (fn [v]
(reset! ?field (wrap v))
(entity.data/maybe-save-field ?field))
:field/can-edit? (:field/can-edit? props)
:field/options (->> options
(map (fn [{:as opt :field-option/keys [label value color]}]
{:text label
:value (unwrap value)}))
doall)))])
[show-select-value props @?field])

(when (:loading? ?field)
[:div.loading-bar.absolute.bottom-0.left-0.right-0 {:class "h-[3px]"}])])

Expand Down Expand Up @@ -586,9 +592,10 @@
img)))

(ui/defview images-field [?images {:as props :field/keys [label can-edit?]}]
(let [!?current (h/use-state-with-deps (first ?images) [?images])
(let [hook-deps (h/use-deps (:init ?images))
!?current (h/use-state-with-deps (first ?images) hook-deps)
use-order (ui/use-orderable-parent ?images {:axis :x})
[selected-url loading?] (ui/use-last-loaded (some-> @!?current ('?id) deref (asset.ui/asset-src :card)) [?images])]
[selected-url loading?] (ui/use-last-loaded (some-> @!?current ('?id) deref (asset.ui/asset-src :card)) hook-deps)]
[:div.field-wrapper
(form.ui/show-label ?images label)
(when selected-url
Expand Down
12 changes: 6 additions & 6 deletions src/sb/app/membership/ui.cljc
Expand Up @@ -32,7 +32,7 @@
(when (:image/avatar account) [ui/avatar {:size 20} account])
[:div.flex-v.gap-2
[:h1.font-medium.text-2xl.flex-auto.flex.items-center.mt-2 (-> membership :membership/member :account/display-name)]
(entity.ui/use-persisted-attr membership :entity/tags field-params)]
[entity.ui/persisted-attr membership :entity/tags field-params]]

[:div.flex.px-1.rounded-bl-lg.border-b.border-l.absolute.top-0.right-0
dev-panel
Expand All @@ -52,11 +52,11 @@
[radix/dialog-close
[:div.modal-title-icon [icons/close]]]]]]
[:div.px-body.flex-v.gap-6
(entity.ui/use-persisted-attr membership
:entity/field-entries
{:entity/fields (->> membership :membership/entity :entity/member-fields)
:membership/roles roles
:field/can-edit? can-edit?})]]))
[entity.ui/persisted-attr membership
:entity/field-entries
{:entity/fields (->> membership :membership/entity :entity/member-fields)
:membership/roles roles
:field/can-edit? can-edit?}]]]))

(defn show-tag [{:keys [tag/label tag/color] :or {color "#dddddd"}}]
[:div.tag-md
Expand Down
2 changes: 1 addition & 1 deletion src/sb/app/org/admin_ui.cljc
Expand Up @@ -11,7 +11,7 @@
[{:as params :keys [org-id]}]
(let [org (data/settings params)
use-attr (fn [attr & [props]]
(entity.ui/use-persisted-attr org attr (merge {:field/can-edit? true} props)))]
(entity.ui/persisted-attr org attr (merge {:field/can-edit? true} props)))]
[:<>
(header/entity org nil)
[:div {:class form.ui/form-classes}
Expand Down
11 changes: 7 additions & 4 deletions src/sb/app/project/data.cljc
Expand Up @@ -24,8 +24,6 @@

{:project/open-requests {:doc "Currently active requests for help"
s- [:sequential :request/map]},
:project/team-complete? {:doc "Project team marked sufficient"
s- :boolean}
:project/community-actions {s- [:sequential :community-action/as-map]}
:project/approved? {:doc "Set by an admin when :board/new-projects-require-approval? is enabled. Unapproved projects are hidden."
s- :boolean}
Expand All @@ -34,6 +32,10 @@
:project/number {:doc "Number assigned to a project by its board (stored as text because may contain annotations)",
:todo "This could be stored in the board entity, a map of {project, number}, so that projects may participate in multiple boards"
s- :string}
:entity/admission-policy {:doc "A policy for who may join a team."
s- [:enum
:admission-policy/open
:admission-policy/invite-only]}
:project/admin-description {:doc "A description field only writable by an admin"
s- :prose/as-map}
:entity/archived? {:doc "Marks a project inactive, hidden."
Expand All @@ -46,6 +48,7 @@
:entity/parent
:entity/title
:entity/created-at
:entity/admission-policy
(? :entity/uploads)
(? :entity/updated-at)
(? :entity/draft?)
Expand All @@ -65,8 +68,7 @@
(? :project/admin-description)
(? :project/sticky?)
(? :project/open-requests)
(? :entity/description)
(? :project/team-complete?)]
(? :entity/description)]
}
:community-action/as-map {s- [:map-of
:community-action/label
Expand All @@ -88,6 +90,7 @@
:entity/kind
:entity/title
:entity/description
:entity/admission-policy
{:entity/video [:video/url]}
{:project/badges [:badge/label
:badge/color]}
Expand Down

0 comments on commit fcf7a1c

Please sign in to comment.