@orion-studios/payload-studio 0.5.0-beta.60 → 0.5.0-beta.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2829,6 +2829,7 @@ function AdminStudioPageEditView(props) {
2829
2829
  const iframeRef = (0, import_react14.useRef)(null);
2830
2830
  const [saving, setSaving] = (0, import_react14.useState)(null);
2831
2831
  const [dirty, setDirty] = (0, import_react14.useState)(false);
2832
+ const [hasUnpublishedChanges, setHasUnpublishedChanges] = (0, import_react14.useState)(false);
2832
2833
  const [canUndo, setCanUndo] = (0, import_react14.useState)(false);
2833
2834
  const [canRedo, setCanRedo] = (0, import_react14.useState)(false);
2834
2835
  const builderBasePath = getPropString4(props, "builderBasePath", "/builder");
@@ -2848,6 +2849,44 @@ function AdminStudioPageEditView(props) {
2848
2849
  setDidResolvePathFallback(true);
2849
2850
  }, [pageIDFromParams]);
2850
2851
  const canPublish = isAdmin3(user) || isEditor(user);
2852
+ const refreshUnpublishedState = async (id) => {
2853
+ try {
2854
+ const response = await fetch(
2855
+ `/api/pages/versions?depth=0&limit=25&sort=-updatedAt&where[parent][equals]=${encodeURIComponent(id)}`,
2856
+ {
2857
+ credentials: "include"
2858
+ }
2859
+ );
2860
+ if (!response.ok) {
2861
+ return;
2862
+ }
2863
+ const payload = await response.json();
2864
+ const docs = Array.isArray(payload.docs) ? payload.docs : [];
2865
+ let latestDraft = 0;
2866
+ let latestPublished = 0;
2867
+ docs.forEach((doc) => {
2868
+ const status = doc.version?._status;
2869
+ const millis = typeof doc.updatedAt === "string" ? Date.parse(doc.updatedAt) : Number.NaN;
2870
+ if (!Number.isFinite(millis)) {
2871
+ return;
2872
+ }
2873
+ if (status === "draft") {
2874
+ latestDraft = Math.max(latestDraft, millis);
2875
+ }
2876
+ if (status === "published") {
2877
+ latestPublished = Math.max(latestPublished, millis);
2878
+ }
2879
+ });
2880
+ setHasUnpublishedChanges(latestDraft > 0 && latestDraft >= latestPublished);
2881
+ } catch {
2882
+ }
2883
+ };
2884
+ (0, import_react14.useEffect)(() => {
2885
+ if (!pageID) {
2886
+ return;
2887
+ }
2888
+ void refreshUnpublishedState(pageID);
2889
+ }, [pageID]);
2851
2890
  const requestSave = (status) => {
2852
2891
  const iframe = iframeRef.current;
2853
2892
  if (!iframe?.contentWindow) {
@@ -2883,6 +2922,13 @@ function AdminStudioPageEditView(props) {
2883
2922
  if (data.type === "save-result") {
2884
2923
  setSaving(null);
2885
2924
  if (data.ok) {
2925
+ if (data.status === "draft") {
2926
+ setHasUnpublishedChanges(true);
2927
+ } else if (data.status === "published") {
2928
+ setHasUnpublishedChanges(false);
2929
+ } else if (pageID) {
2930
+ void refreshUnpublishedState(pageID);
2931
+ }
2886
2932
  import_ui6.toast.success(typeof data.message === "string" ? data.message : "Saved.");
2887
2933
  } else {
2888
2934
  import_ui6.toast.error(typeof data.message === "string" ? data.message : "Save failed.");
@@ -2969,6 +3015,23 @@ function AdminStudioPageEditView(props) {
2969
3015
  ] }),
2970
3016
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
2971
3017
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { color: dirty ? "var(--theme-elevation-900)" : "var(--theme-elevation-600)", fontSize: "0.85rem", fontWeight: 700 }, children: dirty ? "Unsaved changes" : "All changes saved" }),
3018
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3019
+ "div",
3020
+ {
3021
+ style: {
3022
+ background: hasUnpublishedChanges ? "#fff3cd" : "#e7f7ee",
3023
+ border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "#87c79e"}`,
3024
+ borderRadius: 999,
3025
+ color: hasUnpublishedChanges ? "#6a4a00" : "#0e5a2a",
3026
+ fontSize: "0.75rem",
3027
+ fontWeight: 800,
3028
+ padding: "0.2rem 0.55rem",
3029
+ whiteSpace: "nowrap"
3030
+ },
3031
+ title: hasUnpublishedChanges ? "There are saved draft changes not yet published." : "The live page matches the latest published content.",
3032
+ children: hasUnpublishedChanges ? "Unpublished draft changes" : "Live is up to date"
3033
+ }
3034
+ ),
2972
3035
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2973
3036
  "button",
2974
3037
  {
@@ -1646,6 +1646,7 @@ function AdminStudioPageEditView(props) {
1646
1646
  const iframeRef = useRef3(null);
1647
1647
  const [saving, setSaving] = useState8(null);
1648
1648
  const [dirty, setDirty] = useState8(false);
1649
+ const [hasUnpublishedChanges, setHasUnpublishedChanges] = useState8(false);
1649
1650
  const [canUndo, setCanUndo] = useState8(false);
1650
1651
  const [canRedo, setCanRedo] = useState8(false);
1651
1652
  const builderBasePath = getPropString4(props, "builderBasePath", "/builder");
@@ -1665,6 +1666,44 @@ function AdminStudioPageEditView(props) {
1665
1666
  setDidResolvePathFallback(true);
1666
1667
  }, [pageIDFromParams]);
1667
1668
  const canPublish = isAdmin3(user) || isEditor(user);
1669
+ const refreshUnpublishedState = async (id) => {
1670
+ try {
1671
+ const response = await fetch(
1672
+ `/api/pages/versions?depth=0&limit=25&sort=-updatedAt&where[parent][equals]=${encodeURIComponent(id)}`,
1673
+ {
1674
+ credentials: "include"
1675
+ }
1676
+ );
1677
+ if (!response.ok) {
1678
+ return;
1679
+ }
1680
+ const payload = await response.json();
1681
+ const docs = Array.isArray(payload.docs) ? payload.docs : [];
1682
+ let latestDraft = 0;
1683
+ let latestPublished = 0;
1684
+ docs.forEach((doc) => {
1685
+ const status = doc.version?._status;
1686
+ const millis = typeof doc.updatedAt === "string" ? Date.parse(doc.updatedAt) : Number.NaN;
1687
+ if (!Number.isFinite(millis)) {
1688
+ return;
1689
+ }
1690
+ if (status === "draft") {
1691
+ latestDraft = Math.max(latestDraft, millis);
1692
+ }
1693
+ if (status === "published") {
1694
+ latestPublished = Math.max(latestPublished, millis);
1695
+ }
1696
+ });
1697
+ setHasUnpublishedChanges(latestDraft > 0 && latestDraft >= latestPublished);
1698
+ } catch {
1699
+ }
1700
+ };
1701
+ useEffect9(() => {
1702
+ if (!pageID) {
1703
+ return;
1704
+ }
1705
+ void refreshUnpublishedState(pageID);
1706
+ }, [pageID]);
1668
1707
  const requestSave = (status) => {
1669
1708
  const iframe = iframeRef.current;
1670
1709
  if (!iframe?.contentWindow) {
@@ -1700,6 +1739,13 @@ function AdminStudioPageEditView(props) {
1700
1739
  if (data.type === "save-result") {
1701
1740
  setSaving(null);
1702
1741
  if (data.ok) {
1742
+ if (data.status === "draft") {
1743
+ setHasUnpublishedChanges(true);
1744
+ } else if (data.status === "published") {
1745
+ setHasUnpublishedChanges(false);
1746
+ } else if (pageID) {
1747
+ void refreshUnpublishedState(pageID);
1748
+ }
1703
1749
  toast.success(typeof data.message === "string" ? data.message : "Saved.");
1704
1750
  } else {
1705
1751
  toast.error(typeof data.message === "string" ? data.message : "Save failed.");
@@ -1786,6 +1832,23 @@ function AdminStudioPageEditView(props) {
1786
1832
  ] }),
1787
1833
  /* @__PURE__ */ jsxs12("div", { style: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
1788
1834
  /* @__PURE__ */ jsx13("div", { style: { color: dirty ? "var(--theme-elevation-900)" : "var(--theme-elevation-600)", fontSize: "0.85rem", fontWeight: 700 }, children: dirty ? "Unsaved changes" : "All changes saved" }),
1835
+ /* @__PURE__ */ jsx13(
1836
+ "div",
1837
+ {
1838
+ style: {
1839
+ background: hasUnpublishedChanges ? "#fff3cd" : "#e7f7ee",
1840
+ border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "#87c79e"}`,
1841
+ borderRadius: 999,
1842
+ color: hasUnpublishedChanges ? "#6a4a00" : "#0e5a2a",
1843
+ fontSize: "0.75rem",
1844
+ fontWeight: 800,
1845
+ padding: "0.2rem 0.55rem",
1846
+ whiteSpace: "nowrap"
1847
+ },
1848
+ title: hasUnpublishedChanges ? "There are saved draft changes not yet published." : "The live page matches the latest published content.",
1849
+ children: hasUnpublishedChanges ? "Unpublished draft changes" : "Live is up to date"
1850
+ }
1851
+ ),
1789
1852
  /* @__PURE__ */ jsx13(
1790
1853
  "button",
1791
1854
  {
@@ -1,9 +1,9 @@
1
- import {
2
- assertStudioDocumentV1
3
- } from "./chunk-HXGAG6I7.mjs";
4
1
  import {
5
2
  studioDocumentToLayout
6
3
  } from "./chunk-OHAGPJBM.mjs";
4
+ import {
5
+ assertStudioDocumentV1
6
+ } from "./chunk-HXGAG6I7.mjs";
7
7
  import {
8
8
  __export
9
9
  } from "./chunk-6BWS3CLP.mjs";
@@ -33,7 +33,7 @@ function createPayloadClient(config) {
33
33
 
34
34
  // src/nextjs/queries/pages.ts
35
35
  import { unstable_cache } from "next/cache";
36
- var PAGE_QUERY_CACHE_VERSION = "v3-published-query-fix";
36
+ var PAGE_QUERY_CACHE_VERSION = "v4-published-only-public";
37
37
  function withStudioDocumentLayout(page) {
38
38
  if (!page) {
39
39
  return null;
@@ -64,13 +64,18 @@ async function queryPageByPath(payload, path, draft) {
64
64
  equals: path
65
65
  }
66
66
  };
67
+ const publishedWhere = {
68
+ _status: {
69
+ equals: "published"
70
+ }
71
+ };
67
72
  const result = await payload.find({
68
73
  collection: "pages",
69
74
  depth: 2,
70
75
  draft,
71
76
  limit: 1,
72
77
  overrideAccess: false,
73
- where: pathWhere
78
+ where: draft ? pathWhere : { and: [pathWhere, publishedWhere] }
74
79
  });
75
80
  if (result.docs.length > 0) {
76
81
  return withStudioDocumentLayout(result.docs[0] || null);
@@ -87,7 +92,7 @@ async function queryPageByPath(payload, path, draft) {
87
92
  draft,
88
93
  limit: 1,
89
94
  overrideAccess: false,
90
- where: homeWhere
95
+ where: draft ? homeWhere : { and: [homeWhere, publishedWhere] }
91
96
  });
92
97
  return withStudioDocumentLayout(homeResult.docs[0] || null);
93
98
  }
@@ -118,7 +123,12 @@ function createPageQueries(getPayloadClient, contentTag = "website-content") {
118
123
  draft: false,
119
124
  limit: 1e3,
120
125
  pagination: false,
121
- overrideAccess: false
126
+ overrideAccess: false,
127
+ where: {
128
+ _status: {
129
+ equals: "published"
130
+ }
131
+ }
122
132
  });
123
133
  return pages.docs.map((doc) => doc.path).filter((path) => typeof path === "string" && path.length > 0);
124
134
  }
package/dist/index.js CHANGED
@@ -2858,7 +2858,7 @@ var createDefaultStudioDocument = (title) => ({
2858
2858
  });
2859
2859
 
2860
2860
  // src/nextjs/queries/pages.ts
2861
- var PAGE_QUERY_CACHE_VERSION = "v3-published-query-fix";
2861
+ var PAGE_QUERY_CACHE_VERSION = "v4-published-only-public";
2862
2862
  function withStudioDocumentLayout(page) {
2863
2863
  if (!page) {
2864
2864
  return null;
@@ -2889,13 +2889,18 @@ async function queryPageByPath(payload, path2, draft) {
2889
2889
  equals: path2
2890
2890
  }
2891
2891
  };
2892
+ const publishedWhere = {
2893
+ _status: {
2894
+ equals: "published"
2895
+ }
2896
+ };
2892
2897
  const result = await payload.find({
2893
2898
  collection: "pages",
2894
2899
  depth: 2,
2895
2900
  draft,
2896
2901
  limit: 1,
2897
2902
  overrideAccess: false,
2898
- where: pathWhere
2903
+ where: draft ? pathWhere : { and: [pathWhere, publishedWhere] }
2899
2904
  });
2900
2905
  if (result.docs.length > 0) {
2901
2906
  return withStudioDocumentLayout(result.docs[0] || null);
@@ -2912,7 +2917,7 @@ async function queryPageByPath(payload, path2, draft) {
2912
2917
  draft,
2913
2918
  limit: 1,
2914
2919
  overrideAccess: false,
2915
- where: homeWhere
2920
+ where: draft ? homeWhere : { and: [homeWhere, publishedWhere] }
2916
2921
  });
2917
2922
  return withStudioDocumentLayout(homeResult.docs[0] || null);
2918
2923
  }
@@ -2943,7 +2948,12 @@ function createPageQueries(getPayloadClient, contentTag = "website-content") {
2943
2948
  draft: false,
2944
2949
  limit: 1e3,
2945
2950
  pagination: false,
2946
- overrideAccess: false
2951
+ overrideAccess: false,
2952
+ where: {
2953
+ _status: {
2954
+ equals: "published"
2955
+ }
2956
+ }
2947
2957
  });
