@stackbit/cms-core 1.0.20-develop.1 → 1.0.20-develop.2

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.
@@ -46,7 +46,8 @@ import {
46
46
  contentChangeResultCounts,
47
47
  updateOperationValueFieldWithCrossReference,
48
48
  getErrorAtLine,
49
- findContentSourcesDataForTypeOrId
49
+ findContentSourcesDataForTypeOrId,
50
+ getDocumentFieldForLocale
50
51
  } from './content-store-utils';
51
52
  import {
52
53
  getSiteMapEntriesFromStackbitConfig,
@@ -1986,6 +1987,122 @@ export class ContentStore {
1986
1987
  }
1987
1988
  }
1988
1989
 
1990
+ async getStagedChanges({
1991
+ scope,
1992
+ locale,
1993
+ shallow,
1994
+ objects
1995
+ }: {
1996
+ scope: 'all' | 'code' | 'content';
1997
+ locale?: string;
1998
+ shallow?: boolean;
1999
+ objects: { srcObjectId: string; srcProjectId: string; srcType: string; srcEnvironment?: string }[];
2000
+ }): Promise<ContentStoreTypes.StagedChange[]> {
2001
+ const getObjectStrId = (srcType: string, srcProjectId: string, srcObjectId: string) => `${srcType}:${srcProjectId}:${srcObjectId}`;
2002
+
2003
+ const documents = this.getDocuments({ locale });
2004
+ const assets = this.getAssets({ locale });
2005
+ const allObjects = [...documents, ...assets];
2006
+
2007
+ const isPublishingSpecificDocuments = scope === 'content' && objects.length;
2008
+
2009
+ let publishableObjects: (ContentStoreTypes.Document | ContentStoreTypes.Asset)[];
2010
+ // filter content only if scope is content, if scope is all ignore objects
2011
+ if (isPublishingSpecificDocuments) {
2012
+ const objectIds = objects.map((object) => object.srcObjectId);
2013
+ publishableObjects = [
2014
+ ..._.filter(documents, (document) => objectIds.includes(document.srcObjectId)),
2015
+ ..._.filter(assets, (asset) => objectIds.includes(asset.srcObjectId))
2016
+ ];
2017
+ } else {
2018
+ // scope === 'all' or scope === 'content' with empty objects
2019
+ publishableObjects = allObjects;
2020
+ }
2021
+
2022
+ const visited: string[] = publishableObjects.map((object) => getObjectStrId(object.srcType, object.srcProjectId, object.srcObjectId));
2023
+
2024
+ const findUsedChangedObjects = (
2025
+ rootObject: ContentStoreTypes.Document,
2026
+ fields: ContentStoreTypes.DocumentField[]
2027
+ ): Array<ContentStoreTypes.Document | ContentStoreTypes.Asset> => {
2028
+ return _.flatMap(fields, (field) => {
2029
+ const localizedField = getDocumentFieldForLocale(field, locale);
2030
+
2031
+ if (localizedField?.type === 'list') {
2032
+ return findUsedChangedObjects(rootObject, localizedField.items);
2033
+ } else if (localizedField?.type === 'object' || localizedField?.type === 'model') {
2034
+ return localizedField.isUnset ? [] : findUsedChangedObjects(rootObject, Object.values(localizedField.fields));
2035
+ } else if (localizedField?.type === 'reference') {
2036
+ if (localizedField.isUnset) {
2037
+ return [];
2038
+ }
2039
+
2040
+ const { refId } = localizedField;
2041
+
2042
+ const objectStrId = getObjectStrId(rootObject.srcType, rootObject.srcProjectId, refId);
2043
+ if (visited.includes(objectStrId)) {
2044
+ return [];
2045
+ }
2046
+
2047
+ visited.push(objectStrId);
2048
+
2049
+ const refObject = _.find(allObjects, {
2050
+ srcObjectId: refId,
2051
+ srcType: rootObject.srcType,
2052
+ srcProjectId: rootObject.srcProjectId
2053
+ });
2054
+ if (refObject) {
2055
+ if (refObject.type === 'asset') {
2056
+ return refObject.isChanged ? [refObject] : [];
2057
+ }
2058
+ return [...(refObject.isChanged ? [refObject] : []), ...findUsedChangedObjects(refObject, Object.values(refObject.fields))];
2059
+ }
2060
+ }
2061
+
2062
+ return [];
2063
+ });
2064
+ };
2065
+
2066
+ const changes = publishableObjects.reduce((result: ContentStoreTypes.StagedChange[], object: ContentStoreTypes.Document | ContentStoreTypes.Asset) => {
2067
+ const changedObjects = [];
2068
+
2069
+ if (object.isChanged) {
2070
+ changedObjects.push(object);
2071
+ }
2072
+
2073
+ if (isPublishingSpecificDocuments && object.type !== 'asset' && !shallow) {
2074
+ // when publishing specific documents, go over changed fields and see if their reference objects are not changed in case
2075
+ // it's not already in the publishableObjects list;
2076
+ changedObjects.push(...findUsedChangedObjects(object, Object.values(object.fields)));
2077
+ }
2078
+
2079
+ result.push(
2080
+ ...changedObjects.map(
2081
+ (object): ContentStoreTypes.StagedChange => ({
2082
+ changeId: object.srcObjectId,
2083
+ changeType: object.type === 'document' ? 'content' : 'asset',
2084
+ label: object.type === 'asset' ? object.srcObjectLabel : object.getPreview({ locale }).previewTitle,
2085
+ status: object.status,
2086
+ srcModelName: object.srcModelName,
2087
+ srcObjectId: object.srcObjectId,
2088
+ srcProjectId: object.srcProjectId,
2089
+ srcEnvironment: object.srcEnvironment,
2090
+ srcType: object.srcType,
2091
+ createdAt: object.createdAt,
2092
+ createdBy: object.createdBy,
2093
+ updatedAt: object.updatedAt,
2094
+ updatedBy: object.updatedBy || [],
2095
+ locale: object.locale
2096
+ })
2097
+ )
2098
+ );
2099
+
2100
+ return result;
2101
+ }, []);
2102
+
2103
+ return changes;
2104
+ }
2105
+
1989
2106
  getAsset({ srcAssetId, srcProjectId, srcType }: { srcAssetId: string; srcProjectId: string; srcType: string }): ContentStoreTypes.Asset | undefined {
1990
2107
  const contentSourceId = getContentSourceId(srcType, srcProjectId);
1991
2108
  const contentSourceData = this.getContentSourceDataByIdOrThrow(contentSourceId);
@@ -81,6 +81,7 @@ export interface ContentChangeResult {
81
81
  export interface User {
82
82
  name: string;
83
83
  email: string;
84
+ role?: string;
84
85
  sso?: StackbitTypes.UserSSOProfile;
85
86
  connections: {
86
87
  type: string;
@@ -5,3 +5,4 @@ export * from './content-store-api-document-fields';
5
5
  export * from './content-store-update-operation';
6
6
  export * from './search-filter';
7
7
  export * from './custom-actions';
8
+ export * from './publish-types';
@@ -0,0 +1,25 @@
1
+ import { DocumentStatus } from '@stackbit/types/src/content-source-document';
2
+
3
+ export type StagedChange = {
4
+ changeId: string;
5
+ isStaged?: boolean;
6
+ filepath?: string;
7
+ changeType: 'content' | 'asset' | 'schema';
8
+ label: string;
9
+ updatedBy: string[];
10
+ updatedAt?: string;
11
+ createdAt?: string;
12
+ createdBy?: string;
13
+ status: DocumentStatus;
14
+ srcObjectId: string;
15
+ srcModelName?: string;
16
+ srcProjectId: string;
17
+ srcEnvironment?: string;
18
+ srcType: string;
19
+ locale?: string;
20
+ };
21
+
22
+ export enum PublishProjectScope {
23
+ All = 'all',
24
+ Content = 'content'
25
+ }
@@ -187,7 +187,7 @@ export const getFilteredModelForUser = ({
187
187
  throw new Error(`Model with name ${name} not found in source`);
188
188
  }
189
189
 
190
- const shouldResolvePermissions = permissionsForModel || typeof model?.permissions === 'function';
190
+ const shouldResolvePermissions = permissionsForModel || model?.permissions;
191
191
  if (!user || !shouldResolvePermissions) {
192
192
  return model;
193
193
  }
@@ -207,7 +207,7 @@ export const getFilteredModelForUser = ({
207
207
  }) ?? permissionsResult;
208
208
  const permissions = _.isEmpty(permissionsHookResult) ? undefined : permissionsHookResult;
209
209
 
210
- const shouldHideModel = permissions?.canView === false;
210
+ const shouldHideModel = model.hidden || permissions?.canView === false;
211
211
  return {
212
212
  ...model,
213
213
  permissions,
@@ -1,12 +0,0 @@
1
- import * as ContentStoreTypes from '../types';
2
- import { SearchFilterItem } from '../types';
3
- import { ScheduledAction } from '@stackbit/types';
4
- import { SchemaForSearch } from './search-utils';
5
- declare type CustomFilterMethod = (filter: SearchFilterItem, document: ContentStoreTypes.Document, opts: {
6
- locale?: string;
7
- schema: SchemaForSearch;
8
- activeScheduledActionsByDocumentId: Record<string, ScheduledAction[]>;
9
- }) => boolean;
10
- export declare const CUSTOM_FILTERS: Record<string, CustomFilterMethod>;
11
- export {};
12
- //# sourceMappingURL=custom-search-filters.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"custom-search-filters.d.ts","sourceRoot":"","sources":["../../src/utils/custom-search-filters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,iBAAiB,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAqB,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAiE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEhH,aAAK,kBAAkB,GAAG,CACtB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,EACpC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC;IAAC,kCAAkC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;CAAE,KACxH,OAAO,CAAC;AAEb,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAwC7D,CAAC"}
@@ -1,46 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CUSTOM_FILTERS = void 0;
4
- const search_utils_1 = require("./search-utils");
5
- exports.CUSTOM_FILTERS = {
6
- hasSchedules: (filter, document, opts) => {
7
- var _a;
8
- const field = {
9
- type: 'boolean',
10
- value: !!((_a = opts.activeScheduledActionsByDocumentId[document.srcObjectId]) === null || _a === void 0 ? void 0 : _a.length)
11
- };
12
- return (0, search_utils_1.isBooleanFieldMatches)({ field, filter, locale: opts.locale });
13
- },
14
- scheduledActionId: (filter, document, opts) => {
15
- var _a, _b;
16
- const field = {
17
- type: 'list',
18
- items: (_b = (_a = opts.activeScheduledActionsByDocumentId[document.srcObjectId]) === null || _a === void 0 ? void 0 : _a.map((scheduledAction) => ({
19
- type: 'string',
20
- value: scheduledAction.id
21
- }))) !== null && _b !== void 0 ? _b : []
22
- };
23
- const model = {
24
- type: 'object',
25
- name: '',
26
- fields: [
27
- {
28
- name: '',
29
- type: 'list',
30
- items: {
31
- type: 'string'
32
- }
33
- }
34
- ]
35
- };
36
- return (0, search_utils_1.isListFieldMatches)({ field, filter, model, locale: opts.locale, document });
37
- },
38
- scheduledActionDate: (filter, document, opts) => {
39
- var _a, _b;
40
- return ((_b = (_a = opts.activeScheduledActionsByDocumentId[document.srcObjectId]) === null || _a === void 0 ? void 0 : _a.some((scheduledAction) => {
41
- const field = { type: 'date', value: scheduledAction.executeAt };
42
- return (0, search_utils_1.isDateFieldMatches)({ field, filter, locale: opts.locale });
43
- })) !== null && _b !== void 0 ? _b : false);
44
- }
45
- };
46
- //# sourceMappingURL=custom-search-filters.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"custom-search-filters.js","sourceRoot":"","sources":["../../src/utils/custom-search-filters.ts"],"names":[],"mappings":";;;AAIA,iDAAgH;AAQnG,QAAA,cAAc,GAAuC;IAC9D,YAAY,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;;QACrC,MAAM,KAAK,GAAG;YACV,IAAI,EAAE,SAAkB;YACxB,KAAK,EAAE,CAAC,CAAC,CAAA,MAAA,IAAI,CAAC,kCAAkC,CAAC,QAAQ,CAAC,WAAW,CAAC,0CAAE,MAAM,CAAA;SACjF,CAAC;QACF,OAAO,IAAA,oCAAqB,EAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,iBAAiB,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;;QAC1C,MAAM,KAAK,GAAsB;YAC7B,IAAI,EAAE,MAAM;YACZ,KAAK,EACD,MAAA,MAAA,IAAI,CAAC,kCAAkC,CAAC,QAAQ,CAAC,WAAW,CAAC,0CAAE,GAAG,CAAC,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;gBACrF,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,eAAe,CAAC,EAAE;aAC5B,CAAC,CAAC,mCAAI,EAAE;SAChB,CAAC;QACF,MAAM,KAAK,GAAU;YACjB,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,EAAE;YACR,MAAM,EAAE;gBACJ;oBACI,IAAI,EAAE,EAAE;oBACR,IAAI,EAAE,MAAM;oBACZ,KAAK,EAAE;wBACH,IAAI,EAAE,QAAQ;qBACjB;iBACJ;aACJ;SACJ,CAAC;QACF,OAAO,IAAA,iCAAkB,EAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,mBAAmB,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;;QAC5C,OAAO,CACH,MAAA,MAAA,IAAI,CAAC,kCAAkC,CAAC,QAAQ,CAAC,WAAW,CAAC,0CAAE,IAAI,CAAC,CAAC,eAAe,EAAE,EAAE;YACpF,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,MAAe,EAAE,KAAK,EAAE,eAAe,CAAC,SAAS,EAAE,CAAC;YAC1E,OAAO,IAAA,iCAAkB,EAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACtE,CAAC,CAAC,mCAAI,KAAK,CACd,CAAC;IACN,CAAC;CACJ,CAAC"}