mirror of
https://github.com/astuto/astuto.git
synced 2025-12-16 11:47:56 +01:00
Add setting to show in filter by status only statuses present in board posts (#411)
This commit is contained in:
committed by
GitHub
parent
675a8709ef
commit
cab2229e09
@@ -4,4 +4,8 @@
|
|||||||
|
|
||||||
scroll-margin-top: 96px;
|
scroll-margin-top: 96px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.generalSiteSettingsSubmit {
|
||||||
|
@extend .mb-4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
class BoardsController < ApplicationController
|
class BoardsController < ApplicationController
|
||||||
include ApplicationHelper
|
include ApplicationHelper
|
||||||
|
include BoardsHelper
|
||||||
|
|
||||||
before_action :authenticate_user!, only: [:create, :update, :update_order, :destroy]
|
before_action :authenticate_user!, only: [:create, :update, :update_order, :destroy]
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ class BoardsController < ApplicationController
|
|||||||
def show
|
def show
|
||||||
@board = Board.friendly.find(params[:id])
|
@board = Board.friendly.find(params[:id])
|
||||||
@page_title = @board.name
|
@page_title = @board.name
|
||||||
|
@post_statuses_to_show_in_filter = get_post_statuses_to_show_in_filter
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
class StaticPagesController < ApplicationController
|
class StaticPagesController < ApplicationController
|
||||||
|
include BoardsHelper
|
||||||
|
|
||||||
skip_before_action :load_tenant_data, only: [:showcase, :pending_tenant, :blocked_tenant]
|
skip_before_action :load_tenant_data, only: [:showcase, :pending_tenant, :blocked_tenant]
|
||||||
before_action :allow_iframe_embedding, only: [:embedded_roadmap]
|
before_action :allow_iframe_embedding, only: [:embedded_roadmap]
|
||||||
|
|
||||||
@@ -7,6 +9,7 @@ class StaticPagesController < ApplicationController
|
|||||||
|
|
||||||
if @board
|
if @board
|
||||||
@page_title = @board.name
|
@page_title = @board.name
|
||||||
|
@post_statuses_to_show_in_filter = get_post_statuses_to_show_in_filter
|
||||||
render 'boards/show'
|
render 'boards/show'
|
||||||
else
|
else
|
||||||
@page_title = t('roadmap.title')
|
@page_title = t('roadmap.title')
|
||||||
|
|||||||
9
app/helpers/boards_helper.rb
Normal file
9
app/helpers/boards_helper.rb
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
module BoardsHelper
|
||||||
|
def get_post_statuses_to_show_in_filter
|
||||||
|
if Current.tenant.tenant_setting.hide_unused_statuses_in_filter_by_status
|
||||||
|
@board.posts.map(&:post_status_id).uniq
|
||||||
|
else
|
||||||
|
PostStatus.pluck(:id) << nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -23,6 +23,7 @@ interface Props {
|
|||||||
currentUserFullName: string;
|
currentUserFullName: string;
|
||||||
tenantSetting: ITenantSetting;
|
tenantSetting: ITenantSetting;
|
||||||
componentRenderedAt: number;
|
componentRenderedAt: number;
|
||||||
|
postStatusesToShowInFilter: Array<number>;
|
||||||
authenticityToken: string;
|
authenticityToken: string;
|
||||||
posts: PostsState;
|
posts: PostsState;
|
||||||
postStatuses: PostStatusesState;
|
postStatuses: PostStatusesState;
|
||||||
@@ -96,6 +97,7 @@ class BoardP extends React.Component<Props> {
|
|||||||
currentUserFullName,
|
currentUserFullName,
|
||||||
tenantSetting,
|
tenantSetting,
|
||||||
componentRenderedAt,
|
componentRenderedAt,
|
||||||
|
postStatusesToShowInFilter,
|
||||||
authenticityToken,
|
authenticityToken,
|
||||||
posts,
|
posts,
|
||||||
postStatuses,
|
postStatuses,
|
||||||
@@ -140,14 +142,19 @@ class BoardP extends React.Component<Props> {
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
<PostStatusFilter
|
{
|
||||||
postStatuses={postStatuses.items}
|
postStatusesToShowInFilter.length > 0 &&
|
||||||
areLoading={postStatuses.areLoading}
|
<PostStatusFilter
|
||||||
error={postStatuses.error}
|
postStatuses={postStatuses.items.filter(postStatus => postStatusesToShowInFilter.includes(postStatus.id))}
|
||||||
|
areLoading={postStatuses.areLoading}
|
||||||
|
error={postStatuses.error}
|
||||||
|
|
||||||
currentFilter={filters.postStatusIds}
|
currentFilter={filters.postStatusIds}
|
||||||
handleFilterClick={handlePostStatusFilterChange}
|
handleFilterClick={handlePostStatusFilterChange}
|
||||||
/>
|
|
||||||
|
showNoStatusFilter={postStatusesToShowInFilter.includes(null)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{ tenantSetting.show_powered_by && <PoweredByLink /> }
|
{ tenantSetting.show_powered_by && <PoweredByLink /> }
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ interface Props {
|
|||||||
|
|
||||||
handleFilterClick(postStatusId: number): void;
|
handleFilterClick(postStatusId: number): void;
|
||||||
currentFilter: Array<number>;
|
currentFilter: Array<number>;
|
||||||
|
|
||||||
|
showNoStatusFilter?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PostStatusFilter = ({
|
const PostStatusFilter = ({
|
||||||
@@ -24,6 +26,8 @@ const PostStatusFilter = ({
|
|||||||
|
|
||||||
handleFilterClick,
|
handleFilterClick,
|
||||||
currentFilter,
|
currentFilter,
|
||||||
|
|
||||||
|
showNoStatusFilter = true,
|
||||||
}: Props) => (
|
}: Props) => (
|
||||||
<SidebarBox title={I18n.t('board.filter_box.title')} customClass="postStatusFilterContainer">
|
<SidebarBox title={I18n.t('board.filter_box.title')} customClass="postStatusFilterContainer">
|
||||||
{
|
{
|
||||||
@@ -39,13 +43,18 @@ const PostStatusFilter = ({
|
|||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
<PostStatusListItem
|
|
||||||
name={I18n.t('common.no_status')}
|
|
||||||
color='black'
|
|
||||||
|
|
||||||
handleClick={() => handleFilterClick(0)}
|
{
|
||||||
isCurrentFilter={currentFilter.includes(0)}
|
showNoStatusFilter &&
|
||||||
/>
|
<PostStatusListItem
|
||||||
|
name={I18n.t('common.no_status')}
|
||||||
|
color='black'
|
||||||
|
|
||||||
|
handleClick={() => handleFilterClick(0)}
|
||||||
|
isCurrentFilter={currentFilter.includes(0)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
|
||||||
{ areLoading ? <Spinner /> : null }
|
{ areLoading ? <Spinner /> : null }
|
||||||
{ error ? <DangerText>{error}</DangerText> : null }
|
{ error ? <DangerText>{error}</DangerText> : null }
|
||||||
</SidebarBox>
|
</SidebarBox>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ interface Props {
|
|||||||
currentUserFullName: string;
|
currentUserFullName: string;
|
||||||
tenantSetting: ITenantSetting;
|
tenantSetting: ITenantSetting;
|
||||||
componentRenderedAt: number;
|
componentRenderedAt: number;
|
||||||
|
postStatusesToShowInFilter: Array<number>;
|
||||||
authenticityToken: string;
|
authenticityToken: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,6 +38,7 @@ class BoardRoot extends React.Component<Props> {
|
|||||||
currentUserFullName,
|
currentUserFullName,
|
||||||
tenantSetting,
|
tenantSetting,
|
||||||
componentRenderedAt,
|
componentRenderedAt,
|
||||||
|
postStatusesToShowInFilter,
|
||||||
authenticityToken,
|
authenticityToken,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -49,6 +51,7 @@ class BoardRoot extends React.Component<Props> {
|
|||||||
currentUserFullName={currentUserFullName}
|
currentUserFullName={currentUserFullName}
|
||||||
tenantSetting={tenantSetting}
|
tenantSetting={tenantSetting}
|
||||||
componentRenderedAt={componentRenderedAt}
|
componentRenderedAt={componentRenderedAt}
|
||||||
|
postStatusesToShowInFilter={postStatusesToShowInFilter}
|
||||||
authenticityToken={authenticityToken}
|
authenticityToken={authenticityToken}
|
||||||
/>
|
/>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export interface ISiteSettingsGeneralForm {
|
|||||||
collapseBoardsInHeader: string;
|
collapseBoardsInHeader: string;
|
||||||
showVoteCount: boolean;
|
showVoteCount: boolean;
|
||||||
showVoteButtonInBoard: boolean;
|
showVoteButtonInBoard: boolean;
|
||||||
|
hideUnusedStatusesInFilterByStatus: boolean;
|
||||||
showPoweredBy: boolean;
|
showPoweredBy: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +70,7 @@ interface Props {
|
|||||||
collapseBoardsInHeader: string,
|
collapseBoardsInHeader: string,
|
||||||
showVoteCount: boolean,
|
showVoteCount: boolean,
|
||||||
showVoteButtonInBoard: boolean,
|
showVoteButtonInBoard: boolean,
|
||||||
|
hideUnusedStatusesInFilterByStatus: boolean,
|
||||||
showPoweredBy: boolean,
|
showPoweredBy: boolean,
|
||||||
authenticityToken: string
|
authenticityToken: string
|
||||||
): Promise<any>;
|
): Promise<any>;
|
||||||
@@ -107,6 +109,7 @@ const GeneralSiteSettingsP = ({
|
|||||||
collapseBoardsInHeader: originForm.collapseBoardsInHeader,
|
collapseBoardsInHeader: originForm.collapseBoardsInHeader,
|
||||||
showVoteCount: originForm.showVoteCount,
|
showVoteCount: originForm.showVoteCount,
|
||||||
showVoteButtonInBoard: originForm.showVoteButtonInBoard,
|
showVoteButtonInBoard: originForm.showVoteButtonInBoard,
|
||||||
|
hideUnusedStatusesInFilterByStatus: originForm.hideUnusedStatusesInFilterByStatus,
|
||||||
showPoweredBy: originForm.showPoweredBy,
|
showPoweredBy: originForm.showPoweredBy,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -129,6 +132,7 @@ const GeneralSiteSettingsP = ({
|
|||||||
data.collapseBoardsInHeader,
|
data.collapseBoardsInHeader,
|
||||||
data.showVoteCount,
|
data.showVoteCount,
|
||||||
data.showVoteButtonInBoard,
|
data.showVoteButtonInBoard,
|
||||||
|
data.hideUnusedStatusesInFilterByStatus,
|
||||||
data.showPoweredBy,
|
data.showPoweredBy,
|
||||||
authenticityToken
|
authenticityToken
|
||||||
).then(res => {
|
).then(res => {
|
||||||
@@ -344,7 +348,7 @@ const GeneralSiteSettingsP = ({
|
|||||||
className="selectPicker"
|
className="selectPicker"
|
||||||
>
|
>
|
||||||
<option value={TENANT_SETTING_LOGO_LINKS_TO_ROOT_PAGE}>
|
<option value={TENANT_SETTING_LOGO_LINKS_TO_ROOT_PAGE}>
|
||||||
{ I18n.t('site_settings.general.logo_links_to_root_page') }
|
{ I18n.t('site_settings.general.logo_links_to_root_page') } ({watch('rootBoardId') === '0' ? I18n.t('roadmap.title') : boards.find(board => board.id === Number(watch('rootBoardId')))?.name})
|
||||||
</option>
|
</option>
|
||||||
<option value={TENANT_SETTING_LOGO_LINKS_TO_CUSTOM_URL}>
|
<option value={TENANT_SETTING_LOGO_LINKS_TO_CUSTOM_URL}>
|
||||||
{ I18n.t('site_settings.general.logo_links_to_custom_url') }
|
{ I18n.t('site_settings.general.logo_links_to_custom_url') }
|
||||||
@@ -414,6 +418,16 @@ const GeneralSiteSettingsP = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="formGroup">
|
||||||
|
<div className="checkboxSwitch">
|
||||||
|
<input {...register('hideUnusedStatusesInFilterByStatus')} type="checkbox" id="hide_unused_statuses_in_filter_by_status_checkbox" />
|
||||||
|
<label htmlFor="hide_unused_statuses_in_filter_by_status_checkbox">{ getLabel('tenant_setting', 'hide_unused_statuses_in_filter_by_status') }</label>
|
||||||
|
<SmallMutedText>
|
||||||
|
{ I18n.t('site_settings.general.hide_unused_statuses_in_filter_by_status_help') }
|
||||||
|
</SmallMutedText>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="formGroup">
|
<div className="formGroup">
|
||||||
<div className="checkboxSwitch">
|
<div className="checkboxSwitch">
|
||||||
<input {...register('showPoweredBy')} type="checkbox" id="show_powered_by_checkbox" />
|
<input {...register('showPoweredBy')} type="checkbox" id="show_powered_by_checkbox" />
|
||||||
@@ -424,7 +438,7 @@ const GeneralSiteSettingsP = ({
|
|||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<Button onClick={() => null} disabled={!isDirty}>
|
<Button onClick={() => null} disabled={!isDirty} className="generalSiteSettingsSubmit">
|
||||||
{I18n.t('common.buttons.update')}
|
{I18n.t('common.buttons.update')}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
@@ -445,4 +459,4 @@ const GeneralSiteSettingsP = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GeneralSiteSettingsP;
|
export default GeneralSiteSettingsP;
|
||||||
@@ -33,6 +33,7 @@ const mapDispatchToProps = (dispatch: any) => ({
|
|||||||
collapseBoardsInHeader: TenantSettingCollapseBoardsInHeader,
|
collapseBoardsInHeader: TenantSettingCollapseBoardsInHeader,
|
||||||
showVoteCount: boolean,
|
showVoteCount: boolean,
|
||||||
showVoteButtonInBoard: boolean,
|
showVoteButtonInBoard: boolean,
|
||||||
|
hideUnusedStatusesInFilterByStatus: boolean,
|
||||||
showPoweredBy: boolean,
|
showPoweredBy: boolean,
|
||||||
authenticityToken: string
|
authenticityToken: string
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
@@ -52,6 +53,7 @@ const mapDispatchToProps = (dispatch: any) => ({
|
|||||||
collapse_boards_in_header: collapseBoardsInHeader,
|
collapse_boards_in_header: collapseBoardsInHeader,
|
||||||
show_vote_count: showVoteCount,
|
show_vote_count: showVoteCount,
|
||||||
show_vote_button_in_board: showVoteButtonInBoard,
|
show_vote_button_in_board: showVoteButtonInBoard,
|
||||||
|
hide_unused_statuses_in_filter_by_status: hideUnusedStatusesInFilterByStatus,
|
||||||
show_powered_by: showPoweredBy,
|
show_powered_by: showPoweredBy,
|
||||||
},
|
},
|
||||||
locale,
|
locale,
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ interface ITenantSetting {
|
|||||||
show_vote_count?: boolean;
|
show_vote_count?: boolean;
|
||||||
show_vote_button_in_board?: boolean;
|
show_vote_button_in_board?: boolean;
|
||||||
show_roadmap_in_header?: boolean;
|
show_roadmap_in_header?: boolean;
|
||||||
|
hide_unused_statuses_in_filter_by_status?: boolean;
|
||||||
show_powered_by?: boolean;
|
show_powered_by?: boolean;
|
||||||
collapse_boards_in_header?: TenantSettingCollapseBoardsInHeader;
|
collapse_boards_in_header?: TenantSettingCollapseBoardsInHeader;
|
||||||
logo_links_to?: TenantSettingLogoLinksTo;
|
logo_links_to?: TenantSettingLogoLinksTo;
|
||||||
|
|||||||
@@ -12,12 +12,13 @@ class TenantSettingPolicy < ApplicationPolicy
|
|||||||
:feedback_approval_policy,
|
:feedback_approval_policy,
|
||||||
:show_vote_count,
|
:show_vote_count,
|
||||||
:show_vote_button_in_board,
|
:show_vote_button_in_board,
|
||||||
|
:hide_unused_statuses_in_filter_by_status,
|
||||||
:show_powered_by,
|
:show_powered_by,
|
||||||
:logo_links_to,
|
:logo_links_to,
|
||||||
:logo_custom_url,
|
:logo_custom_url,
|
||||||
:show_roadmap_in_header,
|
:show_roadmap_in_header,
|
||||||
:collapse_boards_in_header,
|
:collapse_boards_in_header,
|
||||||
:custom_css
|
:custom_css,
|
||||||
]
|
]
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
currentUserFullName: user_signed_in? ? current_user.full_name_or_email : '',
|
currentUserFullName: user_signed_in? ? current_user.full_name_or_email : '',
|
||||||
tenantSetting: @tenant_setting,
|
tenantSetting: @tenant_setting,
|
||||||
componentRenderedAt: Time.now.to_i,
|
componentRenderedAt: Time.now.to_i,
|
||||||
|
postStatusesToShowInFilter: @post_statuses_to_show_in_filter,
|
||||||
authenticityToken: form_authenticity_token
|
authenticityToken: form_authenticity_token
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
brandDisplaySetting: @tenant_setting.brand_display,
|
brandDisplaySetting: @tenant_setting.brand_display,
|
||||||
showVoteCount: @tenant_setting.show_vote_count,
|
showVoteCount: @tenant_setting.show_vote_count,
|
||||||
showVoteButtonInBoard: @tenant_setting.show_vote_button_in_board,
|
showVoteButtonInBoard: @tenant_setting.show_vote_button_in_board,
|
||||||
|
hideUnusedStatusesInFilterByStatus: @tenant_setting.hide_unused_statuses_in_filter_by_status,
|
||||||
showPoweredBy: @tenant_setting.show_powered_by,
|
showPoweredBy: @tenant_setting.show_powered_by,
|
||||||
rootBoardId: @tenant_setting.root_board_id.to_s,
|
rootBoardId: @tenant_setting.root_board_id.to_s,
|
||||||
customDomain: @tenant.custom_domain,
|
customDomain: @tenant.custom_domain,
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ en:
|
|||||||
feedback_approval_policy: 'Feedback approval policy'
|
feedback_approval_policy: 'Feedback approval policy'
|
||||||
show_vote_count: 'Show vote count to users'
|
show_vote_count: 'Show vote count to users'
|
||||||
show_vote_button_in_board: 'Show vote buttons in board page'
|
show_vote_button_in_board: 'Show vote buttons in board page'
|
||||||
|
hide_unused_statuses_in_filter_by_status: 'Hide unused statuses in filter by status'
|
||||||
show_powered_by: 'Show "Powered by Astuto"'
|
show_powered_by: 'Show "Powered by Astuto"'
|
||||||
root_board_id: 'Root page'
|
root_board_id: 'Root page'
|
||||||
logo_links_to: 'Logo links to'
|
logo_links_to: 'Logo links to'
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ en:
|
|||||||
custom_domain_learn_more: 'Learn how to configure a custom domain'
|
custom_domain_learn_more: 'Learn how to configure a custom domain'
|
||||||
show_vote_count_help: 'If you enable this setting, users will be able to see the vote count of posts. This may incentivize users to vote on already popular posts, leading to a snowball effect.'
|
show_vote_count_help: 'If you enable this setting, users will be able to see the vote count of posts. This may incentivize users to vote on already popular posts, leading to a snowball effect.'
|
||||||
show_vote_button_in_board_help: 'If you enable this setting, users will be able to vote posts from the board page. This may incentivize users to vote on more posts, leading to a higher number of votes but of lower significance.'
|
show_vote_button_in_board_help: 'If you enable this setting, users will be able to vote posts from the board page. This may incentivize users to vote on more posts, leading to a higher number of votes but of lower significance.'
|
||||||
|
hide_unused_statuses_in_filter_by_status_help: 'If you enable this setting, only statuses that are assigned to at least one post in that board will be shown in the filter by status sidebar filter.'
|
||||||
boards:
|
boards:
|
||||||
title: 'Boards'
|
title: 'Boards'
|
||||||
empty: 'There are no boards. Create one below!'
|
empty: 'There are no boards. Create one below!'
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class AddHideUnusedStatusesInFilterByStatusToTenantSettings < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_column :tenant_settings, :hide_unused_statuses_in_filter_by_status, :boolean, default: false, null: false
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2024_09_16_140807) do
|
ActiveRecord::Schema.define(version: 2024_09_17_140122) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@@ -185,6 +185,7 @@ ActiveRecord::Schema.define(version: 2024_09_16_140807) do
|
|||||||
t.boolean "use_browser_locale", default: false, null: false
|
t.boolean "use_browser_locale", default: false, null: false
|
||||||
t.integer "logo_links_to", default: 0, null: false
|
t.integer "logo_links_to", default: 0, null: false
|
||||||
t.string "logo_custom_url"
|
t.string "logo_custom_url"
|
||||||
|
t.boolean "hide_unused_statuses_in_filter_by_status", default: false, null: false
|
||||||
t.index ["tenant_id"], name: "index_tenant_settings_on_tenant_id"
|
t.index ["tenant_id"], name: "index_tenant_settings_on_tenant_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user