Skip to content

Commit b042af3

Browse files
authored
Merge pull request #64 from sapio-lang/ux-improvements
UX Fixes
2 parents 1c67763 + 5ccd7be commit b042af3

File tree

6 files changed

+232
-168
lines changed

6 files changed

+232
-168
lines changed

src/App.css

+6-3
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,19 @@ body {
5757

5858
.App {
5959
height: 100vh;
60+
max-height: 100vh;
6061
background-color: black;
6162
color: white;
6263
display: grid;
6364
grid-template-rows: 1fr auto;
65+
overflow: hidden;
6466
}
6567

6668
.App-area {
6769
display: grid;
6870
grid-template-columns: 200px 1fr;
71+
overflow: scroll;
72+
max-height: 100%;
6973
}
7074

7175
.App-gutter {
@@ -79,6 +83,8 @@ body {
7983

8084
.area-inner {
8185
width: calc(100vw - 200px);
86+
overflow-y: scroll;
87+
max-height: 100%;
8288
}
8389

8490
.area-overlays {
@@ -106,8 +112,5 @@ body {
106112
}
107113

108114
.settings-container {
109-
padding-left: 50px;
110-
padding-right: 50px;
111-
padding-bottom: 20px;
112115
height: 100%;
113116
}

src/AppSlice.tsx

+13-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
22
import { Data } from './Data/ContractManager';
33
import { AppDispatch, RootState } from './Store/store';
4-
import { hasOwn } from './util';
4+
import { createSelectorCreator, defaultMemoize } from 'reselect';
5+
import _ from 'lodash';
56

67
type ContractArgs = {
78
arguments: Record<string | number, unknown>;
@@ -138,14 +139,17 @@ export const selectStatusBar: (state: RootState) => boolean = (
138139
state: RootState
139140
) => state.appReducer.status_bar;
140141

141-
export const selectHasEffect: (
142-
state: RootState
143-
) => (s: string, key: string) => boolean = (state: RootState) => {
144-
return (s, key) => {
145-
const d = state.appReducer.data?.args.context.effects?.effects ?? {};
146-
return hasOwn(d, s) && hasOwn(d[s]!, key);
147-
};
148-
};
142+
const createDeepEqualSelector = createSelectorCreator(
143+
defaultMemoize,
144+
_.isEqual
145+
);
146+
export const selectHasEffect = createDeepEqualSelector(
147+
[
148+
(state: RootState, path: string) =>
149+
state.appReducer.data?.args.context.effects?.effects ?? {},
150+
],
151+
(d) => Object.fromEntries(Object.keys(d).map((k) => [k, null]))
152+
);
149153

150154
export const selectShowing: (state: RootState) => Pages = (state: RootState) =>
151155
state.appReducer.showing;

src/UX/Entity/Detail/UTXODetail.tsx

+78-51
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { PhantomTransactionModel } from '../../../Data/Transaction';
2222
import { UTXOModel } from '../../../Data/UTXO';
2323
import {
2424
get_wtxid_backwards,
25+
hasOwn,
2526
is_mock_outpoint,
2627
PrettyAmountField,
2728
} from '../../../util';
@@ -43,13 +44,23 @@ import {
4344
recreate_contract,
4445
selectHasEffect,
4546
} from '../../../AppSlice';
47+
import { RootState } from '../../../Store/store';
4648

4749
interface UTXODetailProps {
4850
entity: UTXOModel;
4951
contract: ContractModel;
5052
}
5153

54+
const C = React.memo(UTXODetailInner, (prev, next) => {
55+
const b = prev.entity == next.entity && prev.contract == next.contract;
56+
console.log('NEWCHECK?', b);
57+
return b;
58+
});
5259
export function UTXODetail(props: UTXODetailProps) {
60+
return <C {...props}></C>;
61+
}
62+
63+
export function UTXODetailInner(props: UTXODetailProps) {
5364
const theme = useTheme();
5465
const dispatch = useDispatch();
5566
const select_continuations = useSelector(selectContinuation);
@@ -136,9 +147,7 @@ export function UTXODetail(props: UTXODetailProps) {
136147
const obj = select_continuations(`${txid}:${idx}`);
137148
const continuations = obj
138149
? Object.entries(obj).map(([k, v]) => {
139-
return (
140-
<ContinuationOption key={k} k={k} v={v}></ContinuationOption>
141-
);
150+
return <ContinuationOption key={k} v={v} />;
142151
})
143152
: null;
144153
const cont = continuations ? (
@@ -171,33 +180,11 @@ export function UTXODetail(props: UTXODetailProps) {
171180
);
172181
}
173182

174-
function ContinuationOption(props: { k: string; v: Continuation }) {
183+
function ContinuationOption(props: { v: Continuation }) {
175184
const [is_open, setOpen] = React.useState(false);
176-
const select_effect = useSelector(selectHasEffect);
177-
const name = props.k.substr(props.k.lastIndexOf('/') + 1);
185+
const name = props.v.path.substr(props.v.path.lastIndexOf('/') + 1);
178186
const dispatch = useDispatch();
179-
const form = React.useRef<any | null>(null);
180-
const name_form = React.useRef<any | null>(null);
181-
const name_schema: JSONSchema7 = {
182-
title: 'Name for this Update',
183-
type: 'string',
184-
};
185-
const this_effect_name = React.useRef('');
186-
const submit = (e: ISubmitEvent<any>) => {
187-
const name = this_effect_name.current;
188-
const data = e.formData;
189-
dispatch(add_effect_to_contract([props.k, name, data]));
190-
};
191187

192-
const validate_name_unique = (
193-
data: string,
194-
errors: FormValidation
195-
): FormValidation => {
196-
if (data === '') errors.addError('Name Required');
197-
if (select_effect(props.k, data)) errors.addError('Name Already Used');
198-
this_effect_name.current = data;
199-
return errors;
200-
};
201188
return (
202189
<div>
203190
<Button onClick={() => setOpen(true)} variant="contained">
@@ -206,32 +193,14 @@ function ContinuationOption(props: { k: string; v: Continuation }) {
206193
<Dialog open={is_open} onClose={() => setOpen(false)}>
207194
<DialogTitle>
208195
<Typography variant="h5">{name}</Typography>
209-
<ASM className="txhex" value={props.k} label="Full Path" />
196+
<ASM
197+
className="txhex"
198+
value={props.v.path}
199+
label="Full Path"
200+
/>
210201
</DialogTitle>
211202
<DialogContent>
212-
<Form
213-
schema={name_schema}
214-
validate={validate_name_unique}
215-
liveValidate
216-
// NOTE: This is a bug documented here
217-
// https://github.com/rjsf-team/react-jsonschema-form/issues/2135
218-
// eslint-disable-next-line
219-
// @ts-ignore
220-
ref={name_form}
221-
>
222-
<div
223-
// Cancels native submit button
224-
></div>
225-
</Form>
226-
<Form
227-
schema={props.v.schema}
228-
onSubmit={submit}
229-
// NOTE: This is a bug documented here
230-
// https://github.com/rjsf-team/react-jsonschema-form/issues/2135
231-
// eslint-disable-next-line
232-
// @ts-ignore
233-
ref={form}
234-
></Form>
203+
<MemoizeContForm {...props} />
235204
</DialogContent>
236205
<DialogActions>
237206
<Button onClick={() => dispatch(recreate_contract())}>
@@ -243,3 +212,61 @@ function ContinuationOption(props: { k: string; v: Continuation }) {
243212
</div>
244213
);
245214
}
215+
216+
const name_schema: JSONSchema7 = {
217+
title: 'Name for this Update',
218+
type: 'string',
219+
};
220+
const MemoizeContForm = React.memo(ContForm, (prev, next) => {
221+
return prev.v.path === next.v.path;
222+
});
223+
function ContForm(props: { v: Continuation }) {
224+
const dispatch = useDispatch();
225+
const form = React.useRef<any | null>(null);
226+
const name_form = React.useRef<any | null>(null);
227+
const this_effect_name = React.useRef('');
228+
const submit = (e: ISubmitEvent<any>) => {
229+
const name = this_effect_name.current;
230+
const data = e.formData;
231+
dispatch(add_effect_to_contract([props.v.path, name, data]));
232+
};
233+
const has_effect = useSelector((s: RootState) =>
234+
selectHasEffect(s, props.v.path)
235+
);
236+
const validate_name_unique = (
237+
data: string,
238+
errors: FormValidation
239+
): FormValidation => {
240+
if (data === '') errors.addError('Name Required');
241+
if (hasOwn(has_effect, data)) errors.addError('Name Already Used');
242+
this_effect_name.current = data;
243+
return errors;
244+
};
245+
return (
246+
<div>
247+
<Form
248+
schema={name_schema}
249+
validate={validate_name_unique}
250+
liveValidate
251+
// NOTE: This is a bug documented here
252+
// https://github.com/rjsf-team/react-jsonschema-form/issues/2135
253+
// eslint-disable-next-line
254+
// @ts-ignore
255+
ref={name_form}
256+
>
257+
<div
258+
// Cancels native submit button
259+
></div>
260+
</Form>
261+
<Form
262+
schema={props.v.schema}
263+
onSubmit={submit}
264+
// NOTE: This is a bug documented here
265+
// https://github.com/rjsf-team/react-jsonschema-form/issues/2135
266+
// eslint-disable-next-line
267+
// @ts-ignore
268+
ref={form}
269+
></Form>
270+
</div>
271+
);
272+
}

src/UX/Settings/Settings.css

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
.SettingPane {
2+
max-height: 100%;
3+
margin-bottom: 100px;
4+
height: 100%;
5+
}
6+
7+
.SettingForm {
8+
max-height: 100%;
9+
height: 100%;
10+
}
11+
12+
.Settings {
13+
max-height: 100%;
14+
display: grid;
15+
height: 100%;
16+
grid-template-columns: max-content auto;
17+
}
18+
19+
.SettingsPanes {
20+
max-height: 100%;
21+
padding-right: 50px;
22+
overflow: scroll;
23+
height: 100%;
24+
padding-left: 50px;
25+
}
26+
27+
.SettingsNav {
28+
border-bottom: 1;
29+
border-color: 'divider';
30+
max-height: 100%;
31+
height: fit-content;
32+
}

0 commit comments

Comments
 (0)