@knime/hub-features 1.13.0 → 1.14.0

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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # @knime/hub-features
2
2
 
3
+ ## 1.14.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c75b415: Added SideDrawerHeader component
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [c75b415]
12
+ - @knime/components@1.36.0
13
+
3
14
  ## 1.13.0
4
15
 
5
16
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knime/hub-features",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "description": "Vue components & composables for shared hub features",
5
5
  "homepage": "https://knime.github.io/webapps-common/",
6
6
  "license": "GPL 3 and Additional Permissions according to Sec. 7 (SEE the file LICENSE)",
@@ -31,7 +31,7 @@
31
31
  "lodash-es": "4.17.21",
32
32
  "ofetch": "^1.4.1",
33
33
  "typescript": "^5.8.3",
34
- "@knime/components": "1.35.1",
34
+ "@knime/components": "1.36.0",
35
35
  "@knime/styles": "1.11.1",
36
36
  "@knime/utils": "1.5.5"
37
37
  },
@@ -0,0 +1,166 @@
1
+ <script setup lang="ts">
2
+ import { computed, nextTick, onMounted, ref } from "vue";
3
+ import { useTextareaAutosize } from "@vueuse/core";
4
+
5
+ import {
6
+ Button,
7
+ InputField,
8
+ Label,
9
+ LoadingIcon,
10
+ SideDrawerHeader,
11
+ TextArea,
12
+ } from "@knime/components";
13
+
14
+ type Props = {
15
+ isCreationPending?: boolean;
16
+ };
17
+
18
+ withDefaults(defineProps<Props>(), { isCreationPending: false });
19
+
20
+ const emit = defineEmits<{
21
+ create: [{ name: string; description: string }];
22
+ cancel: [hasUnsavedChanges: boolean];
23
+ }>();
24
+
25
+ const versionName = ref("");
26
+ const versionDescription = ref("");
27
+
28
+ const descriptionEditor = ref<InstanceType<typeof TextArea> | null>(null);
29
+
30
+ onMounted(() => {
31
+ useTextareaAutosize({
32
+ element: descriptionEditor.value?.$el.getElementsByTagName("textarea")[0],
33
+ input: versionDescription,
34
+ });
35
+ });
36
+
37
+ const doValidate = ref(false);
38
+
39
+ const isVersionNameInvalid = computed(() => {
40
+ return doValidate.value && versionName.value.length <= 0;
41
+ });
42
+
43
+ const hasUnsavedChanges = computed(() => {
44
+ return versionName.value !== "" || versionDescription.value !== "";
45
+ });
46
+
47
+ const onCreate = async () => {
48
+ doValidate.value = true;
49
+ await nextTick();
50
+
51
+ if (!isVersionNameInvalid.value) {
52
+ emit("create", {
53
+ name: versionName.value,
54
+ description: versionDescription.value,
55
+ });
56
+ }
57
+ };
58
+ </script>
59
+
60
+ <template>
61
+ <div class="create-version-form">
62
+ <SideDrawerHeader
63
+ title="Create Version"
64
+ description="Give your version a name and description. Versions can be used to create a deployment.
65
+ "
66
+ :is-sub-drawer="true"
67
+ @close="$emit('cancel', hasUnsavedChanges)"
68
+ />
69
+ <div class="form-content">
70
+ <Label text="Version name">
71
+ <InputField
72
+ v-model="versionName"
73
+ type="text"
74
+ required
75
+ :is-valid="!isVersionNameInvalid"
76
+ />
77
+ <div v-if="isVersionNameInvalid" class="error">
78
+ Please enter at least 1 character.
79
+ </div>
80
+ </Label>
81
+ <Label text="Description">
82
+ <TextArea
83
+ ref="descriptionEditor"
84
+ v-model="versionDescription"
85
+ class="description"
86
+ />
87
+ </Label>
88
+ <div class="controls">
89
+ <Button
90
+ with-border
91
+ compact
92
+ class="button cancel"
93
+ @click="$emit('cancel', hasUnsavedChanges)"
94
+ >
95
+ <strong>Cancel</strong>
96
+ </Button>
97
+ <Button
98
+ primary
99
+ compact
100
+ class="button create"
101
+ :disabled="isVersionNameInvalid || isCreationPending"
102
+ @click="onCreate"
103
+ >
104
+ <LoadingIcon v-if="isCreationPending" />
105
+ <strong v-if="!isCreationPending">Create</strong>
106
+ </Button>
107
+ </div>
108
+ </div>
109
+ </div>
110
+ </template>
111
+
112
+ <style lang="postcss" scoped>
113
+ .create-version-form {
114
+ height: 100%;
115
+ max-height: 100%;
116
+ width: 100%;
117
+ display: flex;
118
+ flex-direction: column;
119
+
120
+ & .form-content {
121
+ display: flex;
122
+ flex-direction: column;
123
+ height: 100%;
124
+ padding: 30px 30px 0;
125
+ gap: 30px;
126
+ overscroll-behavior: none;
127
+ isolation: isolate;
128
+ overflow: auto;
129
+ z-index: 1;
130
+ background-color: var(--knime-gray-ultra-light);
131
+
132
+ & .description {
133
+ width: 100%;
134
+ max-width: unset;
135
+ display: flex;
136
+
137
+ & :deep(textarea) {
138
+ width: 100%;
139
+ box-sizing: content-box;
140
+ max-height: 200px;
141
+ resize: none;
142
+ }
143
+ }
144
+
145
+ & .error {
146
+ position: absolute;
147
+ word-break: keep-all;
148
+ margin-top: 6px;
149
+ font-weight: 300;
150
+ font-size: 13px;
151
+ color: var(--theme-color-error);
152
+ line-height: 18px;
153
+ }
154
+
155
+ & .controls {
156
+ border-top: 1px solid var(--knime-silver-sand);
157
+ display: flex;
158
+ margin: 0 -30px;
159
+ padding: 10px 20px;
160
+ gap: 10px;
161
+ justify-content: space-between;
162
+ margin-top: auto;
163
+ }
164
+ }
165
+ }
166
+ </style>
@@ -5,10 +5,10 @@ import { Button, LocalDateTime, SubMenu } from "@knime/components";
5
5
  import MenuIcon from "@knime/styles/img/icons/menu-options.svg";
