mirror of
https://github.com/discourse/discourse.git
synced 2025-06-06 23:07:28 +08:00
FEATURE: delete multiple inactive themes/components (#23788)
Ability to select multiple inactive themes or components and delete them all together
This commit is contained in:

committed by
GitHub

parent
60e624e768
commit
e94b553e9a
@ -8,6 +8,13 @@
|
|||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="info">
|
<div class="info">
|
||||||
|
{{#if @selectInactiveMode}}
|
||||||
|
<Input
|
||||||
|
@checked={{this.theme.markedToDelete}}
|
||||||
|
id={{this.theme.id}}
|
||||||
|
@type="checkbox"
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
<span class="name">
|
<span class="name">
|
||||||
{{this.theme.name}}
|
{{this.theme.name}}
|
||||||
</span>
|
</span>
|
||||||
|
@ -41,11 +41,61 @@
|
|||||||
{{#if this.hasInactiveThemes}}
|
{{#if this.hasInactiveThemes}}
|
||||||
<div class="themes-list-item inactive-indicator">
|
<div class="themes-list-item inactive-indicator">
|
||||||
<span class="empty">
|
<span class="empty">
|
||||||
{{#if this.themesTabActive}}
|
<div class="info">
|
||||||
{{i18n "admin.customize.theme.inactive_themes"}}
|
{{#if this.selectInactiveMode}}
|
||||||
|
<Input
|
||||||
|
@type="checkbox"
|
||||||
|
@checked={{(or
|
||||||
|
(eq this.allInactiveSelected true)
|
||||||
|
(eq this.someInactiveSelected true)
|
||||||
|
)}}
|
||||||
|
class="toggle-all-inactive"
|
||||||
|
indeterminate={{this.someInactiveSelected}}
|
||||||
|
{{on "click" this.toggleAllInactive}}
|
||||||
|
/>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{i18n "admin.customize.theme.inactive_components"}}
|
<DButton
|
||||||
|
class="btn-flat select-inactive-mode"
|
||||||
|
@action={{this.toggleInactiveMode}}
|
||||||
|
>
|
||||||
|
{{d-icon "list"}}
|
||||||
|
</DButton>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{#if this.selectInactiveMode}}
|
||||||
|
<span class="select-inactive-mode-label">
|
||||||
|
{{i18n
|
||||||
|
"admin.customize.theme.selected"
|
||||||
|
count=this.selectedCount
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
{{else if this.themesTabActive}}
|
||||||
|
<span class="header">
|
||||||
|
{{i18n "admin.customize.theme.inactive_themes"}}
|
||||||
|
</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="header">
|
||||||
|
{{i18n "admin.customize.theme.inactive_components"}}
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.selectInactiveMode}}
|
||||||
|
<a
|
||||||
|
href
|
||||||
|
{{on "click" this.toggleInactiveMode}}
|
||||||
|
class="cancel-select-inactive-mode"
|
||||||
|
>
|
||||||
|
{{i18n "admin.customize.theme.cancel"}}
|
||||||
|
</a>
|
||||||
|
<DButton
|
||||||
|
class="btn btn-delete"
|
||||||
|
@action={{this.deleteConfirmation}}
|
||||||
|
@disabled={{(eq this.selectedCount 0)}}
|
||||||
|
>
|
||||||
|
{{d-icon "trash-alt"}}
|
||||||
|
Delete
|
||||||
|
</DButton>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@ -57,6 +107,7 @@
|
|||||||
@classNames="inactive-theme"
|
@classNames="inactive-theme"
|
||||||
@theme={{theme}}
|
@theme={{theme}}
|
||||||
@navigateToTheme={{action "navigateToTheme" theme}}
|
@navigateToTheme={{action "navigateToTheme" theme}}
|
||||||
|
@selectInactiveMode={{this.selectInactiveMode}}
|
||||||
/>
|
/>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -3,16 +3,19 @@ import { inject as service } from "@ember/service";
|
|||||||
import { equal, gt, gte } from "@ember/object/computed";
|
import { equal, gt, gte } from "@ember/object/computed";
|
||||||
import { COMPONENTS, THEMES } from "admin/models/theme";
|
import { COMPONENTS, THEMES } from "admin/models/theme";
|
||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed, { bind } from "discourse-common/utils/decorators";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
|
import DeleteThemesConfirm from "discourse/components/modal/delete-themes-confirm";
|
||||||
|
|
||||||
@classNames("themes-list")
|
@classNames("themes-list")
|
||||||
export default class ThemesList extends Component {
|
export default class ThemesList extends Component {
|
||||||
@service router;
|
@service router;
|
||||||
|
@service modal;
|
||||||
|
|
||||||
THEMES = THEMES;
|
THEMES = THEMES;
|
||||||
COMPONENTS = COMPONENTS;
|
COMPONENTS = COMPONENTS;
|
||||||
filterTerm = null;
|
filterTerm = null;
|
||||||
|
selectInactiveMode = false;
|
||||||
|
|
||||||
@gt("themesList.length", 0) hasThemes;
|
@gt("themesList.length", 0) hasThemes;
|
||||||
|
|
||||||
@ -40,6 +43,7 @@ export default class ThemesList extends Component {
|
|||||||
"currentTab",
|
"currentTab",
|
||||||
"themesList.@each.user_selectable",
|
"themesList.@each.user_selectable",
|
||||||
"themesList.@each.default",
|
"themesList.@each.default",
|
||||||
|
"themesList.@each.markedToDelete",
|
||||||
"filterTerm"
|
"filterTerm"
|
||||||
)
|
)
|
||||||
inactiveThemes(themes) {
|
inactiveThemes(themes) {
|
||||||
@ -56,6 +60,16 @@ export default class ThemesList extends Component {
|
|||||||
return this._filterThemes(results, this.filterTerm);
|
return this._filterThemes(results, this.filterTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@discourseComputed("themesList.@each.markedToDelete")
|
||||||
|
selectedThemesOrComponents() {
|
||||||
|
return this.themesList.filter((theme) => theme.markedToDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed("themesList.@each.markedToDelete")
|
||||||
|
selectedCount() {
|
||||||
|
return this.selectedThemesOrComponents.length;
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"themesList",
|
"themesList",
|
||||||
"currentTab",
|
"currentTab",
|
||||||
@ -84,6 +98,18 @@ export default class ThemesList extends Component {
|
|||||||
}
|
}
|
||||||
return this._filterThemes(results, this.filterTerm);
|
return this._filterThemes(results, this.filterTerm);
|
||||||
}
|
}
|
||||||
|
@discourseComputed("themesList.@each.markedToDelete")
|
||||||
|
someInactiveSelected() {
|
||||||
|
return (
|
||||||
|
this.selectedCount > 0 &&
|
||||||
|
this.selectedCount !== this.inactiveThemes.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@discourseComputed("themesList.@each.markedToDelete")
|
||||||
|
allInactiveSelected() {
|
||||||
|
return this.selectedCount === this.inactiveThemes.length;
|
||||||
|
}
|
||||||
|
|
||||||
_filterThemes(themes, term) {
|
_filterThemes(themes, term) {
|
||||||
term = term?.trim()?.toLowerCase();
|
term = term?.trim()?.toLowerCase();
|
||||||
@ -93,9 +119,17 @@ export default class ThemesList extends Component {
|
|||||||
return themes.filter(({ name }) => name.toLowerCase().includes(term));
|
return themes.filter(({ name }) => name.toLowerCase().includes(term));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
toggleInactiveMode(event) {
|
||||||
|
event?.preventDefault();
|
||||||
|
this.inactiveThemes.forEach((theme) => theme.set("markedToDelete", false));
|
||||||
|
this.toggleProperty("selectInactiveMode");
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
changeView(newTab) {
|
changeView(newTab) {
|
||||||
if (newTab !== this.currentTab) {
|
if (newTab !== this.currentTab) {
|
||||||
|
this.set("selectInactiveMode", false);
|
||||||
this.set("currentTab", newTab);
|
this.set("currentTab", newTab);
|
||||||
if (!this.showFilter) {
|
if (!this.showFilter) {
|
||||||
this.set("filterTerm", null);
|
this.set("filterTerm", null);
|
||||||
@ -107,4 +141,41 @@ export default class ThemesList extends Component {
|
|||||||
navigateToTheme(theme) {
|
navigateToTheme(theme) {
|
||||||
this.router.transitionTo("adminCustomizeThemes.show", theme);
|
this.router.transitionTo("adminCustomizeThemes.show", theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggleAllInactive() {
|
||||||
|
const markedToDelete = this.selectedCount === 0;
|
||||||
|
this.inactiveThemes.forEach((theme) =>
|
||||||
|
theme.set("markedToDelete", markedToDelete)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
deleteConfirmation() {
|
||||||
|
this.modal.show(DeleteThemesConfirm, {
|
||||||
|
model: {
|
||||||
|
selectedThemesOrComponents: this.selectedThemesOrComponents,
|
||||||
|
type: this.themesTabActive ? "themes" : "components",
|
||||||
|
refreshAfterDelete: () => {
|
||||||
|
this.set("selectInactiveMode", false);
|
||||||
|
if (this.themesTabActive) {
|
||||||
|
this.set(
|
||||||
|
"themes",
|
||||||
|
this.themes.filter(
|
||||||
|
(theme) => !this.selectedThemesOrComponents.includes(theme)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.set(
|
||||||
|
"components",
|
||||||
|
this.components.filter(
|
||||||
|
(component) =>
|
||||||
|
!this.selectedThemesOrComponents.includes(component)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
<DModal
|
||||||
|
@closeModal={{@closeModal}}
|
||||||
|
@title={{i18n "admin.customize.bulk_delete"}}
|
||||||
|
>
|
||||||
|
<:body>
|
||||||
|
{{i18n (concat "admin.customize.bulk_" @model.type "_delete_confirm")}}
|
||||||
|
<ul>
|
||||||
|
{{#each @model.selectedThemesOrComponents as |theme|}}
|
||||||
|
<li>{{theme.name}}</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</:body>
|
||||||
|
<:footer>
|
||||||
|
<DButton class="btn-primary" @action={{this.delete}} @label="yes_value" />
|
||||||
|
<DModalCancel @close={{@closeModal}} />
|
||||||
|
</:footer>
|
||||||
|
</DModal>
|
@ -0,0 +1,21 @@
|
|||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
|
export default class DeleteThemesConfirmComponent extends Component {
|
||||||
|
@action
|
||||||
|
delete() {
|
||||||
|
ajax(`/admin/themes/bulk_destroy.json`, {
|
||||||
|
type: "DELETE",
|
||||||
|
data: {
|
||||||
|
theme_ids: this.args.model.selectedThemesOrComponents.mapBy("id"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.args.model.refreshAfterDelete();
|
||||||
|
this.args.closeModal();
|
||||||
|
})
|
||||||
|
.catch(popupAjaxError);
|
||||||
|
}
|
||||||
|
}
|
@ -266,10 +266,14 @@
|
|||||||
border-bottom: 1px solid var(--primary-low);
|
border-bottom: 1px solid var(--primary-low);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
.select-inactive-mode-label {
|
||||||
|
color: var(--tertiary);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
&.inactive-theme {
|
&.inactive-theme {
|
||||||
color: var(--primary-high);
|
color: var(--primary-high);
|
||||||
background: var(--primary-very-low);
|
background: var(--primary-very-low);
|
||||||
font-size: var(--font-down-1);
|
|
||||||
&:not(.selected):hover {
|
&:not(.selected):hover {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
}
|
}
|
||||||
@ -285,6 +289,11 @@
|
|||||||
padding-left: 0.33em;
|
padding-left: 0.33em;
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
}
|
}
|
||||||
|
.btn.select-inactive-mode {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&:not(.inactive-indicator):not(.selected):hover {
|
&:not(.inactive-indicator):not(.selected):hover {
|
||||||
background-color: var(--primary-very-low);
|
background-color: var(--primary-very-low);
|
||||||
@ -319,11 +328,25 @@
|
|||||||
.info {
|
.info {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: var(--font-up-1);
|
align-items: center;
|
||||||
|
height: 2em;
|
||||||
.icons {
|
.icons {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cancel-select-inactive-mode {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.btn-delete {
|
||||||
|
font-size: var(--font-down-1);
|
||||||
|
margin-left: 0.5em;
|
||||||
|
svg {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.components-list {
|
.components-list {
|
||||||
|
@ -265,6 +265,18 @@ class Admin::ThemesController < Admin::AdminController
|
|||||||
respond_to { |format| format.json { head :no_content } }
|
respond_to { |format| format.json { head :no_content } }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def bulk_destroy
|
||||||
|
themes = Theme.where(id: params[:theme_ids])
|
||||||
|
raise Discourse::InvalidParameters.new(:id) unless themes.present?
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
themes.each { |theme| StaffActionLogger.new(current_user).log_theme_destroy(theme) }
|
||||||
|
themes.destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
respond_to { |format| format.json { head :no_content } }
|
||||||
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@theme = Theme.include_relations.find_by(id: params[:id])
|
@theme = Theme.include_relations.find_by(id: params[:id])
|
||||||
raise Discourse::InvalidParameters.new(:id) unless @theme
|
raise Discourse::InvalidParameters.new(:id) unless @theme
|
||||||
|
@ -5112,6 +5112,9 @@ en:
|
|||||||
install: "Install"
|
install: "Install"
|
||||||
delete: "Delete"
|
delete: "Delete"
|
||||||
delete_confirm: 'Are you sure you want to delete "%{theme_name}"?'
|
delete_confirm: 'Are you sure you want to delete "%{theme_name}"?'
|
||||||
|
bulk_delete: 'Are you sure?'
|
||||||
|
bulk_themes_delete_confirm: "This will uninstall the following themes, they will no longer be useable by any users on your site:"
|
||||||
|
bulk_components_delete_confirm: "This will uninstall the following components, they will no longer be useable by any users on your site:"
|
||||||
color: "Color"
|
color: "Color"
|
||||||
opacity: "Opacity"
|
opacity: "Opacity"
|
||||||
copy: "Duplicate"
|
copy: "Duplicate"
|
||||||
@ -5182,6 +5185,8 @@ en:
|
|||||||
convert_theme_tooltip: "Convert this theme to component"
|
convert_theme_tooltip: "Convert this theme to component"
|
||||||
inactive_themes: "Inactive themes:"
|
inactive_themes: "Inactive themes:"
|
||||||
inactive_components: "Unused components:"
|
inactive_components: "Unused components:"
|
||||||
|
selected: "%{count} selected"
|
||||||
|
cancel: "Cancel"
|
||||||
broken_theme_tooltip: "This theme has errors in its CSS, HTML or YAML"
|
broken_theme_tooltip: "This theme has errors in its CSS, HTML or YAML"
|
||||||
disabled_component_tooltip: "This component has been disabled"
|
disabled_component_tooltip: "This component has been disabled"
|
||||||
default_theme_tooltip: "This theme is the site's default theme"
|
default_theme_tooltip: "This theme is the site's default theme"
|
||||||
|
@ -230,6 +230,7 @@ Discourse::Application.routes.draw do
|
|||||||
post "import" => "themes#import"
|
post "import" => "themes#import"
|
||||||
post "upload_asset" => "themes#upload_asset"
|
post "upload_asset" => "themes#upload_asset"
|
||||||
post "generate_key_pair" => "themes#generate_key_pair"
|
post "generate_key_pair" => "themes#generate_key_pair"
|
||||||
|
delete "bulk_destroy" => "themes#bulk_destroy"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1052,4 +1052,23 @@ RSpec.describe Admin::ThemesController do
|
|||||||
include_examples "theme update not allowed"
|
include_examples "theme update not allowed"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#bulk_destroy" do
|
||||||
|
fab!(:theme) { Fabricate(:theme, name: "Awesome Theme") }
|
||||||
|
fab!(:theme_2) { Fabricate(:theme, name: "Another awesome Theme") }
|
||||||
|
let(:theme_ids) { [theme.id, theme_2.id] }
|
||||||
|
|
||||||
|
before { sign_in(admin) }
|
||||||
|
|
||||||
|
it "destroys all selected the themes" do
|
||||||
|
expect do
|
||||||
|
delete "/admin/themes/bulk_destroy.json", params: { theme_ids: theme_ids }
|
||||||
|
end.to change { Theme.count }.by(-2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "logs the theme destroy action for each theme" do
|
||||||
|
StaffActionLogger.any_instance.expects(:log_theme_destroy).twice
|
||||||
|
delete "/admin/themes/bulk_destroy.json", params: { theme_ids: theme_ids }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -7,6 +7,41 @@ describe "Admin Customize Themes", type: :system do
|
|||||||
|
|
||||||
before { sign_in(admin) }
|
before { sign_in(admin) }
|
||||||
|
|
||||||
|
describe "when visiting the page to customize themes" do
|
||||||
|
fab!(:theme_2) { Fabricate(:theme) }
|
||||||
|
fab!(:theme_3) { Fabricate(:theme) }
|
||||||
|
let(:admin_customize_themes_page) { PageObjects::Pages::AdminCustomizeThemes.new }
|
||||||
|
let(:delete_themes_confirm_modal) { PageObjects::Modals::DeleteThemesConfirm.new }
|
||||||
|
|
||||||
|
it "should allow admin to bulk delete inactive themes" do
|
||||||
|
visit("/admin/customize/themes")
|
||||||
|
|
||||||
|
expect(admin_customize_themes_page).to have_inactive_themes
|
||||||
|
|
||||||
|
admin_customize_themes_page.click_select_inactive_mode
|
||||||
|
expect(admin_customize_themes_page).to have_inactive_themes_selected(count: 0)
|
||||||
|
admin_customize_themes_page.toggle_all_inactive
|
||||||
|
expect(admin_customize_themes_page).to have_inactive_themes_selected(count: 3)
|
||||||
|
|
||||||
|
admin_customize_themes_page.cancel_select_inactive_mode
|
||||||
|
expect(admin_customize_themes_page).to have_select_inactive_mode_button
|
||||||
|
|
||||||
|
admin_customize_themes_page.click_select_inactive_mode
|
||||||
|
expect(admin_customize_themes_page).to have_disabled_delete_theme_button
|
||||||
|
|
||||||
|
admin_customize_themes_page.toggle_all_inactive
|
||||||
|
|
||||||
|
admin_customize_themes_page.click_delete_themes_button
|
||||||
|
|
||||||
|
expect(delete_themes_confirm_modal).to have_theme("Cool theme 1")
|
||||||
|
expect(delete_themes_confirm_modal).to have_theme("Cool theme 2")
|
||||||
|
expect(delete_themes_confirm_modal).to have_theme("Cool theme 3")
|
||||||
|
delete_themes_confirm_modal.confirm
|
||||||
|
|
||||||
|
expect(admin_customize_themes_page).to have_no_inactive_themes
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "when visiting the page to customize the theme" do
|
describe "when visiting the page to customize the theme" do
|
||||||
it "should allow admin to update the color scheme of the theme" do
|
it "should allow admin to update the color scheme of the theme" do
|
||||||
visit("/admin/customize/themes/#{theme.id}")
|
visit("/admin/customize/themes/#{theme.id}")
|
||||||
|
15
spec/system/page_objects/modals/delete_themes_confirm.rb
Normal file
15
spec/system/page_objects/modals/delete_themes_confirm.rb
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module PageObjects
|
||||||
|
module Modals
|
||||||
|
class DeleteThemesConfirm < PageObjects::Pages::Base
|
||||||
|
def has_theme?(name)
|
||||||
|
has_css?(".modal li", text: name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def confirm
|
||||||
|
find(".modal-footer .btn-primary").click
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
43
spec/system/page_objects/pages/admin_customize_themes.rb
Normal file
43
spec/system/page_objects/pages/admin_customize_themes.rb
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module PageObjects
|
||||||
|
module Pages
|
||||||
|
class AdminCustomizeThemes < PageObjects::Pages::Base
|
||||||
|
def has_inactive_themes?
|
||||||
|
has_css?(".inactive-indicator")
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_no_inactive_themes?
|
||||||
|
has_no_css?(".inactive-indicator")
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_select_inactive_mode_button?
|
||||||
|
has_css?(".select-inactive-mode")
|
||||||
|
end
|
||||||
|
|
||||||
|
def click_select_inactive_mode
|
||||||
|
find(".select-inactive-mode").click
|
||||||
|
end
|
||||||
|
|
||||||
|
def cancel_select_inactive_mode
|
||||||
|
find(".cancel-select-inactive-mode").click
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_inactive_themes_selected?(count:)
|
||||||
|
has_css?(".inactive-theme input:checked", count: count)
|
||||||
|
end
|
||||||
|
|
||||||
|
def toggle_all_inactive
|
||||||
|
find(".toggle-all-inactive").click
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_disabled_delete_theme_button?
|
||||||
|
find_button("Delete", disabled: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def click_delete_themes_button
|
||||||
|
find(".btn-delete").click
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Reference in New Issue
Block a user