diff --git a/.vscode/settings.json b/.vscode/settings.json index 4614872..4b9d217 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,6 +20,7 @@ "titleBar.activeBackground": "#8d5eb7", "titleBar.activeForeground": "#e7e7e7", "titleBar.inactiveBackground": "#8d5eb799", - "titleBar.inactiveForeground": "#e7e7e799" + "titleBar.inactiveForeground": "#e7e7e799", + "statusBar.background": "#8d5eb7" } } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 88de519..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,110 +0,0 @@ -# Contributing - -We welcome contributions! - -## License - -By contributing your code to Panda CMS you grant Panda Software Limited a non-exclusive, irrevocable, worldwide, royalty-free, sublicenseable, transferable license under all of Your relevant intellectual property rights (including copyright, patent, and any other rights), to use, copy, prepare derivative works of, distribute and publicly perform and display the Contributions on any licensing terms, including without limitation: (a) open source licenses like the MIT or BSD licenses; and (b) binary, proprietary, or commercial licenses. Except for the licenses granted herein, You reserve all right, title, and interest in and to the Contribution. - -You confirm that you are able to grant us these rights. You represent that You are legally entitled to grant the above license. If Your employer has rights to intellectual property that You create, You represent that You have received permission to make the Contributions on behalf of that employer, or that Your employer has waived such rights for the Contributions. - -You represent that the Contributions are Your original works of authorship, and to Your knowledge, no other person claims, or has the right to claim, any right in any invention or patent related to the Contributions. You also represent that You are not legally obligated, whether by entering into an agreement or otherwise, in any way that conflicts with the terms of this license. - -Panda Software Limited acknowledges that, except as explicitly described in this Agreement, any Contribution which you provide is on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -## Developing - -Run the following command and ensure your Gemfile is setup as follows: - -``` -bundle config set panda_cms.local PATH_TO_PANDA_CMS_DIRECTORY -``` - -```ruby -gem "panda_cms", github: "pandacms/panda_cms", branch: "main" -``` - -Alternatively, you may want to use a path to a folder on disk in the `Gemfile` itself: - -```ruby -gem "panda_cms", path: "../panda_cms" -``` - -## Assets - -Whilst developing, you'll likely want to run the task `rake panda_cms:assets:watch_admin` to ensure your assets are updated. When you're done, run `rake panda_cms:assets:compile`. - -## Branching - -When creating new branches, please use the following format: `prefix/name-of-branch`. Prefixes we use are: - -* `bugfix` - fixes to bugs -* `feature` - new features or functionality -* `hotfix` - quick fixes, such as text or UI changes, that aren't part of a larger bugfix -* `docs` - documentation improvements (that aren't part of another update) -* `config` - configuration changes -* `dep` – dependency updates, e.g. gem updates or similar -* `release` - a new release of the gem -* `ux` - frontend changes that do not fit into the categories above -* `devex` - developer experience (e.g. IDEs, scripts, etc.) - -If available, include the ID of the Github issue in the branch, e.g. `bugfix/123-correct-timezones-on-page-edit` - -Here's an example of a PR which follows these guidelines: https://github.com/pandacms/panda_cms/pull/5 - -## Lefthook - -We use [Lefthook](https://github.com/evilmartians/lefthook) for running pre-commit hooks. You can install this using: - -```bash -lefthook install -``` - -## Tests - -To setup tests, from the `panda_cms/spec/dummy` directory, run: - -```bash -RAILS_ENV=test rails db:create -RAILS_ENV=test rails db:schema:load -``` - -Then, for test runs, from the `panda_cms` directory, run: - -```bash -bundle exec rspec -``` - -System tests are run using `rack_test`, or for JavaScript, `selenium_chrome_headless`. This will run Chrome headlessly (without the browser window visible), and save failure screenshots to `spec/dummy/tmp/capybara`. If you want to see the browser (using the `selenium_chrome` driver), prefix your commands with `SHOW_BROWSER=1`, such as: - -```bash -SHOW_BROWSER=1 bundle exec rspec spec/system/website_spec.rb -``` - -You can also use the `pause` command within a test to pause browser execution. Resume by returning to your console and pressing the enter key. - -## Using the dummy application - -Panda CMS includes a dummy application (which is mildly more advanced than the traditional Rails "dummy" application) we use to test the functionality of the CMS is available and working. This is using RSpec (so lives in `spec/dummy` rather than the traditional `test/dummy`). - -In future, we may need different versions of dummy applications to test different asset pipelines or versions of Rails. - -We don't recommend using the `dummy` app to develop in (see https://github.com/pandacms/demo_site for a real application you can use alongside the "Developing" section above). But, if needed, you can use this in development mode. To setup the `dummy` application for use in development mode, run the following from `spec/dummy`: - -``` -rails db:create -rails db:schema:load -rails db:seed -``` - -To run the `dummy` application in development mode, from the `spec/dummy` directory, run: - -``` -bin/dev -``` - -Set up your authentication provider and visit http://localhost:3000/admin to login. - -We haven't yet added instructions on how to set up your authentication provider; you may have some luck signing in with GitHub in the meantime. If you're using the default configuration, try login for the first time then set your user to be `admin = true`. We'll sort some better setup steps soon. 🙂 - -This runs a Rails server, and watch tasks for both the engine's CSS and dummy application's CSS. diff --git a/Gemfile.lock b/Gemfile.lock index eeadb67..61b0b6e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -422,6 +422,7 @@ GEM activesupport (>= 7.0.0) rack railties (>= 7.0.0) + pstore (0.1.3) psych (5.1.2) stringio public_suffix (6.0.1) @@ -686,6 +687,7 @@ DEPENDENCIES msgpack (~> 1.7) panda_cms! propshaft (~> 1.0) + pstore puma (~> 6.4) rails-route-checker (~> 0.6) rspec-github (~> 2.4) diff --git a/app/components/panda_cms/admin/flash_message_component.rb b/app/components/panda_cms/admin/flash_message_component.rb index 90e6937..89c9421 100644 --- a/app/components/panda_cms/admin/flash_message_component.rb +++ b/app/components/panda_cms/admin/flash_message_component.rb @@ -19,7 +19,7 @@ def text_colour_css when :warning "text-warning" when :info, :notice - "text-highlight" + "text-active" else "text-mid" end diff --git a/app/controllers/panda_cms/admin/menus_controller.rb b/app/controllers/panda_cms/admin/menus_controller.rb index 2f96d9b..3bd443e 100644 --- a/app/controllers/panda_cms/admin/menus_controller.rb +++ b/app/controllers/panda_cms/admin/menus_controller.rb @@ -3,8 +3,7 @@ module PandaCms module Admin class MenusController < ApplicationController - before_action :set_initial_breadcrumb, only: %i[index new edit create update] - before_action :set_paper_trail_whodunnit, only: %i[create update] + before_action :set_initial_breadcrumb, only: %i[index] before_action :authenticate_admin_user! # Lists all menus which can be managed by the administrator @@ -15,47 +14,6 @@ def index render :index, locals: {menus: menus} end - # Loads the menu editor - # @type GET - def edit - add_breadcrumb menu.name, edit_admin_menu_path(menu) - end - - # GET /admin/menus/new - # @type GET - def new - @menu = PandaCms::Menu.new - @menu.menu_items.new - set_new_menu_breadcrumb - end - - # POST /admin/menus - def create - @menu = PandaCms::Menu.new(menu_params) - - if @menu.save - redirect_to admin_menus_path, notice: "Menu was successfully created." - else - flash[:error] = @menu.errors.full_messages.join(", ") - set_new_menu_breadcrumb - render :new, status: :unprocessable_entity - end - end - - # @type PATCH/PUT - # @return - def update - if menu.update!(menu_params) - redirect_to edit_admin_menu_path(menu), - status: :see_other, - flash: {success: "This menu was successfully updated!"} - else - add_breadcrumb menu.name, edit_admin_menu_path(menu) - flash[:error] = "There was an error updating the menu." - render :edit, status: :unprocessable_entity - end - end - private def menu @@ -65,17 +23,6 @@ def menu def set_initial_breadcrumb add_breadcrumb "Menus", admin_menus_path end - - def set_new_menu_breadcrumb - add_breadcrumb "Add New Menu", new_admin_menu_path - end - - # Only allow a list of trusted parameters through. - # @type private - # @return ActionController::StrongParameters - def menu_params - params.require(:menu).permit(:name, menu_items_attributes: %i[id text external_url sort_order panda_cms_page_id _destroy]) - end end end end diff --git a/app/javascript/panda_cms/controllers/slug_controller.js b/app/javascript/panda_cms/controllers/slug_controller.js index 5177e80..a1bb51c 100644 --- a/app/javascript/panda_cms/controllers/slug_controller.js +++ b/app/javascript/panda_cms/controllers/slug_controller.js @@ -1,12 +1,6 @@ -<<<<<<<< HEAD:app/javascript/panda_cms/controllers/slug_controller.js import { Controller } from "@hotwired/stimulus"; export default class extends Controller { -======== -import { Controller as PandaCmsController } from "@hotwired/stimulus"; - -export class TextFieldUpdateController extends PandaCmsController { ->>>>>>>> 051dfc5 (Improve rich text editor support):app/javascript/panda_cms/controllers/text_field_update_controller.js static targets = [ "existing_root", "input_select", @@ -14,7 +8,8 @@ export class TextFieldUpdateController extends PandaCmsController { "output_text", ]; - connect() {} + connect() { + } generatePath() { this.output_textTarget.value = "/" + this.createSlug(this.input_textTarget.value); diff --git a/app/javascript/panda_cms/panda_cms.js b/app/javascript/panda_cms/panda_cms.js new file mode 100644 index 0000000..01e6c9b --- /dev/null +++ b/app/javascript/panda_cms/panda_cms.js @@ -0,0 +1,35 @@ +import { Application as PandaCmsApplication } from "@hotwired/stimulus" + +const pandaCmsApplication = PandaCmsApplication.start() + +// Configure Stimulus development experience +pandaCmsApplication.debug = false +window.pandaStimulus = pandaCmsApplication + +// Eager load all controllers defined in the import map under controllers/**/*_controller +import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" +eagerLoadControllersFrom("controllers", pandaCmsApplication) + +import { + Alert, + Autosave, + ColorPreview, + Dropdown, + Modal, + Tabs, + Popover, + Toggle, + Slideover, +} from "tailwindcss-stimulus-components" + +pandaCmsApplication.register("alert", Alert) +pandaCmsApplication.register("autosave", Autosave) +pandaCmsApplication.register("color-preview", ColorPreview) +pandaCmsApplication.register("dropdown", Dropdown) +pandaCmsApplication.register("modal", Modal) +pandaCmsApplication.register("popover", Popover) +pandaCmsApplication.register("slideover", Slideover) +pandaCmsApplication.register("tabs", Tabs) +pandaCmsApplication.register("toggle", Toggle) + +export { pandaCmsApplication } diff --git a/app/javascript/panda_cms/panda_cms_base.js b/app/javascript/panda_cms/panda_cms_base.js deleted file mode 100644 index d29d73b..0000000 --- a/app/javascript/panda_cms/panda_cms_base.js +++ /dev/null @@ -1,36 +0,0 @@ -import { Application as PandaCmsApplication } from "@hotwired/stimulus"; - -const panda_cms = PandaCmsApplication.start(); - -// Configure Stimulus development experience -panda_cms.debug = false; -window.pandaStimulus = panda_cms; - -import { SlugController } from "controllers/slug_controller"; -panda_cms.register("slug", SlugController); - -import { - Alert, - Autosave, - ColorPreview, - Dropdown, - Modal, - Tabs, - Popover, - Toggle, - Slideover, -} from "tailwindcss-stimulus-components"; -panda_cms.register("alert", Alert); -panda_cms.register("autosave", Autosave); -panda_cms.register("color-preview", ColorPreview); -panda_cms.register("dropdown", Dropdown); -panda_cms.register("modal", Modal); -panda_cms.register("popover", Popover); -panda_cms.register("slideover", Slideover); -panda_cms.register("tabs", Tabs); -panda_cms.register("toggle", Toggle); - -import RailsNestedForm from 'stimulus-components-rails-nested-form' -panda_cms.register("nested-form", RailsNestedForm); - -export { panda_cms }; diff --git a/app/javascript/panda_cms/stimulus-components-rails-nested-form.js b/app/javascript/panda_cms/stimulus-components-rails-nested-form.js deleted file mode 100644 index 4aa593c..0000000 --- a/app/javascript/panda_cms/stimulus-components-rails-nested-form.js +++ /dev/null @@ -1,2 +0,0 @@ -import{Controller as e}from"@hotwired/stimulus";const t=class _RailsNestedForm extends e{add(e){e.preventDefault();const t=this.templateTarget.innerHTML.replace(/NEW_RECORD/g,(new Date).getTime().toString());this.targetTarget.insertAdjacentHTML("beforebegin",t);const r=new CustomEvent("rails-nested-form:add",{bubbles:!0});this.element.dispatchEvent(r)}remove(e){e.preventDefault();const t=e.target.closest(this.wrapperSelectorValue);if(t.dataset.newRecord==="true")t.remove();else{t.style.display="none";const e=t.querySelector("input[name*='_destroy']");e.value="1"}const r=new CustomEvent("rails-nested-form:remove",{bubbles:!0});this.element.dispatchEvent(r)}};t.targets=["target","template"],t.values={wrapperSelector:{type:String,default:".nested-form-wrapper"}};let r=t;export{r as default}; - diff --git a/app/lib/panda_cms/slug.rb b/app/lib/panda_cms/slug.rb index a438663..3458e63 100644 --- a/app/lib/panda_cms/slug.rb +++ b/app/lib/panda_cms/slug.rb @@ -5,7 +5,7 @@ class Slug # # @param string [String] The provided string to turn into a slug # @return string Generated slug - # @see text_field_update_controller.js should also implement this logic + # @see slug_controller.js should also implement this logic def self.generate(string) # Trim whitespace and downcase the string string = string.to_s.strip.downcase diff --git a/app/views/panda_cms/admin/forms/new.html.erb b/app/views/panda_cms/admin/forms/new.html.erb index 146dceb..07c2cfc 100644 --- a/app/views/panda_cms/admin/forms/new.html.erb +++ b/app/views/panda_cms/admin/forms/new.html.erb @@ -1,14 +1,13 @@ <%= render PandaCms::Admin::ContainerComponent.new do |component| %> <% component.with_heading(text: "Add Page", level: 1) do |heading| %> <% end %> - <%= panda_cms_form_with model: page, url: admin_pages_path, method: :post do |f| %> - <% options = nested_set_options(PandaCms::Page, page) { |i| "#{"-" * i.level} #{i.title} (#{i.path})" } %> -
- - <%= f.select :parent_id, options, {}, { "data-text-field-update-target": "input_select", "data-action": "change->text-field-update#setPrePath" } %> - <%= f.text_field :title, { data: { "text-field-update-target": "input_text", action: "focusout->text-field-update#generatePath" } } %> - <%= f.text_field :path, { data: { prefix: PandaCms::Current.root, "text-field-update-target": "output_text" } } %> + <% options = nested_set_options(PandaCms::Page, page) { |i| "#{"-" * i.level} #{i.title} (#{i.path})" } %> +
+ + <%= f.select :parent_id, options, {}, { "data-slug-target": "input_select", "data-action": "change->slug#setPrePath" } %> + <%= f.text_field :title, { data: { "slug-target": "input_text", action: "focusout->slug#generatePath" } } %> + <%= f.text_field :path, { data: { prefix: PandaCms::Current.root, "slug-target": "output_text" } } %> <%= f.collection_select :panda_cms_template_id, PandaCms::Template.available, :id, :name %> <%= f.button %>
diff --git a/app/views/panda_cms/admin/menus/_form.html.erb b/app/views/panda_cms/admin/menus/_form.html.erb deleted file mode 100644 index 0d03d17..0000000 --- a/app/views/panda_cms/admin/menus/_form.html.erb +++ /dev/null @@ -1,21 +0,0 @@ - <%= panda_cms_form_with model: menu, url: admin_menus_path, method: :post do |form| %> - <%= form.text_field :name %> - -
- - - <%= form.fields_for :menu_items do |item| %> - <%= render "menu_item_fields", form: item %> - <% end %> - -
- - <%= render PandaCms::Admin::ButtonComponent.new(text: "Add Menu Item", action: :add, data: {action: "nested-form#add"}, size: :small) %> -
- - <%= form.submit "Create" %> - <% end %> diff --git a/app/views/panda_cms/admin/menus/_menu_item_fields.html.erb b/app/views/panda_cms/admin/menus/_menu_item_fields.html.erb deleted file mode 100644 index 912b1a5..0000000 --- a/app/views/panda_cms/admin/menus/_menu_item_fields.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -
- <%= form.text_field :text %> - <%= form.text_field :external_url %> - <%= form.collection_select :panda_cms_page_id, PandaCms::Page.all, :id, :title, include_blank: true %> - <%= render PandaCms::Admin::ButtonComponent.new(text: "Remove Menu Item", action: :delete, data: {action: "nested-form#remove"}, size: :small) %> - <%= form.hidden_field :_destroy %> -
diff --git a/app/views/panda_cms/admin/menus/edit.html.erb b/app/views/panda_cms/admin/menus/edit.html.erb deleted file mode 100644 index ef1e5ce..0000000 --- a/app/views/panda_cms/admin/menus/edit.html.erb +++ /dev/null @@ -1,58 +0,0 @@ -<%= render PandaCms::Admin::ContainerComponent.new do |component| %> - <% component.with_heading(text: "Edit Menu", level: 1) %> - - <%= panda_cms_form_with model: @menu, url: admin_menu_path, method: :put do |form| %> - <%= form.text_field :name %> - - <% if @menu.kind == "static" %> -
- - - <% if @menu.menu_items.count > 0 %> - <%= form.fields_for :menu_items, @menu.menu_items.sort_by(&:lft) do |item| %> - <%= render "menu_item_fields", form: item %> - <% end %> - <% end %> - -
- - <%= render PandaCms::Admin::ButtonComponent.new(text: "Add Menu Item", action: :add, data: {action: "nested-form#add"}, size: :small) %> -
- <% else %> - - - - - - - - - - <% @menu.menu_items.root.self_and_descendants.each do |menu_item| %> - - - - - - <% end %> - -
TextPageExternal Link
-
-
-
<%= menu_item.text %>
-
-
-
-
<%= menu_item.page.title %>
-
-
<%= menu_item.external_url %>
-
- <% end %> - - <%= form.button %> - <% end %> -<% end %> diff --git a/app/views/panda_cms/admin/menus/index.html.erb b/app/views/panda_cms/admin/menus/index.html.erb index cafa567..abe679a 100644 --- a/app/views/panda_cms/admin/menus/index.html.erb +++ b/app/views/panda_cms/admin/menus/index.html.erb @@ -1,8 +1,6 @@ <%= render PandaCms::Admin::ContainerComponent.new do |component| %> <% component.with_heading(text: "Menus", level: 1) do |heading| %> - <% heading.with_button(action: :add, text: "Add Menu", link: new_admin_menu_path) %> <% end %> - <%= render PandaCms::Admin::TableComponent.new(term: "menu", rows: menus) do |table| %> <% table.column("Name") { |menu| link_to menu.name, edit_admin_menu_path(menu) } %> <% table.column("Kind") { |menu| render PandaCms::Admin::TagComponent.new(status: :active, text: menu.kind.titleize) } %> diff --git a/app/views/panda_cms/admin/menus/new.html.erb b/app/views/panda_cms/admin/menus/new.html.erb deleted file mode 100644 index e18b9ec..0000000 --- a/app/views/panda_cms/admin/menus/new.html.erb +++ /dev/null @@ -1,5 +0,0 @@ -<%= render PandaCms::Admin::ContainerComponent.new do |component| %> - <% component.with_heading(text: "Add Menu", level: 1) do |heading| %> - <% end %> - <%= render "form", menu: @menu %> -<% end %> diff --git a/app/views/panda_cms/admin/pages/new.html.erb b/app/views/panda_cms/admin/pages/new.html.erb index b9a671e..c3e4a55 100644 --- a/app/views/panda_cms/admin/pages/new.html.erb +++ b/app/views/panda_cms/admin/pages/new.html.erb @@ -1,14 +1,13 @@ <%= render PandaCms::Admin::ContainerComponent.new do |component| %> <% component.with_heading(text: "Add Page", level: 1) do |heading| %> <% end %> - <%= panda_cms_form_with model: page, url: admin_pages_path, method: :post do |f| %> - <% options = nested_set_options(PandaCms::Page, page) { |i| "#{"-" * i.level} #{i.title} (#{i.path})" } %> -
- - <%= f.select :parent_id, options, {}, { "data-text-field-update-target": "input_select", "data-action": "change->text-field-update#setPrePath" } %> - <%= f.text_field :title, { data: { "text-field-update-target": "input_text", action: "focusout->text-field-update#generatePath" } } %> - <%= f.text_field :path, { meta: t(".path.meta"), data: { prefix: PandaCms::Current.root, "text-field-update-target": "output_text" } } %> + <% options = nested_set_options(PandaCms::Page, page) { |i| "#{"-" * i.level} #{i.title} (#{i.path})" } %> +
+ + <%= f.select :parent_id, options, {}, { "data-slug-target": "input_select", "data-action": "change->slug#setPrePath" } %> + <%= f.text_field :title, { data: { "slug-target": "input_text", action: "focusout->slug#generatePath" } } %> + <%= f.text_field :path, { meta: t(".path.meta"), data: { prefix: PandaCms::Current.root, "slug-target": "output_text" } } %> <%= f.collection_select :panda_cms_template_id, PandaCms::Template.available, :id, :name %> <%= f.button %>
diff --git a/app/views/panda_cms/admin/posts/_form.html.erb b/app/views/panda_cms/admin/posts/_form.html.erb index 90d30c5..03dd24c 100644 --- a/app/views/panda_cms/admin/posts/_form.html.erb +++ b/app/views/panda_cms/admin/posts/_form.html.erb @@ -1,8 +1,8 @@ <%= panda_cms_form_with model: post, url: url do |f| %> -
- - <%= f.text_field :title, { required: true, data: { "text-field-update-target": "input_text", action: "focusout->text-field-update#generatePath" } } %> - <%= f.text_field :slug, { required: true, data: { prefix: PandaCms::Current.root + "/#{PandaCms.posts[:prefix]}", "text-field-update-target": "output_text" } } %> +
+ + <%= f.text_field :title, { required: true, data: { "slug-target": "input_text", action: "focusout->slug#generatePath" } } %> + <%= f.text_field :slug, { required: true, data: { prefix: PandaCms::Current.root + "/#{PandaCms.config.posts[:prefix]}", "slug-target": "output_text" } } %> <%= f.select :user_id, PandaCms::User.for_select_list %> <%= f.datetime_field :published_at, { required: true } %> <%= f.select :status, PandaCms::Post.statuses.keys.map { |status| [status.humanize, status] } %> diff --git a/app/views/panda_cms/admin/sessions/new.html.erb b/app/views/panda_cms/admin/sessions/new.html.erb index fbdaf9e..62727ef 100644 --- a/app/views/panda_cms/admin/sessions/new.html.erb +++ b/app/views/panda_cms/admin/sessions/new.html.erb @@ -5,7 +5,7 @@
<% @providers.each do |provider| %>
- <%= form_tag "#{PandaCms.route_namespace}/auth/#{provider}", method: "post", data: {turbo: false} do %> + <%= form_tag "#{PandaCms.root_path}/auth/#{provider}", method: "post", data: {turbo: false} do %>