2948
2958
  return pages.docs.map((doc) => doc.path).filter((path2) => typeof path2 === "string" && path2.length > 0);
2949
2959
  }
package/dist/index.mjs CHANGED
@@ -9,14 +9,14 @@ import {
9
9
  } from "./chunk-4AOYZGIY.mjs";
10
10
  import {
11
11
  nextjs_exports
12
- } from "./chunk-Y2TOGMF2.mjs";
13
- import {
14
- studio_exports
15
- } from "./chunk-HXGAG6I7.mjs";
12
+ } from "./chunk-Z7NIOJNB.mjs";
16
13
  import {
17
14
  studio_pages_exports
18
15
  } from "./chunk-OHAGPJBM.mjs";
19
16
  import "./chunk-SIL2J5MF.mjs";
17
+ import {
18
+ studio_exports
19
+ } from "./chunk-HXGAG6I7.mjs";
20
20
  import "./chunk-6BWS3CLP.mjs";
21
21
  export {
22
22
  admin_exports as admin,
@@ -312,7 +312,7 @@ var studioDocumentToLayout = (document) => document.nodes.map((node) => ({
312
312
  }));
313
313
 
314
314
  // src/nextjs/queries/pages.ts
315
- var PAGE_QUERY_CACHE_VERSION = "v3-published-query-fix";
315
+ var PAGE_QUERY_CACHE_VERSION = "v4-published-only-public";
316
316
  function withStudioDocumentLayout(page) {
317
317
  if (!page) {
318
318
  return null;
@@ -343,13 +343,18 @@ async function queryPageByPath(payload, path, draft) {
343
343
  equals: path
344
344
  }
345
345
  };
346
+ const publishedWhere = {
347
+ _status: {
348
+ equals: "published"
349
+ }
350
+ };
346
351
  const result = await payload.find({
347
352
  collection: "pages",
348
353
  depth: 2,
349
354
  draft,
350
355
  limit: 1,
351
356
  overrideAccess: false,
352
- where: pathWhere
357
+ where: draft ? pathWhere : { and: [pathWhere, publishedWhere] }
353
358
  });
354
359
  if (result.docs.length > 0) {
355
360
  return withStudioDocumentLayout(result.docs[0] || null);
@@ -366,7 +371,7 @@ async function queryPageByPath(payload, path, draft) {
366
371
  draft,
367
372
  limit: 1,
368
373
  overrideAccess: false,
369
- where: homeWhere
374
+ where: draft ? homeWhere : { and: [homeWhere, publishedWhere] }
370
375
  });
371
376
  return withStudioDocumentLayout(homeResult.docs[0] || null);
372
377
  }
@@ -397,7 +402,12 @@ function createPageQueries(getPayloadClient, contentTag = "website-content") {
397
402
  draft: false,
398
403
  limit: 1e3,
399
404
  pagination: false,
400
- overrideAccess: false
405
+ overrideAccess: false,
406
+ where: {
407
+ _status: {
408
+ equals: "published"
409
+ }
410
+ }
401
411
  });
