diff --git a/README.md b/README.md index 4e80c0d..24fd8f1 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ by allowing users to visualize, create and update existing CI/CD workflows. > and [Appwrite’s Hacktoberfest 2024 Hackathon](https://appwrite.io/blog/post/appwrite-hacktoberfest-hackathon-2024). > > Although there are some alternative solutions that can help a lot writing workflow files -> directly from IDE, a core principle to this work was discovering new technologies and apply them for an MVP. +> directly from IDE, this project mainly is a MVP to discover new technologies > -> The amount of time dedicated is very limited (around ~4 weekends, starting from 1st of October), and the features needed for a complete project are numerous. +> The amount of time dedicated in this project is very limited, and the features needed for a complete project are numerous. > Therefore, some features will **undoubtedly be missing** and may be implemented in the future. ## Disclaimer for hackathon entry @@ -34,7 +34,7 @@ Since they have two different deadlines, development will be subdivided into two Those two branches are linked in a multi-environment railway project which is currently visible to everyone: [Railway Deployment](https://railway.app/project/8e131c67-73c1-4ab6-9fa4-31dfa6c9000e). -GitHub workflow that deploy the app: [deploy.yml](https://github.com/riccardoperra/pipelineui/blob/main/.github/workflows/deploy.yml#L10) +GitHub workflow that deploy the app: [deploy.yml](https://github.com/riccardoperra/pipelineui/blob/main/.github/workflows/deploy.yml) Github environment deployments: @@ -44,6 +44,7 @@ Github environment deployments: ## Table of contents - [Features](#features) + - [Available editor features](./packages/app/src/routes/about/supported-workflow-features.mdx) - [Technical info](#-technical-info) - [UI](#ui) - [YAML Editor](#yaml-editor) @@ -88,14 +89,16 @@ Workflow files are persisted into [AppWrite Cloud](https://appwrite.io/) and **a PipelineUI is entirely built with [Solid](https://github.com/solidjs/solid) and [SolidStart](https://github.com/solidjs/solid-start) with enabled SSR. -The core features of this project can be summarized in a few points: +The core technical points of this project can be summarized in those bullet items: -- SolidStart server fns calls for session, workflow retrieval and scratches crud -- SolidStart mutations and server actions -- Appwrite OAuth integration with SolidStart api routes -- Appwrite Database integration with SolidStart server function -- CodeMirror with LSP via web-worker and linter integration -- MDX routes for /about pages +- SolidStart SSR with mutations and server functions for session, workflow and scratches crud +- Language Service Protocol and Linter integration with CodeMirror via web-worker +- MDX prerendered routes for /about pages + - [About](https://pipelineui.dev/about) + - [Supported workflow features](https://pipelineui.dev/about/supported-workflow-features) +- Editor local first state management with statebuilder via plugin, with YAML synchronization +- Appwrite OAuth integration with SolidStart API routes +- Appwrite Database integration with SolidStart server functions ### User interface @@ -143,7 +146,7 @@ The user interface has been built with: ### Flow diagram -The implemented Flow diagram is very limited and it has been built with solid taking advantage of some other dependencies: +The implemented Flow diagram is very basic and it has been built with solid taking advantage of some other dependencies: - [elkjs](https://github.com/kieler/elkjs): ELK layout algorithm, used to calculate the flow item positions - [panzoom](https://github.com/anvaka/panzoom): Cross-browser compatible pan and zoom library @@ -155,25 +158,27 @@ The implemented Flow diagram is very limited and it has been built with solid ta ### Backend -Backend has been built with [appwrite](https://appwrite.io/), which has been wrapped via solid server functions -to provide authentication and the database persistence. +Backend persistence and authentication has been done with [appwrite](https://appwrite.io/). Used Appwrite features: - Auth - Database -Most of the code is available into [packages/app/lib/server](packages/app/src/lib/server). +Most of the Appwrite code is available into + +- [packages/app/src/lib/server](packages/app/src/lib/server). +- [packages/app/src/lib/scratchApi.ts](packages/app/src/lib/scratchApi.ts). +- [packages/app/src/routes/api/oauth.ts](packages/app/src/routes/api/oauth.ts). --- ### Other dependencies -This projects also uses some of mine older dependencies that were used to speed up the development. -These have also been updated to fix the bugs encountered. +Here's a list of my personal dependencies, which they have been used to be tested and improved during the development. - [@codeui/kit](https://github.com/riccardoperra/codeui): [CodeImage](https://github.com/riccardoperra/codeimage) design - system which wraps Kobalte. + system (Kobalte + VanillaExtract) - [statebuilder](https://github.com/riccardoperra/statebuilder): Pluggable state management - [solid-codemirror](https://github.com/riccardoperra/solid-codemirror): SolidJS adapter for CodeMirror diff --git a/packages/app/src/components/Editor/CodeEditor/YamlEditorFallback.tsx b/packages/app/src/components/Editor/CodeEditor/YamlEditorFallback.tsx new file mode 100644 index 0000000..41c38f5 --- /dev/null +++ b/packages/app/src/components/Editor/CodeEditor/YamlEditorFallback.tsx @@ -0,0 +1,62 @@ +import {For, useContext} from 'solid-js'; +import {EditorContext} from '../editor.context'; +import * as fallbackStyles from '~/ui/components/Fallback.css'; + +export function YamlEditorFallback() { + const editor = useContext(EditorContext); + return ( +
+ + {(row, index) => { + const match = row.match(/^(\s*)(\S.*)/)!; + const leadingWhitespace = match ? match[1] : row; + const text = match ? match[2] : null; + + return ( +
+ + {String(index() + 1).padStart(3, '0')} + + + {leadingWhitespace} + + + {text || leadingWhitespace} + +
+ ); + }} +
+
+ ); +} diff --git a/packages/app/src/components/Editor/Editor.tsx b/packages/app/src/components/Editor/Editor.tsx index a66eefc..e13f940 100644 --- a/packages/app/src/components/Editor/Editor.tsx +++ b/packages/app/src/components/Editor/Editor.tsx @@ -1,19 +1,11 @@ import Resizable from '@corvu/resizable'; -import { - createEffect, - For, - lazy, - Match, - Show, - Suspense, - Switch, - useContext, -} from 'solid-js'; +import {lazy, Match, Show, Suspense, Switch} from 'solid-js'; import {provideState} from 'statebuilder'; -import * as fallbackStyles from '~/ui/components/Fallback.css'; import {OverlayLoader} from '~/ui/components/Loader/Loader'; import {EditorStore} from '../../store/editor/editor.store'; import {EditorUiStore} from '../../store/editor/ui.store'; +import {YamlMergeView} from './CodeEditor/MergeView'; +import {YamlEditorFallback} from './CodeEditor/YamlEditorFallback'; import {DiagnosticPanel} from './DiagnosticPanel/DiagnosticPanel'; import * as styles from './Editor.css'; import {EditorHeader} from './Header/Header'; @@ -24,8 +16,6 @@ import {EditorResizableHandler} from './layout/Resizable/Resizable'; import {EditorSidebar} from './LeftSidebar/EditorSidebar'; import {PropertiesPanelEditor} from './Properties/PropertiesPanelEditor'; import {EditorStatusBar} from './StatusBar/StatusBar'; -import {YamlMergeView} from './CodeEditor/MergeView'; -import {EditorContext} from './editor.context'; const YamlEditor = lazy(() => import('./CodeEditor/YamlEditor').then(m => ({default: m.YamlEditor})), @@ -44,10 +34,6 @@ export function Editor(props: EditorProps) { const editorUi = provideState(EditorUiStore); const editor = provideState(EditorStore); - createEffect(() => { - console.log({props}); - }); - return (
); } - -function YamlEditorFallback() { - const editor = useContext(EditorContext); - return ( -
- - {(row, index) => { - const match = row.match(/^(\s*)(\S.*)/)!; - const leadingWhitespace = match ? match[1] : row; - const text = match ? match[2] : null; - - return ( -
- - {String(index() + 1).padStart(3, '0')} - - - {leadingWhitespace} - - - {text || leadingWhitespace} - -
- ); - }} -
-
- ); -} diff --git a/packages/app/src/components/Editor/Header/Header.tsx b/packages/app/src/components/Editor/Header/Header.tsx index 7d0d34d..6e0d875 100644 --- a/packages/app/src/components/Editor/Header/Header.tsx +++ b/packages/app/src/components/Editor/Header/Header.tsx @@ -53,7 +53,7 @@ function EditorHeaderForkButton() { ( - )} diff --git a/packages/app/src/components/Editor/layout/Panel/Form/PanelAccordion/PanelAccordion.css.ts b/packages/app/src/components/Editor/layout/Panel/Form/PanelAccordion/PanelAccordion.css.ts index e5e6e76..f4a3899 100644 --- a/packages/app/src/components/Editor/layout/Panel/Form/PanelAccordion/PanelAccordion.css.ts +++ b/packages/app/src/components/Editor/layout/Panel/Form/PanelAccordion/PanelAccordion.css.ts @@ -44,6 +44,7 @@ export const panelAccordionTrigger = style({ display: 'flex', height: '36px', alignItems: 'center', + fontWeight: 600, gap: appTheme.spacing['2'], paddingLeft: appTheme.spacing['3'], background: `transparent`, diff --git a/packages/app/src/components/Editor/layout/Panel/Form/PanelAccordion/PanelAccordion.tsx b/packages/app/src/components/Editor/layout/Panel/Form/PanelAccordion/PanelAccordion.tsx index b2341a8..864092b 100644 --- a/packages/app/src/components/Editor/layout/Panel/Form/PanelAccordion/PanelAccordion.tsx +++ b/packages/app/src/components/Editor/layout/Panel/Form/PanelAccordion/PanelAccordion.tsx @@ -31,7 +31,7 @@ export function PanelAccordionItem(props: FlowProps) { {props.name} - size={'xs'} variant={'ghost'} theme={'secondary'} diff --git a/packages/app/src/components/Home/Footer/Footer.tsx b/packages/app/src/components/Home/Footer/Footer.tsx index 34be2a0..485f93c 100644 --- a/packages/app/src/components/Home/Footer/Footer.tsx +++ b/packages/app/src/components/Home/Footer/Footer.tsx @@ -22,7 +22,7 @@ export function HomeFooter() {
- {_(msg`Built with`)} + {_(msg`Built with`)}{' '} Solid {' '} diff --git a/packages/app/src/global-codeui.css.ts b/packages/app/src/global-codeui.css.ts index dec81f0..aeb45fd 100644 --- a/packages/app/src/global-codeui.css.ts +++ b/packages/app/src/global-codeui.css.ts @@ -1,8 +1,10 @@ import {globalStyle, globalFontFace} from '@vanilla-extract/css'; import {themeVars} from '@codeui/kit'; +import gabaritoFont from '/fonts/Gabarito-VariableFont_wght.ttf?inline'; + globalFontFace('Gabarito', { - src: 'url(/fonts/Gabarito-VariableFont_wght.ttf)', + src: `url(${gabaritoFont})`, }); globalStyle('[data-cui-theme=dark] html, body', { diff --git a/packages/app/src/lib/statebuilder/async.ts b/packages/app/src/lib/statebuilder/async.ts index ef3039e..52e5dea 100644 --- a/packages/app/src/lib/statebuilder/async.ts +++ b/packages/app/src/lib/statebuilder/async.ts @@ -1,5 +1,18 @@ import {AccessorWithLatest, createAsync} from '@solidjs/router'; -import {createComputed, createSignal, on, Setter} from 'solid-js'; +import { + createComputed, + createEffect, + createReaction, + createRenderEffect, + createRoot, + createSignal, + getOwner, + on, + onCleanup, + Owner, + Setter, + untrack, +} from 'solid-js'; import {create} from 'statebuilder'; export interface AsyncSignalState { @@ -28,20 +41,31 @@ function makeAsyncSignal( }, ): AsyncSignalState { const asyncState = createAsync(fetcher, options); + const [mode, setMode] = createSignal<'auto' | 'manual'>('auto'); const [signal, setSignal] = createSignal( options?.initialValue, ); - createComputed( - on(asyncState, latest => { - // Sync latest signal retrieved by asyncState in order to be available globally after navigation - setSignal(() => latest); - }), - ); + createEffect(() => { + setSignal(() => asyncState()); + }); + + const value = () => { + const $mode = mode(); + if ($mode === 'auto') { + return asyncState(); + } + return signal(); + }; + + const set: Setter = ((arg0: any) => { + setMode('manual'); + setSignal(arg0); + }) as Setter; - const state: AsyncSignalState = Object.assign(signal, { + const state: AsyncSignalState = Object.assign(value, { raw: asyncState, - set: setSignal, + set, }); return state;