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

Disable share role and share drop buttons when resource is locked #10514

Merged
merged 9 commits into from
Mar 5, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Bugfix: Indicate shares that are not manageable due to file locking

We indicate shares that are not manageable when a resource is locked, so the user doesn't run into errors,
while trying to delete or update a share.

https://github.com/owncloud/web/pull/10514
https://github.com/owncloud/web/issues/10507
3 changes: 3 additions & 0 deletions packages/design-system/src/components/OcIcon/OcIcon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
:aria-labelledby="accessibleLabel === '' ? null : svgTitleId"
:focusable="accessibleLabel === '' ? 'false' : null"
:style="color !== '' ? { fill: color } : {}"
@loaded="$emit('loaded')"
/>
</component>
</template>
Expand Down Expand Up @@ -86,6 +87,7 @@ export default defineComponent({
components: {
InlineSvg
},
inheritAttrs: true,
props: {
/**
* The name of the icon to display.
Expand Down Expand Up @@ -155,6 +157,7 @@ export default defineComponent({
default: ''
}
},
emits: ['loaded'],
computed: {
svgTitleId() {
return uniqueId('oc-icon-title-')
Expand Down
52 changes: 27 additions & 25 deletions packages/design-system/src/components/OcResource/OcResource.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,24 @@
class="oc-resource-link"
@click="emitClick"
>
<oc-img
v-if="hasThumbnail"
:key="thumbnail"
v-oc-tooltip="tooltipLabelIcon"
:src="thumbnail"
class="oc-resource-thumbnail"
width="40"
height="40"
:aria-label="tooltipLabelIcon"
/>
<span v-if="hasThumbnail" v-oc-tooltip="tooltipLabelIcon" :aria-label="tooltipLabelIcon">
AlexAndBear marked this conversation as resolved.
Show resolved Hide resolved
<oc-img
:key="thumbnail"
:src="thumbnail"
class="oc-resource-thumbnail"
width="40"
height="40"
/>
<span v-if="showStatusIcon" class="oc-resource-thumbnail-status-badge">
<oc-icon v-bind="statusIconAttrs" size="xsmall" />
</span>
</span>
<oc-resource-icon
v-else
v-oc-tooltip="tooltipLabelIcon"
:aria-label="tooltipLabelIcon"
:resource="resource"
>
<template v-if="showStatusIcon" #status>
<oc-icon v-bind="statusIconAttrs" size="xsmall" />
</template>
</oc-resource-icon>
<span v-if="showStatusIcon && hasThumbnail" class="oc-resource-thumbnail-status-badge">
<oc-icon v-bind="statusIconAttrs" size="xsmall" />
</span>
/>
</oc-resource-link>
<div class="oc-resource-details oc-text-overflow" :class="{ 'oc-pl-s': isIconDisplayed }">
<oc-resource-link
Expand Down Expand Up @@ -285,16 +280,23 @@ export default defineComponent({
max-width: $oc-size-icon-default * 1.5;

&-status-badge {
background: var(--oc-color-swatch-passive-hover);
opacity: 0.9;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
bottom: 0px;
right: 0px;
width: var(--oc-space-small);
height: var(--oc-space-small);
padding: var(--oc-space-xsmall);
line-height: var(--oc-space-small);
right: -7px;
border: 2px solid var(--oc-color-background-default);
border-radius: 30px;
background: rgba(155, 155, 155, 0.8);
color: white;
padding: 2px;

.oc-icon {
AlexAndBear marked this conversation as resolved.
Show resolved Hide resolved
svg {
fill: var(--oc-color-background-default) !important;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ exports[`OcResource displays parent folder name default if calculated name is em
</span>
<!--v-if-->
</span>
<!--v-if-->
</button>
<div class="oc-resource-details oc-text-overflow oc-pl-s">
<button class="oc-button oc-rounded oc-button-m oc-button-justify-content-left oc-button-gap-undefined oc-button-passive oc-button-passive-raw oc-text-overflow" draggable="false" type="button">
Expand Down
125 changes: 101 additions & 24 deletions packages/design-system/src/components/OcResourceIcon/OcResourceIcon.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
<template>
<span>
<oc-icon
ref="iconRef"
:key="`resource-icon-${icon.name}`"
:name="icon.name"
:color="icon.color"
:size="size"
:class="['oc-resource-icon', iconTypeClass]"
/>
<span v-if="$slots.status" class="oc-resource-icon-status-badge">
<span class="oc-resource-icon-status-badge-inner" :style="{ background: icon.color }">
<slot name="status" />
</span>
@loaded="iconLoaded = true"
>
</oc-icon>
<span
v-if="Object.keys(badgeIconAttrs).length"
ref="badgeRef"
class="oc-resource-icon-status-badge"
:style="badgeStyle"
>
<oc-icon v-bind="badgeIconAttrs" />
</span>
</span>
</template>

<script lang="ts">
import { computed, defineComponent, inject, PropType, unref } from 'vue'
import { computed, defineComponent, inject, nextTick, PropType, ref, unref, watch } from 'vue'
import { Resource } from '@ownclouders/web-client'

import OcIcon from '../OcIcon/OcIcon.vue'
Expand Down Expand Up @@ -66,6 +72,10 @@ export default defineComponent({
}
},
setup(props) {
const iconRef = ref()
const iconLoaded = ref(false)
const badgeRef = ref()
const badgeStyle = ref({})
const iconMappingInjection = inject<OcResourceIconMapping>(ocResourceIconMappingInjectionKey)

const isFolder = computed(() => {
Expand Down Expand Up @@ -104,6 +114,43 @@ export default defineComponent({
}
})

watch([() => props.size, iconLoaded], async () => {
await nextTick()

if (!unref(iconLoaded)) {
return false
}

const iconBoundingClientRect = unref(iconRef)?.$el?.getBoundingClientRect()
if (!iconBoundingClientRect) {
return
}

const innerIconBoundingClientRect = unref(iconRef)
?.$el?.getElementsByTagName('g')?.[0]
?.getBoundingClientRect()
if (!innerIconBoundingClientRect) {
return
}

const iconOffsetHeight =
(iconBoundingClientRect.height - innerIconBoundingClientRect.height) / 2
const iconOffsetWidth = (iconBoundingClientRect.width - innerIconBoundingClientRect.width) / 2

const badgeBoundingClientRect = unref(badgeRef)?.getBoundingClientRect()
if (!badgeBoundingClientRect) {
return
}

const badgeBottom = iconOffsetHeight - badgeBoundingClientRect.height / 3
const badgeRight = iconOffsetWidth - badgeBoundingClientRect.width / 1.8

badgeStyle.value = {
right: `${badgeRight}px`,
bottom: `${badgeBottom}px`
}
})

const iconTypeClass = computed(() => {
if (unref(isSpace)) {
return 'oc-resource-icon-space'
Expand All @@ -114,9 +161,42 @@ export default defineComponent({
return 'oc-resource-icon-file'
})

const badgeIconSize = computed(() => {
if (['xxxlarge', 'xxlarge'].includes(props.size)) {
return 'medium'
}

return 'xsmall'
})

const badgeIconAttrs = computed(() => {
if (props.resource.locked) {
return {
name: 'lock',
fillType: 'fill',
size: unref(badgeIconSize)
}
}
if (props.resource.processing) {
return {
name: 'loop-right',
fillType: 'line',
size: unref(badgeIconSize)
}
}

return {}
})

return {
icon,
iconTypeClass
iconRef,
badgeRef,
badgeStyle,
iconTypeClass,
badgeIconAttrs,
badgeIconSize,
iconLoaded
}
}
})
Expand All @@ -127,30 +207,27 @@ export default defineComponent({
display: inline-flex;
align-items: center;
vertical-align: middle;

&-file svg {
height: 70%;
}
}

.oc-resource-icon-status-badge {
background: var(--oc-color-swatch-passive-hover);
opacity: 0.9;
position: absolute;
bottom: -3px;
right: -2px;
width: 12px;
height: 12px;
padding: var(--oc-space-xsmall);
display: flex;
justify-content: center;
align-items: center;
border: 2px solid var(--oc-color-background-default);
border-radius: 30px;
transition: background-color 200ms ease-in-out;
background: var(--oc-color-background-default);

&-inner {
position: absolute;
top: 2px;
left: 2px;
width: var(--oc-space-small);
height: var(--oc-space-small);
padding: var(--oc-space-xsmall);
line-height: var(--oc-space-small);
border-radius: 30px;
padding: 2px;

.oc-icon {
svg {
fill: var(--oc-color-background-default) !important;
AlexAndBear marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
</style>
12 changes: 0 additions & 12 deletions packages/design-system/src/components/OcTile/OcTile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -260,18 +260,6 @@ export default defineComponent({
height: 100%;
width: 100%;
text-align: center;

.oc-resource-icon-status-badge {
background: var(--oc-color-background-highlight) !important;
.oc-icon {
svg {
fill: var(--oc-color-background-highlight) !important;
}
}
.oc-spinner {
color: var(--oc-color-background-highlight) !important;
}
}
}

&-hover {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
v-else
class="details-icon-wrapper oc-width-1-1 oc-flex oc-flex-middle oc-flex-center oc-mb"
>
<oc-resource-icon class="details-icon" :resource="resource" size="xxxlarge" />
<oc-resource-icon
class="details-icon oc-position-relative"
:resource="resource"
size="xxxlarge"
/>
</div>
<div
v-if="!isPublicLinkContext && shareIndicators.length"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
<template>
<span class="oc-flex oc-flex-middle">
<oc-button :id="editShareBtnId" class="collaborator-edit-dropdown-options-btn" appearance="raw">
<oc-icon name="more-2" />
</oc-button>
<div v-oc-tooltip="dropButtonTooltip">
<oc-button
:id="editShareBtnId"
class="collaborator-edit-dropdown-options-btn"
appearance="raw"
:disabled="isLocked"
AlexAndBear marked this conversation as resolved.
Show resolved Hide resolved
>
<oc-icon name="more-2" />
</oc-button>
</div>
<oc-drop
ref="expirationDateDrop"
:toggle="'#' + editShareBtnId"
Expand Down Expand Up @@ -119,6 +126,10 @@ export default defineComponent({
deniable: {
type: Boolean,
default: false
},
isLocked: {
type: Boolean,
default: false
}
},
emits: [
Expand All @@ -136,6 +147,14 @@ export default defineComponent({
emit('setDenyShare', value)
}

const dropButtonTooltip = computed(() => {
if (props.isLocked) {
return language.$gettext('Resource is temporarily locked, unable to manage share')
}

return ''
})

const dateExpire = computed(() =>
formatRelativeDateFromDateTime(
DateTime.fromJSDate(props.expirationDate).endOf('day'),
Expand All @@ -147,7 +166,8 @@ export default defineComponent({
configurationManager,
resource: inject<Ref<Resource>>('resource'),
toggleShareDenied,
dateExpire
dateExpire,
dropButtonTooltip
}
},
data: function () {
Expand Down
Loading