-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(page type): Convert to page type should create slice zone for mai…
…n tab if necessary
- Loading branch information
1 parent
eada429
commit 708f67e
Showing
3 changed files
with
369 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import { | ||
CustomType, | ||
DynamicSection, | ||
DynamicSlicesConfig, | ||
} from "@prismicio/types-internal/lib/customtypes"; | ||
|
||
export function getSectionEntries( | ||
customType: CustomType | ||
): [string, DynamicSection][] { | ||
return Object.entries(customType.json); | ||
} | ||
|
||
export function getMainSectionEntry( | ||
customType: CustomType | ||
): [string, DynamicSection] | undefined { | ||
// Currently we cannot rely on the name of the main section | ||
// since it's possible to rename it | ||
const sections = getSectionEntries(customType); | ||
return sections[0]; | ||
} | ||
|
||
export function getSection( | ||
customType: CustomType, | ||
sectionId: string | ||
): DynamicSection | undefined { | ||
return customType.json[sectionId]; | ||
} | ||
|
||
export function getSectionSliceZoneConfig( | ||
customType: CustomType, | ||
sectionId: string | ||
): DynamicSlicesConfig | undefined { | ||
const section = getSection(customType, sectionId); | ||
|
||
if (section === undefined) { | ||
return undefined; | ||
} | ||
|
||
// In Slice Machine we currently only support one slice zone per section | ||
// so we retrieve the first one | ||
const maybeSliceZone = Object.values(section).find( | ||
(value) => value.type === "Slices" | ||
); | ||
|
||
return maybeSliceZone?.config ?? undefined; | ||
} | ||
|
||
export function findAvailableSectionSlicesKey( | ||
customType: CustomType, | ||
sectionId: string | ||
): string { | ||
const sectionsEntries = getSectionEntries(customType); | ||
const sectionIndex = sectionsEntries.findIndex(([key]) => key === sectionId); | ||
|
||
const existingKeys = sectionsEntries.flatMap(([_, section]) => | ||
Object.keys(section).filter((key) => section[key].type === "Slices") | ||
); | ||
|
||
let i = sectionIndex; | ||
let proposedKey; | ||
do { | ||
proposedKey = `slices${i !== 0 ? i.toString() : ""}`; | ||
i++; | ||
} while (existingKeys.includes(proposedKey)); | ||
|
||
return proposedKey; | ||
} | ||
|
||
export function createSectionSliceZone( | ||
customType: CustomType, | ||
sectionId: string | ||
): CustomType { | ||
const maybeSectionSliceZoneConfig = getSectionSliceZoneConfig( | ||
customType, | ||
sectionId | ||
); | ||
|
||
// If the section already has a slice zone, return the custom type as is | ||
if (maybeSectionSliceZoneConfig) { | ||
return customType; | ||
} | ||
|
||
// Get the next available key for the slice zone | ||
const availableSectionSlicesKey = findAvailableSectionSlicesKey( | ||
customType, | ||
sectionId | ||
); | ||
|
||
return { | ||
...customType, | ||
json: { | ||
...customType.json, | ||
[sectionId]: { | ||
...customType.json[sectionId], | ||
[availableSectionSlicesKey]: { | ||
type: "Slices", | ||
fieldset: "Slice Zone", | ||
}, | ||
}, | ||
}, | ||
}; | ||
} | ||
|
||
export function convertToPageType(customType: CustomType): CustomType { | ||
let newCustomType: CustomType = { | ||
...customType, | ||
format: "page", | ||
}; | ||
|
||
// Create the slice zone for the main section if it doesn't exist | ||
const mainSectionEntry = getMainSectionEntry(customType); | ||
if (mainSectionEntry) { | ||
const [mainSectionKey] = mainSectionEntry; | ||
newCustomType = createSectionSliceZone(newCustomType, mainSectionKey); | ||
} | ||
|
||
return newCustomType; | ||
} |
247 changes: 247 additions & 0 deletions
247
packages/slice-machine/src/domain/__tests__/CustomTypeModel.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
import { describe, expect } from "vitest"; | ||
|
||
import { | ||
CustomType, | ||
DynamicSection, | ||
} from "@prismicio/types-internal/lib/customtypes"; | ||
|
||
import * as CustomTypeModel from "../CustomTypeModel"; | ||
|
||
describe("CustomTypeModel test suite", () => { | ||
const mainSection: DynamicSection = { | ||
uid: { | ||
config: { | ||
label: "MainSectionField", | ||
}, | ||
type: "UID", | ||
}, | ||
slices: { | ||
type: "Slices", | ||
fieldset: "Slice Zone", | ||
config: { | ||
choices: { | ||
hero_banner: { | ||
type: "SharedSlice", | ||
}, | ||
promo_section_image_tiles: { | ||
type: "SharedSlice", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}; | ||
const anotherSection: DynamicSection = { | ||
uid: { | ||
config: { | ||
label: "AnotherSectionField", | ||
}, | ||
type: "UID", | ||
}, | ||
}; | ||
const mockCustomType: CustomType = { | ||
format: "custom", | ||
id: "id", | ||
json: { | ||
mainSection, | ||
anotherSection, | ||
}, | ||
label: "lama", | ||
repeatable: true, | ||
status: true, | ||
}; | ||
|
||
it("getSectionEntries should return the sections entries", () => { | ||
expect(CustomTypeModel.getSectionEntries(mockCustomType)).toEqual([ | ||
["mainSection", mainSection], | ||
["anotherSection", anotherSection], | ||
]); | ||
}); | ||
|
||
it("getSectionEntries should return an empty array if there are no sections", () => { | ||
expect( | ||
CustomTypeModel.getSectionEntries({ | ||
...mockCustomType, | ||
json: {}, | ||
}) | ||
).toEqual([]); | ||
}); | ||
|
||
it("getMainSectionEntry should return the first section even if not named Main", () => { | ||
expect(CustomTypeModel.getMainSectionEntry(mockCustomType)).toEqual([ | ||
"mainSection", | ||
mainSection, | ||
]); | ||
}); | ||
|
||
it("getMainSectionEntry should return undefined if there is are sections", () => { | ||
expect( | ||
CustomTypeModel.getMainSectionEntry({ | ||
...mockCustomType, | ||
json: {}, | ||
}) | ||
).toEqual(undefined); | ||
}); | ||
|
||
it("getSection should return the section matching the key", () => { | ||
expect( | ||
CustomTypeModel.getSection(mockCustomType, "anotherSection") | ||
).toEqual(anotherSection); | ||
}); | ||
|
||
it("getSection should return undefined if there are no sections", () => { | ||
expect( | ||
CustomTypeModel.getSection( | ||
{ | ||
...mockCustomType, | ||
json: {}, | ||
}, | ||
"mainSection" | ||
) | ||
).toEqual(undefined); | ||
}); | ||
|
||
it("getSectionSliceZoneConfig should return the config of the given section", () => { | ||
expect( | ||
CustomTypeModel.getSectionSliceZoneConfig(mockCustomType, "mainSection") | ||
).toEqual({ | ||
choices: { | ||
hero_banner: { | ||
type: "SharedSlice", | ||
}, | ||
promo_section_image_tiles: { | ||
type: "SharedSlice", | ||
}, | ||
}, | ||
}); | ||
}); | ||
|
||
it("getSectionSliceZoneConfig should return undefined if there are no sections", () => { | ||
expect( | ||
CustomTypeModel.getSectionSliceZoneConfig( | ||
{ | ||
...mockCustomType, | ||
json: {}, | ||
}, | ||
"mainSection" | ||
) | ||
).toEqual(undefined); | ||
}); | ||
|
||
it("findAvailableSectionSlicesKey should return 'slices'", () => { | ||
expect( | ||
CustomTypeModel.findAvailableSectionSlicesKey( | ||
{ | ||
...mockCustomType, | ||
json: { | ||
anotherSection: {}, | ||
}, | ||
}, | ||
"anotherSection" | ||
) | ||
).toEqual("slices"); | ||
}); | ||
|
||
it("findAvailableSectionSlicesKey should return 'slices1'", () => { | ||
expect( | ||
CustomTypeModel.findAvailableSectionSlicesKey( | ||
mockCustomType, | ||
"anotherSection" | ||
) | ||
).toEqual("slices1"); | ||
}); | ||
|
||
it("findAvailableSectionSlicesKey should return 'slices2'", () => { | ||
expect( | ||
CustomTypeModel.findAvailableSectionSlicesKey( | ||
{ | ||
...mockCustomType, | ||
json: { | ||
mainSection, | ||
SecondSection: { | ||
slices1: { | ||
type: "Slices", | ||
}, | ||
}, | ||
anotherSection, | ||
}, | ||
}, | ||
"anotherSection" | ||
) | ||
).toEqual("slices2"); | ||
}); | ||
|
||
it("findAvailableSectionSlicesKey should return 'slices3'", () => { | ||
expect( | ||
CustomTypeModel.findAvailableSectionSlicesKey( | ||
{ | ||
...mockCustomType, | ||
json: { | ||
mainSection, | ||
SecondSection: { | ||
slices2: { | ||
type: "Slices", | ||
}, | ||
}, | ||
anotherSection, | ||
}, | ||
}, | ||
"anotherSection" | ||
) | ||
).toEqual("slices3"); | ||
}); | ||
|
||
it("createSectionSliceZone should return the given custom type with a slice zone for given section", () => { | ||
expect( | ||
CustomTypeModel.createSectionSliceZone(mockCustomType, "anotherSection") | ||
).toEqual({ | ||
...mockCustomType, | ||
json: { | ||
...mockCustomType.json, | ||
anotherSection: { | ||
...mockCustomType.json.anotherSection, | ||
slices1: { | ||
type: "Slices", | ||
fieldset: "Slice Zone", | ||
}, | ||
}, | ||
}, | ||
}); | ||
}); | ||
|
||
it("createSectionSliceZone should return the same custom type if slice zone already exist for given section", () => { | ||
expect( | ||
CustomTypeModel.createSectionSliceZone(mockCustomType, "mainSection") | ||
).toEqual(mockCustomType); | ||
}); | ||
|
||
it("convertToPageType should convert the given custom type", () => { | ||
expect(CustomTypeModel.convertToPageType(mockCustomType)).toEqual({ | ||
...mockCustomType, | ||
format: "page", | ||
}); | ||
}); | ||
|
||
it("convertToPageType should convert the given custom type with a slice zone for Main section when it doesn't exist", () => { | ||
expect( | ||
CustomTypeModel.convertToPageType({ | ||
...mockCustomType, | ||
json: { | ||
mainSection: {}, | ||
anotherSection, | ||
}, | ||
}) | ||
).toEqual({ | ||
...mockCustomType, | ||
json: { | ||
mainSection: { | ||
slices: { | ||
type: "Slices", | ||
fieldset: "Slice Zone", | ||
}, | ||
}, | ||
anotherSection, | ||
}, | ||
format: "page", | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters