@knime/hub-features 1.27.0 → 1.29.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.
Files changed (28) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/package.json +4 -4
  3. package/src/analytics/analytics.ts +39 -13
  4. package/src/analytics/schema/cloudhome-event-functions.ts +245 -0
  5. package/src/analytics/schema/code-generator.js +17 -8
  6. package/src/analytics/schema/{event-functions.ts → editor-event-functions.ts} +7 -9
  7. package/src/analytics/schema/schema.d.ts +133 -7
  8. package/src/analytics/schema/schema.json +833 -157
  9. package/src/analytics/types.ts +4 -1
  10. package/src/httpClient/constants.ts +1 -0
  11. package/src/{common/ofetchClient.ts → httpClient/createHttpClient.ts} +6 -5
  12. package/src/httpClient/index.ts +2 -0
  13. package/src/index.ts +1 -0
  14. package/src/useDownloadArtifact/useDownloadArtifact.ts +2 -2
  15. package/src/useFileUpload/useFileUpload.ts +2 -2
  16. package/src/common/constants.ts +0 -1
  17. package/src/components/versions/components/CreateVersionForm.vue +0 -155
  18. package/src/components/versions/components/CurrentState.vue +0 -258
  19. package/src/components/versions/components/LabelList.vue +0 -253
  20. package/src/components/versions/components/ManageVersions.vue +0 -191
  21. package/src/components/versions/components/NoVersionItem.vue +0 -23
  22. package/src/components/versions/components/VersionHistory.vue +0 -138
  23. package/src/components/versions/components/VersionItem.vue +0 -278
  24. package/src/components/versions/components/VersionLimitInfo.vue +0 -37
  25. package/src/components/versions/composables/useVersionsApi.ts +0 -254
  26. package/src/components/versions/constants.ts +0 -3
  27. package/src/components/versions/index.ts +0 -7
  28. package/src/components/versions/types.ts +0 -77
@@ -1,6 +1,9 @@
1
1
  import type { AnalyticsEventSchema } from "./schema/schema";
2
2
 
3
- export type DefaultContext = Record<string, string | boolean | number>;
3
+ export type DefaultContext = { eventSource: "cloudhome" | "editor" } & Record<
4
+ string,
5
+ string | boolean | number
6
+ >;
4
7
  export type Metadata = Omit<AnalyticsEventSchema, "events">;
5
8
 
6
9
  type NewEvents = AnalyticsEventSchema["events"];
@@ -0,0 +1 @@
1
+ export const API_BASE_URL = "/_/api";
@@ -1,9 +1,9 @@
1
1
  import { merge } from "lodash-es"; // eslint-disable-line depend/ban-dependencies
2
2
  import { type FetchOptions, ofetch } from "ofetch";
3
3
 
4
- import { DEFAULT_API_BASE_URL } from "./constants";
4
+ import { API_BASE_URL } from "./constants";
5
5
 
