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

wip #255

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft

wip #255

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
3 changes: 3 additions & 0 deletions packages/zcli-themes/macros/new_request_page/follow_up.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{#with parent}}
Follow-up to <a href="{{url}}">request #{{id}}</a>
{{/with}}
297 changes: 297 additions & 0 deletions packages/zcli-themes/macros/new_request_page/request_form.hbs

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions packages/zcli-themes/src/commands/themes/migrate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Command, Flags, CliUx } from '@oclif/core'
import * as path from 'path'
import * as chalk from 'chalk'
import getManifest from '../../lib/getManifest'
import migrate from '../../lib/migrate'
import migrateNoBackwards from '../../lib/migrateNoBackwards'

export default class Migrate extends Command {
static description = 'migrate a theme to the latest api_version'

static enableJsonFlag = true

static flags = {
backwardCompatible: Flags.boolean({ default: false, description: 'Use the new api but keep existing functionality and customizations', allowNo: true })
}

static args = [
{ name: 'themeDirectory', required: true, default: '.' }
]

static examples = [
'$ zcli themes:migrate ./copenhagen_theme --backwardCompatible'
]

static strict = false

async run () {
const { flags, argv: [themeDirectory] } = await this.parse(Migrate)
const { backwardCompatible } = flags
const themePath = path.resolve(themeDirectory)
const manifest = getManifest(themePath)

const { api_version: apiVersion } = manifest

try {
CliUx.ux.action.start('Migrating theme')
switch (apiVersion) {
case 1:
case 2: {
this.log(chalk.green('Migration from version 1 and 2 coming soon'))
break
}
case 3: {
if (backwardCompatible) {
migrate(themePath)
} else {
this.log(chalk.green('Migrating version 3 without backward compatibility'))

migrateNoBackwards(themePath, manifest)
}

break
}
case 4: {
this.log(chalk.green('Theme is already using the latest available api_version'))
break
}
default:
break
}
return {}
} catch (error) {
console.log(error)
}
}
}
36 changes: 36 additions & 0 deletions packages/zcli-themes/src/lib/migrate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as path from 'path'
import * as fs from 'fs'
import { globSync } from 'glob'
import getManifest from './getManifest'
import getTemplates from './getTemplates'

export default async function migrate (themePath: string): Promise<string | void> {
migrateManifest(themePath)
migrateTemplates(themePath)
}

function migrateManifest (themePath: string) {
const manifest = getManifest(themePath)

manifest.api_version = 4

fs.writeFileSync(`${themePath}/manifest.json`, JSON.stringify(manifest, null, 2) + '\n')
}

function migrateTemplates (themePath: string) {
const templates = getTemplates(themePath)
const macrosPath = path.join(__dirname, '..', '..', 'macros')

for (const dentifier of Object.keys(templates)) {
let template = templates[dentifier]
const macros = globSync(`${macrosPath}/${dentifier}/*.hbs`.replace(/\\/g, '/'), { posix: true })

for (const macro of macros) {
const source = fs.readFileSync(macro, 'utf8')
const { name: helper } = path.parse(macro)
template = template.replace(new RegExp(`{{${helper}.*}}`), source)
}

fs.writeFileSync(`${themePath}/templates/${dentifier}.hbs`, template)
}
}
91 changes: 91 additions & 0 deletions packages/zcli-themes/src/lib/migrateNoBackwards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import * as path from 'path'
import * as fs from 'fs'
import type { Manifest } from '../types'
import * as chalk from 'chalk'
import { CLIError } from '@oclif/core/lib/errors'

export default function migrateNoBackwards (themePath: string, manifest: Manifest): void {
updateOrCreateManifest(themePath, manifest)
updateNewRequestTemplate(themePath)
updateDocumentHeadTemplate(themePath)
updateHomePageTemplate(themePath)
}

function updateOrCreateManifest (themePath: string, manifestContent: Manifest): void {
const updated_manifest = manifestContent
updated_manifest.api_version = 4

const manifestFilePath = `${themePath}/manifest.json`

try {
fs.writeFileSync(manifestFilePath, JSON.stringify(updated_manifest, null, 2), { flag: 'w' })
} catch (error) {
throw new CLIError(chalk.red(`manifest.json file was malformed at path: "${manifestFilePath}"`))
}
}

function updateNewRequestTemplate (themePath: string): void {
const templateFilePath = `${themePath}/templates/new_request_page.hbs`
const additionalModuleFilePath = path.join(__dirname, '..', 'templates', 'request_form_script.hbs')

try {
const templateFile = fs.readFileSync(templateFilePath, 'utf-8')
let updatedFile = templateFile.replace(/\n\s*<span class="follow-up-hint"[^>]*>([\s\S]*?)<\/span>/g, '')
updatedFile = updatedFile.replace(/{{request_form .*}}/g, '<div id="new-request-form"></div>')

const additionalModule = fs.readFileSync(additionalModuleFilePath, 'utf-8')
fs.writeFileSync(templateFilePath, updatedFile + additionalModule, { flag: 'w' })
} catch (error) {
throw new CLIError(chalk.red(`file was malformed at path: "${templateFilePath}"`))
}
}

