Skip to content

Commit 298039d

Browse files
committed
initial macro groups
1 parent 093d485 commit 298039d

15 files changed

+344
-100
lines changed

.eslintrc.js

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module.exports = {
1717
"plugin:react/recommended",
1818
"plugin:react/jsx-runtime",
1919
"plugin:import/recommended",
20+
"plugin:react-hooks/recommended",
2021
"plugin:@typescript-eslint/recommended",
2122
"plugin:@typescript-eslint/recommended-requiring-type-checking",
2223
"plugin:@typescript-eslint/strict",

src/common/macros/sanitize-macros.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ export const sanitizeMacros = (
3232

3333
patchMutationInstruction( action, settings );
3434

35+
if ( action.group === undefined ) {
36+
action.group =
37+
Math.max( ...macro.actions.map( ( a ) => a.group ?? 0 ), 0 ) + 1;
38+
}
39+
3540
sanitizeActionable( action, settings );
3641
} catch ( e ) {
3742
logger &&
@@ -127,12 +132,12 @@ export const getAvailableOperationsForAction = (
127132
settings: SettingsAndPluginsMeta
128133
): Operator[] => {
129134
if ( action.path[0] === ":function" ) {
130-
return [Operator.Execute];
135+
return [ Operator.Execute ];
131136
} else if ( action.path[0] === ":macro" ) {
132137
if ( action.path[2] === "enabled" ) {
133138
return getAvailableOperationsForTypeOfField( "boolean" );
134139
} else if ( action.path[2] === "program" ) {
135-
return [Operator.Execute, Operator.SetToDefault];
140+
return [ Operator.Execute, Operator.SetToDefault ];
136141
}
137142
return [];
138143
} else {
@@ -187,7 +192,7 @@ export function sanitizeActionable<T extends MacroAction | MacroCondition>(
187192
settings: SettingsAndPluginsMeta
188193
) {
189194
if ( action.path.length === 0 ) {
190-
action.path = [":app"];
195+
action.path = [ ":app" ];
191196
}
192197

193198
if ( action.path[0] === ":app" ) {
@@ -197,7 +202,7 @@ export function sanitizeActionable<T extends MacroAction | MacroCondition>(
197202
);
198203

199204
if ( !field ) {
200-
action.path = [":app", "audio", "music"];
205+
action.path = [ ":app", "audio", "music" ];
201206

202207
field = getAppFieldDefinition(
203208
settings,
@@ -209,7 +214,7 @@ export function sanitizeActionable<T extends MacroAction | MacroCondition>(
209214
patchValue( action, field );
210215
}
211216
} else if ( action.path[0] === ":plugin" ) {
212-
const [, pluginName] = action.path;
217+
const [ , pluginName ] = action.path;
213218

214219
const plugin =
215220
settings.enabledPlugins.find( ( p ) => p.name === pluginName ) ??
@@ -242,7 +247,7 @@ export function sanitizeActionable<T extends MacroAction | MacroCondition>(
242247
? action.path[2]
243248
: Object.keys( plugin.config ?? {} ).find( ( k ) => k !== "system" );
244249

245-
action.path = [":plugin", plugin.name];
250+
action.path = [ ":plugin", plugin.name ];
246251

247252
if ( fieldName ) {
248253
action.path.push( fieldName );

src/common/types/macros.ts

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export interface MacroAction<T extends TargetType = TargetType> {
4444
path: TargetedPath<T>;
4545
value?: unknown;
4646
operator: Operator;
47+
group?: number;
4748
}
4849

4950
export interface MacroCondition<T extends TargetType = TargetType> {

src/main/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import pluginServer from "./plugins/server";
1111
import browserWindows from "./windows";
1212
import { getBootupLogs } from "./log";
1313
import { GO_TO_START_PAGE, LOG_MESSAGE } from "common/ipc-handle-names";
14+
import electronIsDev from "electron-is-dev";
1415

1516
const settingsPath = path.join( getUserDataPath(), "settings.json" );
1617

@@ -51,7 +52,7 @@ const createConfigurationWindow = () => {
5152
windows.config = null;
5253
},
5354
nodeIntegration: true,
54-
removeMenu: true,
55+
removeMenu: !electronIsDev,
5556
backgroundThrottling: true,
5657
devTools: true,
5758
filepath: "command-center.html",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import {
2+
MacroAction,
3+
MacroActionSequence,
4+
MacroDTO,
5+
PluginMetaData,
6+
} from "common/types";
7+
import { ActionablePanel } from "./actionable-panel";
8+
9+
const colors = [
10+
"--blue-3",
11+
"--yellow-3",
12+
"--green-3",
13+
"--red-3",
14+
"--purple-3",
15+
"--orange-3",
16+
"--pink-3",
17+
];
18+
19+
export const ActionableGroupPanel = ( {
20+
groupId,
21+
actions,
22+
macro,
23+
pluginsMetadata,
24+
index,
25+
}: {
26+
groupId: string;
27+
macro: MacroDTO;
28+
actions: MacroAction[];
29+
pluginsMetadata: PluginMetaData[];
30+
index: number;
31+
} ) => {
32+
return (
33+
<div
34+
className="hover"
35+
style={{
36+
margin: "var(--size-5)",
37+
order: groupId,
38+
position: "relative",
39+
}}>
40+
<div
41+
style={{
42+
padding: "var(--size-0)",
43+
borderLeft:
44+
macro.actionSequence === MacroActionSequence.AllSync
45+
? `3px solid var(${colors[0]})`
46+
: `3px solid var(${colors[index % colors.length]})`,
47+
}}>
48+
{actions.map( ( action, index ) => (
49+
<ActionablePanel
50+
macro={macro}
51+
index={index}
52+
key={action.id}
53+
action={action}
54+
pluginsMetadata={pluginsMetadata}
55+
/>
56+
) )}
57+
</div>
58+
</div>
59+
);
60+
};

src/renderer/command-center/macros-ui/actionable-panel/actionable-panel.tsx

+121-71
Original file line numberDiff line numberDiff line change
@@ -4,93 +4,143 @@ import { ActionableTargetFunction } from "./actionable-target-function";
44
import { ActionableTargetApp } from "./actionable-target-app";
55
import { ActionableTargetPlugin } from "./actionable-target-plugin";
66
import { useMacroStore } from "../use-macros-store";
7-
import { TargetType } from "common/types";
7+
import { MacroAction, TargetType } from "common/types";
88
import { ActionableTargetMacro } from "./actionable-target-macro";
99

10-
export const ActionablePanel = ( props: ActionablePanelProps ) => {
10+
const isMacroAction = ( action: object ): action is MacroAction => {
11+
return "group" in action;
12+
};
13+
14+
export const ActionablePanel = ( props: ActionablePanelProps & { index: number } ) => {
1115
// eslint-disable-next-line @typescript-eslint/unbound-method
12-
const { deleteActionable, updateActionable } = useMacroStore();
13-
const { action, macro } = props;
16+
const { deleteActionable, updateActionable, reOrderAction } = useMacroStore();
17+
const { action, macro, index } = props;
1418

1519
return (
1620
<div
1721
className="hover"
1822
style={{
19-
margin: "var(--size-6)",
23+
margin: "var(--size-2)",
24+
order: isMacroAction( action ) ? ( action.group ?? 0 ) * 100 + index : 0,
2025
}}>
2126
<div
2227
style={{
23-
display: "grid",
24-
gridTemplateColumns: "auto auto 1fr",
25-
gridGap: "var(--size-3)",
26-
alignItems: "center",
27-
justifyContent: "start",
28-
marginBottom: "var(--size-1)",
28+
padding: "var(--size-2)",
2929
}}>
30-
<span
31-
style={{ fontWeight: 500, display: "flex", alignItems: "center" }}>
32-
<i
33-
className="material-icons"
34-
style={{ fontSize: "var(--font-size-3)" }}>
35-
{action.path[0] === ":function"
36-
? "code"
37-
: action.path[0] === ":app"
38-
? "settings_applications"
39-
: "extension"}
40-
</i>
41-
<select
42-
onChange={( evt ) => {
43-
updateActionable( macro, {
44-
...action,
45-
path: [evt.target.value as TargetType],
46-
} );
47-
}}
48-
value={action.path[0]}>
49-
<option value=":app">App</option>
50-
<option value=":plugin">Plugin</option>
51-
<option value=":macro">Macro</option>
52-
<option value=":function">Function</option>
53-
</select>
54-
</span>
55-
<button
30+
<div
5631
style={{
57-
justifySelf: "end",
58-
color: "var(--red-4)",
59-
fontSize: "var(--font-size-00)",
60-
}}
61-
onClick={() => {
62-
deleteActionable( macro, action );
32+
display: "flex",
33+
justifyContent: "space-between",
34+
marginBottom: "var(--size-1)",
6335
}}>
64-
<i
65-
className="material-icons small"
66-
style={{ fontSize: "var(--font-size-2)" }}>
67-
delete
68-
</i>
69-
</button>
70-
</div>
36+
<span
37+
style={{
38+
fontWeight: 500,
39+
gap: "var(--size-3)",
40+
display: "flex",
41+
alignItems: "center",
42+
}}>
43+
<i
44+
className="material-icons"
45+
style={{ fontSize: "var(--font-size-3)" }}>
46+
{action.path[0] === ":function"
47+
? "code"
48+
: action.path[0] === ":app"
49+
? "settings_applications"
50+
: "extension"}
51+
</i>
7152

72-
{action.error && (
73-
<p style={{ color: "var(--red-6)" }}>
74-
{" "}
75-
- {action.error.type}: {action.error.message}
76-
</p>
77-
)}
78-
<ErrorBoundary
79-
message="There was an error with this action"
80-
key={action.id}>
81-
{action.path[0] === ":app" && (
82-
<ActionableTargetApp {...props} action={action} />
83-
)}
84-
{action.path[0] === ":function" && (
85-
<ActionableTargetFunction {...props} action={action} />
86-
)}
87-
{action.path[0] === ":plugin" && (
88-
<ActionableTargetPlugin {...props} action={action} />
89-
)}
90-
{action.path[0] === ":macro" && (
91-
<ActionableTargetMacro {...props} action={action} />
53+
<select
54+
onChange={( evt ) => {
55+
updateActionable( macro, {
56+
...action,
57+
path: [ evt.target.value as TargetType ],
58+
} );
59+
}}
60+
value={action.path[0]}>
61+
<option value=":app">App</option>
62+
<option value=":plugin">Plugin</option>
63+
<option value=":macro">Macro</option>
64+
<option value=":function">Function</option>
65+
</select>
66+
</span>
67+
<span
68+
style={{
69+
display: "flex",
70+
alignItems: "center",
71+
}}>
72+
{isMacroAction( action ) && (
73+
<>
74+
<i
75+
style={{ cursor: "pointer" }}
76+
className="material-icons"
77+
onClick={() =>
78+
reOrderAction(
79+
macro.id,
80+
action.id,
81+
action.group!,
82+
-1
83+
)
84+
}>
85+
arrow_upward
86+
</i>
87+
<i
88+
style={{ cursor: "pointer" }}
89+
className="material-icons"
90+
onClick={() =>
91+
reOrderAction(
92+
macro.id,
93+
action.id,
94+
action.group!,
95+
1
96+
)
97+
}>
98+
arrow_downward
99+
</i>
100+
</>
101+
)}
102+
103+
<button
104+
style={{
105+
justifySelf: "end",
106+
color: "var(--red-4)",
107+
fontSize: "var(--font-size-00)",
108+
}}
109+
onClick={() => {
110+
deleteActionable( macro, action );
111+
}}>
112+
<i
113+
className="material-icons small"
114+
style={{ fontSize: "var(--font-size-2)" }}>
115+
delete
116+
</i>
117+
</button>
118+
</span>
119+
</div>
120+
121+
{action.error && (
122+
<p style={{ color: "var(--red-6)" }}>
123+
{" "}
124+
- {action.error.type}: {action.error.message}
125+
</p>
92126
)}
93-
</ErrorBoundary>
127+
<ErrorBoundary
128+
message="There was an error with this action"
129+
key={action.id}>
130+
{action.path[0] === ":app" && (
131+
<ActionableTargetApp {...props} action={action} />
132+
)}
133+
{action.path[0] === ":function" && (
134+
<ActionableTargetFunction {...props} action={action} />
135+
)}
136+
{action.path[0] === ":plugin" && (
137+
<ActionableTargetPlugin {...props} action={action} />
138+
)}
139+
{action.path[0] === ":macro" && (
140+
<ActionableTargetMacro {...props} action={action} />
141+
)}
142+
</ErrorBoundary>
143+
</div>
94144
</div>
95145
);
96146
};

0 commit comments

Comments
 (0)