Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

71 Exclude deleted content #72

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,16 @@ public ActionResult GetContentType([FromQuery] [BindRequired] Guid guid)
[HttpGet]
[Route("[action]", Name = GetContentTypesRouteName)]
[SwaggerResponse(StatusCodes.Status200OK, null, typeof(IEnumerable<ContentTypeDto>))]
public async Task<ActionResult> GetContentTypes([FromQuery] GetContentTypesQuery? query, CancellationToken cancellationToken)
public async Task<ActionResult> GetContentTypes([FromQuery] GetContentTypesQuery query, CancellationToken cancellationToken)
{
query!.IncludeDeleted ??= true;

var contentTypesFilterCriteria = new ContentTypesFilterCriteria { Name = query?.Name, Type = query?.Type };

var contentTypes =
_contentTypeService.GetAll(contentTypesFilterCriteria);

var contentTypesUsageCounters = await _contentTypeService.GetAllCounters(cancellationToken);
var contentTypesUsageCounters = await _contentTypeService.GetAllCounters(query.IncludeDeleted.Value, cancellationToken);
var contentTypeDtos = contentTypes.Select(_contentTypeMapper.Map);

contentTypeDtos = contentTypeDtos.Join(contentTypesUsageCounters, type => type.ID, counter => counter.ContentTypeId, (type, counter) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using EPiServer.Data;
Expand All @@ -16,13 +17,17 @@ public ContentTypeUsagesRepository(ServiceAccessor<IAsyncDatabaseExecutor> dataE
_dataExecutorAccessor = dataExecutorAccessor;
}

public async Task<IEnumerable<ContentTypeUsageCounter>> ListContentTypesUsagesCounters(
public async Task<IEnumerable<ContentTypeUsageCounter>> ListContentTypesUsagesCounters(bool includeDeleted,
CancellationToken cancellationToken)
{
var executor = _dataExecutorAccessor();
return await executor.ExecuteAsync((Func<Task<IEnumerable<ContentTypeUsageCounter>>>)(async () =>
{
var command1 = executor.CreateCommand();
var deletedParam = executor.CreateParameter("Deleted", DbType.Byte, ParameterDirection.Input, includeDeleted);

var command1 = executor.CreateCommand();
command1.CommandType = CommandType.Text;
command1.Parameters.Add(deletedParam);
command1.CommandText = @"DECLARE @Results TABLE (
ContentTypeId INT,
Scope NVARCHAR(255)
Expand Down Expand Up @@ -75,6 +80,7 @@ INNER JOIN
tblPageLanguage ON tblWorkPage.fkPageID=tblPageLanguage.fkPageID
INNER JOIN
tblLanguageBranch ON tblLanguageBranch.pkID=tblWorkPage.fkLanguageBranchID
WHERE (tblPage.Deleted = @Deleted AND @Deleted = 0) OR @Deleted = 1
GROUP BY tblPage.fkPageTypeID, tblPage.pkID, tblLanguageBranch.LanguageID
) as ContentTypeUsageTable
RIGHT OUTER JOIN (SELECT CT.pkID AS ID
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@

using Reinforced.Typings.Attributes;

namespace Forte.Optimizely.ContentUsage.Api.Features.ContentType;

[TsInterface]
public class GetContentTypesQuery
{
public string? Name { get; set; }
public string? Type { get; set; }
public ContentTypesSorting? SortBy { get; set; }
public bool? IncludeDeleted { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ public IEnumerable<ContentType> GetAll(ContentTypesFilterCriteria? filterCriteri
return contentTypes;
}

public async Task<IEnumerable<ContentTypeUsageCounter>> GetAllCounters(CancellationToken cancellationToken)
public async Task<IEnumerable<ContentTypeUsageCounter>> GetAllCounters(
bool includeDeleted,
CancellationToken cancellationToken)
{
return await _contentTypeUsagesRepository.ListContentTypesUsagesCounters(cancellationToken);
return await _contentTypeUsagesRepository.ListContentTypesUsagesCounters(includeDeleted, cancellationToken);
}

public ContentType? Get(Guid guid)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@use 'sass:map';
@import "../../Styles/utils";

.forte-optimizely-content-usage-filters {
.#{$class-name-prefix}-filters {
display: flex;
flex-direction: column;
margin-bottom: spacer(1);
Expand Down Expand Up @@ -44,5 +44,18 @@
}
}
}

& input[type="checkbox"] {
margin-top: 0 !important;
}
}

& .#{$class-name-prefix}-filter-checkbox-container {
& > label {
& > div {
height: 100%;
align-items: center;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ContentTypeBasesFilter from "./ContentTypeBasesFilter";
import "./Filters.scss";
import NumberOfRowsFilter from "./NumberOfRowsFilter";
import SearchInput from "./SearchInput";
import IncludeDeletedFilter from "./IncludeDeletedFilter";

interface FiltersProps<TableDataType> {
searchValue?: string;
Expand All @@ -17,6 +18,8 @@ interface FiltersProps<TableDataType> {
rowsPerPageOptions?: number[];
selectedRowsPerPage?: number;
onRowsPerPageChange?: (option: number) => void;
includeDeleted?: boolean;
onIncludeDeletedChange?: React.ChangeEventHandler<HTMLInputElement>;
}

function Filters<TableDataType>({
Expand All @@ -30,6 +33,8 @@ function Filters<TableDataType>({
rowsPerPageOptions,
selectedRowsPerPage,
onRowsPerPageChange,
includeDeleted,
onIncludeDeletedChange,
}: FiltersProps<TableDataType>) {
return (
<div className="forte-optimizely-content-usage-filters">
Expand Down Expand Up @@ -57,6 +62,14 @@ function Filters<TableDataType>({
onChange={onRowsPerPageChange}
/>
)}

{typeof includeDeleted !== "undefined" && !!onIncludeDeletedChange && (
<IncludeDeletedFilter
includeDeleted={includeDeleted}
onIncludeDeletedChange={onIncludeDeletedChange}
/>
)}

</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { FC } from "react";
import { useTranslations } from "../../Contexts/TranslationsProvider";
import Checkbox from "../Form/Checkbox/Checkbox";
import classNames from "classnames";
import { classNamePrefix } from "../../Utils/styles";

interface IncludeDeletedFilterProps {
includeDeleted?: boolean;
onIncludeDeletedChange?: React.ChangeEventHandler<HTMLInputElement>;
}

const IncludeDeletedFilter: FC<IncludeDeletedFilterProps> = ({
includeDeleted,
onIncludeDeletedChange,
}) => {
const translations = useTranslations();

return (
<div className={classNames('oui-dropdown-group', classNamePrefix('filter-checkbox-container'))}>
<Checkbox
checked={includeDeleted}
onChange={onIncludeDeletedChange}
>
{translations.filters.includeDeleted}
</Checkbox>
</div>
);
};

export default IncludeDeletedFilter;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import "../../../Styles/utils";

.#{$class-name-prefix}-checkbox {
width: 14px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { ChangeEvent, ReactNode } from 'react';
import { Checkbox as OuiCheckbox } from 'optimizely-oui';
import classNames from 'classnames';
import { classNamePrefix } from '../../../Utils/styles';

import './Checkbox.scss';

interface CheckboxProps {
checked?: boolean;
className?: string;
defaultChecked?: boolean;
isDisabled?: boolean;
children?: ReactNode;
labelWeight?: string;
description?: string;
indeterminate?: boolean;
onChange?: (event: ChangeEvent) => void;
}

const Checkbox = ({ className, children, ...props }: CheckboxProps) => {
return (
<OuiCheckbox
{...props}
className={classNames(classNamePrefix('checkbox'), className)}
label={children}
/>
);
};

export default Checkbox;
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ interface LoadDataFunction {
): Promise<any> | Response;
}

const contentTypesLoader: LoadDataFunction = (api) => {
const contentTypesLoader: LoadDataFunction = (api, initialLoad) => {
if(!initialLoad) return Promise.resolve([{}, {}]);
const contentTypeBases = api.getContentTypeBases();
const contentTypes = api.getContentTypes();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ContentTypeBaseDto,
GetContentUsagesQuery,
GetContentUsagesResponse,
GetContentTypesQuery,
} from "../dtos";

export interface ContentUsageAPIEndpoints {
Expand Down Expand Up @@ -59,8 +60,8 @@ export default class ContentUsageAPIClient {
return this.get<ContentTypeBaseDto[]>(this.endpoints.contentTypeBases);
}

public async getContentTypes() {
return this.get<ContentTypeDto[]>(this.endpoints.contentTypes);
public async getContentTypes(query?: Partial<GetContentTypesQuery>) {
return this.getWithQuerySchema<Partial<GetContentTypesQuery>, ContentTypeDto[]>(this.endpoints.contentTypes, query);
}

public async getContentType(guid: string) {
Expand All @@ -73,7 +74,7 @@ export default class ContentUsageAPIClient {
): Promise<APIResponse<ResponseSchema>> {
const params = {} as Record<string, string>;

for (const [key, value] of Object.entries(query)) {
for (const [key, value] of Object.entries(query ?? {})) {
params[key] = value.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ enum FilteredTableDataQueryParam {
ShowColumn = "showColumn",
Page = "page",
RowsPerPage = "rowsPerPage",
IncludeDeleted = "includeDeleted"
}

interface FilteredTableDataHookOptions<TableDataType> {
Expand Down Expand Up @@ -59,6 +60,8 @@ export function useFilteredTableData<TableDataType>({
totalPages: number;
currentPage: number;
goToPage: (page: number) => void;
includeDeleted: boolean;
onIncludeDeletedChange: React.ChangeEventHandler<HTMLInputElement>;
} {
const triggerUpdate = useRef<boolean>(false);
const [datasetChanged, setDatasetChanged] = useState<boolean>(false);
Expand All @@ -82,6 +85,7 @@ export function useFilteredTableData<TableDataType>({
}))
);
const [searchParams, setSearchParams] = useSearchParams();
const [includeDeleted, setIncludeDeleted] = useState<boolean>(false);
const location = useLocation();

const debouncedSetSearchParams = useDebounce<
Expand All @@ -102,6 +106,7 @@ export function useFilteredTableData<TableDataType>({
sortDirection: false,
rowsPerPage: false,
contentTypeBases: false,
includeDeleted: false,
});

useEffect(() => {
Expand Down Expand Up @@ -172,6 +177,10 @@ export function useFilteredTableData<TableDataType>({
);
}

if (changesTracker.includeDeleted){
prevSearchParams.set(FilteredTableDataQueryParam.IncludeDeleted, String(includeDeleted));
}

triggerUpdate.current = false;
setChangesTracker({
currentPage: false,
Expand All @@ -181,6 +190,7 @@ export function useFilteredTableData<TableDataType>({
sortDirection: false,
rowsPerPage: false,
contentTypeBases: false,
includeDeleted: false,
});

return prevSearchParams;
Expand All @@ -193,6 +203,7 @@ export function useFilteredTableData<TableDataType>({
sortDirection,
rowsPerPage,
contentTypeBases,
includeDeleted
]);

const setPageToStart = useCallback(() => {
Expand Down Expand Up @@ -265,6 +276,15 @@ export function useFilteredTableData<TableDataType>({
[tableColumns, setTableColumns, setSortBy, sortBy]
);

const onIncludeDeletedChange: React.ChangeEventHandler<HTMLInputElement> = useCallback((event) => {
const newIncludeDeletedValue = event.target.checked;
setIncludeDeleted(newIncludeDeletedValue);
setChangesTracker({
...changesTracker,
includeDeleted: true
})
}, [changesTracker, setChangesTracker, setIncludeDeleted])

const onColumnVisiblityChange = useCallback(
(id: string, visible: boolean) => {
if (tableColumns.filter((column) => column.visible).length > 1 || visible)
Expand Down Expand Up @@ -543,6 +563,13 @@ export function useFilteredTableData<TableDataType>({
} else {
setPageToStart();
}

if (queryParams.has(FilteredTableDataQueryParam.IncludeDeleted)) {
const param = queryParams.get(FilteredTableDataQueryParam.IncludeDeleted).toLocaleLowerCase() === 'true';
setIncludeDeleted(param);
} else {
setIncludeDeleted(false);
}
},
[
tableColumns,
Expand All @@ -555,6 +582,7 @@ export function useFilteredTableData<TableDataType>({
setSearchQuery,
setSortBy,
setSortDirection,
setIncludeDeleted,
initialSortDirection,
initialContentTypeBases,
initialTableColumns,
Expand Down Expand Up @@ -615,5 +643,7 @@ export function useFilteredTableData<TableDataType>({
totalPages,
currentPage,
goToPage: handlePageChange,
includeDeleted,
onIncludeDeletedChange
};
}
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
@import 'variables/breakpoints';

$class-name-prefix: 'forte-optimizely-content-usage';
4 changes: 4 additions & 0 deletions src/Forte.Optimizely.ContentUsage/Frontend/Utils/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const CLASS_NAME_PREFIX = 'forte-optimizely-content-usage';

export const classNamePrefix = (className?: string) =>
className ? `${CLASS_NAME_PREFIX}-${className}` : CLASS_NAME_PREFIX;
Loading