function updateDocumentHeadTemplate (themePath: string): void {
const templateFilePath = `${themePath}/templates/document_head.hbs`
const additionalScriptsFilePath = path.join(__dirname, '..', 'templates', 'document_head_scripts.hbs')

try {
const templateFile = fs.readFileSync(templateFilePath, 'utf-8')
const additionalModule = fs.readFileSync(additionalScriptsFilePath, 'utf-8')
fs.writeFileSync(templateFilePath, templateFile + additionalModule, { flag: 'w' })
} catch (error) {
throw new CLIError(chalk.red(`file was malformed at path: "${templateFilePath}"`))
}
}

function updateHomePageTemplate (themePath: string): void {
const templateFilePath = `${themePath}/templates/home_page.hbs`

try {
const templateFile = fs.readFileSync(templateFilePath, 'utf-8')

const patternsToRemove = [
// Articles patterns
/({{#each categories}}[\s\S]*?)({{#each (?:articles|articles_count|more_articles)}}[\s\S]*?{{\/each}})([\s\S]*{{\/each}})/g,
/({{#each categories}}[\s\S]*?)({{#each [\S]*?\.(?:articles|articles_count|more_articles)}}[\s\S]*?{{\/each}})([\s\S]*{{\/each}})/g,
/({{#each categories}}[\s\S]*?)({{#with (?:articles|articles_count|more_articles)}}[\s\S]*?{{\/with}})([\s\S]*{{\/each}})/g,
/({{#each categories}}[\s\S]*?)({{#with [\S]*?\.(?:articles|articles_count|more_articles)}}[\s\S]*?{{\/with}})([\s\S]*{{\/each}})/g,
/({{#each categories}}[\s\S]*?)({{(?:articles|articles_count|more_articles)}})([\s\S]*{{\/each}})/g,
/({{#each categories}}[\s\S]*?)({{[\S]*?\.(?:articles|articles_count|more_articles)}})([\s\S]*{{\/each}})/g
]

let updatedFile = templateFile

patternsToRemove.forEach(element => {
updatedFile = replaceRecursive(updatedFile, element, updatedFile.match(element) !== null)
})

fs.writeFileSync(templateFilePath, updatedFile, { flag: 'w' })
} catch (error) {
throw new CLIError(chalk.red(`file was malformed at path: "${templateFilePath}"`))
}
}

function replaceRecursive (templateFile: string, pattern: RegExp, match: boolean): string {
if (match) {
const updatedFile = templateFile.replace(pattern, '$1$3')
return replaceRecursive(updatedFile, pattern, updatedFile.match(pattern) !== null)
} else {
return templateFile
}
}
25 changes: 25 additions & 0 deletions packages/zcli-themes/src/templates/document_head_scripts.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script type="text/javascript">
// Load ES module polyfill only for browsers that don't support ES modules
if (!(HTMLScriptElement.supports && HTMLScriptElement.supports('importmap'))) {
document.write('<script async src="{{asset 'es-module-shims.js'}}"><\/script>');
}
</script>
<script type="importmap">
{
"imports": {
"new-request-form": "{{asset 'new-request-form-bundle.js'}}",
"flash-notifications": "{{asset 'flash-notifications-bundle.js'}}",
"new-request-form-translations": "{{asset 'new-request-form-translations-bundle.js'}}",
"shared": "{{asset 'shared-bundle.js'}}",
"wysiwyg": "{{asset 'wysiwyg-bundle.js'}}"
}
}
</script>
<script type="module">
import { renderFlashNotifications } from "flash-notifications";

const settings = {{json settings}};
const closeLabel = {{json (t 'close')}}

renderFlashNotifications(settings, closeLabel);
</script>
31 changes: 31 additions & 0 deletions packages/zcli-themes/src/templates/request_form_script.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

<script type="module">
import { renderNewRequestForm } from "new-request-form";

const container = document.getElementById("new-request-form");

const settings = {{json settings}};

const props = {
requestForm: {{json new_request_form}},
newRequestPath: {{json (page_path 'new_request')}},
parentId: {{json parent.id}},
parentIdPath: {{json parent.url}},
locale: {{json help_center.locale}},
baseLocale: {{json help_center.base_locale}},
hasAtMentions: {{json help_center.at_mentions_enabled}},
userRole: {{json user.role}},
brandId: {{json brand.id}},
wysiwyg: true,
answerBotModal: {
answerBot: {{json answer_bot}},
hasRequestManagement: {{json help_center.request_management_enabled}},
isSignedIn: {{json signed_in}},
helpCenterPath: {{json (page_path 'help_center')}},
requestsPath: {{json (page_path 'requests')}},
requestPath: {{json (page_path 'request' id=answer_bot.request_id)}}
},
};

renderNewRequestForm(settings, props, container);
</script>
Loading