@knime/hub-features 1.28.0 → 1.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/package.json +6 -6
- package/src/analytics/schema/cloudhome-event-functions.ts +7 -9
- package/src/analytics/schema/code-generator.js +1 -3
- package/src/analytics/schema/editor-event-functions.ts +7 -9
- package/src/analytics/schema/schema.d.ts +12 -12
- package/src/analytics/schema/schema.json +13 -13
- package/src/httpClient/constants.ts +1 -0
- package/src/{common/ofetchClient.ts → httpClient/createHttpClient.ts} +6 -5
- package/src/httpClient/index.ts +2 -0
- package/src/index.ts +1 -0
- package/src/useDownloadArtifact/useDownloadArtifact.ts +2 -2
- package/src/useFileUpload/useFileUpload.ts +2 -2
- package/src/common/constants.ts +0 -1
- package/src/components/versions/components/CreateVersionForm.vue +0 -155
- package/src/components/versions/components/CurrentState.vue +0 -258
- package/src/components/versions/components/LabelList.vue +0 -253
- package/src/components/versions/components/ManageVersions.vue +0 -191
- package/src/components/versions/components/NoVersionItem.vue +0 -23
- package/src/components/versions/components/VersionHistory.vue +0 -138
- package/src/components/versions/components/VersionItem.vue +0 -278
- package/src/components/versions/components/VersionLimitInfo.vue +0 -37
- package/src/components/versions/composables/useVersionsApi.ts +0 -254
- package/src/components/versions/constants.ts +0 -3
- package/src/components/versions/index.ts +0 -7
- package/src/components/versions/types.ts +0 -77
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed } from "vue";
|
|
3
|
-
|
|
4
|
-
import { Button, LocalDateTime, SubMenu } from "@knime/components";
|
|
5
|
-
import MenuIcon from "@knime/styles/img/icons/menu-options.svg";
|
|
6
|
-
import WrenchIcon from "@knime/styles/img/icons/wrench.svg";
|
|
7
|
-
|
|
8
|
-
import HubAvatar from "../../avatars/HubAvatar.vue";
|
|
9
|
-
import type { ItemSavepoint, WithAvatar, WithLabels } from "../types";
|
|
10
|
-
|
|
11
|
-
import LabelList from "./LabelList.vue";
|
|
12
|
-
|
|
13
|
-
const props = defineProps<{
|
|
14
|
-
isSelected: boolean;
|
|
15
|
-
hasEditCapability: boolean;
|
|
16
|
-
hasPreviousVersion: boolean;
|
|
17
|
-
currentStateSavepoint: ItemSavepoint & WithAvatar & WithLabels;
|
|
18
|
-
isVersionLimitExceeded?: boolean;
|
|
19
|
-
}>();
|
|
20
|
-
|
|
21
|
-
const emit = defineEmits<{
|
|
22
|
-
createVersion: [];
|
|
23
|
-
discard: [];
|
|
24
|
-
select: [];
|
|
25
|
-
}>();
|
|
26
|
-
|
|
27
|
-
const menuItems = computed(() => {
|
|
28
|
-
return props.hasEditCapability && props.hasPreviousVersion
|
|
29
|
-
? [
|
|
30
|
-
{
|
|
31
|
-
text: "Discard",
|
|
32
|
-
action: () => emit("discard"),
|
|
33
|
-
},
|
|
34
|
-
]
|
|
35
|
-
: [];
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const onMenuItemClick = (_: Event, item: (typeof menuItems.value)[number]) => {
|
|
39
|
-
item.action();
|
|
40
|
-
};
|
|
41
|
-
</script>
|
|
42
|
-
|
|
43
|
-
<template>
|
|
44
|
-
<div class="wrapper">
|
|
45
|
-
<div
|
|
46
|
-
class="current-state"
|
|
47
|
-
:class="{ selected: isSelected }"
|
|
48
|
-
@click="!isSelected && $emit('select')"
|
|
49
|
-
>
|
|
50
|
-
<div class="left">
|
|
51
|
-
<div class="draft">
|
|
52
|
-
<h6><WrenchIcon class="draft-icon" /><span>Draft</span></h6>
|
|
53
|
-
|
|
54
|
-
<div class="labels">
|
|
55
|
-
<LabelList :labels="currentStateSavepoint.labels" />
|
|
56
|
-
</div>
|
|
57
|
-
|
|
58
|
-
<span class="date">
|
|
59
|
-
Latest edits on
|
|
60
|
-
<LocalDateTime
|
|
61
|
-
class="date"
|
|
62
|
-
show-time
|
|
63
|
-
:date="currentStateSavepoint.changes[0].createdOn"
|
|
64
|
-
/>
|
|
65
|
-
</span>
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
<div class="right">
|
|
69
|
-
<Button
|
|
70
|
-
v-if="hasEditCapability && !isVersionLimitExceeded"
|
|
71
|
-
with-border
|
|
72
|
-
compact
|
|
73
|
-
class="create-button"
|
|
74
|
-
@click.stop="$emit('createVersion')"
|
|
75
|
-
>
|
|
76
|
-
Create version
|
|
77
|
-
</Button>
|
|
78
|
-
<HubAvatar
|
|
79
|
-
class="profile-picture"
|
|
80
|
-
v-bind="currentStateSavepoint.avatar"
|
|
81
|
-
/>
|
|
82
|
-
<div v-if="menuItems.length" class="controls">
|
|
83
|
-
<nav>
|
|
84
|
-
<SubMenu
|
|
85
|
-
:items="menuItems"
|
|
86
|
-
button-title="Options"
|
|
87
|
-
@item-click="onMenuItemClick"
|
|
88
|
-
>
|
|
89
|
-
<MenuIcon class="open-icon" />
|
|
90
|
-
</SubMenu>
|
|
91
|
-
</nav>
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
</template>
|
|
97
|
-
|
|
98
|
-
<style lang="postcss" scoped>
|
|
99
|
-
@import url("@knime/styles/css/mixins.css");
|
|
100
|
-
|
|
101
|
-
.wrapper {
|
|
102
|
-
position: relative;
|
|
103
|
-
margin-left: 30px;
|
|
104
|
-
|
|
105
|
-
&::before {
|
|
106
|
-
position: absolute;
|
|
107
|
-
top: 0;
|
|
108
|
-
left: -22px;
|
|
109
|
-
width: 2px;
|
|
110
|
-
height: calc(100% + 30px);
|
|
111
|
-
content: "";
|
|
112
|
-
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 5 5'%3E%3Ccircle cx='1' cy='1' r='.5' fill='%236E6E6E'/%3E%3C/svg%3E");
|
|
113
|
-
background-repeat: repeat-y;
|
|
114
|
-
background-size: 5px;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
& .current-state {
|
|
118
|
-
display: flex;
|
|
119
|
-
gap: 10px;
|
|
120
|
-
align-items: center;
|
|
121
|
-
justify-content: space-between;
|
|
122
|
-
padding: 10px;
|
|
123
|
-
background-color: var(--knime-gray-ultra-light);
|
|
124
|
-
transition: background-color 0.25s ease;
|
|
125
|
-
|
|
126
|
-
& .left {
|
|
127
|
-
& .draft {
|
|
128
|
-
display: flex;
|
|
129
|
-
flex-direction: column;
|
|
130
|
-
gap: 3px;
|
|
131
|
-
word-break: normal;
|
|
132
|
-
overflow-wrap: anywhere;
|
|
133
|
-
|
|
134
|
-
& h6 {
|
|
135
|
-
display: flex;
|
|
136
|
-
align-items: center;
|
|
137
|
-
margin: 0;
|
|
138
|
-
font-size: 13px;
|
|
139
|
-
font-weight: 700;
|
|
140
|
-
line-height: 18px;
|
|
141
|
-
transition: color 0.25s ease;
|
|
142
|
-
|
|
143
|
-
& .draft-icon {
|
|
144
|
-
@mixin svg-icon-size 20;
|
|
145
|
-
|
|
146
|
-
padding: 4px;
|
|
147
|
-
margin-right: 4px;
|
|
148
|
-
background: var(--knime-carrot-light);
|
|
149
|
-
border-radius: 1000px;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
& .labels {
|
|
154
|
-
display: flex;
|
|
155
|
-
flex-flow: row wrap;
|
|
156
|
-
gap: 5px;
|
|
157
|
-
align-items: center;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
& .date {
|
|
161
|
-
margin: 0;
|
|
162
|
-
font-size: 11px;
|
|
163
|
-
font-weight: 300;
|
|
164
|
-
line-height: 16px;
|
|
165
|
-
transition: color 0.25s ease;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
& .right {
|
|
171
|
-
display: flex;
|
|
172
|
-
gap: 8px;
|
|
173
|
-
align-items: center;
|
|
174
|
-
justify-content: flex-end;
|
|
175
|
-
|
|
176
|
-
& .create-button {
|
|
177
|
-
white-space: nowrap;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
& .controls {
|
|
181
|
-
display: flex;
|
|
182
|
-
flex-direction: column;
|
|
183
|
-
justify-content: center;
|
|
184
|
-
padding-left: 5px;
|
|
185
|
-
margin-right: -4px;
|
|
186
|
-
border-left: 1px solid var(--knime-silver-sand);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
&::before {
|
|
191
|
-
position: absolute;
|
|
192
|
-
top: 12px;
|
|
193
|
-
left: -6px;
|
|
194
|
-
width: 12px;
|
|
195
|
-
height: 12px;
|
|
196
|
-
content: "";
|
|
197
|
-
background-color: var(--knime-gray-ultra-light);
|
|
198
|
-
transform: rotateZ(45deg);
|
|
199
|
-
transition: background-color 0.25s ease;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
&::after {
|
|
203
|
-
position: absolute;
|
|
204
|
-
top: 15px;
|
|
205
|
-
left: -24px;
|
|
206
|
-
width: 6px;
|
|
207
|
-
height: 6px;
|
|
208
|
-
content: "";
|
|
209
|
-
background-color: var(--knime-masala);
|
|
210
|
-
border-radius: 100%;
|
|
211
|
-
box-shadow: 0 0 0 0 transparent;
|
|
212
|
-
transition:
|
|
213
|
-
background-color 0.25s ease,
|
|
214
|
-
box-shadow 0.25s ease;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
&:hover {
|
|
218
|
-
cursor: pointer;
|
|
219
|
-
box-shadow: 0 2px 10px 0 var(--knime-gray-dark-semi);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
&.selected {
|
|
223
|
-
background-color: var(--knime-cornflower-semi);
|
|
224
|
-
|
|
225
|
-
& .left {
|
|
226
|
-
& h6,
|
|
227
|
-
& .date {
|
|
228
|
-
color: var(--knime-cornflower-dark);
|
|
229
|
-
|
|
230
|
-
& .draft-icon {
|
|
231
|
-
background: none;
|
|
232
|
-
stroke: var(--knime-cornflower-dark);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
& .controls {
|
|
238
|
-
border-left: 1px solid var(--knime-cornflower-light);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
&::before {
|
|
242
|
-
background-color: var(--knime-cornflower-semi);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
&::after {
|
|
246
|
-
background-color: var(--knime-cornflower);
|
|
247
|
-
box-shadow:
|
|
248
|
-
0 0 0 3px var(--knime-porcelain),
|
|
249
|
-
0 0 0 5px var(--knime-cornflower);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
@media only screen and (width <= 900px) {
|
|
254
|
-
width: calc(100vw - 100px);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
</style>
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { type Ref, computed, onMounted, ref } from "vue";
|
|
3
|
-
import { useEventBus } from "@vueuse/core";
|
|
4
|
-
import { autoUpdate, offset, useFloating } from "@floating-ui/vue";
|
|
5
|
-
import { isEqual } from "lodash-es"; // eslint-disable-line depend/ban-dependencies
|
|
6
|
-
|
|
7
|
-
import { FunctionButton } from "@knime/components";
|
|
8
|
-
import { truncateString } from "@knime/utils";
|
|
9
|
-
|
|
10
|
-
import Popover from "../../Popover.vue";
|
|
11
|
-
import type { AssignedLabel } from "../types";
|
|
12
|
-
|
|
13
|
-
type PopoverElement = HTMLElement & {
|
|
14
|
-
closeMenu: () => void;
|
|
15
|
-
openMenu: () => void;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const LABEL_LENGTH = 25;
|
|
19
|
-
|
|
20
|
-
const props = withDefaults(
|
|
21
|
-
defineProps<{
|
|
22
|
-
labels: Array<AssignedLabel>;
|
|
23
|
-
defaultLabelCount?: number;
|
|
24
|
-
}>(),
|
|
25
|
-
{ defaultLabelCount: 3 },
|
|
26
|
-
);
|
|
27
|
-
const emit = defineEmits(["labelOver", "labelLeave"]);
|
|
28
|
-
|
|
29
|
-
const eventBus = useEventBus("versionLabels");
|
|
30
|
-
const eventBusKey = "versionLabelShowPopover";
|
|
31
|
-
|
|
32
|
-
const showAll = ref(false);
|
|
33
|
-
const activeLabel: Ref<AssignedLabel | null> = ref(null);
|
|
34
|
-
|
|
35
|
-
const popover: Ref<PopoverElement | null> = ref(null);
|
|
36
|
-
const floatingPanel: Ref<HTMLElement | null> = ref(null);
|
|
37
|
-
const floatingAnchor: Ref<HTMLElement | null> = ref(null);
|
|
38
|
-
// 40px is the offset of the arrow on the popover plus the top padding
|
|
39
|
-
// this is necessary to compensate for the offset calculation
|
|
40
|
-
const defaultCrossAxisOffset = -46;
|
|
41
|
-
const defaultMainAxisOffset = 75;
|
|
42
|
-
|
|
43
|
-
const createMiddleware = () => [
|
|
44
|
-
offset({
|
|
45
|
-
crossAxis: defaultCrossAxisOffset,
|
|
46
|
-
mainAxis: defaultMainAxisOffset,
|
|
47
|
-
}),
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
const { floatingStyles } = useFloating(floatingAnchor, floatingPanel, {
|
|
51
|
-
whileElementsMounted: autoUpdate,
|
|
52
|
-
placement: "left-start",
|
|
53
|
-
strategy: "fixed",
|
|
54
|
-
middleware: createMiddleware(),
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const popoverTopOffset = ref(0);
|
|
58
|
-
const popoverFloatingStyles = computed(() => {
|
|
59
|
-
const parsedTop = parseInt(floatingStyles.value.top.replace("px", ""), 10);
|
|
60
|
-
const compensatedTop = `${parsedTop + popoverTopOffset.value}px`;
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
...floatingStyles.value,
|
|
64
|
-
top: compensatedTop,
|
|
65
|
-
};
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const isShowMoreVisible = computed(
|
|
69
|
-
() => props.labels.length > props.defaultLabelCount && !showAll.value,
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
const showMoreButtonText = computed(
|
|
73
|
-
() => `+${props.labels.length - props.defaultLabelCount}`,
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const filteredLabels = computed(() =>
|
|
77
|
-
showAll.value ? props.labels : props.labels.slice(0, props.defaultLabelCount),
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
const calculateDistanceToUpperBorder = (labelElement: HTMLElement) => {
|
|
81
|
-
const labelRect = labelElement.getBoundingClientRect();
|
|
82
|
-
const floatingAnchorRect = floatingAnchor.value!.getBoundingClientRect();
|
|
83
|
-
|
|
84
|
-
return Math.round(labelRect.top - floatingAnchorRect.top);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const isActiveLabel = (label: AssignedLabel) =>
|
|
88
|
-
isEqual(activeLabel.value, label);
|
|
89
|
-
|
|
90
|
-
const togglePopover = (label: AssignedLabel, labelElement: HTMLElement) => {
|
|
91
|
-
if (isActiveLabel(label)) {
|
|
92
|
-
activeLabel.value = null;
|
|
93
|
-
popover.value?.closeMenu();
|
|
94
|
-
} else {
|
|
95
|
-
eventBus.emit(eventBusKey);
|
|
96
|
-
popoverTopOffset.value = calculateDistanceToUpperBorder(labelElement);
|
|
97
|
-
|
|
98
|
-
activeLabel.value = label;
|
|
99
|
-
popover.value?.openMenu();
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const showMore = () => {
|
|
104
|
-
showAll.value = !showAll.value;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const mouseOver = () => emit("labelOver");
|
|
108
|
-
const mouseLeave = () => emit("labelLeave");
|
|
109
|
-
|
|
110
|
-
onMounted(() => {
|
|
111
|
-
eventBus.on((event: unknown) => {
|
|
112
|
-
if (event === eventBusKey) {
|
|
113
|
-
popover.value?.closeMenu();
|
|
114
|
-
activeLabel.value = null;
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
</script>
|
|
119
|
-
|
|
120
|
-
<template>
|
|
121
|
-
<template v-if="labels.length > 0">
|
|
122
|
-
<div class="label-list-with-popover">
|
|
123
|
-
<div ref="floatingAnchor" class="label-list">
|
|
124
|
-
<FunctionButton
|
|
125
|
-
v-for="label in filteredLabels"
|
|
126
|
-
:key="label.labelId"
|
|
127
|
-
compact
|
|
128
|
-
class="with-border"
|
|
129
|
-
:active="isActiveLabel(label)"
|
|
130
|
-
@mouseover="mouseOver"
|
|
131
|
-
@mouseleave="mouseLeave"
|
|
132
|
-
@click.stop="togglePopover(label, $event.currentTarget)"
|
|
133
|
-
@keydown.esc.stop="popover?.closeMenu()"
|
|
134
|
-
>
|
|
135
|
-
{{ truncateString(label.label.name, LABEL_LENGTH) }}
|
|
136
|
-
</FunctionButton>
|
|
137
|
-
|
|
138
|
-
<FunctionButton
|
|
139
|
-
v-if="isShowMoreVisible"
|
|
140
|
-
compact
|
|
141
|
-
class="with-border"
|
|
142
|
-
@mouseover="mouseOver"
|
|
143
|
-
@mouseleave="mouseLeave"
|
|
144
|
-
@click.stop="showMore"
|
|
145
|
-
>{{ showMoreButtonText }}</FunctionButton
|
|
146
|
-
>
|
|
147
|
-
</div>
|
|
148
|
-
|
|
149
|
-
<div
|
|
150
|
-
ref="floatingPanel"
|
|
151
|
-
class="floating-panel"
|
|
152
|
-
:style="popoverFloatingStyles"
|
|
153
|
-
@click.stop
|
|
154
|
-
@mouseover="mouseOver"
|
|
155
|
-
@mouseleave="mouseLeave"
|
|
156
|
-
>
|
|
157
|
-
<Popover
|
|
158
|
-
ref="popover"
|
|
159
|
-
:use-button="false"
|
|
160
|
-
:button-with-border="false"
|
|
161
|
-
arrow-position="right"
|
|
162
|
-
@close="activeLabel = null"
|
|
163
|
-
>
|
|
164
|
-
<template #content>
|
|
165
|
-
<h6 class="headline">
|
|
166
|
-
{{ activeLabel?.label.name }}
|
|
167
|
-
</h6>
|
|
168
|
-
<div class="panel">
|
|
169
|
-
<div class="description">
|
|
170
|
-
{{ activeLabel?.label.description }}
|
|
171
|
-
</div>
|
|
172
|
-
<div class="message">{{ activeLabel?.message }}</div>
|
|
173
|
-
</div>
|
|
174
|
-
</template>
|
|
175
|
-
</Popover>
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
</template>
|
|
179
|
-
</template>
|
|
180
|
-
|
|
181
|
-
<style lang="postcss" scoped>
|
|
182
|
-
.label-list-with-popover {
|
|
183
|
-
position: relative;
|
|
184
|
-
|
|
185
|
-
& .label-list {
|
|
186
|
-
position: relative;
|
|
187
|
-
display: flex;
|
|
188
|
-
flex-flow: row wrap;
|
|
189
|
-
gap: var(--space-4);
|
|
190
|
-
align-items: center;
|
|
191
|
-
padding: var(--space-6) 0;
|
|
192
|
-
|
|
193
|
-
& .function-button {
|
|
194
|
-
&.with-border {
|
|
195
|
-
padding: 2px var(--space-8);
|
|
196
|
-
border: 1px solid var(--knime-silver-sand);
|
|
197
|
-
|
|
198
|
-
&.active {
|
|
199
|
-
border-color: var(--theme-button-function-background-color-active);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
&:empty {
|
|
205
|
-
display: none;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
& .floating-panel {
|
|
210
|
-
z-index: 3;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/* the position is set back because it interferes with the position calculation of floating UI */
|
|
215
|
-
.popover.expanded :deep(.content) {
|
|
216
|
-
position: initial;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
.headline,
|
|
220
|
-
.panel {
|
|
221
|
-
line-height: 1.5;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.headline {
|
|
225
|
-
padding-right: 18px;
|
|
226
|
-
margin: 0;
|
|
227
|
-
margin: 0 0 var(--space-8);
|
|
228
|
-
font-size: 16px;
|
|
229
|
-
font-weight: 700;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
.panel {
|
|
233
|
-
& .description {
|
|
234
|
-
margin-bottom: var(--space-6);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
& .message,
|
|
238
|
-
& .description {
|
|
239
|
-
font-size: 13px;
|
|
240
|
-
font-weight: 300;
|
|
241
|
-
|
|
242
|
-
&:empty {
|
|
243
|
-
display: none;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
@media only screen and (width <= 900px) {
|
|
249
|
-
.label-list-with-popover {
|
|
250
|
-
display: none;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
</style>
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { useEventBus } from "@vueuse/core";
|
|
3
|
-
import { throttle } from "lodash-es"; // eslint-disable-line depend/ban-dependencies
|
|
4
|
-
|
|
5
|
-
import { FunctionButton } from "@knime/components";
|
|
6
|
-
import CloseIcon from "@knime/styles/img/icons/close.svg";
|
|
7
|
-
import HistoryIcon from "@knime/styles/img/icons/history.svg";
|
|
8
|
-
|
|
9
|
-
import { CURRENT_STATE_VERSION } from "../constants";
|
|
10
|
-
import type {
|
|
11
|
-
ItemSavepoint,
|
|
12
|
-
NamedItemVersion,
|
|
13
|
-
VersionLimit,
|
|
14
|
-
WithAvatar,
|
|
15
|
-
WithLabels,
|
|
16
|
-
} from "../types";
|
|
17
|
-
|
|
18
|
-
import CurrentState from "./CurrentState.vue";
|
|
19
|
-
import VersionHistory from "./VersionHistory.vue";
|
|
20
|
-
import VersionLimitInfo from "./VersionLimitInfo.vue";
|
|
21
|
-
|
|
22
|
-
type ManageVersionsProps = {
|
|
23
|
-
hasUnversionedChanges: boolean;
|
|
24
|
-
unversionedSavepoint?: (ItemSavepoint & WithAvatar & WithLabels) | null;
|
|
25
|
-
currentVersion: NamedItemVersion["version"] | null;
|
|
26
|
-
versionHistory: Array<NamedItemVersion & WithAvatar & WithLabels>;
|
|
27
|
-
loading: boolean;
|
|
28
|
-
hasLoadedAllVersions: boolean;
|
|
29
|
-
hasAdminRights: boolean;
|
|
30
|
-
hasEditCapability: boolean;
|
|
31
|
-
versionLimit?: VersionLimit;
|
|
32
|
-
upgradeUrl?: string;
|
|
33
|
-
isPrivate?: boolean;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
defineProps<ManageVersionsProps>();
|
|
37
|
-
|
|
38
|
-
defineEmits<{
|
|
39
|
-
close: [];
|
|
40
|
-
loadAll: [];
|
|
41
|
-
create: [];
|
|
42
|
-
delete: [version: NamedItemVersion["version"]];
|
|
43
|
-
restore: [version: NamedItemVersion["version"]];
|
|
44
|
-
select: [version: NamedItemVersion["version"]];
|
|
45
|
-
discardCurrentState: [];
|
|
46
|
-
}>();
|
|
47
|
-
|
|
48
|
-
const labelsEventBus = useEventBus("versionLabels");
|
|
49
|
-
|
|
50
|
-
const closeLabelPopovers = throttle(() => {
|
|
51
|
-
labelsEventBus.emit("versionLabelShowPopover");
|
|
52
|
-
// eslint-disable-next-line no-magic-numbers
|
|
53
|
-
}, 10000); // Arbitrary delay to reduce overhead, is automatically reset @scrollend
|
|
54
|
-
</script>
|
|
55
|
-
|
|
56
|
-
<template>
|
|
57
|
-
<div class="manage-versions-container">
|
|
58
|
-
<FunctionButton class="close" @click="$emit('close')">
|
|
59
|
-
<CloseIcon />
|
|
60
|
-
</FunctionButton>
|
|
61
|
-
|
|
62
|
-
<div class="manage-versions">
|
|
63
|
-
<div class="header">
|
|
64
|
-
<HistoryIcon class="history-icon" /><!--
|
|
65
|
-
-->
|
|
66
|
-
<h4>Version history</h4>
|
|
67
|
-
<div
|
|
68
|
-
v-if="hasUnversionedChanges && unversionedSavepoint"
|
|
69
|
-
class="changes"
|
|
70
|
-
>
|
|
71
|
-
<CurrentState
|
|
72
|
-
:has-edit-capability="hasEditCapability"
|
|
73
|
-
:has-previous-version="versionHistory.length > 0"
|
|
74
|
-
:is-selected="currentVersion === CURRENT_STATE_VERSION"
|
|
75
|
-
:current-state-savepoint="unversionedSavepoint"
|
|
76
|
-
:is-version-limit-exceeded="
|
|
77
|
-
versionLimit?.limit !== undefined &&
|
|
78
|
-
versionLimit.currentUsage >= versionLimit.limit
|
|
79
|
-
"
|
|
80
|
-
@select="$emit('select', CURRENT_STATE_VERSION)"
|
|
81
|
-
@create-version="$emit('create')"
|
|
82
|
-
@discard="$emit('discardCurrentState')"
|
|
83
|
-
/>
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
<div
|
|
87
|
-
class="overflow-container"
|
|
88
|
-
@scroll="closeLabelPopovers"
|
|
89
|
-
@scrollend="closeLabelPopovers.cancel"
|
|
90
|
-
>
|
|
91
|
-
<div class="versions">
|
|
92
|
-
<VersionHistory
|
|
93
|
-
:selected-version="currentVersion"
|
|
94
|
-
:version-history
|
|
95
|
-
:loading
|
|
96
|
-
:has-unversioned-changes
|
|
97
|
-
:has-loaded-all-versions
|
|
98
|
-
:has-admin-rights
|
|
99
|
-
:has-edit-capability
|
|
100
|
-
@delete="$emit('delete', $event)"
|
|
101
|
-
@restore="$emit('restore', $event)"
|
|
102
|
-
@load-all="$emit('loadAll')"
|
|
103
|
-
@select="$emit('select', $event ?? CURRENT_STATE_VERSION)"
|
|
104
|
-
/>
|
|
105
|
-
<VersionLimitInfo
|
|
106
|
-
v-if="versionLimit?.limit !== undefined"
|
|
107
|
-
class="version-limit-info"
|
|
108
|
-
:version-limit="{
|
|
109
|
-
limit: versionLimit.limit,
|
|
110
|
-
currentUsage: versionLimit.currentUsage,
|
|
111
|
-
}"
|
|
112
|
-
:upgrade-url
|
|
113
|
-
:is-private
|
|
114
|
-
/>
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
</template>
|
|
120
|
-
|
|
121
|
-
<style lang="postcss" scoped>
|
|
122
|
-
@import url("@knime/styles/css/mixins.css");
|
|
123
|
-
|
|
124
|
-
.manage-versions-container {
|
|
125
|
-
position: relative;
|
|
126
|
-
display: flex;
|
|
127
|
-
flex-direction: column;
|
|
128
|
-
align-items: flex-start;
|
|
129
|
-
justify-content: flex-start;
|
|
130
|
-
height: 100%;
|
|
131
|
-
overscroll-behavior: none;
|
|
132
|
-
background-color: var(--knime-gray-light-semi);
|
|
133
|
-
isolation: isolate;
|
|
134
|
-
|
|
135
|
-
& .close {
|
|
136
|
-
position: absolute;
|
|
137
|
-
top: 6px;
|
|
138
|
-
right: 6px;
|
|
139
|
-
z-index: 3;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
& .manage-versions {
|
|
143
|
-
display: flex;
|
|
144
|
-
flex-direction: column;
|
|
145
|
-
width: 100%;
|
|
146
|
-
height: 100%;
|
|
147
|
-
|
|
148
|
-
& .header {
|
|
149
|
-
z-index: 2;
|
|
150
|
-
padding: 32px 30px 30px;
|
|
151
|
-
background-color: var(--knime-white);
|
|
152
|
-
|
|
153
|
-
& h4 {
|
|
154
|
-
display: inline;
|
|
155
|
-
margin: 0;
|
|
156
|
-
font-size: 22px;
|
|
157
|
-
line-height: 26px;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
& .history-icon {
|
|
161
|
-
@mixin svg-icon-size 24;
|
|
162
|
-
|
|
163
|
-
position: relative;
|
|
164
|
-
top: 1px;
|
|
165
|
-
margin-right: 9px;
|
|
166
|
-
vertical-align: sub;
|
|
167
|
-
stroke: var(--knime-masala);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
& .overflow-container {
|
|
172
|
-
overflow-y: auto;
|
|
173
|
-
|
|
174
|
-
& .versions {
|
|
175
|
-
width: 100%;
|
|
176
|
-
padding: 30px;
|
|
177
|
-
|
|
178
|
-
& .version-limit-info {
|
|
179
|
-
margin-top: 30px;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
& .changes {
|
|
185
|
-
width: 100%;
|
|
186
|
-
padding-top: 30px;
|
|
187
|
-
background-color: var(--knime-white);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
</style>
|