keystone_ui-pages 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/builds/keystone_ui_pages/editor.js +22 -22
- data/app/controllers/keystone_ui/pages/manage/access_exceptions_controller.rb +19 -0
- data/app/controllers/keystone_ui/pages/manage/pages_controller.rb +19 -2
- data/app/controllers/keystone_ui/pages/pages_controller.rb +7 -1
- data/app/helpers/keystone_ui/pages/editor_helper.rb +3 -0
- data/app/javascript/keystone_ui_pages/AccessExceptionChoice.jsx +16 -0
- data/app/javascript/keystone_ui_pages/PageEditor.jsx +10 -2
- data/app/javascript/keystone_ui_pages/operations.js +2 -0
- data/app/models/keystone_ui/pages/page.rb +30 -0
- data/app/views/keystone_ui/pages/manage/pages/index.html.erb +31 -2
- data/app/views/keystone_ui/pages/manage/pages/new.html.erb +5 -0
- data/app/views/keystone_ui/pages/manage/pages/show.html.erb +1 -1
- data/config/routes.rb +4 -0
- data/db/migrate/20261019120000_add_access_to_keystone_ui_pages_pages.rb +8 -0
- data/db/migrate/20261019130000_add_archived_at_to_keystone_ui_pages_pages.rb +7 -0
- data/lib/keystone_ui/pages/version.rb +1 -1
- data/lib/keystone_ui/pages.rb +10 -2
- data/the_local/agents/keystone_ui-pages-develop.md +36 -8
- data/the_local/interface.yml +3 -0
- metadata +5 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KeystoneUi
|
|
4
|
+
module Pages
|
|
5
|
+
module Manage
|
|
6
|
+
class AccessExceptionsController < BaseController
|
|
7
|
+
include EditsPages
|
|
8
|
+
|
|
9
|
+
def update
|
|
10
|
+
if page.update(access_exception: params[:access_exception].presence)
|
|
11
|
+
shown
|
|
12
|
+
else
|
|
13
|
+
render json: { error: page.errors.full_messages.to_sentence }, status: :unprocessable_entity
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -7,7 +7,8 @@ module KeystoneUi
|
|
|
7
7
|
module Manage
|
|
8
8
|
class PagesController < BaseController
|
|
9
9
|
def index
|
|
10
|
-
@
|
|
10
|
+
@archived = params[:archived].present?
|
|
11
|
+
@pages = owned_pages.public_send(@archived ? :archived : :current).order(:name)
|
|
11
12
|
@printable = Printer.chrome.present?
|
|
12
13
|
end
|
|
13
14
|
|
|
@@ -15,7 +16,7 @@ module KeystoneUi
|
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def create
|
|
18
|
-
page = Page.create!(params.require(:page).permit(:name, :slug).merge(owner: page_owner))
|
|
19
|
+
page = Page.create!(params.require(:page).permit(:name, :slug, :place).merge(owner: page_owner))
|
|
19
20
|
redirect_to manage_page_path(page)
|
|
20
21
|
end
|
|
21
22
|
|
|
@@ -30,6 +31,22 @@ module KeystoneUi
|
|
|
30
31
|
redirect_to manage_page_path(page)
|
|
31
32
|
end
|
|
32
33
|
|
|
34
|
+
def unpublish
|
|
35
|
+
page = owned_pages.find(params[:id])
|
|
36
|
+
page.unpublish
|
|
37
|
+
redirect_to manage_page_path(page)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def archive
|
|
41
|
+
owned_pages.find(params[:id]).archive
|
|
42
|
+
redirect_to manage_pages_path
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def restore
|
|
46
|
+
owned_pages.find(params[:id]).restore
|
|
47
|
+
redirect_to manage_pages_path
|
|
48
|
+
end
|
|
49
|
+
|
|
33
50
|
private
|
|
34
51
|
|
|
35
52
|
def local_address?(address)
|
|
@@ -11,11 +11,17 @@ module KeystoneUi
|
|
|
11
11
|
def show
|
|
12
12
|
page = owned_pages.find_by(slug: params[:slug])
|
|
13
13
|
@version = page&.live_version
|
|
14
|
-
refuse if @version.nil? || !viewable?(page)
|
|
14
|
+
return refuse if @version.nil? || !viewable?(page)
|
|
15
|
+
|
|
16
|
+
@values = visitor_values(page)
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
private
|
|
18
20
|
|
|
21
|
+
def visitor_values(page)
|
|
22
|
+
send(KeystoneUi::Pages.values_method, page) if KeystoneUi::Pages.values_method
|
|
23
|
+
end
|
|
24
|
+
|
|
19
25
|
def viewable?(page)
|
|
20
26
|
return true unless KeystoneUi::Pages.view_check_method
|
|
21
27
|
|
|
@@ -23,6 +23,9 @@ module KeystoneUi
|
|
|
23
23
|
samples: Values.samples_for(page),
|
|
24
24
|
sample: chosen_sample(page),
|
|
25
25
|
samples_url: manage_page_sample_path(page),
|
|
26
|
+
access_exceptions: KeystoneUi::Pages.access_exceptions.invert.to_a,
|
|
27
|
+
access_exception: page.access_exception,
|
|
28
|
+
access_exception_url: manage_page_access_exception_path(page),
|
|
26
29
|
history_url: manage_page_versions_path(page),
|
|
27
30
|
undo_url: manage_page_undo_path(page),
|
|
28
31
|
redo_url: manage_page_redo_path(page),
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import Select from "keystone_ui-react/src/Select.jsx"
|
|
3
|
+
|
|
4
|
+
export default function AccessExceptionChoice({ exceptions, chosen, onChoose }) {
|
|
5
|
+
if (exceptions.length === 0) return null
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<label className="flex items-center gap-2 text-sm">
|
|
9
|
+
<span className="whitespace-nowrap">Access exception</span>
|
|
10
|
+
<Select defaultValue={chosen ?? ""} onChange={(event) => onChoose(event.target.value)} className="py-1">
|
|
11
|
+
<option value="">None</option>
|
|
12
|
+
{exceptions.map(([label, value]) => <option key={value} value={value}>{label}</option>)}
|
|
13
|
+
</Select>
|
|
14
|
+
</label>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -2,13 +2,14 @@ import React, { useEffect, useLayoutEffect, useRef, useState } from "react"
|
|
|
2
2
|
import { DragDropManager, Draggable, Droppable, KeyboardSensor, PointerSensor } from "@dnd-kit/dom"
|
|
3
3
|
import { Sortable } from "@dnd-kit/dom/sortable"
|
|
4
4
|
import Button from "keystone_ui-react/src/Button.jsx"
|
|
5
|
-
import { addColumn, addElement, addRow, addSection, arrange, bindField, chooseSample, duplicateNode, moveNode, removeNode, setField, showWhen, stepHistory } from "./operations"
|
|
5
|
+
import { addColumn, addElement, addRow, addSection, arrange, bindField, chooseAccessException, chooseSample, duplicateNode, moveNode, removeNode, setField, showWhen, stepHistory } from "./operations"
|
|
6
6
|
import LayoutPanel from "./LayoutPanel"
|
|
7
7
|
import DeviceWidth, { DEVICES } from "./DeviceWidth"
|
|
8
8
|
import SelectionToolbar from "./SelectionToolbar"
|
|
9
9
|
import ElementPalette from "./ElementPalette"
|
|
10
10
|
import SelectionPath from "./SelectionPath"
|
|
11
11
|
import SampleChoice from "./SampleChoice"
|
|
12
|
+
import AccessExceptionChoice from "./AccessExceptionChoice"
|
|
12
13
|
import ShowWhen from "./ShowWhen"
|
|
13
14
|
import ThemeMode from "./ThemeMode"
|
|
14
15
|
import LookChoice from "./LookChoice"
|
|
@@ -28,7 +29,7 @@ const innermost = (target) => NODES.map(([selector, kind]) => [target.closest(se
|
|
|
28
29
|
|
|
29
30
|
const PLACED_SENSORS = [PointerSensor.configure({ preventActivation: () => false }), KeyboardSensor]
|
|
30
31
|
|
|
31
|
-
export default function PageEditor({ name, publish_url, elements, canvas: drawn, document: saved, elements_url, sections_url, columns_url, rows_url, nodes_url, arrangements, defaults, shares, value_names, looks = [], samples = [], sample, samples_url, history_url, live_url, back_url, undo_url, redo_url, undoable: couldUndo, redoable: couldRedo, token }) {
|
|
32
|
+
export default function PageEditor({ name, publish_url, unpublish_url, elements, canvas: drawn, document: saved, elements_url, sections_url, columns_url, rows_url, nodes_url, arrangements, defaults, shares, value_names, looks = [], samples = [], sample, samples_url, access_exceptions = [], access_exception, access_exception_url, history_url, live_url, back_url, undo_url, redo_url, undoable: couldUndo, redoable: couldRedo, token }) {
|
|
32
33
|
const [canvas, setCanvas] = useState(drawn)
|
|
33
34
|
const [undoable, setUndoable] = useState(couldUndo)
|
|
34
35
|
const [redoable, setRedoable] = useState(couldRedo)
|
|
@@ -210,12 +211,19 @@ export default function PageEditor({ name, publish_url, elements, canvas: drawn,
|
|
|
210
211
|
<ThemeMode />
|
|
211
212
|
<LookChoice looks={looks} />
|
|
212
213
|
<SampleChoice samples={samples} chosen={sample} onChoose={(choice) => chooseSample(samples_url, token, choice).then(shown, refused)} />
|
|
214
|
+
<AccessExceptionChoice exceptions={access_exceptions} chosen={access_exception} onChoose={(choice) => chooseAccessException(access_exception_url, token, choice).then(shown, refused)} />
|
|
213
215
|
</div>
|
|
214
216
|
<div className="flex items-center gap-2">
|
|
215
217
|
<Button type="button" size="sm" variant="secondary" disabled={!undoable} title={undoable ? "Undo the last change" : "Nothing to undo"} onClick={() => stepHistory(undo_url, token).then(shown, refused)}>↶ Undo</Button>
|
|
216
218
|
<Button type="button" size="sm" variant="secondary" disabled={!redoable} title={redoable ? "Redo the change you undid" : "Nothing to redo"} onClick={() => stepHistory(redo_url, token).then(shown, refused)}>↷ Redo</Button>
|
|
217
219
|
{live_url && <a href={live_url} className="text-sm whitespace-nowrap hover:underline">View live</a>}
|
|
218
220
|
<a href={history_url} className="text-sm hover:underline">History</a>
|
|
221
|
+
{unpublish_url && (
|
|
222
|
+
<form method="post" action={unpublish_url}>
|
|
223
|
+
<input type="hidden" name="authenticity_token" value={token} />
|
|
224
|
+
<Button type="submit" size="sm" variant="secondary">Unpublish</Button>
|
|
225
|
+
</form>
|
|
226
|
+
)}
|
|
219
227
|
<form method="post" action={publish_url}>
|
|
220
228
|
<input type="hidden" name="authenticity_token" value={token} />
|
|
221
229
|
<Button type="submit" size="sm">Publish</Button>
|
|
@@ -27,6 +27,8 @@ export const bindField = (url, token, elementId, field, name, fallback) => sent(
|
|
|
27
27
|
|
|
28
28
|
export const chooseSample = (url, token, choice) => sent(url, token, "POST", { choice })
|
|
29
29
|
|
|
30
|
+
export const chooseAccessException = (url, token, accessException) => sent(url, token, "POST", { access_exception: accessException })
|
|
31
|
+
|
|
30
32
|
export const showWhen = (url, token, nodeId, name, equals) => sent(`${url}/${nodeId}/condition`, token, "POST", { name, equals })
|
|
31
33
|
|
|
32
34
|
export const stepHistory = (url, token) => sent(url, token, "POST")
|
|
@@ -14,9 +14,16 @@ module KeystoneUi
|
|
|
14
14
|
attribute :undo_history, :json, default: -> { [] }
|
|
15
15
|
attribute :undone_changes, :json, default: -> { [] }
|
|
16
16
|
|
|
17
|
+
scope :archived, -> { where.not(archived_at: nil) }
|
|
18
|
+
scope :current, -> { where(archived_at: nil) }
|
|
19
|
+
|
|
17
20
|
validates :name, :slug, presence: true
|
|
21
|
+
validates :place, inclusion: { in: -> { KeystoneUi::Pages.places.keys } }, allow_nil: true, if: -> { KeystoneUi::Pages.places.any? }
|
|
22
|
+
validates :access_exception, inclusion: { in: -> { KeystoneUi::Pages.access_exceptions.keys } }, allow_nil: true, if: -> { KeystoneUi::Pages.access_exceptions.any? }
|
|
18
23
|
|
|
19
24
|
def publish
|
|
25
|
+
return if archived_at
|
|
26
|
+
|
|
20
27
|
transaction do
|
|
21
28
|
live_version&.update!(status: :superseded)
|
|
22
29
|
versions.create!(number: next_number, document: document, status: :live)
|
|
@@ -43,6 +50,29 @@ module KeystoneUi
|
|
|
43
50
|
update!(document: undone_changes.last, undone_changes: undone_changes[0...-1], undo_history: undo_history + [ document ])
|
|
44
51
|
end
|
|
45
52
|
|
|
53
|
+
def unpublish
|
|
54
|
+
live_version&.update!(status: :superseded)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def archive
|
|
58
|
+
transaction do
|
|
59
|
+
unpublish
|
|
60
|
+
update!(archived_at: Time.current)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def restore
|
|
65
|
+
update!(archived_at: nil)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def state
|
|
69
|
+
return :archived if archived_at
|
|
70
|
+
return :published if live_version
|
|
71
|
+
return :unpublished if versions.exists?
|
|
72
|
+
|
|
73
|
+
:draft
|
|
74
|
+
end
|
|
75
|
+
|
|
46
76
|
def live_version
|
|
47
77
|
versions.find_by(status: :live)
|
|
48
78
|
end
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
<%= ui_page(max_width: :xl) do %>
|
|
2
|
-
<%= ui_page_header(title: "Pages") %>
|
|
2
|
+
<%= ui_page_header(title: @archived ? "Archived pages" : "Pages", action_url: (new_manage_page_path unless @archived), action_label: "Create") do |header| %>
|
|
3
|
+
<% header.action { ui_button(label: "Create", href: new_manage_page_path) } unless @archived %>
|
|
4
|
+
<% end %>
|
|
5
|
+
|
|
6
|
+
<p class="mb-4 text-sm">
|
|
7
|
+
<%= @archived ? link_to("Show current pages", manage_pages_path) : link_to("Show archived", manage_pages_path(archived: 1)) %>
|
|
8
|
+
</p>
|
|
3
9
|
|
|
4
10
|
<div class="ks-table overflow-x-auto">
|
|
5
11
|
<table class="relative min-w-full divide-y divide-gray-300 dark:divide-white/15">
|
|
@@ -8,6 +14,12 @@
|
|
|
8
14
|
<th class="ks-table-header ks-table-header-first text-left text-sm">Name</th>
|
|
9
15
|
<th class="ks-table-header ks-table-header-middle text-left text-sm">Status</th>
|
|
10
16
|
<th class="ks-table-header ks-table-header-middle text-left text-sm">Last published</th>
|
|
17
|
+
<% if KeystoneUi::Pages.places.any? %>
|
|
18
|
+
<th class="ks-table-header ks-table-header-middle text-left text-sm">Place</th>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% if KeystoneUi::Pages.access_exceptions.any? %>
|
|
21
|
+
<th class="ks-table-header ks-table-header-middle text-left text-sm">Access exception</th>
|
|
22
|
+
<% end %>
|
|
11
23
|
<th class="ks-table-header ks-table-header-last text-right text-sm"><span class="sr-only">Open</span></th>
|
|
12
24
|
</tr>
|
|
13
25
|
</thead>
|
|
@@ -16,8 +28,14 @@
|
|
|
16
28
|
<% live = page.live_version %>
|
|
17
29
|
<tr data-page="<%= page.slug %>">
|
|
18
30
|
<td class="ks-table-cell-first text-sm whitespace-nowrap"><%= page.name %></td>
|
|
19
|
-
<td class="ks-table-cell-middle text-sm whitespace-nowrap"><%= ui_badge(label:
|
|
31
|
+
<td class="ks-table-cell-middle text-sm whitespace-nowrap"><%= ui_badge(label: page.state.to_s.capitalize, variant: live ? :success : :neutral) %></td>
|
|
20
32
|
<td class="ks-table-cell-middle text-sm whitespace-nowrap"><%= live&.created_at&.to_date&.to_fs(:long) %></td>
|
|
33
|
+
<% if KeystoneUi::Pages.places.any? %>
|
|
34
|
+
<td data-access class="ks-table-cell-middle text-sm whitespace-nowrap"><%= KeystoneUi::Pages.places[page.place] %></td>
|
|
35
|
+
<% end %>
|
|
36
|
+
<% if KeystoneUi::Pages.access_exceptions.any? %>
|
|
37
|
+
<td data-access class="ks-table-cell-middle text-sm whitespace-nowrap"><%= KeystoneUi::Pages.access_exceptions[page.access_exception] %></td>
|
|
38
|
+
<% end %>
|
|
21
39
|
<td class="ks-table-cell-middle text-sm whitespace-nowrap text-right">
|
|
22
40
|
<%= link_to "Edit", manage_page_path(page) %>
|
|
23
41
|
<% if live %>
|
|
@@ -26,6 +44,17 @@
|
|
|
26
44
|
<%= link_to "PDF", manage_page_pdf_path(page), class: "ml-4" %>
|
|
27
45
|
<% end %>
|
|
28
46
|
<% end %>
|
|
47
|
+
<div class="ml-4 inline-block">
|
|
48
|
+
<% if page.archived_at %>
|
|
49
|
+
<%= ui_form(action: restore_manage_page_path(page), method: :post) do %>
|
|
50
|
+
<%= ui_button(label: "Restore", type: :submit, variant: :secondary, size: :sm) %>
|
|
51
|
+
<% end %>
|
|
52
|
+
<% else %>
|
|
53
|
+
<%= ui_form(action: archive_manage_page_path(page), method: :post) do %>
|
|
54
|
+
<%= ui_button(label: "Archive", type: :submit, variant: :secondary, size: :sm) %>
|
|
55
|
+
<% end %>
|
|
56
|
+
<% end %>
|
|
57
|
+
</div>
|
|
29
58
|
</td>
|
|
30
59
|
</tr>
|
|
31
60
|
<% end %>
|
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
<label class="ks-label mb-1">Address</label>
|
|
9
9
|
<%= ui_input(name: "page[slug]", placeholder: "e.g. pricing") %>
|
|
10
10
|
|
|
11
|
+
<% if KeystoneUi::Pages.places.any? %>
|
|
12
|
+
<label class="ks-label mb-1">Place</label>
|
|
13
|
+
<%= ui_select(name: "page[place]", options: KeystoneUi::Pages.places.invert.to_a) %>
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
11
16
|
<%= ui_button(label: "Create", type: :submit) %>
|
|
12
17
|
<% end %>
|
|
13
18
|
<% end %>
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
<% end %>
|
|
5
5
|
|
|
6
6
|
<div data-page-builder>
|
|
7
|
-
<%= react_ui("keystone_ui_pages/editor", editor_props(@page).merge(name: @page.name, publish_url: publish_manage_page_path(@page))) %>
|
|
7
|
+
<%= react_ui("keystone_ui_pages/editor", editor_props(@page).merge(name: @page.name, publish_url: publish_manage_page_path(@page), unpublish_url: (unpublish_manage_page_path(@page) if @page.live_version))) %>
|
|
8
8
|
</div>
|
data/config/routes.rb
CHANGED
|
@@ -4,6 +4,9 @@ KeystoneUi::Pages::Engine.routes.draw do
|
|
|
4
4
|
namespace :manage do
|
|
5
5
|
resources :pages, only: %i[index new create show] do
|
|
6
6
|
post :publish, on: :member
|
|
7
|
+
post :unpublish, on: :member
|
|
8
|
+
post :archive, on: :member
|
|
9
|
+
post :restore, on: :member
|
|
7
10
|
resources :elements, only: %i[create update] do
|
|
8
11
|
post :bind, on: :member
|
|
9
12
|
end
|
|
@@ -17,6 +20,7 @@ KeystoneUi::Pages::Engine.routes.draw do
|
|
|
17
20
|
end
|
|
18
21
|
resource :document, only: %i[update]
|
|
19
22
|
post :sample, to: "samples#update"
|
|
23
|
+
post :access_exception, to: "access_exceptions#update"
|
|
20
24
|
post :undo, to: "edit_history#undo"
|
|
21
25
|
post :redo, to: "edit_history#redo"
|
|
22
26
|
resource :live, only: %i[show]
|
data/lib/keystone_ui/pages.rb
CHANGED
|
@@ -9,8 +9,8 @@ require "keystone_ui/pages/engine"
|
|
|
9
9
|
module KeystoneUi
|
|
10
10
|
module Pages
|
|
11
11
|
class << self
|
|
12
|
-
attr_writer :base_controller, :layout, :editor_layout, :pdf_stylesheet
|
|
13
|
-
attr_accessor :edit_check_method, :view_check_method, :owner_method, :refusal_method, :chrome_path
|
|
12
|
+
attr_writer :base_controller, :layout, :editor_layout, :pdf_stylesheet, :places, :access_exceptions
|
|
13
|
+
attr_accessor :edit_check_method, :view_check_method, :values_method, :owner_method, :refusal_method, :chrome_path
|
|
14
14
|
|
|
15
15
|
def base_controller
|
|
16
16
|
@base_controller || "ActionController::Base"
|
|
@@ -27,6 +27,14 @@ module KeystoneUi
|
|
|
27
27
|
def pdf_stylesheet
|
|
28
28
|
@pdf_stylesheet || "tailwind.css"
|
|
29
29
|
end
|
|
30
|
+
|
|
31
|
+
def places
|
|
32
|
+
@places || {}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def access_exceptions
|
|
36
|
+
@access_exceptions || {}
|
|
37
|
+
end
|
|
30
38
|
end
|
|
31
39
|
|
|
32
40
|
def self.pdf(page, values: {})
|
|
@@ -46,14 +46,32 @@ inherit from the base controller, so define it there.
|
|
|
46
46
|
- `KeystoneUi::Pages.view_check_method = :may_view_page?` — a method taking the
|
|
47
47
|
page and returning true when the current visitor may see the published page
|
|
48
48
|
at `/pages/:slug`. Unset, every published page is shown.
|
|
49
|
+
- `KeystoneUi::Pages.places = { "marketing" => "Marketing site" }` — a hash of
|
|
50
|
+
the places a page can belong to, each stored value to the label editors see.
|
|
51
|
+
When it is not empty, the New page form offers them, a page with a place not
|
|
52
|
+
in it is refused, and the page list shows each page's place. The view check
|
|
53
|
+
reads it as `page.place`. Unset, pages have no place.
|
|
54
|
+
- `KeystoneUi::Pages.access_exceptions = { "public_preview" => "Public preview" }`
|
|
55
|
+
— a hash of the exceptions an editor can set on a page, each stored value to
|
|
56
|
+
its label. When it is not empty, the builder's top bar has an Access exception
|
|
57
|
+
choice that sets or clears one, an exception not in it is refused, and the page
|
|
58
|
+
list shows each page's exception. The view check reads it as
|
|
59
|
+
`page.access_exception`. Unset, the choice is not shown.
|
|
60
|
+
- `KeystoneUi::Pages.values_method = :page_values` — a method taking the page
|
|
61
|
+
and returning a hash of value names to values for the current visitor. The
|
|
62
|
+
engine calls it each time it draws a published page at `/pages/:slug`, so
|
|
63
|
+
bound fields and show-when conditions follow the visitor there. The drawing is
|
|
64
|
+
cached per version and per set of values, so no visitor gets a copy drawn for
|
|
65
|
+
other values. Unset, published pages draw with no values.
|
|
49
66
|
- `KeystoneUi::Pages.edit_check_method = :may_edit_pages?` — a method with no
|
|
50
67
|
arguments returning true when the current user may use the editor's screens:
|
|
51
68
|
the page list, the builder, View live, History and the PDF link. It runs
|
|
52
69
|
before every one of those requests. Unset, everyone may.
|
|
53
70
|
- `KeystoneUi::Pages.refusal_method = :refuse_page` — a method with no
|
|
54
71
|
arguments that renders the response when a request is refused: a failed view
|
|
55
|
-
or edit check, an unknown slug, or a page with no live version
|
|
56
|
-
|
|
72
|
+
or edit check, an unknown slug, or a page with no live version, which covers a
|
|
73
|
+
draft, an unpublished page and an archived page. Unset, the response is an
|
|
74
|
+
empty 404.
|
|
57
75
|
- `KeystoneUi::Pages.layout = "application"` — the host layout published pages
|
|
58
76
|
and View live are drawn in. Defaults to `"application"`.
|
|
59
77
|
- `KeystoneUi::Pages.editor_layout = "editor"` — the host layout the page
|
|
@@ -186,9 +204,10 @@ The catalog offers these Keystone UI components by default: `button`,
|
|
|
186
204
|
|
|
187
205
|
The drawing is kept in `Rails.cache` under the version and the values, so
|
|
188
206
|
the same version and values are drawn once. A page that uses host values
|
|
189
|
-
should be drawn this way
|
|
190
|
-
it with no values: bound fields
|
|
191
|
-
conditions on a value hide what they
|
|
207
|
+
should be drawn this way unless the host sets `values_method`, since without
|
|
208
|
+
it the published address `/pages/:slug` draws with no values: bound fields
|
|
209
|
+
show their fallback text there, and conditions on a value hide what they
|
|
210
|
+
guard unless they compare against blank.
|
|
192
211
|
|
|
193
212
|
6. To make a PDF:
|
|
194
213
|
|
|
@@ -254,9 +273,18 @@ The catalog offers these Keystone UI components by default: `button`,
|
|
|
254
273
|
`values:` passed to the helper and to PDFs all use the same names. The gem
|
|
255
274
|
turns symbol keys into strings, so either works, but the names must match.
|
|
256
275
|
- **The editor's page list** at `/pages/manage/pages` shows each page's name,
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
276
|
+
its state, and when it was last published, plus its place and access
|
|
277
|
+
exception when the host names any. Each row links to Edit and has an Archive
|
|
278
|
+
button, and a published page also links to View live and, when Chrome or
|
|
279
|
+
Chromium is found, to its PDF. Show archived lists archived pages instead,
|
|
280
|
+
each with a Restore button.
|
|
281
|
+
- **A page's state** is Draft before its first publish, Published while it has
|
|
282
|
+
a live version, Unpublished once that version is taken down, and Archived.
|
|
283
|
+
The builder's Unpublish button, shown next to Publish on a published page,
|
|
284
|
+
takes the live version down and keeps the page's history. Archiving takes the
|
|
285
|
+
live version down too and hides the page from the list. An archived page
|
|
286
|
+
cannot be published, and restoring it returns it to Draft or Unpublished,
|
|
287
|
+
never straight to Published. Visitors are refused every state but Published.
|
|
260
288
|
- **View live** draws the live version in `KeystoneUi::Pages.layout` with the
|
|
261
289
|
values of the sample chosen in the builder, behind the edit check. It is
|
|
262
290
|
linked from the page list and from the builder's top bar once the page is
|
data/the_local/interface.yml
CHANGED
|
@@ -9,6 +9,9 @@ develop:
|
|
|
9
9
|
- KeystoneUi::Pages.base_controller
|
|
10
10
|
- KeystoneUi::Pages.owner_method
|
|
11
11
|
- KeystoneUi::Pages.view_check_method
|
|
12
|
+
- KeystoneUi::Pages.places
|
|
13
|
+
- KeystoneUi::Pages.access_exceptions
|
|
14
|
+
- KeystoneUi::Pages.values_method
|
|
12
15
|
- KeystoneUi::Pages.edit_check_method
|
|
13
16
|
- KeystoneUi::Pages.refusal_method
|
|
14
17
|
- KeystoneUi::Pages.layout
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: keystone_ui-pages
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tyler Schneider
|
|
@@ -77,6 +77,7 @@ files:
|
|
|
77
77
|
- app/assets/builds/keystone_ui_pages/editor.js
|
|
78
78
|
- app/controllers/concerns/keystone_ui/pages/edits_pages.rb
|
|
79
79
|
- app/controllers/concerns/keystone_ui/pages/host_checks.rb
|
|
80
|
+
- app/controllers/keystone_ui/pages/manage/access_exceptions_controller.rb
|
|
80
81
|
- app/controllers/keystone_ui/pages/manage/base_controller.rb
|
|
81
82
|
- app/controllers/keystone_ui/pages/manage/columns_controller.rb
|
|
82
83
|
- app/controllers/keystone_ui/pages/manage/documents_controller.rb
|
|
@@ -94,6 +95,7 @@ files:
|
|
|
94
95
|
- app/helpers/keystone_ui/pages/drawing_helper.rb
|
|
95
96
|
- app/helpers/keystone_ui/pages/editor_helper.rb
|
|
96
97
|
- app/helpers/keystone_ui/pages/host_helper.rb
|
|
98
|
+
- app/javascript/keystone_ui_pages/AccessExceptionChoice.jsx
|
|
97
99
|
- app/javascript/keystone_ui_pages/DeviceWidth.jsx
|
|
98
100
|
- app/javascript/keystone_ui_pages/ElementFields.jsx
|
|
99
101
|
- app/javascript/keystone_ui_pages/ElementPalette.jsx
|
|
@@ -125,6 +127,8 @@ files:
|
|
|
125
127
|
- db/migrate/20261014120001_create_keystone_ui_pages_versions.rb
|
|
126
128
|
- db/migrate/20261015130000_create_keystone_ui_pages_pdfs.rb
|
|
127
129
|
- db/migrate/20261016120000_add_edit_history_to_keystone_ui_pages_pages.rb
|
|
130
|
+
- db/migrate/20261019120000_add_access_to_keystone_ui_pages_pages.rb
|
|
131
|
+
- db/migrate/20261019130000_add_archived_at_to_keystone_ui_pages_pages.rb
|
|
128
132
|
- lib/keystone_ui-pages.rb
|
|
129
133
|
- lib/keystone_ui/pages.rb
|
|
130
134
|
- lib/keystone_ui/pages/catalog.rb
|