* Fix breadcrumb colors * HorizontalTabs * Team List Item WIP * Horizontal Tabs * Cards * Remove team list item WIP * Login Page * Add welcome back i118n * EventType page work * Update EventType Icons * WIP Availability * Horizontal Tab Work * Add build command for in root * Update build DIr/command * Add Edit Button + change buttons to v2 * Availablitiy page * Fix IPAD * Make mobile look a little nicer * WIP bookingshell * Remove list items from breaking build * Add Embed ModalBox for routing forms * Mian bulk of Booking Page. * Few updates to components * Fix chormatic feedback * Add duplicate form support * Fix duplication logic * Change to feathericons everywhere and other fixes * Dont allow routes for fallback route * Fix banner * Fix Empty Screen * Text area + embded window fixes * Semi fix avatar * Fix all TS issues * Fix tests * Troubleshoot container + Active on count * Support routing using query params * Improve mobile * NITS * Fix padding on input * Support multiselect in router endpoint * Fix the issue where app goes in embed mode after viewing embed once * Fix icons * Add router url tests * Add Responses download and form toggling tests * Add required validation test * Change Icons everywhere * App typeform app * Improvements in cli * Starting to move event types settings to tabs * Begin migration to single page form * Single page tabs * Limits Page * Advanced tab * Add RHF to dependancies * Add typeform how-to-use page * Add typeform how-to-use page and screenshots * Most of advanced tab * Solved RHF mismtach * Build fixes * RHF conditionals fixes * Improved legibility * Fix TS error * Add missing image * Update CliApp.tsx * Major refactor/organisation into optional V2 UI * Portal EditLocationModal * Fix dialoug form * Update imports * Auto Animate + custom inputs WIP * Custom Inputs * WIP Apps * Fixing stories imports * Stripe app * Remove duplicate dialog * Remove duplicate dialog * Major locations cleanup, 10s of bug fixes and app-store improvements * Fix missing pieces * More fixes * Fix embed URL * Fix app toggles + number of active apps * Fix container padding on disabledBorder prop * Removes strict * more fixes * EventType Team page WIP * Fix embed * NIT * Add Darkmode gray color * V2 Shell WIP * Fix headings on shell V2 * Fix mobile layout with V2 shell * V2 create event type button * Checked Team Select * Hidden to happen on save - not on toggle * Team Attendee Select animation * Fix scheduling type and remove multi select label * Fix overflow on teams url * Revert console * Revert api * Fix Embed TS errors * Fix TS errors * Fix Eslint errors * Fix TS errors for UI * Fix ESLINT error * Fix TS errors * Add missing import * Fix CLI * Add a default placeholder * Remove hardcoded daily:integrations * Fix message for payment page * Revert api and console to main * Update README * Fix TS errors * Fix Lint warnings * Fix Tests * Fix conflict issues * Fix conflict issues Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: zomars <zomars@me.com>
181 lines
4.8 KiB
TypeScript
181 lines
4.8 KiB
TypeScript
import chokidar from "chokidar";
|
|
import fs from "fs";
|
|
import { debounce } from "lodash";
|
|
import path from "path";
|
|
import prettier from "prettier";
|
|
|
|
import prettierConfig from "../../config/prettier-preset";
|
|
|
|
let isInWatchMode = false;
|
|
if (process.argv[2] === "--watch") {
|
|
isInWatchMode = true;
|
|
}
|
|
|
|
const formatOutput = (source: string) => prettier.format(source, prettierConfig);
|
|
|
|
const APP_STORE_PATH = path.join(__dirname, "..", "..", "app-store");
|
|
type App = {
|
|
name: string;
|
|
path: string;
|
|
};
|
|
function getAppName(candidatePath) {
|
|
function isValidAppName(candidatePath) {
|
|
if (
|
|
!candidatePath.startsWith("_") &&
|
|
candidatePath !== "ee" &&
|
|
!candidatePath.includes("/") &&
|
|
!candidatePath.includes("\\")
|
|
) {
|
|
return candidatePath;
|
|
}
|
|
}
|
|
if (isValidAppName(candidatePath)) {
|
|
// Already a dirname of an app
|
|
return candidatePath;
|
|
}
|
|
// Get dirname of app from full path
|
|
const dirName = path.relative(APP_STORE_PATH, candidatePath);
|
|
return isValidAppName(dirName) ? dirName : null;
|
|
}
|
|
|
|
function generateFiles() {
|
|
const browserOutput = [`import dynamic from "next/dynamic"`];
|
|
const serverOutput = [];
|
|
const appDirs: App[] = [];
|
|
|
|
fs.readdirSync(`${APP_STORE_PATH}`).forEach(function (dir) {
|
|
if (dir === "ee") {
|
|
fs.readdirSync(path.join(APP_STORE_PATH, dir)).forEach(function (eeDir) {
|
|
if (fs.statSync(path.join(APP_STORE_PATH, dir, eeDir)).isDirectory()) {
|
|
if (!getAppName(path.resolve(eeDir))) {
|
|
appDirs.push({
|
|
name: eeDir,
|
|
path: path.join(dir, eeDir),
|
|
});
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
if (fs.statSync(path.join(APP_STORE_PATH, dir)).isDirectory()) {
|
|
if (!getAppName(dir)) {
|
|
return;
|
|
}
|
|
appDirs.push({
|
|
name: dir,
|
|
path: dir,
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
function forEachAppDir(callback: (arg: App) => void) {
|
|
for (let i = 0; i < appDirs.length; i++) {
|
|
callback(appDirs[i]);
|
|
}
|
|
}
|
|
|
|
function getObjectExporter(
|
|
objectName,
|
|
{
|
|
fileToBeImported,
|
|
importBuilder,
|
|
entryBuilder,
|
|
}: {
|
|
fileToBeImported: string;
|
|
importBuilder?: (arg: App) => string;
|
|
entryBuilder: (arg: App) => string;
|
|
}
|
|
) {
|
|
const output = [];
|
|
forEachAppDir((app) => {
|
|
if (
|
|
fs.existsSync(path.join(APP_STORE_PATH, app.path, fileToBeImported)) &&
|
|
typeof importBuilder === "function"
|
|
) {
|
|
output.push(importBuilder(app));
|
|
}
|
|
});
|
|
|
|
output.push(`export const ${objectName} = {`);
|
|
|
|
forEachAppDir((app) => {
|
|
if (fs.existsSync(path.join(APP_STORE_PATH, app.path, fileToBeImported))) {
|
|
output.push(entryBuilder(app));
|
|
}
|
|
});
|
|
|
|
output.push(`};`);
|
|
return output;
|
|
}
|
|
|
|
serverOutput.push(
|
|
...getObjectExporter("apiHandlers", {
|
|
fileToBeImported: "api/index.ts",
|
|
// Import path must have / even for windows and not \
|
|
entryBuilder: (app) => ` ${app.name}: import("./${app.path.replace(/\\/g, "/")}/api"),`,
|
|
})
|
|
);
|
|
|
|
browserOutput.push(
|
|
...getObjectExporter("appStoreMetadata", {
|
|
fileToBeImported: "_metadata.ts",
|
|
// Import path must have / even for windows and not \
|
|
importBuilder: (app) =>
|
|
`import { metadata as ${app.name}_meta } from "./${app.path.replace(/\\/g, "/")}/_metadata";`,
|
|
entryBuilder: (app) => ` ${app.name}:${app.name}_meta,`,
|
|
})
|
|
);
|
|
|
|
browserOutput.push(
|
|
...getObjectExporter("InstallAppButtonMap", {
|
|
fileToBeImported: "components/InstallAppButton.tsx",
|
|
entryBuilder: (app) =>
|
|
` ${app.name}: dynamic(() =>import("./${app.path}/components/InstallAppButton")),`,
|
|
})
|
|
);
|
|
|
|
const banner = `/**
|
|
This file is autogenerated using the command \`yarn app-store:build --watch\`.
|
|
Don't modify this file manually.
|
|
**/
|
|
`;
|
|
fs.writeFileSync(
|
|
`${APP_STORE_PATH}/apps.server.generated.ts`,
|
|
formatOutput(`${banner}${serverOutput.join("\n")}`)
|
|
);
|
|
fs.writeFileSync(
|
|
`${APP_STORE_PATH}/apps.browser.generated.tsx`,
|
|
formatOutput(`${banner}${browserOutput.join("\n")}`)
|
|
);
|
|
console.log("Generated `apps.server.generated.ts` and `apps.browser.generated.tsx`");
|
|
}
|
|
|
|
const debouncedGenerateFiles = debounce(generateFiles);
|
|
|
|
if (isInWatchMode) {
|
|
chokidar
|
|
.watch(APP_STORE_PATH)
|
|
.on("addDir", (dirPath) => {
|
|
const appName = getAppName(dirPath);
|
|
if (appName) {
|
|
console.log(`Added ${appName}`);
|
|
debouncedGenerateFiles();
|
|
}
|
|
})
|
|
.on("change", (filePath) => {
|
|
if (filePath.endsWith("config.json")) {
|
|
console.log("Config file changed");
|
|
debouncedGenerateFiles();
|
|
}
|
|
})
|
|
.on("unlinkDir", (dirPath) => {
|
|
const appName = getAppName(dirPath);
|
|
if (appName) {
|
|
console.log(`Removed ${appName}`);
|
|
debouncedGenerateFiles();
|
|
}
|
|
});
|
|
} else {
|
|
generateFiles();
|
|
}
|