hotfix: enhance radio button and file upload components

- Improved the styling and functionality of the radio button component, including a new radio button style.
- Added a loading spinner to the file upload component to indicate when large files are being processed.
- Added the ability to sort files in the file upload component.
- Fixed an issue where the radio button component was not correctly updating the model value.
- Updated the dataset creation and edit forms to use the new radio button component.
- Added a global declaration for the `sort_order` property on the `File` interface.
- Updated the API to filter authors by first and last name.
- Removed the import of `_checkbox-radio-switch.css` as the radio button styling is now handled within the component.
This commit is contained in:
Kaimbacher 2025-03-27 16:04:23 +01:00
parent b93e46207f
commit 9823364670
11 changed files with 272 additions and 181 deletions

View file

@ -27,7 +27,10 @@ export default class AuthorsController {
if (request.input('filter')) {
// users = users.whereRaw('name like %?%', [request.input('search')])
const searchTerm = request.input('filter');
authors.whereILike('first_name', `%${searchTerm}%`).orWhereILike('last_name', `%${searchTerm}%`);
authors.andWhere((query) => {
query.whereILike('first_name', `%${searchTerm}%`)
.orWhereILike('last_name', `%${searchTerm}%`);
});
// .orWhere('email', 'like', `%${searchTerm}%`);
}

View file

@ -524,6 +524,8 @@ export default class DatasetController {
// Attach the extracted extension to the file object for later use
part.file.extname = ext;
// part.file.sortOrder = part.file.sortOrder;
const tmpPath = this.getTmpPath(multipartConfig);
(part.file as any).tmpPath = tmpPath;
@ -699,7 +701,7 @@ export default class DatasetController {
newFile.fileSize = file.size;
newFile.mimeType = mimeType;
newFile.label = file.clientName;
newFile.sortOrder = index;
newFile.sortOrder = index + 1;
newFile.visibleInFrontdoor = true;
newFile.visibleInOai = true;
// let path = coverImage.filePath;

6
index.d.ts vendored
View file

@ -183,3 +183,9 @@ declare module 'saxon-js' {
export function transform(options: ITransformOptions): Promise<ITransformOutput> | ITransformOutput;
}
declare global {
interface File {
sort_order?: number;
}
}

220
package-lock.json generated
View file

@ -484,9 +484,9 @@
}
},
"node_modules/@adonisjs/http-server": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/@adonisjs/http-server/-/http-server-7.5.0.tgz",
"integrity": "sha512-krO0c1doG20sKUWOtreHbT9mDSmNah4aIG+xp3fRKwpoCxDRao1wQCN4qtpsUJVVJH/qzx4p1cC6kQiJsJrCfg==",
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/@adonisjs/http-server/-/http-server-7.6.0.tgz",
"integrity": "sha512-ZrQxdIyTJ4gTtUNXp6S956R1tLS5BT2HNP7SAiQSeVmn6J5CL0fBZ2+hx7L0yrF34MUUgZvykIEeLsm3rusXGQ==",
"license": "MIT",
"dependencies": {
"@paralleldrive/cuid2": "^2.2.2",
@ -729,9 +729,9 @@
}
},
"node_modules/@adonisjs/shield": {
"version": "8.1.2",
"resolved": "https://registry.npmjs.org/@adonisjs/shield/-/shield-8.1.2.tgz",
"integrity": "sha512-ksC3KMTnGVYyjos/PM7WMQ/mUNhDuxvpFqNd2YAgPEWYVc+kr3WTTkaRrC7srl6jFmbOOv4R4aQ9RIvo1S0pjg==",
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/@adonisjs/shield/-/shield-8.2.0.tgz",
"integrity": "sha512-RddRbs92y87GGFUgDSWD/Pg7qYHh8+MctUphFZwtbTblvDckrjZxuYyp+vmVATPuvDvK7sOlatuZHT4HQSz9zQ==",
"license": "MIT",
"dependencies": {
"@poppinss/utils": "^6.9.2",
@ -921,14 +921,14 @@
}
},
"node_modules/@babel/generator": {
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz",
"integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz",
"integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.26.10",
"@babel/types": "^7.26.10",
"@babel/parser": "^7.27.0",
"@babel/types": "^7.27.0",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^3.0.2"
@ -951,14 +951,14 @@
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.26.5",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz",
"integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz",
"integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/compat-data": "^7.26.5",
"@babel/compat-data": "^7.26.8",
"@babel/helper-validator-option": "^7.25.9",
"browserslist": "^4.24.0",
"lru-cache": "^5.1.1",
@ -969,9 +969,9 @@
}
},
"node_modules/@babel/helper-create-class-features-plugin": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz",
"integrity": "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.0.tgz",
"integrity": "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -980,7 +980,7 @@
"@babel/helper-optimise-call-expression": "^7.25.9",
"@babel/helper-replace-supers": "^7.26.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
"@babel/traverse": "^7.26.9",
"@babel/traverse": "^7.27.0",
"semver": "^6.3.1"
},
"engines": {
@ -1120,27 +1120,27 @@
}
},
"node_modules/@babel/helpers": {
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz",
"integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz",
"integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/template": "^7.26.9",
"@babel/types": "^7.26.10"
"@babel/template": "^7.27.0",
"@babel/types": "^7.27.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz",
"integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz",
"integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==",
"license": "MIT",
"dependencies": {
"@babel/types": "^7.26.10"
"@babel/types": "^7.27.0"
},
"bin": {
"parser": "bin/babel-parser.js"
@ -1199,14 +1199,14 @@
}
},
"node_modules/@babel/plugin-transform-typescript": {
"version": "7.26.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz",
"integrity": "sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.0.tgz",
"integrity": "sha512-fRGGjO2UEGPjvEcyAZXRXAS8AfdaQoq7HnxAbJoAoW10B9xOKesmmndJv+Sym2a+9FHWZ9KbyyLCe9s0Sn5jtg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.25.9",
"@babel/helper-create-class-features-plugin": "^7.25.9",
"@babel/helper-create-class-features-plugin": "^7.27.0",
"@babel/helper-plugin-utils": "^7.26.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
"@babel/plugin-syntax-typescript": "^7.25.9"
@ -1219,17 +1219,17 @@
}
},
"node_modules/@babel/preset-typescript": {
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz",
"integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.0.tgz",
"integrity": "sha512-vxaPFfJtHhgeOVXRKuHpHPAOgymmy8V8I65T1q53R7GCZlefKeCaTyDs3zOPHTTbmquvNlQYC5klEvWsBAtrBQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.25.9",
"@babel/helper-plugin-utils": "^7.26.5",
"@babel/helper-validator-option": "^7.25.9",
"@babel/plugin-syntax-jsx": "^7.25.9",
"@babel/plugin-transform-modules-commonjs": "^7.25.9",
"@babel/plugin-transform-typescript": "^7.25.9"
"@babel/plugin-transform-modules-commonjs": "^7.26.3",
"@babel/plugin-transform-typescript": "^7.27.0"
},
"engines": {
"node": ">=6.9.0"
@ -1239,32 +1239,32 @@
}
},
"node_modules/@babel/template": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
"integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz",
"integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.26.9",
"@babel/types": "^7.26.9"
"@babel/parser": "^7.27.0",
"@babel/types": "^7.27.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz",
"integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz",
"integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.26.2",
"@babel/generator": "^7.26.10",
"@babel/parser": "^7.26.10",
"@babel/template": "^7.26.9",
"@babel/types": "^7.26.10",
"@babel/generator": "^7.27.0",
"@babel/parser": "^7.27.0",
"@babel/template": "^7.27.0",
"@babel/types": "^7.27.0",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@ -1273,9 +1273,9 @@
}
},
"node_modules/@babel/types": {
"version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz",
"integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==",
"version": "7.27.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
"integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==",
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.25.9",
@ -3173,9 +3173,9 @@
}
},
"node_modules/@tanstack/virtual-core": {
"version": "3.13.4",
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.4.tgz",
"integrity": "sha512-fNGO9fjjSLns87tlcto106enQQLycCKR4DPNpgq3djP5IdcPFdPAmaKjsgzIeRhH7hWrELgW12hYnRthS5kLUw==",
"version": "3.13.5",
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.5.tgz",
"integrity": "sha512-gMLNylxhJdUlfRR1G3U9rtuwUh2IjdrrniJIDcekVJN3/3i+bluvdMi3+eodnxzJq5nKnxnigo9h0lIpaqV6HQ==",
"dev": true,
"license": "MIT",
"funding": {
@ -3184,13 +3184,13 @@
}
},
"node_modules/@tanstack/vue-virtual": {
"version": "3.13.4",
"resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.13.4.tgz",
"integrity": "sha512-1fPrd3hE1SS4R/9JbX1AlzueY4duCK7ixuLcMW5GMnk9N6WbLo9MioNKiv22V+UaXKOLNy8tLdzT8NYerOFTOQ==",
"version": "3.13.5",
"resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.13.5.tgz",
"integrity": "sha512-1hhUA6CUjmKc5JDyKLcYOV6mI631FaKKxXh77Ja4UtIy6EOofYaLPk8vVgvK6vLMUSfHR2vI3ZpPY9ibyX60SA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@tanstack/virtual-core": "3.13.4"
"@tanstack/virtual-core": "3.13.5"
},
"funding": {
"type": "github",
@ -3348,9 +3348,9 @@
"license": "MIT"
},
"node_modules/@types/chai": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.0.tgz",
"integrity": "sha512-FWnQYdrG9FAC8KgPVhDFfrPL1FBsL3NtIt2WsxKvwu/61K6HiuDF3xAb7c7w/k9ML2QOUHcwTgU7dKLFPK6sBg==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.1.tgz",
"integrity": "sha512-iu1JLYmGmITRzUgNiLMZD3WCoFzpYtueuyAgHTXqgwSRAMIlFTnZqG6/xenkpUGRJEzSfklUTI4GNSzks/dc0w==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3459,19 +3459,6 @@
}
},
"node_modules/@types/express-serve-static-core": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz",
"integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*",
"@types/send": "*"
}
},
"node_modules/@types/express/node_modules/@types/express-serve-static-core": {
"version": "4.19.6",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz",
"integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==",
@ -3580,9 +3567,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "22.13.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.12.tgz",
"integrity": "sha512-ixiWrCSRi33uqBMRuICcKECW7rtgY43TbsHDpM2XK7lXispd48opW+0IXrBVxv9NMhaz/Ue9kyj6r3NTVyXm8A==",
"version": "22.13.14",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.14.tgz",
"integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
@ -3670,9 +3657,9 @@
"license": "MIT"
},
"node_modules/@types/semver": {
"version": "7.5.8",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz",
"integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==",
"dev": true,
"license": "MIT"
},
@ -3750,9 +3737,9 @@
}
},
"node_modules/@types/supertest": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.2.tgz",
"integrity": "sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==",
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz",
"integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3761,9 +3748,9 @@
}
},
"node_modules/@types/validator": {
"version": "13.12.2",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz",
"integrity": "sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==",
"version": "13.12.3",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.3.tgz",
"integrity": "sha512-2ipwZ2NydGQJImne+FhNdhgRM37e9lCev99KnqkbFHd94Xn/mErARWI1RSLem1QA19ch5kOhzIZd7e8CA2FI8g==",
"license": "MIT"
},
"node_modules/@types/ws": {
@ -4088,9 +4075,9 @@
}
},
"node_modules/@vavite/multibuild/node_modules/@types/node": {
"version": "18.19.82",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.82.tgz",
"integrity": "sha512-s6RBC3H0JGG5Xm2IOP2R0KKNZL2s46UGZZ1r21EF3+qL377EwJ+Bnf9PMatFnYtmYMNnzVLodD6EN7FZw0Vbxg==",
"version": "18.19.84",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.84.tgz",
"integrity": "sha512-ACYy2HGcZPHxEeWTqowTF7dhXN+JU1o7Gr4b41klnn6pj2LD6rsiGqSZojMdk1Jh2ys3m76ap+ae1vvE4+5+vg==",
"license": "MIT",
"dependencies": {
"undici-types": "~5.26.4"
@ -6367,9 +6354,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.123",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.123.tgz",
"integrity": "sha512-refir3NlutEZqlKaBLK0tzlVLe5P2wDKS7UQt/3SpibizgsRAPOsqQC3ffw1nlv3ze5gjRQZYHoPymgVZkplFA==",
"version": "1.5.126",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.126.tgz",
"integrity": "sha512-AtH1uLcTC72LA4vfYcEJJkrMk/MY/X0ub8Hv7QGAePW2JkeUFHEL/QfS4J77R6M87Sss8O0OcqReSaN1bpyA+Q==",
"dev": true,
"license": "ISC"
},
@ -6709,9 +6696,9 @@
}
},
"node_modules/eslint-plugin-prettier": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.4.tgz",
"integrity": "sha512-SFtuYmnhwYCtuCDTKPoK+CEzCnEgKTU2qTLwoCxvrC0MFBTIXo1i6hDYOI4cwHaE5GZtlWmTN3YfucYi7KJwPw==",
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.5.tgz",
"integrity": "sha512-IKKP8R87pJyMl7WWamLgPkloB16dagPIdd2FjBDbyRYPKo93wS/NbCOPh6gH+ieNLC+XZrhJt/kWj0PS/DFdmg==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -6727,7 +6714,7 @@
"peerDependencies": {
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
"eslint-config-prettier": "*",
"eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
@ -9301,9 +9288,9 @@
}
},
"node_modules/luxon": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz",
"integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==",
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.6.0.tgz",
"integrity": "sha512-WE7p0p7W1xji9qxkLYsvcIxZyfP48GuFrWIBQZIsbjCyf65dG1rv4n83HcOyEyhvzxJCrUoObCRNFgRNIQ5KNA==",
"license": "MIT",
"engines": {
"node": ">=12"
@ -12620,9 +12607,9 @@
}
},
"node_modules/synckit": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.10.2.tgz",
"integrity": "sha512-cSGiaCPhFzeFIQY8KKEacv46LclENY4d60jgkwCrKomvRkIjtMyss1dPkHLp/62c1leuOjEedB1+lWcwqTJSvA==",
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.10.3.tgz",
"integrity": "sha512-R1urvuyiTaWfeCggqEvpDJwAlDVdsT9NM+IP//Tk2x7qHCkSvBk/fwFgw/TLAHzZlrAnnazMcRw0ZD8HlYFTEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -13216,9 +13203,9 @@
}
},
"node_modules/type-fest": {
"version": "4.37.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.37.0.tgz",
"integrity": "sha512-S/5/0kFftkq27FPNye0XM1e2NsnoD/3FS+pBmbjmmtLT6I+i344KoOf7pvXreaFsDamWeaJX55nczA1m5PsBDg==",
"version": "4.38.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.38.0.tgz",
"integrity": "sha512-2dBz5D5ycHIoliLYLi0Q2V7KRaDlH0uWIvmk7TYlAg5slqwiPv1ezJdZm1QEM0xgk29oYWMCbIG7E6gHpvChlg==",
"license": "(MIT OR CC0-1.0)",
"engines": {
"node": ">=16"
@ -13416,9 +13403,9 @@
}
},
"node_modules/validator": {
"version": "13.12.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
"integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
"version": "13.15.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.15.0.tgz",
"integrity": "sha512-36B2ryl4+oL5QxZ3AzD0t5SsMNGvTtQHpjgFO5tbNxfXbMFkY822ktCDe1MnlqV3301QQI9SLHDNJokDI+Z9pA==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
@ -13434,9 +13421,9 @@
}
},
"node_modules/vite": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz",
"integrity": "sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==",
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.3.tgz",
"integrity": "sha512-IzwM54g4y9JA/xAeBPNaDXiBF8Jsgl3VBQ2YQ/wOY6fyW3xMdSoltIV3Bo59DErdqdE6RxUfv8W69DvUorE4Eg==",
"license": "MIT",
"dependencies": {
"esbuild": "^0.25.0",
@ -13721,15 +13708,16 @@
}
},
"node_modules/webpack-dev-server": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.0.tgz",
"integrity": "sha512-90SqqYXA2SK36KcT6o1bvwvZfJFcmoamqeJY7+boioffX9g9C0wjjJRGUrQIuh43pb0ttX7+ssavmj/WN2RHtA==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.1.tgz",
"integrity": "sha512-ml/0HIj9NLpVKOMq+SuBPLHcmbG+TGIjXRHsYfZwocUBIqEvws8NnS/V9AFQ5FKP+tgn5adwVwRrTEpGL33QFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/bonjour": "^3.5.13",
"@types/connect-history-api-fallback": "^1.5.4",
"@types/express": "^4.17.21",
"@types/express-serve-static-core": "^4.17.21",
"@types/serve-index": "^1.9.4",
"@types/serve-static": "^1.15.5",
"@types/sockjs": "^0.3.36",

