Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: resource conflict modal #10205

Merged
merged 1 commit into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 3 additions & 80 deletions packages/design-system/src/components/OcModal/OcModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,6 @@
@keydown.enter.prevent="confirm"
/>
</template>
<div v-if="checkboxLabel" class="oc-modal-body-actions oc-flex oc-flex-left">
<oc-checkbox
v-model="checkboxValue"
size="medium"
:label="checkboxLabel"
:aria-label="checkboxLabel"
/>
</div>
</div>

<div v-if="!hideActions" class="oc-modal-body-actions oc-flex oc-flex-right">
Expand All @@ -70,15 +62,6 @@
@click="cancelModalAction"
v-text="buttonCancelText"
/>
<oc-button
v-if="buttonSecondaryText"
ref="secondaryButton"
class="oc-modal-body-actions-secondary oc-ml-s"
:variation="buttonSecondaryVariation"
:appearance="buttonSecondaryAppearance"
@click="secondaryModalAction"
v-text="buttonSecondaryText"
/>
<oc-button
v-if="!withoutButtonConfirm"
ref="primaryButton"
Expand All @@ -98,7 +81,6 @@
<script lang="ts">
import { defineComponent, PropType, ComponentPublicInstance, ref, onMounted, unref } from 'vue'
import OcButton from '../OcButton/OcButton.vue'
import OcCheckbox from '../OcCheckbox/OcCheckbox.vue'
import OcIcon from '../OcIcon/OcIcon.vue'
import OcTextInput from '../OcTextInput/OcTextInput.vue'
import { FocusTrap } from 'focus-trap-vue'
Expand Down Expand Up @@ -126,7 +108,6 @@ export default defineComponent({

components: {
OcButton,
OcCheckbox,
OcIcon,
OcTextInput,
FocusTrap
Expand Down Expand Up @@ -169,14 +150,6 @@ export default defineComponent({
required: false,
default: null
},
/**
* Modal checkbox label
*/
checkboxLabel: {
type: String,
required: false,
default: ''
},
/**
* Contextual helper label
*/
Expand Down Expand Up @@ -223,36 +196,6 @@ export default defineComponent({
return ['outline', 'filled', 'raw'].includes(value)
}
},
/**
* Text of the secondary button
*/
buttonSecondaryText: {
type: String,
required: false,
default: ''
},
/**
* Variation type of the secondary button
*/
buttonSecondaryVariation: {
type: String,
required: false,
default: 'passive',
validator: (value: string) => {
return ['passive', 'primary', 'danger', 'success', 'warning'].includes(value)
}
},
/**
* Appearance of the secondary button
*/
buttonSecondaryAppearance: {
type: String,
required: false,
default: 'outline',
validator: (value: string) => {
return ['outline', 'filled', 'raw'].includes(value)
}
},
/**
* Text of the confirm button
*/
Expand Down Expand Up @@ -376,28 +319,22 @@ export default defineComponent({
default: false
}
},
emits: ['cancel', 'confirm', 'confirm-secondary', 'input', 'checkbox-changed'],
emits: ['cancel', 'confirm', 'input'],
setup() {
const primaryButton = ref(null)
const secondaryButton = ref(null)
const cancelButton = ref(null)

const setButtonsEqualWidth = () => {
const _primaryButton = unref(primaryButton)
const _secondaryButton = unref(secondaryButton)
const _cancelButton = unref(cancelButton)

const primaryWidth = _primaryButton?.$el?.offsetWidth || 0
const secondaryWidth = _secondaryButton?.$el?.offsetWidth || 0
const cancelWidth = _cancelButton?.$el?.offsetWidth || 0
const maxWidth = Math.max(primaryWidth, secondaryWidth, cancelWidth)
const maxWidth = Math.max(primaryWidth, cancelWidth)

if (_primaryButton?.$el) {
_primaryButton.$el.style.minWidth = `${maxWidth}px`
}
if (_secondaryButton?.$el) {
_secondaryButton.$el.style.minWidth = `${maxWidth}px`
}
if (_cancelButton?.$el) {
_cancelButton.$el.style.minWidth = `${maxWidth}px`
}
Expand All @@ -408,14 +345,12 @@ export default defineComponent({

return {
primaryButton,
secondaryButton,
cancelButton
}
},
data() {
return {
userInputValue: null,
checkboxValue: false
userInputValue: null
}
},
computed: {
Expand Down Expand Up @@ -456,10 +391,6 @@ export default defineComponent({
inputValue: {
handler: 'inputAssignPropAsValue',
immediate: true
},
checkboxValue: {
handler: 'checkboxValueChanged',
immediate: true
}
},
methods: {
Expand All @@ -469,9 +400,6 @@ export default defineComponent({
*/
this.$emit('cancel')
},
secondaryModalAction() {
this.$emit('confirm-secondary')
},
confirm() {
if (this.buttonConfirmDisabled || this.inputError) {
return
Expand All @@ -493,9 +421,6 @@ export default defineComponent({
},
inputAssignPropAsValue(value) {
this.userInputValue = value
},
checkboxValueChanged(value) {
this.$emit('checkbox-changed', value)
}
}
})
Expand Down Expand Up @@ -694,7 +619,6 @@ export default defineComponent({
message="Do you accept our terms of use?"
button-cancel-text="Decline"
button-confirm-text="Accept"
checkbox-label="I accept the terms of use"
class="oc-mb-l oc-position-relative"
/>
</div>
Expand All @@ -708,7 +632,6 @@ export default defineComponent({
message="Do you accept our terms of use?"
button-cancel-text="Decline"
button-confirm-text="Accept"
button-secondary-text="Accept some"
class="oc-mb-l oc-position-relative"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@ exports[`OcModal displays input 1`] = `
<!--v-if-->
<!--v-if-->
<oc-text-input-stub class="oc-modal-body-input" clearbuttonaccessiblelabel="" clearbuttonenabled="false" disabled="false" fixmessageline="true" id="oc-textinput-1" label="Folder name" modelvalue="New folder" passwordpolicy="[object Object]" readonly="false" type="text"></oc-text-input-stub>
<!--v-if-->
</div>
<div class="oc-modal-body-actions oc-flex oc-flex-right">
<oc-button-stub appearance="outline" class="oc-modal-body-actions-cancel" disabled="false" gapsize="medium" justifycontent="center" showspinner="false" size="medium" style="min-width: 0px;" submit="button" type="button" variation="passive">Cancel</oc-button-stub>
<!--v-if-->
<oc-button-stub appearance="filled" class="oc-modal-body-actions-confirm oc-ml-s" disabled="false" gapsize="medium" justifycontent="center" showspinner="false" size="medium" style="min-width: 0px;" submit="button" type="button" variation="primary">Confirm</oc-button-stub>
</div>
</div>
Expand All @@ -36,11 +34,9 @@ exports[`OcModal hides icon if not specified 1`] = `
<p class="oc-modal-body-message oc-mt-rm oc-mb-rm">Example message</p>
<!--v-if-->
<!--v-if-->
<!--v-if-->
</div>
<div class="oc-modal-body-actions oc-flex oc-flex-right">
<oc-button-stub appearance="outline" class="oc-modal-body-actions-cancel" disabled="false" gapsize="medium" justifycontent="center" showspinner="false" size="medium" style="min-width: 0px;" submit="button" type="button" variation="passive">Cancel</oc-button-stub>
<!--v-if-->
<oc-button-stub appearance="filled" class="oc-modal-body-actions-confirm oc-ml-s" disabled="false" gapsize="medium" justifycontent="center" showspinner="false" size="medium" style="min-width: 0px;" submit="button" type="button" variation="primary">Confirm</oc-button-stub>
</div>
</div>
Expand All @@ -60,11 +56,9 @@ exports[`OcModal matches snapshot 1`] = `
<p class="oc-modal-body-message oc-mt-rm oc-mb-rm">Example message</p>
<!--v-if-->
<!--v-if-->
<!--v-if-->
</div>
<div class="oc-modal-body-actions oc-flex oc-flex-right">
<oc-button-stub appearance="outline" class="oc-modal-body-actions-cancel" disabled="false" gapsize="medium" justifycontent="center" showspinner="false" size="medium" style="min-width: 0px;" submit="button" type="button" variation="passive">Cancel</oc-button-stub>
<!--v-if-->
<oc-button-stub appearance="filled" class="oc-modal-body-actions-confirm oc-ml-s" disabled="false" gapsize="medium" justifycontent="center" showspinner="false" size="medium" style="min-width: 0px;" submit="button" type="button" variation="primary">Confirm</oc-button-stub>
</div>
</div>
Expand All @@ -84,11 +78,9 @@ exports[`OcModal overrides props message with slot 1`] = `
<div class="oc-modal-body-message">
<p>Slot message</p>
</div>
<!--v-if-->
</div>
<div class="oc-modal-body-actions oc-flex oc-flex-right">
<oc-button-stub appearance="outline" class="oc-modal-body-actions-cancel" disabled="false" gapsize="medium" justifycontent="center" showspinner="false" size="medium" style="min-width: 0px;" submit="button" type="button" variation="passive">Cancel</oc-button-stub>
<!--v-if-->
<oc-button-stub appearance="filled" class="oc-modal-body-actions-confirm oc-ml-s" disabled="false" gapsize="medium" justifycontent="center" showspinner="false" size="medium" style="min-width: 0px;" submit="button" type="button" variation="primary">Confirm</oc-button-stub>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ export class ResourceConflict extends ConflictDialog {
const resolvedConflict: ResolveConflict = await this.resolveFileExists(
{ name: conflict.name, isFolder } as Resource,
conflictsLeft,
conflictsLeft === 1,
isFolder,
true
)
Expand Down
133 changes: 133 additions & 0 deletions packages/web-pkg/src/components/Modals/ResourceConflictModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<template>
<span v-text="message" />
<div class="oc-my-m">
<oc-checkbox
v-if="conflictCount > 1"
v-model="checkboxValue"
size="medium"
:label="checkboxLabel"
:aria-label="checkboxLabel"
/>
</div>
<div class="oc-flex oc-flex-right oc-flex-middle oc-mt-m">
<oc-button
class="oc-modal-body-actions-cancel oc-ml-s"
appearance="outline"
variation="passive"
@click="onCancel"
>{{ $gettext('Skip') }}
</oc-button>
<oc-button
class="oc-modal-body-actions-secondary oc-ml-s"
appearance="outline"
variation="passive"
@click="onConfirmSecondary"
>{{ $gettext('Replace') }}
</oc-button>
<oc-button
class="oc-modal-body-actions-confirm oc-ml-s"
appearance="filled"
variation="primary"
@click="onConfirm"
>{{ $gettext('Keep both') }}
</oc-button>
</div>
</template>

<script lang="ts">
import { computed, defineComponent, PropType, ref, unref } from 'vue'
import { useGettext } from 'vue3-gettext'
import { useStore } from '../../composables'
import { Resource } from '@ownclouders/web-client/src'
import { ResolveConflict, ResolveStrategy } from '../../helpers/resource'

export default defineComponent({
name: 'ResourceConflictModal',
props: {
resource: { type: Object as PropType<Resource>, required: true },
conflictCount: { type: Number, required: true },
callbackFn: {
type: Function as PropType<(resolveConflict: ResolveConflict) => void>,
required: true
},
suggestMerge: { type: Boolean, default: true },
separateSkipHandling: { type: Boolean, default: false }
},
setup(props, { expose }) {
const store = useStore()
const { $gettext } = useGettext()

const checkboxValue = ref()
const checkboxLabel = computed(() => {
if (props.conflictCount < 2) {
return ''
}
if (!props.separateSkipHandling) {
return $gettext(
'Apply to all %{count} conflicts',
{ count: props.conflictCount.toString() },
true
)
} else if (props.resource.isFolder) {
return $gettext(
'Apply to all %{count} folders',
{ count: props.conflictCount.toString() },
true
)
} else {
return $gettext(
'Apply to all %{count} files',
{ count: props.conflictCount.toString() },
true
)
}
})

const message = computed(() =>
props.resource.isFolder
? $gettext(
'Folder with name "%{name}" already exists.',
{ name: props.resource.name },
true
)
: $gettext('File with name "%{name}" already exists.', { name: props.resource.name }, true)
)

const onConfirm = async () => {
await store.dispatch('hideModal')
props.callbackFn({
strategy: ResolveStrategy.KEEP_BOTH,
doForAllConflicts: unref(checkboxValue)
})
}

const onConfirmSecondary = async () => {
await store.dispatch('hideModal')
const strategy = props.suggestMerge ? ResolveStrategy.MERGE : ResolveStrategy.REPLACE
props.callbackFn({
strategy,
doForAllConflicts: unref(checkboxValue)
})
}

const onCancel = async () => {
await store.dispatch('hideModal')
props.callbackFn({
strategy: ResolveStrategy.SKIP,
doForAllConflicts: unref(checkboxValue)
})
}

expose({ onConfirm, onConfirmSecondary, onCancel })

return {
message,
checkboxValue,
checkboxLabel,
onConfirm,
onConfirmSecondary,
onCancel
}
}
})
</script>
1 change: 1 addition & 0 deletions packages/web-pkg/src/components/Modals/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as ResourceConflictModal } from './ResourceConflictModal.vue'
1 change: 1 addition & 0 deletions packages/web-pkg/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './AppTemplates'
export * from './ContextActions'
export * from './FilesList'
export * from './Filters'
export * from './Modals'
export * from './SideBar'
export * from './Search'
export * from './Spaces'
Expand Down
Loading