6
- export const defaultConfig: FetchOptions = {
6
+ const defaultConfig: FetchOptions = {
7
7
  headers: {
8
8
  "Content-Type": "application/json",
9
9
 
@@ -12,11 +12,12 @@ export const defaultConfig: FetchOptions = {
12
12
  },
13
13
  } as const;
14
14
 
15
- export const getFetchClient = (customOptions?: FetchOptions) => {
16
- const { baseURL = DEFAULT_API_BASE_URL, ...otherCustomOptions } =
17
- customOptions ?? {};
15
+ const createHttpClient = (customOptions?: FetchOptions) => {
16
+ const { baseURL = API_BASE_URL, ...otherCustomOptions } = customOptions ?? {};
18
17
 
19
18
  return ofetch.create(
20
19
  merge({ baseURL, ...otherCustomOptions }, defaultConfig),
21
20
  );
22
21
  };
22
+
23
+ export { type FetchOptions, defaultConfig, createHttpClient };
@@ -0,0 +1,2 @@
1
+ export * from "./createHttpClient";
2
+ export * from "./constants";
package/src/index.ts CHANGED
@@ -4,3 +4,4 @@ export * from "./useDownloadArtifact";
4
4
  export * from "./components/avatars";
5
5
  export * from "./embeddingSDK";
6
6
  export * from "./authUtils";
7
+ export * from "./httpClient";
@@ -4,7 +4,7 @@ import { FetchError, type FetchOptions } from "ofetch";
4
4
  import type { DownloadItem as DownloadItemExternal } from "@knime/components";
5
5
  import { sleep } from "@knime/utils";
6
6
 
7
- import { getFetchClient } from "../common/ofetchClient";
7
+ import { createHttpClient } from "../httpClient/createHttpClient";
8
8
  import { rfcErrors } from "../rfcErrors";
9
9
 
10
10
  const DEFAULT_MAX_RETRIES = null;
@@ -91,7 +91,7 @@ const isAbortError = (error: unknown) =>
91
91
  export const useDownloadArtifact = (
92
92
  options: UseDownloadArtifactOptions = {},
93
93
  ) => {
94
- const $ofetch = getFetchClient(options.customFetchClientOptions);
94
+ const $ofetch = createHttpClient(options.customFetchClientOptions);
95
95
 
96
96
  const downloadItems = ref<Record<string, DownloadItem>>({});
97
97
  const abortControllers: Record<string, AbortController> = {};
@@ -9,7 +9,7 @@ import {
9
9
  promise,
10
10
  } from "@knime/utils";
11
11
 
12
- import { getFetchClient } from "../common/ofetchClient";
12
+ import { createHttpClient } from "../httpClient/createHttpClient";
13
13
  import { rfcErrors } from "../rfcErrors";
14
14
 
15
15
  const DEFAULT_MAX_UPLOAD_QUEUE_SIZE = 10;
@@ -120,7 +120,7 @@ type UseFileUploadOptions = {
120
120
  * ```
121
121
  */
122
122
  export const useFileUpload = (options: UseFileUploadOptions = {}) => {
123
- const $ofetch = getFetchClient(options.customFetchClientOptions);
123
+ const $ofetch = createHttpClient(options.customFetchClientOptions);
124
124
 
125
125
  const prepareUpload = (
126
126
  parentId: string,
@@ -1 +0,0 @@
1
- export const DEFAULT_API_BASE_URL = "/_/api";
@@ -1,155 +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
- InputField,
7
- Label,
8
- SideDrawerControls,
9
- SideDrawerHeader,
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 doValidate.value && versionName.value.length <= 0;
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
- <SideDrawerHeader
62
- title="Create Version"
63
- description="Give your version a name and description. Versions can be used to create a deployment.
64
- "
65
- :is-sub-drawer="true"
66
- @close="$emit('cancel', hasUnsavedChanges)"
67
- />
68
- <div class="form-content">
69
- <Label text="Version name">
70
- <InputField
71
- v-model="versionName"
72
- type="text"
73
- required
74
- :is-valid="!isVersionNameInvalid"
75
- />
76
- <div v-if="isVersionNameInvalid" class="error">
77
- Please enter at least 1 character.
78
- </div>
79
- </Label>
80
- <Label text="Description">
81
- <TextArea
82
- ref="descriptionEditor"
83
- v-model="versionDescription"
84
- class="description"
85
- />
86
- </Label>
87
- <div class="controls">
88
- <SideDrawerControls
89
- class="create-version-controls"
90
- :edit-enabled="true"
91
- :processing="isCreationPending"
92
- action-label="Create"
93
- :disabled="isVersionNameInvalid || isCreationPending"
94
- @save="onCreate"
95
- @cancel="$emit('cancel', hasUnsavedChanges)"
96
- />
97
- </div>
98
- </div>
99
- </div>
100
- </template>
101
-
102
- <style lang="postcss" scoped>
103
- .create-version-form {
104
- display: flex;
105
- flex-direction: column;
106
- width: 100%;
107
- height: 100%;
108
- max-height: 100%;
109
-
110
- & .form-content {
111
- z-index: 1;
112
- display: flex;
113
- flex-direction: column;
114
- gap: 30px;
115
- height: 100%;
116
- padding: 30px 30px 0;
117
- overflow: auto;
118
- overscroll-behavior: none;
119
- background-color: var(--knime-gray-ultra-light);
120
- isolation: isolate;
121
-
122
- & .description {
123
- display: flex;
124
- width: 100%;
125
- max-width: unset;
126
-
127
- & :deep(textarea) {
128
- box-sizing: content-box;
129
- width: 100%;
130
- max-height: 200px;
131
- resize: none;
132
- }
133
- }
134
-
135
- & .error {
136
- position: absolute;
137
- margin-top: 6px;
138
- font-size: 13px;
139
- font-weight: 300;
140
- line-height: 18px;
141
- color: var(--theme-color-error);
142
- word-break: keep-all;
143
- }
144
-
145
- & .controls {
146
- margin: 0 -30px;
147
- margin-top: auto;
148
- }
149
-
150
- .create-version-controls {
151
- margin: 0;
152
- }
153
- }
154
- }
155
- </style>
@@ -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>