diff --git a/frontend/.changeset/funny-jokes-add.md b/frontend/.changeset/funny-jokes-add.md new file mode 100644 index 00000000..3a1ad940 --- /dev/null +++ b/frontend/.changeset/funny-jokes-add.md @@ -0,0 +1,6 @@ +--- +"@liam-hq/erd-core": patch +"@liam-hq/cli": patch +--- + +New `ReleaseVersion` component into `HelpButton` diff --git a/frontend/packages/cli/src/App.tsx b/frontend/packages/cli/src/App.tsx index d1f31861..ed696fd6 100644 --- a/frontend/packages/cli/src/App.tsx +++ b/frontend/packages/cli/src/App.tsx @@ -1,5 +1,10 @@ import { dbStructureSchema } from '@liam-hq/db-structure' -import { ERDRenderer, initDBStructureStore } from '@liam-hq/erd-core' +import { + CliVersionProvider, + ERDRenderer, + cliVersionSchema, + initDBStructureStore, +} from '@liam-hq/erd-core' import * as v from 'valibot' async function loadSchemaContent() { @@ -20,8 +25,21 @@ async function loadSchemaContent() { loadSchemaContent() +const cliVersionData = { + version: import.meta.env.VITE_CLI_VERSION_VERSION, + gitHash: import.meta.env.VITE_CLI_VERSION_GIT_HASH, + isReleasedGitHash: + import.meta.env.VITE_CLI_VERSION_IS_RELEASED_GIT_HASH === '1', + date: import.meta.env.VITE_CLI_VERSION_DATE, +} +const cliVersion = v.parse(cliVersionSchema, cliVersionData) + function App() { - return + return ( + + + + ) } export default App diff --git a/frontend/packages/cli/vite-plugins/index.ts b/frontend/packages/cli/vite-plugins/index.ts new file mode 100644 index 00000000..d315dddb --- /dev/null +++ b/frontend/packages/cli/vite-plugins/index.ts @@ -0,0 +1 @@ +export * from './set-env.js' diff --git a/frontend/packages/cli/vite-plugins/set-env.ts b/frontend/packages/cli/vite-plugins/set-env.ts new file mode 100644 index 00000000..a0ca80a9 --- /dev/null +++ b/frontend/packages/cli/vite-plugins/set-env.ts @@ -0,0 +1,70 @@ +import { execSync } from 'node:child_process' +import { type Plugin, loadEnv } from 'vite' + +/** + * This Vite plugin initializes and sets the following environment variables for the client-side environment: + * - VITE_CLI_VERSION_VERSION: The current version of the package from package.json. + * - VITE_CLI_VERSION_IS_RELEASED_GIT_HASH: A flag indicating whether the current GIT hash corresponds to a released tag. + * - VITE_CLI_VERSION_GIT_HASH: The current GIT commit hash. + * - VITE_CLI_VERSION_DATE: The commit date of the latest commit. + * + * These variables are essential for maintaining version consistency and tracking within the deployment environment. + */ +export function setEnvPlugin(): Plugin { + const fetchGitHash = () => { + try { + return execSync('git rev-parse HEAD').toString().trim() + } catch (error) { + console.error('Failed to get git hash:', error) + return '' + } + } + + const date = () => { + try { + const gitDate = execSync('git log -1 --format=%ci').toString().trim() + return gitDate.split(' ')[0] + } catch (error) { + console.error('Failed to get git date:', error) + return new Date().toISOString().split('T')[0] // fallback to current date + } + } + + const versionPrefix = '@liam-hq/cli@' + + const isReleasedGitHash = (gitHash: string, packageJsonVersion: string) => { + const latestTagName = `${versionPrefix}${packageJsonVersion}` + try { + execSync('git fetch --tags') + const tagCommit = execSync(`git rev-parse ${latestTagName}`) + .toString() + .trim() + if (gitHash === tagCommit) { + return 1 + } + return 0 + } catch (error) { + console.error('Failed to get git tag:', error) + return 0 + } + } + + return { + name: 'set-env', + config(_, { mode }) { + const env = loadEnv(mode, process.cwd(), '') + + const packageJsonVersion = env.npm_package_version + const gitHash = fetchGitHash() + + process.env.VITE_CLI_VERSION_VERSION = packageJsonVersion + process.env.VITE_CLI_VERSION_IS_RELEASED_GIT_HASH = JSON.stringify( + isReleasedGitHash(gitHash, packageJsonVersion), + ) + process.env.VITE_CLI_VERSION_GIT_HASH = gitHash + process.env.VITE_CLI_VERSION_DATE = date() + }, + } +} + +export default setEnvPlugin diff --git a/frontend/packages/cli/vite.config.ts b/frontend/packages/cli/vite.config.ts index e64d99c9..945ea7d7 100644 --- a/frontend/packages/cli/vite.config.ts +++ b/frontend/packages/cli/vite.config.ts @@ -2,6 +2,7 @@ import { rmSync } from 'node:fs' import react from '@vitejs/plugin-react' import tsconfigPaths from 'vite-tsconfig-paths' import { defineConfig } from 'vitest/config' +import { setEnvPlugin } from './vite-plugins/index.js' const outDir = 'dist-cli/html' @@ -25,7 +26,7 @@ export default defineConfig({ ], }, }, - plugins: [react(), tsconfigPaths()], + plugins: [react(), tsconfigPaths(), setEnvPlugin()], test: { globals: true, environment: 'node', diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/AppBar/HelpButton/HelpButton.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/AppBar/HelpButton/HelpButton.tsx index 7cad801e..d4baac28 100644 --- a/frontend/packages/erd-core/src/components/ERDRenderer/AppBar/HelpButton/HelpButton.tsx +++ b/frontend/packages/erd-core/src/components/ERDRenderer/AppBar/HelpButton/HelpButton.tsx @@ -14,6 +14,7 @@ import { } from '@liam-hq/ui' import { forwardRef } from 'react' import styles from './HelpButton.module.css' +import { ReleaseVersion } from './ReleaseVersion' const handleSelect = (url: string) => () => { window.open(url, '_blank', 'noreferrer') @@ -41,6 +42,7 @@ export const HelpButton = forwardRef((_, ref) => { sideOffset={4} className={styles.menuContent} > + } diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/AppBar/HelpButton/ReleaseVersion.module.css b/frontend/packages/erd-core/src/components/ERDRenderer/AppBar/HelpButton/ReleaseVersion.module.css new file mode 100644 index 00000000..60f2c826 --- /dev/null +++ b/frontend/packages/erd-core/src/components/ERDRenderer/AppBar/HelpButton/ReleaseVersion.module.css @@ -0,0 +1,9 @@ +.cliVersion { + margin: var(--spacing-2); + border-radius: var(--border-radius-full); + background: var(--pane-muted-background); + padding: var(--spacing-1) var(--spacing-2); + color: var(--global-mute-text); + font-family: var(--code-font); + font-size: var(--font-size-1); +} diff --git a/frontend/packages/erd-core/src/components/ERDRenderer/AppBar/HelpButton/ReleaseVersion.tsx b/frontend/packages/erd-core/src/components/ERDRenderer/AppBar/HelpButton/ReleaseVersion.tsx new file mode 100644 index 00000000..1a2bb8dc --- /dev/null +++ b/frontend/packages/erd-core/src/components/ERDRenderer/AppBar/HelpButton/ReleaseVersion.tsx @@ -0,0 +1,27 @@ +import { useCliVersion } from '@/providers' +import type { FC } from 'react' +import styles from './ReleaseVersion.module.css' + +export const ReleaseVersion: FC = () => { + const { cliVersion } = useCliVersion() + + // Example output for cliVersion: + // - Released version: + // v0.0.11 (2024-12-19) + // - Unreleased version: + // v0.0.11 + 0d6169a (2024-12-19) + // + // Explanation: + // - "Released version" means the current Git hash matches a tagged release. + // - "Unreleased version" includes a short Git hash prefix to indicate changes since the last release. + return ( +
+ {`v${cliVersion.version}`} + + {' '} + {cliVersion.isReleasedGitHash || `+ ${cliVersion.gitHash.slice(0, 7)} `} + + {cliVersion.date.length > 0 && ` (${cliVersion.date})`} +
+ ) +} diff --git a/frontend/packages/erd-core/src/index.ts b/frontend/packages/erd-core/src/index.ts index 384c84dc..1d32115b 100644 --- a/frontend/packages/erd-core/src/index.ts +++ b/frontend/packages/erd-core/src/index.ts @@ -1,2 +1,4 @@ export * from './components' +export * from './providers' +export * from './schemas' export * from './stores' diff --git a/frontend/packages/erd-core/src/providers/CliVersionProvider.tsx b/frontend/packages/erd-core/src/providers/CliVersionProvider.tsx new file mode 100644 index 00000000..db45cff8 --- /dev/null +++ b/frontend/packages/erd-core/src/providers/CliVersionProvider.tsx @@ -0,0 +1,29 @@ +import type { CliVersion } from '@/schemas/cliVersion' +import { type FC, type ReactNode, createContext, useContext } from 'react' + +interface CliVersionContextProps { + cliVersion: CliVersion +} + +const CliVersionContext = createContext( + undefined, +) + +export const useCliVersion = (): CliVersionContextProps => { + const context = useContext(CliVersionContext) + if (!context) { + throw new Error('useCliVersion must be used within a CliVersionProvider') + } + return context +} + +export const CliVersionProvider: FC<{ + cliVersion: CliVersion + children: ReactNode +}> = ({ cliVersion, children }) => { + return ( + + {children} + + ) +} diff --git a/frontend/packages/erd-core/src/providers/index.ts b/frontend/packages/erd-core/src/providers/index.ts new file mode 100644 index 00000000..9a99577b --- /dev/null +++ b/frontend/packages/erd-core/src/providers/index.ts @@ -0,0 +1 @@ +export * from './CliVersionProvider' diff --git a/frontend/packages/erd-core/src/schemas/cliVersion/index.ts b/frontend/packages/erd-core/src/schemas/cliVersion/index.ts new file mode 100644 index 00000000..68de0559 --- /dev/null +++ b/frontend/packages/erd-core/src/schemas/cliVersion/index.ts @@ -0,0 +1,2 @@ +export * from './schemas' +export * from './types' diff --git a/frontend/packages/erd-core/src/schemas/cliVersion/schemas.ts b/frontend/packages/erd-core/src/schemas/cliVersion/schemas.ts new file mode 100644 index 00000000..b01dd50e --- /dev/null +++ b/frontend/packages/erd-core/src/schemas/cliVersion/schemas.ts @@ -0,0 +1,8 @@ +import * as v from 'valibot' + +export const cliVersionSchema = v.object({ + version: v.string(), + gitHash: v.string(), + isReleasedGitHash: v.boolean(), + date: v.string(), +}) diff --git a/frontend/packages/erd-core/src/schemas/cliVersion/types.ts b/frontend/packages/erd-core/src/schemas/cliVersion/types.ts new file mode 100644 index 00000000..7022dd2b --- /dev/null +++ b/frontend/packages/erd-core/src/schemas/cliVersion/types.ts @@ -0,0 +1,4 @@ +import type { InferOutput } from 'valibot' +import type { cliVersionSchema } from './schemas' + +export type CliVersion = InferOutput diff --git a/frontend/packages/erd-core/src/schemas/index.ts b/frontend/packages/erd-core/src/schemas/index.ts new file mode 100644 index 00000000..678e9682 --- /dev/null +++ b/frontend/packages/erd-core/src/schemas/index.ts @@ -0,0 +1,3 @@ +export * from './cliVersion' +export * from './queryParam' +export * from './showMode'