diff --git a/frontend/src/components/Dropdown.vue b/frontend/src/components/Dropdown.vue
index 4e9b2b7..3a3261d 100644
--- a/frontend/src/components/Dropdown.vue
+++ b/frontend/src/components/Dropdown.vue
@@ -156,12 +156,12 @@ td {
transform: scale(1);
}
-tbody tr:hover {
+.table-holder tbody tr:hover {
background: var(--gray-400);
cursor: pointer;
}
-tbody tr:active {
+.table-holder tbody tr:active {
background: var(--gray-500);
}
diff --git a/frontend/src/components/packages/PackagesList.vue b/frontend/src/components/packages/PackagesList.vue
index 00c73f8..7fb073a 100644
--- a/frontend/src/components/packages/PackagesList.vue
+++ b/frontend/src/components/packages/PackagesList.vue
@@ -138,19 +138,67 @@ Component wraps functionality for displaying and working with rdfm packages.
{{ pckg.driver }}
-
-
-
+ |
+
|
@@ -171,12 +219,93 @@ Component wraps functionality for displaying and working with rdfm packages.
}
}
-.entry.buttons {
+/* Default state */
+.drdn-wrapper {
+ user-select: none;
+ position: relative;
+ display: inline-block;
+
+ .caret-up,
+ .caret-down {
+ display: inline-block;
+ }
+
+ .caret-up {
+ display: none;
+ }
+
+ .drdn {
+ display: none;
+
+ color: var(--gray-1000);
+ background-color: var(--gray-100);
+ border: 2px solid var(--gray-400);
+ border-radius: 5px;
+
+ position: absolute;
+ top: 100%;
+ right: 5px;
+ width: max-content;
+ z-index: 100;
+
+ padding: 0px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+
+ .action-button {
+ margin: 0px !important;
+ width: 100%;
+ border: 0px;
+ display: flex;
+ align-items: center;
+ text-align: left;
+ color: var(--gray-900);
+
+ &:hover {
+ color: var(--gray-1000);
+
+ svg {
+ fill: var(--gray-1000);
+ }
+ }
+
+ svg {
+ margin-right: 10px;
+ fill: var(--gray-900);
+ }
+ }
+ }
+
+ #main-button {
+ cursor: pointer;
+ }
+}
+
+/* Focused state */
+.drdn-wrapper:focus-within {
+ .caret-up {
+ display: inline-block;
+ }
+
+ .caret-down {
+ display: none;
+ }
+
+ #main-button {
+ pointer-events: none;
+ cursor: pointer;
+ color: var(--gray-900);
+ }
+
+ .drdn {
+ display: block;
+ }
+}
+
+.buttons {
button {
- float: right;
- width: 105px;
- text-align: center !important;
- margin-left: 10px !important;
+ margin: 5px !important;
+ width: 130px;
}
}
@@ -195,6 +324,8 @@ import {
downloadPackageRequest,
type NewPackageData,
} from './packages';
+import CaretDown from '@/images/CaretDown.vue';
+import CaretUp from '@/images/CaretUp.vue';
export enum PackagePopupOpen {
AddPackage,
@@ -207,6 +338,8 @@ export default {
BlurPanel,
RemovePopup,
TitleBar,
+ CaretDown,
+ CaretUp,
},
setup() {
let intervalID: undefined | number = undefined;
@@ -302,15 +435,25 @@ export default {
// Download package functionality
// =======================
- const downloadPackage = async (packageId: number) => {
+ const getPackageDownloadUrl = async (packageId: number) => {
const { success, message } = await downloadPackageRequest(packageId);
- if (!success) {
+ if (!success || !message) {
notifications.notifyError({
headline: 'Error when downloading the package:',
msg: message || 'Could not get the download link',
});
+ throw new Error('Error when downloading the package');
}
- window.open(message!);
+ return message;
+ };
+
+ const download = (packageId: number) =>
+ getPackageDownloadUrl(packageId).then((url) => window.open(url));
+
+ const copyDownloadLink = async (packageId: number) => {
+ const downloadUrl = await getPackageDownloadUrl(packageId);
+ navigator.clipboard.writeText(downloadUrl);
+ notifications.notifySuccess({ headline: 'Download link copied!' });
};
// =======================
@@ -349,7 +492,8 @@ export default {
closeAddPackagePopup,
closeRemovePackagePopup,
openAddPackagePopup,
- downloadPackage,
+ copyDownloadLink,
+ download,
};
},
};
diff --git a/frontend/src/images/CaretDown.vue b/frontend/src/images/CaretDown.vue
index 578310d..6871ff5 100644
--- a/frontend/src/images/CaretDown.vue
+++ b/frontend/src/images/CaretDown.vue
@@ -1,5 +1,5 @@
-