summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/releases/stores/modules/edit_new/getters.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/releases/stores/modules/edit_new/getters.js')
-rw-r--r--app/assets/javascripts/releases/stores/modules/edit_new/getters.js105
1 files changed, 105 insertions, 0 deletions
diff --git a/app/assets/javascripts/releases/stores/modules/edit_new/getters.js b/app/assets/javascripts/releases/stores/modules/edit_new/getters.js
new file mode 100644
index 00000000000..831037c8861
--- /dev/null
+++ b/app/assets/javascripts/releases/stores/modules/edit_new/getters.js
@@ -0,0 +1,105 @@
+import { isEmpty } from 'lodash';
+import { hasContent } from '~/lib/utils/text_utility';
+
+/**
+ * @returns {Boolean} `true` if the app is editing an existing release.
+ * `false` if the app is creating a new release.
+ */
+export const isExistingRelease = (state) => {
+ return Boolean(state.tagName);
+};
+
+/**
+ * @param {Object} link The link to test
+ * @returns {Boolean} `true` if the release link is empty, i.e. it has
+ * empty (or whitespace-only) values for both `url` and `name`.
+ * Otherwise, `false`.
+ */
+const isEmptyReleaseLink = (link) => !hasContent(link.url) && !hasContent(link.name);
+
+/** Returns all release links that aren't empty */
+export const releaseLinksToCreate = (state) => {
+ if (!state.release) {
+ return [];
+ }
+
+ return state.release.assets.links.filter((l) => !isEmptyReleaseLink(l));
+};
+
+/** Returns all release links that should be deleted */
+export const releaseLinksToDelete = (state) => {
+ if (!state.originalRelease) {
+ return [];
+ }
+
+ return state.originalRelease.assets.links;
+};
+
+/** Returns all validation errors on the release object */
+export const validationErrors = (state) => {
+ const errors = {
+ assets: {
+ links: {},
+ },
+ };
+
+ if (!state.release) {
+ return errors;
+ }
+
+ if (!state.release.tagName?.trim?.().length) {
+ errors.isTagNameEmpty = true;
+ }
+
+ // Each key of this object is a URL, and the value is an
+ // array of Release link objects that share this URL.
+ // This is used for detecting duplicate URLs.
+ const urlToLinksMap = new Map();
+
+ state.release.assets.links.forEach((link) => {
+ errors.assets.links[link.id] = {};
+
+ // Only validate non-empty URLs
+ if (isEmptyReleaseLink(link)) {
+ return;
+ }
+
+ if (!hasContent(link.url)) {
+ errors.assets.links[link.id].isUrlEmpty = true;
+ }
+
+ if (!hasContent(link.name)) {
+ errors.assets.links[link.id].isNameEmpty = true;
+ }
+
+ const normalizedUrl = link.url.trim().toLowerCase();
+
+ // Compare each URL to every other URL and flag any duplicates
+ if (urlToLinksMap.has(normalizedUrl)) {
+ // a duplicate URL was found!
+
+ // add a validation error for each link that shares this URL
+ const duplicates = urlToLinksMap.get(normalizedUrl);
+ duplicates.push(link);
+ duplicates.forEach((duplicateLink) => {
+ errors.assets.links[duplicateLink.id].isDuplicate = true;
+ });
+ } else {
+ // no duplicate URL was found
+
+ urlToLinksMap.set(normalizedUrl, [link]);
+ }
+
+ if (!/^(http|https|ftp):\/\//.test(normalizedUrl)) {
+ errors.assets.links[link.id].isBadFormat = true;
+ }
+ });
+
+ return errors;
+};
+
+/** Returns whether or not the release object is valid */
+export const isValid = (_state, getters) => {
+ const errors = getters.validationErrors;
+ return Object.values(errors.assets.links).every(isEmpty) && !errors.isTagNameEmpty;
+};