Skip to content

Commit

Permalink
feat: unify settings into single EditSettings page (#610)
Browse files Browse the repository at this point in the history
* feat: update FormStrategies design

* feat: add tab layout to EditSettings

* feat: add voting settings to new EditSettings page

* feat: add executions to EditSettings

* feat: add controller to EditSettings page

* feat: only allow controller to access EditSettings page

* feat: detect changes

* feat: add TransactionProgress modal

* feat: replace old Settings

* fix: check if voting settings are null instead of falsy

* feat: add extra delay to make sure API has latest changes

* fix: manage isModified via watchEffect

With this we can make `isModified` false during check to avoid
message flashing and bunch of weird edge cases

* chore: update section descriptions

* chore: remove proposal threshold

* chore: move edit-settings to settings

* feat: allow non controller to see settings

* refactor: convert TransactionProgressLoadingIcon to custom icon

* refactor: avoid MerkleWhitelist params generation

This PR also refactors how we detect changes in validationStrategy
as previous one didn't really work in all cases and was making it
really hard to disable MerkleWhitelist strategy params generation

* chore: vertically align FormStrategiesStrategyActive contents

* fix: convert proposal threshold to string

* chore: define type for initialState

* refactor: use computed to manage validationStrategies

* fix: always set modalOpen to current value

Flipping it can cause issues as we manage it in few places (onUnmount
and in open flag change).

* chore: remove annotation on implicit type

* chore: add context to warning

* refactor: move sleep to utils

* fix: always return hash

* feat: use UiLoading for TransactionProgress

* fix: enable scrollbars for tabs on small screens

* fix: handle save toolbar on small screens

* feat: display error if proposalValidation is missing

* fix: add two column layout on small screens

* feat: refresh input value and close if initialValue changes

* feat: add message on offchain spaces settings page

* feat: add buttons to scroll settings

* refactor: use uiUiScrollerHorizontal
  • Loading branch information
Sekhmet authored Aug 23, 2024
1 parent b8e7ded commit a2d709d
Show file tree
Hide file tree
Showing 24 changed files with 1,244 additions and 683 deletions.
7 changes: 5 additions & 2 deletions apps/ui/src/components/FormStrategies.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<script setup lang="ts">
import { StrategyConfig, StrategyTemplate } from '@/networks/types';
import { NetworkID } from '@/types';
const model = defineModel<StrategyConfig[]>({ required: true });
withDefaults(
defineProps<{
networkId: NetworkID;
limit?: number;
unique?: boolean;
title: string;
Expand All @@ -21,12 +23,13 @@ withDefaults(

<template>
<div class="mb-4">
<h3 class="mb-2">{{ title }}</h3>
<span class="mb-3 inline-block">
<h3 class="text-md leading-6">{{ title }}</h3>
<span class="mb-4 inline-block">
{{ description }}
</span>
<StrategiesConfigurator
:model-value="model"
:network-id="networkId"
:unique="unique"
:available-strategies="availableStrategies"
:default-params="defaultParams"
Expand Down
75 changes: 75 additions & 0 deletions apps/ui/src/components/FormStrategiesStrategyActive.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<script setup lang="ts">
import { shorten } from '@/helpers/utils';
import { getNetwork } from '@/networks';
import { StrategyConfig } from '@/networks/types';
import { NetworkID } from '@/types';
type Strategy = Pick<
StrategyConfig,
'id' | 'address' | 'name' | 'params' | 'generateSummary' | 'paramsDefinition'
>;
const props = defineProps<{
readOnly?: boolean;
networkId: NetworkID;
strategy: Strategy;
}>();
defineEmits<{
(e: 'editStrategy', strategy: Strategy);
(e: 'deleteStrategy', strategy: Strategy);
}>();
const network = computed(() => getNetwork(props.networkId));
</script>

<template>
<div
class="flex justify-between items-center rounded-lg border px-4 py-3 text-skin-link"
>
<div class="flex flex-col">
<div class="flex min-w-0 leading-5 mb-1">
<div class="whitespace-nowrap">{{ strategy.name }}</div>
<div
v-if="strategy.generateSummary"
class="ml-2 pr-2 text-skin-text truncate"
>
{{ strategy.generateSummary(strategy.params) }}
</div>
</div>
<a
v-if="strategy.address"
:href="network.helpers.getExplorerUrl(strategy.address, 'contract')"
target="_blank"
class="flex items-center text-skin-text leading-5"
>
<UiStamp
:id="strategy.address"
type="avatar"
:size="18"
class="mr-2 !rounded"
/>
{{ shorten(strategy.address) }}
<IH-arrow-sm-right class="-rotate-45" />
</a>
</div>
<div
v-if="!readOnly"
class="flex gap-3"
:class="{
'self-start': strategy.address
}"
>
<button
v-if="strategy.paramsDefinition"
type="button"
@click="$emit('editStrategy', strategy)"
>
<IH-pencil />
</button>
<button type="button" @click="$emit('deleteStrategy', strategy)">
<IH-trash />
</button>
</div>
</div>
</template>
73 changes: 26 additions & 47 deletions apps/ui/src/components/FormValidation.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<script setup lang="ts">
import { StrategyConfig, StrategyTemplate } from '@/networks/types';
import { NetworkID } from '@/types';
const model = defineModel<StrategyConfig | null>({ required: true });
defineProps<{
networkId: NetworkID;
title: string;
description: string;
availableStrategies: StrategyTemplate[];
Expand All @@ -12,7 +14,21 @@ defineProps<{
const editedStrategy: Ref<StrategyConfig | null> = ref(null);
const editStrategyModalOpen = ref(false);
const votingStrategies = ref([] as StrategyConfig[]);
const votingStrategies = computed({
get: () => model.value?.params?.strategies || [],
set: (value: StrategyConfig[]) => {
if (!model.value) return;
model.value = {
...model.value,
params: {
...model.value?.params,
strategies: value
}
};
}
});
function addStrategy(strategy: StrategyTemplate) {
const strategyConfig = {
Expand Down Expand Up @@ -47,62 +63,24 @@ function handleStrategySave(value: Record<string, any>) {
params: value
};
}
onMounted(() => {
votingStrategies.value = model.value?.params?.strategies || [];
});
watch(
() => votingStrategies.value,
to => {
if (!model.value) return;
model.value = {
...model.value,
params: {
...model.value?.params,
strategies: to
}
};
}
);
</script>

<template>
<div>
<div class="mb-4">
<h3 class="mb-2">{{ title }}</h3>
<h3 class="text-md leading-6">{{ title }}</h3>
<span class="mb-3 inline-block">
{{ description }}
</span>
<div class="mb-3">
<div v-if="!model">No strategy selected</div>
<div
<FormStrategiesStrategyActive
v-else
class="flex justify-between items-center rounded-lg border px-4 py-3 mb-3 text-skin-link"
>
<div class="flex min-w-0">
<div class="whitespace-nowrap">{{ model.name }}</div>
<div
v-if="model.generateSummary"
class="ml-2 pr-2 text-skin-text truncate"
>
{{ model.generateSummary(model.params) }}
</div>
</div>
<div class="flex gap-3">
<button
v-if="model.paramsDefinition"
type="button"
@click="editStrategy(model)"
>
<IH-pencil />
</button>
<button type="button" @click="removeStrategy()">
<IH-trash />
</button>
</div>
</div>
:network-id="networkId"
:strategy="model"
@edit-strategy="editStrategy"
@delete-strategy="removeStrategy"
/>
</div>
<div v-if="!model" class="flex flex-wrap gap-2">
<ButtonStrategy
Expand All @@ -113,12 +91,13 @@ watch(
/>
</div>
<div v-else-if="model.type === 'VotingPower'">
<h3 class="eyebrow mb-2">Included strategies</h3>
<h3 class="eyebrow mb-2 font-medium">Included strategies</h3>
<span class="mb-3 inline-block">
Select strategies that will be used to compute proposal
</span>
<StrategiesConfigurator
v-model="votingStrategies"
:network-id="networkId"
:available-strategies="availableVotingStrategies"
/>
</div>
Expand Down
113 changes: 113 additions & 0 deletions apps/ui/src/components/Modal/ChangeController.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<script setup lang="ts">
import { clone } from '@/helpers/utils';
import { getValidator } from '@/helpers/validation';
const DEFAULT_FORM_STATE = {
controller: ''
};
const props = defineProps<{
open: boolean;
initialState?: { controller: string };
}>();
const emit = defineEmits<{
(e: 'save', value: string);
(e: 'close');
}>();
const CONTROLLER_DEFINITION = {
type: 'string',
format: 'ens-or-address',
title: 'Controller',
examples: ['Address or ENS']
};
const formValidator = getValidator({
$async: true,
type: 'object',
additionalProperties: false,
required: ['controller'],
properties: {
controller: CONTROLLER_DEFINITION
}
});
const form = reactive(clone(DEFAULT_FORM_STATE));
const formValidated = ref(false);
const showPicker = ref(false);
const searchValue = ref('');
const formErrors = ref({} as Record<string, any>);
watch(
() => props.open,
() => {
if (props.initialState) {
form.controller = props.initialState.controller;
} else {
form.controller = '';
}
}
);
watchEffect(async () => {
formValidated.value = false;
formErrors.value = await formValidator.validateAsync(form);
formValidated.value = true;
});
</script>

<template>
<UiModal :open="open" @close="$emit('close')">
<template #header>
<h3>Change controller</h3>
<template v-if="showPicker">
<button
type="button"
class="absolute left-0 -top-1 p-4"
@click="showPicker = false"
>
<IH-arrow-narrow-left class="mr-2" />
</button>
<div class="flex items-center border-t px-2 py-3 mt-3 -mb-3">
<IH-search class="mx-2" />
<input
ref="searchInput"
v-model="searchValue"
type="text"
placeholder="Search name or paste address"
class="flex-auto bg-transparent text-skin-link"
/>
</div>
</template>
</template>
<template v-if="showPicker">
<PickerContact
:loading="false"
:search-value="searchValue"
@pick="
form.controller = $event;
showPicker = false;
"
/>
</template>
<div v-else class="s-box p-4">
<UiInputAddress
v-model="form.controller"
:definition="CONTROLLER_DEFINITION"
:error="formErrors.delegatee"
@pick="showPicker = true"
/>
</div>
<template v-if="!showPicker" #footer>
<UiButton
class="w-full"
:disabled="Object.keys(formErrors).length > 0"
@click="emit('save', form.controller)"
>
Confirm
</UiButton>
</template>
</UiModal>
</template>
Loading

0 comments on commit a2d709d

Please sign in to comment.