diff --git a/src/apps/content-editor/src/app/views/ItemList/ConfirmPublishesDialog.tsx b/src/apps/content-editor/src/app/views/ItemList/ConfirmPublishesDialog.tsx
index c45e9dd79e..3516f395f7 100644
--- a/src/apps/content-editor/src/app/views/ItemList/ConfirmPublishesDialog.tsx
+++ b/src/apps/content-editor/src/app/views/ItemList/ConfirmPublishesDialog.tsx
@@ -49,7 +49,8 @@ export const ConfirmPublishesModal = ({
- Publish {items.length} {pluralizeWord("Item", items.length)}:
+ Publish Changes to {items.length}{" "}
+ {pluralizeWord("Item", items.length)}:
This will make the the following {items.length} content{" "}
@@ -76,7 +77,7 @@ export const ConfirmPublishesModal = ({
}}
data-cy="ConfirmPublishButton"
>
- Publish Changes to ({items.length}) Items
+ Publish Items ({items.length})
diff --git a/src/apps/content-editor/src/app/views/ItemList/ItemListFilters.tsx b/src/apps/content-editor/src/app/views/ItemList/ItemListFilters.tsx
index ab68f247b2..b791dae062 100644
--- a/src/apps/content-editor/src/app/views/ItemList/ItemListFilters.tsx
+++ b/src/apps/content-editor/src/app/views/ItemList/ItemListFilters.tsx
@@ -1,4 +1,4 @@
-import { Box, Menu, MenuItem, Button } from "@mui/material";
+import { Box, Menu, MenuItem, Button, Typography } from "@mui/material";
import {
DateFilter,
FilterButton,
@@ -7,9 +7,13 @@ import {
import { useEffect, useMemo, useState } from "react";
import { useParams } from "../../../../../../shell/hooks/useParams";
import { ArrowDropDownOutlined } from "@mui/icons-material";
-import { useGetLangsQuery } from "../../../../../../shell/services/instance";
+import {
+ useGetContentModelFieldsQuery,
+ useGetLangsQuery,
+} from "../../../../../../shell/services/instance";
import { useDateFilterParams } from "../../../../../../shell/hooks/useDateFilterParams";
import { useGetUsersQuery } from "../../../../../../shell/services/accounts";
+import { useParams as useRouterParams } from "react-router";
const SORT_ORDER = {
dateSaved: "Date Saved",
@@ -24,6 +28,29 @@ const STATUS_FILTER = {
notPublished: "Not Published",
} as const;
+const FILTERABLE_DATA_TYPES = [
+ "text",
+ "wysiwyg_basic",
+ "wysiwyg_advanced",
+ "article_writer",
+ "markdown",
+ "textarea",
+ "number",
+ "images",
+ "date",
+ "datetime",
+ "one_to_many",
+ "one_to_one",
+ "uuid",
+ "number",
+ "currency",
+ "date",
+ "datetime",
+ "link",
+ "internal_link",
+ "sort",
+] as const;
+
const getCountryCode = (langCode: string) => {
if (!langCode) return "";
const splitTag = langCode.split("-");
@@ -48,6 +75,7 @@ const getFlagEmojiFromIETFTag = (langCode: string) => {
};
export const ItemListFilters = () => {
+ const { modelZUID } = useRouterParams<{ modelZUID: string }>();
const [anchorEl, setAnchorEl] = useState({
currentTarget: null,
id: "",
@@ -57,6 +85,8 @@ export const ItemListFilters = () => {
const { data: languages } = useGetLangsQuery({});
const activeLanguageCode = params.get("lang");
const { data: users } = useGetUsersQuery();
+ const { data: fields, isFetching: isFieldsFetching } =
+ useGetContentModelFieldsQuery(modelZUID);
const userOptions = useMemo(() => {
return users?.map((user) => ({
@@ -73,7 +103,9 @@ export const ItemListFilters = () => {
filterId="sortByFilter"
isFilterActive={false}
buttonText={`Sort: ${
- SORT_ORDER[params.get("sort") as keyof typeof SORT_ORDER] ??
+ (SORT_ORDER[params.get("sort") as keyof typeof SORT_ORDER] ||
+ fields?.find((field) => field.name === params.get("sort"))
+ ?.label) ??
SORT_ORDER.dateSaved
}`}
onOpenMenu={(event: React.MouseEvent) => {
@@ -92,6 +124,13 @@ export const ItemListFilters = () => {
vertical: -8,
horizontal: "left",
}}
+ // add set width to the menu
+ PaperProps={{
+ sx: {
+ width: "240px",
+ maxHeight: "420px",
+ },
+ }}
>
{Object.entries(SORT_ORDER).map(([key, value]) => (
))}
+ `1px solid ${theme.palette.border}`,
+ }}
+ >
+ FIELDS
+
+ {fields
+ ?.filter((field) =>
+ FILTERABLE_DATA_TYPES.includes(field.datatype as any)
+ )
+ ?.map((field) => (
+
+ ))}
-
+
);
}
diff --git a/src/apps/content-editor/src/app/views/ItemList/SchedulePublishesDialog.tsx b/src/apps/content-editor/src/app/views/ItemList/SchedulePublishesDialog.tsx
index ecf7d6196f..5967d719c2 100644
--- a/src/apps/content-editor/src/app/views/ItemList/SchedulePublishesDialog.tsx
+++ b/src/apps/content-editor/src/app/views/ItemList/SchedulePublishesDialog.tsx
@@ -74,7 +74,7 @@ export const SchedulePublishesModal = ({
- You can always cancel the publish later if needed
+ You can always cancel the scheduled publish later if needed
diff --git a/src/apps/content-editor/src/app/views/ItemList/index.tsx b/src/apps/content-editor/src/app/views/ItemList/index.tsx
index 4928f4dcda..671ce698af 100644
--- a/src/apps/content-editor/src/app/views/ItemList/index.tsx
+++ b/src/apps/content-editor/src/app/views/ItemList/index.tsx
@@ -127,7 +127,8 @@ export const ItemList = () => {
clonedItem.publishing = publishings?.find(
(publishing) =>
publishing.itemZUID === item.meta.ZUID &&
- publishing.version === item.meta.version
+ publishing.version === item.meta.version &&
+ publishing.unpublishAt === null
);
if (clonedItem.publishing) {
clonedItem.publishing = {
@@ -140,7 +141,8 @@ export const ItemList = () => {
clonedItem.priorPublishing = publishings?.find(
(publishing) =>
publishing.itemZUID === item.meta.ZUID &&
- publishing.version !== item.meta.version
+ publishing.version !== item.meta.version &&
+ publishing.unpublishAt === null
);
if (clonedItem.priorPublishing) {
clonedItem.priorPublishing = {
@@ -192,7 +194,7 @@ export const ItemList = () => {
if (!clonedItem.data[key]) return;
clonedItem.data[key] = new Date(
- clonedItem.data[key]
+ clonedItem.data[key] + "T00:00:00"
)?.toLocaleDateString("en-US", {
year: "numeric",
month: "short",
@@ -215,73 +217,98 @@ export const ItemList = () => {
const sortedAndFilteredItems = useMemo(() => {
let clonedItems = [...processedItems];
clonedItems?.sort((a: any, b: any) => {
- if (sort === "datePublished") {
- // Handle undefined publishAt by setting a default far-future date for sorting purposes
+ if (sort) {
+ if (sort === "datePublished") {
+ // Handle undefined publishAt by setting a default far-future date for sorting purposes
- let dateA = a?.publishing?.publishAt || a?.priorPublishing?.publishAt;
- dateA = dateA ? new Date(dateA).getTime() : Number.NEGATIVE_INFINITY;
+ let dateA = a?.publishing?.publishAt || a?.priorPublishing?.publishAt;
+ dateA = dateA ? new Date(dateA).getTime() : Number.NEGATIVE_INFINITY;
- let dateB = b?.publishing?.publishAt || b?.priorPublishing?.publishAt;
- dateB = dateB ? new Date(dateB).getTime() : Number.NEGATIVE_INFINITY;
+ let dateB = b?.publishing?.publishAt || b?.priorPublishing?.publishAt;
+ dateB = dateB ? new Date(dateB).getTime() : Number.NEGATIVE_INFINITY;
- return dateB - dateA;
- } else if (sort === "dateCreated") {
- return (
- new Date(b.meta.createdAt).getTime() -
- new Date(a.meta.createdAt).getTime()
- );
- } else if (sort === "status") {
- const aPublishing = a?.publishing || a?.priorPublishing;
- const bPublishing = b?.publishing || b?.priorPublishing;
-
- const aDate = aPublishing?.publishAt
- ? new Date(aPublishing.publishAt)
- : null;
- const bDate = bPublishing?.publishAt
- ? new Date(bPublishing.publishAt)
- : null;
-
- // Determine the status of each item
- const aIsPublished = aDate && aDate <= now;
- const bIsPublished = bDate && bDate <= now;
-
- const aIsScheduled = aDate && aDate > now;
- const bIsScheduled = bDate && bDate > now;
-
- // Check if meta.version exists
- const aHasVersion = a?.meta?.version != null;
- const bHasVersion = b?.meta?.version != null;
-
- // Place items without meta.version at the bottom
- if (!aHasVersion && bHasVersion) {
- return 1;
- } else if (aHasVersion && !bHasVersion) {
- return -1;
- }
-
- // Continue with the original sorting logic
- if (aIsPublished && !bIsPublished) {
- return -1; // A is published, B is not
- } else if (!aIsPublished && bIsPublished) {
- return 1; // B is published, A is not
- } else if (aIsPublished && bIsPublished) {
- return bDate.getTime() - aDate.getTime(); // Both are published, sort by publish date descending
- }
-
- if (aIsScheduled && !bIsScheduled) {
- return -1; // A is scheduled, B is not
- } else if (!aIsScheduled && bIsScheduled) {
- return 1; // B is scheduled, A is not
- } else if (aIsScheduled && bIsScheduled) {
- return aDate.getTime() - bDate.getTime(); // Both are scheduled, sort by publish date ascending
+ return dateB - dateA;
+ } else if (sort === "dateCreated") {
+ return (
+ new Date(b.meta.createdAt).getTime() -
+ new Date(a.meta.createdAt).getTime()
+ );
+ } else if (sort === "status") {
+ const aPublishing = a?.publishing || a?.priorPublishing;
+ const bPublishing = b?.publishing || b?.priorPublishing;
+
+ const aDate = aPublishing?.publishAt
+ ? new Date(aPublishing.publishAt)
+ : null;
+ const bDate = bPublishing?.publishAt
+ ? new Date(bPublishing.publishAt)
+ : null;
+
+ // Determine the status of each item
+ const aIsPublished = aDate && aDate <= now;
+ const bIsPublished = bDate && bDate <= now;
+
+ const aIsScheduled = aDate && aDate > now;
+ const bIsScheduled = bDate && bDate > now;
+
+ // Check if meta.version exists
+ const aHasVersion = a?.meta?.version != null;
+ const bHasVersion = b?.meta?.version != null;
+
+ // Place items without meta.version at the bottom
+ if (!aHasVersion && bHasVersion) {
+ return 1;
+ } else if (aHasVersion && !bHasVersion) {
+ return -1;
+ }
+
+ // Continue with the original sorting logic
+ if (aIsPublished && !bIsPublished) {
+ return -1; // A is published, B is not
+ } else if (!aIsPublished && bIsPublished) {
+ return 1; // B is published, A is not
+ } else if (aIsPublished && bIsPublished) {
+ return bDate.getTime() - aDate.getTime(); // Both are published, sort by publish date descending
+ }
+
+ if (aIsScheduled && !bIsScheduled) {
+ return -1; // A is scheduled, B is not
+ } else if (!aIsScheduled && bIsScheduled) {
+ return 1; // B is scheduled, A is not
+ } else if (aIsScheduled && bIsScheduled) {
+ return aDate.getTime() - bDate.getTime(); // Both are scheduled, sort by publish date ascending
+ }
+
+ return 0; // Neither is published nor scheduled, consider them equal
+ } else if (fields?.find((field) => field.name === sort)) {
+ const dataType = fields?.find(
+ (field) => field.name === sort
+ )?.datatype;
+ if (typeof a.data[sort] === "number") {
+ if (a.data[sort] == null) return 1;
+ if (b.data[sort] == null) return -1;
+
+ return dataType === "sort"
+ ? a.data[sort] - b.data[sort]
+ : b.data[sort] - a.data[sort];
+ }
+ if (dataType === "date" || dataType === "datetime") {
+ return (
+ new Date(b.data[sort]).getTime() -
+ new Date(a.data[sort]).getTime()
+ );
+ }
+ const aValue =
+ dataType === "images" ? a.data[sort]?.filename : a.data[sort];
+ const bValue =
+ dataType === "images" ? b.data[sort]?.filename : b.data[sort];
+ return aValue?.trim()?.localeCompare(bValue?.trim());
+ } else {
+ return (
+ new Date(b.meta.updatedAt).getTime() -
+ new Date(a.meta.updatedAt).getTime()
+ );
}
-
- return 0; // Neither is published nor scheduled, consider them equal
- } else {
- return (
- new Date(b.meta.updatedAt).getTime() -
- new Date(a.meta.updatedAt).getTime()
- );
}
});
if (search) {
diff --git a/src/shell/components/FieldTypeDateTime/index.tsx b/src/shell/components/FieldTypeDateTime/index.tsx
index 292248a97d..abb8159795 100644
--- a/src/shell/components/FieldTypeDateTime/index.tsx
+++ b/src/shell/components/FieldTypeDateTime/index.tsx
@@ -299,6 +299,11 @@ export const FieldTypeDateTime = ({
value={timezoneOptionsWithSuggestions.find(
(tz) => tz.id === timezone
)}
+ sx={{
+ "& .MuiAutocomplete-inputRoot": {
+ py: 0.75,
+ },
+ }}
renderInput={(params) => }
renderOption={(props, option) => (
= ({
sx={{
backgroundColor: "common.white",
height: "28px",
+ maxWidth: "320px",
}}
>
- {buttonText}
+
+ {buttonText}
+
{children}
>
diff --git a/src/shell/services/types.ts b/src/shell/services/types.ts
index c654351e41..62c7cd1aac 100644
--- a/src/shell/services/types.ts
+++ b/src/shell/services/types.ts
@@ -232,7 +232,8 @@ export type ContentModelFieldDataType =
| "link"
| "internal_link"
| "yes_no"
- | "color";
+ | "color"
+ | "sort";
export interface ContentModelField {
ZUID: string;