Skip to content
This repository was archived by the owner on Jun 13, 2024. It is now read-only.

Commit 8b745d0

Browse files
authored
feat: Added config loading (#97)
1 parent 12692de commit 8b745d0

4 files changed

Lines changed: 124 additions & 20 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React, { ReactChild, useEffect, useRef, useState } from 'react';
2+
3+
const DropdownContainer = (props: {
4+
className?: string;
5+
children: ReactChild[] | ReactChild;
6+
}) => {
7+
const [isExtended, setExtended] = useState(false);
8+
const [pos, setPos] = useState({ left: 0, top: 0 });
9+
const buttonRef = useRef<HTMLButtonElement>(null);
10+
11+
const updatePos = () => {
12+
if (!buttonRef.current) {
13+
return;
14+
}
15+
16+
const rect = buttonRef.current.getBoundingClientRect();
17+
18+
setPos({ left: rect.x, top: rect.y + rect.height });
19+
};
20+
21+
useEffect(() => {
22+
updatePos();
23+
24+
// hide the box when a click event fires
25+
window.addEventListener(
26+
'click',
27+
() => {
28+
setExtended(false);
29+
},
30+
);
31+
}, [isExtended]);
32+
33+
return (
34+
<>
35+
<button
36+
className={props.className}
37+
ref={buttonRef}
38+
onClick={(event) => {
39+
setExtended(!isExtended);
40+
// prevent the click event from bubbling up to event that will close the drawer
41+
event.stopPropagation();
42+
}}
43+
>
44+
•••
45+
</button>
46+
{isExtended && (
47+
<div className="fixed w-max h-max z-20 flex flex-col" style={pos}>
48+
{React.Children.toArray(props.children)}
49+
</div>
50+
)}
51+
</>
52+
);
53+
};
54+
55+
export default DropdownContainer;

src/components/panes/EditorPane.tsx

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import Editor, { DiffEditor } from '@monaco-editor/react';
2-
import { useStoreState } from '../../state/Hooks';
2+
import { useRef } from 'react';
3+
import { useStoreActions, useStoreState } from '../../state/Hooks';
4+
import DropdownContainer from '../containers/DropdownContainer';
35

46
const EditorPane = () => {
57
const config = useStoreState((state) => state.config);
68
const editingConfig = useStoreState((state) => state.editingConfig);
9+
const loadConfig = useStoreActions((actions) => actions.loadConfig);
10+
const inputFile = useRef<HTMLInputElement>(null);
711

812
const configYAML = (yml: string) => {
913
const matchSDKComment = yml?.match('# SDK Version: .*\n');
@@ -24,28 +28,57 @@ const EditorPane = () => {
2428

2529
return (
2630
<div className="bg-circle-gray-900 h-2/5 w-full flex flex-col">
27-
<div className="border-b text-xl border-circle-gray-800 font-bold">
31+
<div className="border-b text-xl border-circle-gray-800 font-bold flex flex-row">
2832
<div className="ml-4 border-b-4 px-3 py-3 w-max text-sm tracking-wide font-bold text-white border-white">
2933
CONFIG
3034
</div>
35+
<div className="p-2 ml-auto">
36+
<input
37+
type="file"
38+
accept=".yml,.yaml"
39+
ref={inputFile}
40+
className="hidden"
41+
onChange={(e) => {
42+
if (!e.target.files) {
43+
return;
44+
}
45+
46+
e.target.files[0].text().then((yml) => {
47+
loadConfig(yml);
48+
});
49+
}}
50+
/>
51+
<DropdownContainer className="rounded-md bg-circle-blue text-white px-2">
52+
<div className="bg-white flex-col flex rounded shadow text-base">
53+
<button
54+
className="border-b border-circle-gray-300 px-8"
55+
onClick={(e) => {
56+
inputFile.current?.click();
57+
e.stopPropagation();
58+
}}
59+
>
60+
Open
61+
</button>
62+
<button>Save</button>
63+
</div>
64+
</DropdownContainer>
65+
</div>
3166
</div>
3267
<div className="flex-1 overflow-hidden">
33-
{
34-
editingConfig ?
35-
(<DiffEditor
36-
theme="vs-dark"
37-
language="yaml"
38-
original={config && configYAML(config)}
39-
modified={editingConfig && configYAML(editingConfig)}
40-
/>)
41-
:
42-
(<Editor
43-
theme="vs-dark"
44-
language="yaml"
45-
value={config && configYAML(config)}
46-
/>
47-
)
48-
}
68+
{editingConfig ? (
69+
<DiffEditor
70+
theme="vs-dark"
71+
language="yaml"
72+
original={config && configYAML(config)}
73+
modified={editingConfig && configYAML(editingConfig)}
74+
/>
75+
) : (
76+
<Editor
77+
theme="vs-dark"
78+
language="yaml"
79+
value={config && configYAML(config)}
80+
/>
81+
)}
4982
</div>
5083
</div>
5184
);

src/components/panes/WorkflowsPane.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const WorkflowsPane = () => {
2323
bgClassName="bg-circle-gray-200"
2424
className="border border-r-0 h-full border-b-0 border-circle-gray-300"
2525
/>
26+
2627
</div>
2728
);
2829
};

src/state/Store.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import {
22
Config,
33
Job,
44
parameters,
5+
parseConfig,
56
reusable,
6-
Workflow,
7+
Workflow
78
} from '@circleci/circleci-config-sdk';
89
import { CustomCommand } from '@circleci/circleci-config-sdk/dist/src/lib/Components/Commands/exports/Reusable';
910
import { CustomParameter } from '@circleci/circleci-config-sdk/dist/src/lib/Components/Parameters';
@@ -16,7 +17,7 @@ import {
1617
isNode,
1718
Node,
1819
SetConnectionId,
19-
XYPosition,
20+
XYPosition
2021
} from 'react-flow-renderer';
2122
import { v4 } from 'uuid';
2223
import DefinitionsMenu from '../components/menus/definitions/DefinitionsMenu';
@@ -165,6 +166,7 @@ export interface StoreActions {
165166
CustomParameter<PipelineParameterLiteral>
166167
>;
167168

169+
loadConfig: Action<StoreModel, string>;
168170
generateConfig: Action<StoreModel, void | Partial<DefinitionModel>>;
169171
error: Action<StoreModel, any>;
170172
}
@@ -356,6 +358,19 @@ const Actions: StoreActions = {
356358
console.error('An action was not found! ', payload);
357359
}),
358360

361+
loadConfig: action((state, payload) => {
362+
const config = parseConfig(payload);
363+
364+
state.definitions = {
365+
workflows: config.workflows,
366+
jobs: config.jobs,
367+
executors: config.executors || [],
368+
parameters: config.parameters?.parameters || [],
369+
commands: config.commands || [],
370+
};
371+
372+
state.config = config.stringify();
373+
}),
359374
generateConfig: action((state, payload) => {
360375
const workflows = state.workflows.map((flow) => {
361376
const jobs = flow.elements

0 commit comments

Comments
 (0)