402
412
  return pages.docs.map((doc) => doc.path).filter((path) => typeof path === "string" && path.length > 0);
403
413
  }
@@ -4,10 +4,10 @@ import {
4
4
  createPayloadClient,
5
5
  createSiteQueries,
6
6
  resolveMedia
7
- } from "../chunk-Y2TOGMF2.mjs";
8
- import "../chunk-HXGAG6I7.mjs";
7
+ } from "../chunk-Z7NIOJNB.mjs";
9
8
  import "../chunk-OHAGPJBM.mjs";
10
9
  import "../chunk-SIL2J5MF.mjs";
10
+ import "../chunk-HXGAG6I7.mjs";
11
11
  import "../chunk-6BWS3CLP.mjs";
12
12
  export {
13
13
  WEBSITE_CONTENT_TAG,
@@ -1973,19 +1973,23 @@ function BuilderPageEditor({ initialDoc, pageID }) {
1973
1973
  try {
1974
1974
  const normalizedLayout = withHeroMediaFallbacks(layout);
1975
1975
  const persistedLayout = toPersistedLayout(normalizedLayout);
1976
- const response = await fetch(`/api/pages/${pageID}`, {
1977
- body: JSON.stringify({
1978
- _status: status,
1979
- layout: persistedLayout,
1980
- studioDocument: layoutToStudioDocument(
1981
- normalizedLayout,
1982
- title,
1983
- {
1984
- pageWidthDefault: pageDefaults.pageWidthDefault
1985
- }
1986
- ),
1987
- title
1988
- }),
1976
+ const payload = {
1977
+ layout: persistedLayout,
1978
+ studioDocument: layoutToStudioDocument(
1979
+ normalizedLayout,
1980
+ title,
1981
+ {
1982
+ pageWidthDefault: pageDefaults.pageWidthDefault
1983
+ }
1984
+ ),
1985
+ title
1986
+ };
1987
+ if (status === "published") {
1988
+ payload._status = "published";
1989
+ }
1990
+ const endpoint = status === "draft" ? `/api/pages/${pageID}?draft=true` : `/api/pages/${pageID}`;
1991
+ const response = await fetch(endpoint, {
1992
+ body: JSON.stringify(payload),
1989
1993
  credentials: "include",
1990
1994
  headers: {
1991
1995
  "Content-Type": "application/json"
@@ -1945,19 +1945,23 @@ function BuilderPageEditor({ initialDoc, pageID }) {
1945
1945
  try {
1946
1946
  const normalizedLayout = withHeroMediaFallbacks(layout);
1947
1947
  const persistedLayout = toPersistedLayout(normalizedLayout);
1948
- const response = await fetch(`/api/pages/${pageID}`, {
1949
- body: JSON.stringify({
1950
- _status: status,
1951
- layout: persistedLayout,
1952
- studioDocument: layoutToStudioDocument(
1953
- normalizedLayout,
1954
- title,
1955
- {
1956
- pageWidthDefault: pageDefaults.pageWidthDefault
1957
- }
1958
- ),
1959
- title
1960
- }),
1948
+ const payload = {
1949
+ layout: persistedLayout,
1950
+ studioDocument: layoutToStudioDocument(
1951
+ normalizedLayout,
1952
+ title,
1953
+ {
1954
+ pageWidthDefault: pageDefaults.pageWidthDefault
1955
+ }
1956
+ ),
1957
+ title
1958
+ };
1959
+ if (status === "published") {
1960
+ payload._status = "published";
1961
+ }
1962
+ const endpoint = status === "draft" ? `/api/pages/${pageID}?draft=true` : `/api/pages/${pageID}`;
1963
+ const response = await fetch(endpoint, {
1964
+ body: JSON.stringify(payload),
1961
1965
  credentials: "include",
1962
1966
  headers: {
1963
1967
  "Content-Type": "application/json"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orion-studios/payload-studio",
3
- "version": "0.5.0-beta.60",
3
+ "version": "0.5.0-beta.61",
4
4
  "description": "Unified Payload CMS toolkit for Orion Studios",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",