6
6
  import WrenchIcon from "@knime/styles/img/icons/wrench.svg";
7
7
 
8
- import HubAvatar from "../avatars/HubAvatar.vue";
8
+ import HubAvatar from "../../avatars/HubAvatar.vue";
9
+ import type { ItemSavepoint, WithAvatar, WithLabels } from "../types";
9
10
 
10
11
  import LabelList from "./LabelList.vue";
11
- import type { ItemSavepoint, WithAvatar, WithLabels } from "./types";
12
12
 
13
13
  const props = defineProps<{
14
14
  isSelected: boolean;
@@ -7,9 +7,8 @@ import { isEqual } from "lodash-es"; // eslint-disable-line depend/ban-dependenc
7
7
  import { FunctionButton } from "@knime/components";
8
8
  import { truncateString } from "@knime/utils";
9
9
 
10
- import Popover from "../Popover.vue";
11
-
12
- import type { AssignedLabel } from "./types";
10
+ import Popover from "../../Popover.vue";
11
+ import type { AssignedLabel } from "../types";
13
12
 
14
13
  type PopoverElement = HTMLElement & {
15
14
  closeMenu: () => void;
@@ -6,17 +6,18 @@ import { FunctionButton } from "@knime/components";
6
6
  import CloseIcon from "@knime/styles/img/icons/close.svg";
7
7
  import HistoryIcon from "@knime/styles/img/icons/history.svg";
8
8
 
9
- import CurrentState from "./CurrentState.vue";
10
- import VersionHistory from "./VersionHistory.vue";
11
- import VersionLimitInfo from "./VersionLimitInfo.vue";
12
- import { CURRENT_STATE_VERSION } from "./constants";
9
+ import { CURRENT_STATE_VERSION } from "../constants";
13
10
  import type {
14
11
  ItemSavepoint,
15
12
  NamedItemVersion,
16
13
  VersionLimit,
17
14
  WithAvatar,
18
15
  WithLabels,
19
- } from "./types";
16
+ } from "../types";
17
+
18
+ import CurrentState from "./CurrentState.vue";
19
+ import VersionHistory from "./VersionHistory.vue";
20
+ import VersionLimitInfo from "./VersionLimitInfo.vue";
20
21
 
21
22
  type ManageVersionsProps = {
22
23
  hasUnversionedChanges: boolean;
@@ -1,9 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  import { IdleReadyButton } from "@knime/components";
3
3
 
4
+ import type { NamedItemVersion, WithAvatar, WithLabels } from "../types";
5
+
4
6
  import NoVersionItem from "./NoVersionItem.vue";
5
7
  import VersionItem from "./VersionItem.vue";
6
- import type { NamedItemVersion, WithAvatar, WithLabels } from "./types";
7
8
 
8
9
  defineProps<{
9
10
  selectedVersion: NamedItemVersion["version"] | null;
@@ -6,10 +6,10 @@ import { LocalDateTime, SubMenu, Tooltip } from "@knime/components";
6
6
  import MenuIcon from "@knime/styles/img/icons/menu-options.svg";
7
7
  import { truncateString } from "@knime/utils";
8
8
 
9
- import HubAvatar from "../avatars/HubAvatar.vue";
9
+ import HubAvatar from "../../avatars/HubAvatar.vue";
10
+ import type { NamedItemVersion, WithAvatar, WithLabels } from "../types";
10
11
 
11
12
  import LabelList from "./LabelList.vue";
12
- import type { NamedItemVersion, WithAvatar, WithLabels } from "./types";
13
13
 
14
14
  const DESCRIPTION_TRUNCATE_LENGTH = 120;
15
15
 
@@ -3,7 +3,7 @@ import { computed } from "vue";
3
3
 
4
4
  import { InlineMessage } from "@knime/components";
5
5
 
6
- import type { VersionLimit } from "./types";
6
+ import type { VersionLimit } from "../types";
7
7
 
8
8
  const { versionLimit, upgradeUrl = undefined } = defineProps<{
9
9
  versionLimit: Required<VersionLimit>;
@@ -13,7 +13,7 @@ import type {
13
13
  WithLabels,
14
14
  } from "@knime/hub-features/versions";
15
15
 
16
- import { getFetchClient } from "../../common/ofetchClient";
16
+ import { getFetchClient } from "../../../common/ofetchClient";
17
17
 
18
18
  type UseVersionsApiOptions = {
19
19
  customFetchClientOptions?: FetchOptions;
@@ -1,7 +1,7 @@
1
- import CreateVersionForm from "./CreateVersionForm.vue";
2
- import ManageVersions from "./ManageVersions.vue";
1
+ import CreateVersionForm from "./components/CreateVersionForm.vue";
2
+ import ManageVersions from "./components/ManageVersions.vue";
3
3
 
4
4
  export { CreateVersionForm, ManageVersions };
5
5
  export type * from "./types";
6
6
  export * from "./constants";
7
- export * from "./useVersionsApi";
7
+ export * from "./composables/useVersionsApi";
@@ -1,150 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed, nextTick, onMounted, ref } from "vue";
3
- import { useTextareaAutosize } from "@vueuse/core";
4
-
5
- import {
6
- Button,
7
- InputField,
8
- Label,
9
- LoadingIcon,
10
- TextArea,
11
- } from "@knime/components";
12
-
13
- type Props = {
14
- isCreationPending?: boolean;
15
- };
16
-
17
- withDefaults(defineProps<Props>(), { isCreationPending: false });
18
-
19
- const emit = defineEmits<{
20
- create: [{ name: string; description: string }];
21
- cancel: [hasUnsavedChanges: boolean];
22
- }>();
23
-
24
- const versionName = ref("");
25
- const versionDescription = ref("");
26
-
27
- const descriptionEditor = ref<InstanceType<typeof TextArea> | null>(null);
28
-
29
- onMounted(() => {
30
- useTextareaAutosize({
31
- element: descriptionEditor.value?.$el.getElementsByTagName("textarea")[0],
32
- input: versionDescription,
33
- });
34
- });
35
-
36
- const doValidate = ref(false);
37
-
38
- const isVersionNameInvalid = computed(() => {
39
- return versionName.value.length <= 0 && doValidate.value;
40
- });
41
-
42
- const hasUnsavedChanges = computed(() => {
43
- return versionName.value !== "" || versionDescription.value !== "";
44
- });
45
-
46
- const onCreate = async () => {
47
- doValidate.value = true;
48
- await nextTick();
49
-
50
- if (!isVersionNameInvalid.value) {
51
- emit("create", {
52
- name: versionName.value,
53
- description: versionDescription.value,
54
- });
55
- }
56
- };
57
- </script>
58
-
59
- <template>
60
- <div class="create-version-form">
61
- <Label text="Version name">
62
- <InputField
63
- v-model="versionName"
64
- type="text"
65
- required
66
- :is-valid="!isVersionNameInvalid"
67
- />
68
- <div v-if="isVersionNameInvalid" class="error">
69
- Please enter at least 1 character.
70
- </div>
71
- </Label>
72
- <Label text="Description">
73
- <TextArea
74
- ref="descriptionEditor"
75
- v-model="versionDescription"
76
- class="description"
77
- />
78
- </Label>
79
- <div class="controls">
80
- <Button
81
- with-border
82
- compact
83
- class="button cancel"
84
- @click="$emit('cancel', hasUnsavedChanges)"
85
- >
86
- <strong>Cancel</strong>
87
- </Button>
88
- <Button
89
- primary
90
- compact
91
- class="button create"
92
- :disabled="isVersionNameInvalid || isCreationPending"
93
- @click="onCreate"
94
- >
95
- <LoadingIcon v-if="isCreationPending" />
96
- <strong v-if="!isCreationPending">Create</strong>
97
- </Button>
98
- </div>
99
- </div>
100
- </template>
101
-
102
- <style lang="postcss" scoped>
103
- .create-version-form {
104
- height: 100%;
105
- max-height: 100%;
106
- width: 100%;
107
- display: flex;
108
- flex-direction: column;
109
- padding: 30px 30px 0;
110
- gap: 30px;
111
- overscroll-behavior: none;
112
- isolation: isolate;
113
- overflow: auto;
114
- z-index: 1;
115
- background-color: var(--knime-gray-ultra-light);
116
-
117
- & .description {
118
- width: 100%;
119
- max-width: unset;
120
- display: flex;
121
-
122
- & :deep(textarea) {
123
- width: 100%;
124
- box-sizing: content-box;
125
- max-height: 200px;
126
- resize: none;
127
- }
128
- }
129
-
130
- & .error {
131
- position: absolute;
132
- word-break: keep-all;
133
- margin-top: 6px;
134
- font-weight: 300;
135
- font-size: 13px;
136
- color: var(--theme-color-error);
137
- line-height: 18px;
138
- }
139
-
140
- & .controls {
141
- border-top: 1px solid var(--knime-silver-sand);
142
- display: flex;
143
- margin: 0 -30px;
144
- padding: 10px 20px;
145
- gap: 10px;
146
- justify-content: space-between;
147
- margin-top: auto;
148
- }
149
- }
150
- </style>