View file

@ -1,7 +1,7 @@
/* @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap'); */
/* @import url('https://fonts.googleapis.com/css?family=Roboto:400,400i,600,700'); */
@import '_checkbox-radio-switch.css';
/* @import '_checkbox-radio-switch.css'; */
@import '_progress.css';
@import '_scrollbars.css';
@import '_table.css';

View file

@ -17,6 +17,15 @@
<p class="text-lg text-blue-700">Drop files to upload</p>
</div>
<!-- Loading Spinner when processing big files -->
<div v-if="isLoading" class="absolute inset-0 z-60 flex items-center justify-center bg-gray-500 bg-opacity-50">
<svg class="animate-spin h-12 w-12 text-white" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M12 2a10 10 0 0110 10h-4a6 6 0 00-6-6V2z"></path>
</svg>
</div>
<!-- scroll area -->
<div class="h-full p-8 w-full h-full flex flex-col">
<header class="flex items-center justify-center w-full">
@ -32,9 +41,8 @@
<p class="mb-2 text-sm text-gray-500 dark:text-gray-400">
<span class="font-semibold">Click to upload</span> or drag and drop
</p>
<!-- <p class="text-xs text-gray-500 dark:text-gray-400">SVG, PNG, JPG or GIF (MAX. 800x400px)</p> -->
</div>
<input id="dropzone-file" type="file" class="hidden" @change="onChangeFile" multiple="true" />
<input id="dropzone-file" type="file" class="hidden" @click="showSpinner" @change="onChangeFile" @cancel="cancelSpinner" multiple="true" />
</label>
</header>
@ -241,6 +249,8 @@ class FileUploadComponent extends Vue {
@Ref('overlay') overlay: HTMLDivElement;
public isLoading: boolean = false;
private counter: number = 0;
// @Prop() files: Array<TestFile>;
@ -342,10 +352,10 @@ class FileUploadComponent extends Vue {
}
// reset counter and append file to gallery when file is dropped
public dropHandler(event: DragEvent): void {
event.preventDefault();
const dataTransfer = event.dataTransfer;
// let bigFileFound = false;
if (dataTransfer) {
for (const file of event.dataTransfer?.files) {
// let fileName = String(file.name.replace(/\.[^/.]+$/, ''));
@ -353,28 +363,73 @@ class FileUploadComponent extends Vue {
// if (file.type.match('image.*')) {
// this.generateURL(file);
// }
// if (file.size > 62914560) { // 60 MB in bytes
// bigFileFound = true;
// }
this._addFile(file);
}
this.overlay.classList.remove('draggedover');
this.counter = 0;
}
// if (bigFileFound) {
// this.isLoading = true;
// // Assume file processing delay; adjust timeout as needed or rely on async processing completion.
// setTimeout(() => {
// this.isLoading = false;
// }, 1500);
// }
}
public showSpinner() {
// event.preventDefault();
this.isLoading = true;
}
public cancelSpinner() {
// const target = event.target as HTMLInputElement;
// // If no files were selected, remove spinner
// if (!target.files || target.files.length === 0) {
// this.isLoading = false;
// }
this.isLoading = false;
}
public onChangeFile(event: Event) {
event.preventDefault();
let target = event.target as HTMLInputElement;
// let uploadedFile = event.target.files[0];
// let fileName = String(event.target.files[0].name.replace(/\.[^/.]+$/, ''));
for (const file of event.target.files) {
// let fileName = String(event.target.files[0].name.replace(/\.[^/.]+$/, ''));
// file.label = fileName;
// if (file.type.match('image.*')) {
// this.generateURL(file);
// }
this._addFile(file);
if (target && target.files) {
for (const file of event.target.files) {
// let fileName = String(event.target.files[0].name.replace(/\.[^/.]+$/, ''));
// file.label = fileName;
// if (file.type.match('image.*')) {
// this.generateURL(file);
// }
// Immediately set spinner if any file is large (over 100 MB)
// for (const file of target.files) {
// if (file.size > 62914560) { // 100 MB
// bigFileFound = true;
// break;
// }
// }
// if (bigFileFound) {
// this.isLoading = true;
// }
this._addFile(file);
}
}
// if (bigFileFound) {
// this.isLoading = true;
// setTimeout(() => {
// this.isLoading = false;
// }, 1500);
// }
// this.overlay.classList.remove('draggedover');
this.counter = 0;
this.isLoading = false;
}
get errors(): IDictionary {
@ -465,17 +520,6 @@ class FileUploadComponent extends Vue {
return localUrl;
}
// private async downloadFile(id: number): Promise<string> {
// const response = await axios.get<Blob>(`/api/download/${id}`, {
// responseType: 'blob',
// });
// const url = URL.createObjectURL(response.data);
// setTimeout(() => {
// URL.revokeObjectURL(url);
// }, 1000);
// return url;
// }
public getFileSize(file: File) {
if (file.size > 1024) {
if (file.size > 1048576) {
@ -488,17 +532,6 @@ class FileUploadComponent extends Vue {
}
}
// private _addFile(file) {
// // const isImage = file.type.match('image.*');
// // const objectURL = URL.createObjectURL(file);
// // this.files[objectURL] = file;
// // let test: TethysFile = { upload: file, label: "dfdsfs", sorting: 0 };
// // file.sorting = this.files.length;
// file.sort_order = (this.items.length + 1),
// this.files.push(file);
// }
private _addFile(file: File) {
// const reader = new FileReader();
// reader.onload = (event) => {
@ -530,14 +563,11 @@ class FileUploadComponent extends Vue {
// this.items.push(test);
this.items[this.items.length] = test;
} else {
file.sort_order = this.items.length + 1;
this.items.push(file);
}
}
// use to check if a file is being dragged
// private _hasFiles({ types = [] as Array<string> }) {
// return types.indexOf('Files') > -1;
// }
private _hasFiles(dataTransfer: DataTransfer | null): boolean {
return dataTransfer ? dataTransfer.items.length > 0 : false;
}

View file

@ -1,6 +1,15 @@
<script setup>
<script setup lang="ts">
import { computed } from 'vue';
interface Props {
name: string;
type?: 'checkbox' | 'radio' | 'switch';
label?: string | null;
modelValue: Array<any> | string | number | boolean | null;
inputValue: string | number | boolean;
}
const props = defineProps({
name: {
type: String,
@ -9,7 +18,7 @@ const props = defineProps({
type: {
type: String,
default: 'checkbox',
validator: (value) => ['checkbox', 'radio', 'switch'].includes(value),
validator: (value: string) => ['checkbox', 'radio', 'switch'].includes(value),
},
label: {
type: String,
@ -23,19 +32,65 @@ const props = defineProps({
type: [String, Number, Boolean],
required: true,
},
});
const emit = defineEmits(['update:modelValue']);
});// const props = defineProps<Props>();
// const emit = defineEmits(['update:modelValue']);
const emit = defineEmits<{ (e: 'update:modelValue', value: Props['modelValue']): void }>();
const computedValue = computed({
get: () => props.modelValue,
set: (value) => {
emit('update:modelValue', value);
// If type is radio, wrap the new value inside an array.
if (props.type === 'radio') {
emit('update:modelValue', [value]);
} else {
emit('update:modelValue', value);
}
},
});
const inputType = computed(() => (props.type === 'radio' ? 'radio' : 'checkbox'));
// Define isChecked for radio inputs: it's true when the current modelValue equals the inputValue
const isChecked = computed(() => {
if (props.type === 'radio') {
return Array.isArray(computedValue.value) &&
computedValue.value.length > 0 &&
computedValue.value[0] === props.inputValue;
}
return computedValue.value === props.inputValue;
});
</script>
<!-- <template>
<label v-if="type == 'radio'" :class="[type, 'mr-6 mb-3 last:mr-0 inline-flex items-center cursor-pointer relative']">
<input v-model="computedValue" :type="inputType" :name="name" :value="inputValue" class="absolute left-0 opacity-0 -z-1 focus:outline-none focus:ring-0" />
<span
class="check border-gray-700 border transition-colors duration-200 dark:bg-slate-800 block w-5 h-5 rounded-full"
:class="{ 'bg-no-repeat bg-center bg-blue-600 border-blue-600 border-4': isChecked }"/>
<span class="pl-2">{{ label }}</span>
</label>
<label v-else :class="[type, 'mr-6 mb-3 last:mr-0']">
<input v-model="computedValue" :type="inputType" :name="name" :value="inputValue" />
<span class="check" />
<span class="pl-2">{{ label }}</span>
</label>
</template> -->
<template>
<label :class="type" class="mr-6 mb-3 last:mr-0">
<label v-if="type === 'radio'" :class="[type]"
class="mr-6 mb-3 last:mr-0 inline-flex items-center cursor-pointer relative">
<input v-model="computedValue" :type="inputType" :name="name" :value="inputValue"
class="absolute left-0 opacity-0 -z-1 focus:outline-none focus:ring-0"
:checked="isChecked" />
<span class="check border transition-colors duration-200 dark:bg-slate-800 block w-5 h-5 rounded-full" :class="{
'border-gray-700': !isChecked,
'bg-radio-checked bg-no-repeat bg-center bg-blue-600 border-blue-600 border-4': isChecked
}" />
<span class="pl-2">{{ label }}</span>
</label>
<label v-else class="mr-6 mb-3 last:mr-0" :class="[type]">
<input v-model="computedValue" :type="inputType" :name="name" :value="inputValue" />
<span class="check" />
<span class="pl-2">{{ label }}</span>

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import { computed, ref, PropType } from 'vue';
import FormCheckRadio from '@/Components/FormCheckRadio.vue';
import BaseButton from '@/Components/BaseButton.vue';
import FormControl from '@/Components/FormControl.vue';
import { mdiPlusCircle } from '@mdi/js';
// import BaseButton from '@/Components/BaseButton.vue';
// import FormControl from '@/Components/FormControl.vue';
const props = defineProps({
options: {
type: Object,
@ -23,7 +23,7 @@ const props = defineProps({
required: true,
},
type: {
type: String,
type: String as PropType<'checkbox' | 'radio' | 'switch'>,
default: 'checkbox',
validator: (value: string) => ['checkbox', 'radio', 'switch'].includes(value),
},
@ -78,11 +78,11 @@ const addOption = () => {
const inputElClass = computed(() => {
const base = [
'px-3 py-2 max-w-full focus:ring focus:outline-none border-gray-700 rounded w-full',
'px-3 py-2 max-w-full border-gray-700 rounded w-full',
'dark:placeholder-gray-400',
'h-12',
'border',
'bg-transparent'
'bg-transparent'
// props.isReadOnly ? 'bg-gray-50 dark:bg-slate-600' : 'bg-white dark:bg-slate-800',
];
// if (props.icon) {
@ -108,7 +108,7 @@ const inputElClass = computed(() => {
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-6H5v-2h6V5h2v6h6v2h-6v6z" />
</svg>
</div>
<FormCheckRadio v-for="(value, key) in options" :key="key" v-model="computedValue" :type="type" :name="name"
:input-value="key" :label="value" :class="componentClass" />
<FormCheckRadio v-for="(value, key) in options" :key="key" v-model="computedValue" :type="type"
:name="name" :input-value="key" :label="value" :class="componentClass" />
</div>
</template>

View file

@ -320,12 +320,17 @@ const nextStep = async () => {
} else if (formStep.value == 3) {
route = stardust.route('dataset.third.step');
}
// formStep.value++;
// When posting in steps 1-3, remove any file uploads from the data.
await form
.transform((data) => ({
...data,
rights: form.rights && form.rights == true ? 'true' : 'false',
}))
.transform((data: Dataset) => {
// Create payload and set rights (transforming to a string if needed)
const payload: any = { ...data, rights: data.rights ? 'true' : 'false' };
// Remove the files property so that the partial update is done without files
if (payload.files) {
delete payload.files;
}
return payload;
})
.post(route, {
onSuccess: () => {
// console.log(form.data());
@ -334,7 +339,6 @@ const nextStep = async () => {
},
});
};
const prevStep = () => {
formStep.value--;
};
@ -343,7 +347,7 @@ const submit = async () => {
let route = stardust.route('dataset.submit');
const files = form.files.map((obj) => {
return new File([obj.blob], obj.label, { type: obj.type, lastModified: obj.lastModified });
return new File([obj.blob], obj.label, { type: obj.type, lastModified: obj.lastModified, sort_order: obj.sort_order });
});
// formStep.value++;
@ -576,7 +580,7 @@ Removes a selected keyword
<FormField label="Licenses" wrap-body :class="{ 'text-red-400': form.errors.licenses }"
class="mt-8 w-full mx-2 flex-1">
<FormCheckRadioGroup v-model="form.licenses" name="roles" is-column
<FormCheckRadioGroup type="radio" v-model="form.licenses" name="licenses" is-column
:options="props.licenses" />
</FormField>

View file

@ -42,7 +42,7 @@
<!-- (2) licenses -->
<FormField label="Licenses" wrap-body :class="{ 'text-red-400': form.errors.licenses }"
class="mt-8 w-full mx-2 flex-1">
<FormCheckRadioGroup v-model="form.licenses" name="licenses" is-column :options="licenses" />
<FormCheckRadioGroup type="radio" v-model="form.licenses" name="licenses" is-column :options="licenses" />
</FormField>
<div class="flex flex-col md:flex-row">

View file

@ -12,6 +12,9 @@ module.exports = {
gray: 'gray',
},
extend: {
backgroundImage: {
'radio-checked': "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z' /%3E%3C/svg%3E\")",
},
colors: {
'primary': '#22C55E',
'inprogress': 'rgb(94 234 212)',