diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0e9312c..59b2355 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,7 +7,7 @@ stages: - release variables: - PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/gitdock" + PACKAGE_REGISTRY_URL: '${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/gitdock' release-version-creation: stage: version @@ -35,7 +35,7 @@ install-dependencies-windows: cache: key: $CI_COMMIT_REF_SLUG-windows paths: - - node_modules/ + - node_modules/ install-dependencies-mac: stage: dependencies @@ -51,8 +51,7 @@ install-dependencies-mac: cache: key: $CI_COMMIT_REF_SLUG-mac paths: - - node_modules/ - + - node_modules/ install-dependencies-linux: stage: dependencies @@ -67,7 +66,7 @@ install-dependencies-linux: cache: key: $CI_COMMIT_REF_SLUG-linux paths: - - node_modules/ + - node_modules/ feature-tests: stage: test @@ -77,8 +76,8 @@ feature-tests: tags: - linux image: node:latest - needs: ["install-dependencies-linux"] - cache: + needs: ['install-dependencies-linux'] + cache: key: $CI_COMMIT_REF_SLUG-linux paths: - node_modules/ @@ -95,6 +94,23 @@ feature-tests: - export DISPLAY=:99 - npm test +prettier: + stage: test + only: + - tags + - merge_requests + tags: + - linux + image: node:latest + needs: ['install-dependencies-linux'] + cache: + key: $CI_COMMIT_REF_SLUG-linux + paths: + - node_modules/ + policy: pull + script: + - npm run prettier:check + build-windows: stage: build only: @@ -104,8 +120,8 @@ build-windows: - windows - shared-windows - windows-1809 - needs: ["install-dependencies-windows"] - cache: + needs: ['install-dependencies-windows'] + cache: key: $CI_COMMIT_REF_SLUG-windows paths: - node_modules/ @@ -127,8 +143,8 @@ build-mac: tags: - shared-macos-amd64 image: macos-11-xcode-12 - needs: ["install-dependencies-mac"] - cache: + needs: ['install-dependencies-mac'] + cache: key: $CI_COMMIT_REF_SLUG-mac paths: - node_modules/ @@ -150,8 +166,8 @@ build-linux: tags: - linux image: node:latest - needs: ["install-dependencies-linux"] - cache: + needs: ['install-dependencies-linux'] + cache: key: $CI_COMMIT_REF_SLUG-linux paths: - node_modules/ @@ -209,16 +225,16 @@ release: - echo "v$VERSION" - echo "${PACKAGE_REGISTRY_URL}/${VERSION}/GitDock.dmg"} release: - name: "v$VERSION" - tag_name: "v$VERSION" - description: "v$VERSION" - assets: - links: - - name: "MacOS" - url: "${PACKAGE_REGISTRY_URL}/${VERSION}/GitDock.dmg" - - name: "Windows" - url: "${PACKAGE_REGISTRY_URL}/${VERSION}/GitDock.exe" - - name: "Linux deb" - url: "${PACKAGE_REGISTRY_URL}/${VERSION}/GitDock.deb" - - name: "Linux rpm" - url: "${PACKAGE_REGISTRY_URL}/${VERSION}/GitDock.rpm" + name: 'v$VERSION' + tag_name: 'v$VERSION' + description: 'v$VERSION' + assets: + links: + - name: 'MacOS' + url: '${PACKAGE_REGISTRY_URL}/${VERSION}/GitDock.dmg' + - name: 'Windows' + url: '${PACKAGE_REGISTRY_URL}/${VERSION}/GitDock.exe' + - name: 'Linux deb' + url: '${PACKAGE_REGISTRY_URL}/${VERSION}/GitDock.deb' + - name: 'Linux rpm' + url: '${PACKAGE_REGISTRY_URL}/${VERSION}/GitDock.rpm' diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..1fbed0f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,13 @@ +.circleci +.github +assets +node_modules +out/ +package-lock.json +.DS_Store +Thumbs.db +/.vscode +.vscode/* +yarn.lock +builds/ +/.idea diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..ace0e29 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "printWidth": 100, + "singleQuote": true, + "arrowParens": "always", + "trailingComma": "all" +} diff --git a/README.md b/README.md index 1c7ac19..87199b6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ GitDock is a MacOS/Windows/Linux app that displays all your GitLab activities in You can either have a look at this walkthrough video I recorded, or just try it out yourself by downloading it from the [releases](https://gitlab.com/mvanremmerden/gitdock/-/releases). -[![YouTube Video](/docs/img/youtube.png)](https://www.youtube.com/watch?v=WkVS38wo4_w "GitDock ⚓️") +[![YouTube Video](/docs/img/youtube.png)](https://www.youtube.com/watch?v=WkVS38wo4_w 'GitDock ⚓️') ## Installation @@ -40,8 +40,8 @@ Depending on whether you use GitLab.com or a self-managed instance, you can eith Just click the "Login with GitLab" button, and then enter your username and password. Afterwards, you might be seeing the GitLab homepage, but should very quickly and automatically be redirected to your GitDock overview page. -| Start | Login | -| ------ | ------ | +| Start | Login | +| ---------------------------------- | ---------------------------------- | | ![Start page](/docs/img/start.png) | ![Login page](/docs/img/login.png) | @@ -52,9 +52,9 @@ To log in with an account from a self-managed instance, you first have to create Go to the Access Tokens page by first opening the user dropdown, clicking "Preferences" and then navigating to "Access tokens" in the left sidebar. -| User dropdown | Access tokens | -| ------ | ------ | -| ![Preferences](/docs/img/preferences.png) | ![Access tokens](/docs/img/access-tokens.png) | +| User dropdown | Access tokens | +| ----------------------------------------- | --------------------------------------------- | +| ![Preferences](/docs/img/preferences.png) | ![Access tokens](/docs/img/access-tokens.png) | Enter a token name, mark the `read_api` checkbox and then click "Create personal access token". On the following screen, copy the newly created access token and paste it into the GitDock application, together with the URL of your self-managed instance. @@ -66,8 +66,8 @@ Enter a token name, mark the `read_api` checkbox and then click "Create personal Whenever you start a new pipeline, a system notification shows up and the GitDock icon in the menu bar changes to a running pipeline icon. Once the pipeline completes, you will receive another notification with the final pipeline status. -| Running | Completed | -| ------ | ------ | +| Running | Completed | +| --------------------------------------------------- | ------------------------------------------------------- | | ![Running pipeline](/docs/img/running-pipeline.png) | ![Completed pipeline](/docs/img/completed-pipeline.png) | #### To-Dos @@ -78,14 +78,14 @@ Whenever a new To-Do gets created for you, the system notification will show you ### My Issues, MRs & To-Do list -At the top of the app, you will see the typical sections of issues, MRs and the To-Do list. +At the top of the app, you will see the typical sections of issues, MRs and the To-Do list. ![Top section](/docs/img/top-section.png) You might be used to this layout already from our GitLab UI. The only difference is that on the detail pages, you can more easily switch directly to the objects you care about by using the filters to e.g. see the last MRs you have approved and that have already been merged. -| Issues | MRs | To-Do list | -| ------ | ------ | ------ | +| Issues | MRs | To-Do list | +| ------------------------------- | ----------------------------------------------- | ------------------------------ | | ![Issues](/docs/img/issues.png) | ![Merge requests](/docs/img/merge-requests.png) | ![To-Dos](/docs/img/todos.png) | ### My commits @@ -124,7 +124,7 @@ A list of all your recent comments is also visible on the overview page. Due ![Comments](/docs/img/comments.png) -*The loading time for comments is significantly longer than for other objects, as each comment requires 3 API calls to collect all necessary information.* +_The loading time for comments is significantly longer than for other objects, as each comment requires 3 API calls to collect all necessary information._ ### Bookmarks @@ -138,8 +138,8 @@ If you have a specific issue or merge request you care about and know you will h To make Gitdock as accessible and usable as possible, you can switch between dark and light theme. -| Dark | Light | -| ------ | ------ | +| Dark | Light | +| --------------------------- | ----------------------------- | | ![Dark](/docs/img/dark.png) | ![Light](/docs/img/light.png) | #### Analytics diff --git a/index.html b/index.html index 4c4dfd0..938e994 100644 --- a/index.html +++ b/index.html @@ -1,162 +1,184 @@ + + + GitDock + + + + - - - GitDock - - - - - - - '; + i++; + if (i == numberOfRecentlyVisited) { + break; + } + } + } + if (!firstItem) { + let moreString = "'Recently viewed'"; + recentlyVisitedString += + '
  • View more
  • '; + } else { + recentlyVisitedString = + '

    Recently visited objects will show up here.
    Supported browsers: ${BrowserHistory.supportedBrowserNames()}.

    '; + } + mb.window.webContents.executeJavaScript( + 'document.getElementById("history").innerHTML = "' + recentlyVisitedString + '"', + ); + lastRecentlyVisitedExecution = Date.now(); + lastRecentlyVisitedExecutionFinished = true; + }); + } else { + console.log('Recently visited running or not out of delay'); + } } async function getMoreRecentlyVisited() { - recentlyVisitedString = '' - let moreRecentlyVisitedTitlesArray = [] - let firstItem = true - await BrowserHistory.getAllHistory(14320).then(async history => { - let item = Array.prototype.concat.apply([], history); - item.sort(function (a, b) { - if (a.utc_time > b.utc_time) { - return -1 - } - if (b.utc_time > a.utc_time) { - return 1 - } - }); - let i = 0 - mb.window.webContents.executeJavaScript('document.getElementById("detail-headline").innerHTML = ""') - let previousDate = 0 - for (let j = 0; j < item.length; j++) { - if (item[j].title && item[j].url.indexOf(store.host + '/') == 0 && (item[j].url.indexOf('/-/issues/') != -1 || item[j].url.indexOf('/-/merge_requests/') != -1 || item[j].url.indexOf('/-/epics/') != -1) && !moreRecentlyVisitedTitlesArray.includes(item[j].title) && item[j].title.split('·')[0] != 'Not Found' && item[j].title.split('·')[0] != 'New Issue ' && item[j].title.split('·')[0] != 'New Merge Request ' && item[j].title.split('·')[0] != 'New merge request ' && item[j].title.split('·')[0] != 'New Epic ' && item[j].title.split('·')[0] != 'Edit ' && item[j].title.split('·')[0] != 'Merge requests ' && item[j].title.split('·')[0] != 'Issues ' && item[j].title.split('·')[0] != '500 Error - GitLab') { - let nameWithNamespace = item[j].url.replace(store.host + '/', '').split('/-/')[0] - if (nameWithNamespace.split('/')[0] != 'groups') { - url = store.host + '/api/v4/projects/' + nameWithNamespace.split('/')[0] + '%2F' + nameWithNamespace.split('/')[1] + '?access_token=' + store.access_token - } else { - url = store.host + '/api/v4/groups/' + nameWithNamespace.split('/')[0] + '?access_token=' + store.access_token - } - let currentDate = new Date(item[j].utc_time).toLocaleDateString("en-US", { weekday: 'long', month: 'long', day: 'numeric', timeZone: timezone }) - if (previousDate != currentDate) { - if (currentDate == new Date(Date.now()).toLocaleDateString("en-US", { weekday: 'long', month: 'long', day: 'numeric', timeZone: timezone })) { - recentlyVisitedString += '
    Today
    ' - } else { - if (!firstItem) { - recentlyVisitedString += '' - } - recentlyVisitedString += '
    ' + currentDate + '
    ' - } - recentlyVisitedString += '' - mb.window.webContents.executeJavaScript('document.getElementById("detail-content").innerHTML = "' + recentlyVisitedString + '"') - }) + let currentDate = new Date(item[j].utc_time).toLocaleDateString('en-US', { + weekday: 'long', + month: 'long', + day: 'numeric', + timeZone: timezone, + }); + if (previousDate != currentDate) { + if ( + currentDate == + new Date(Date.now()).toLocaleDateString('en-US', { + weekday: 'long', + month: 'long', + day: 'numeric', + timeZone: timezone, + }) + ) { + recentlyVisitedString += '
    Today
    '; + } else { + if (!firstItem) { + recentlyVisitedString += ''; + } + recentlyVisitedString += '
    ' + currentDate + '
    '; + } + recentlyVisitedString += ''; + mb.window.webContents.executeJavaScript( + 'document.getElementById("detail-content").innerHTML = "' + recentlyVisitedString + '"', + ); + }); } function searchRecentlyVisited(searchterm) { - let foundArray = moreRecentlyVisitedArray.filter(item => { - return item.title.toLowerCase().includes(searchterm) - }) - foundString = ''; + mb.window.webContents.executeJavaScript( + 'document.getElementById("detail-content").innerHTML = "' + foundString + '"', + ); } async function getUsersProjects() { - let result = await fetch(store.host + '/api/v4/users/' + store.user_id + '/starred_projects?min_access_level=30&per_page=' + numberOfFavoriteProjects + '&order_by=updated_at&access_token=' + store.access_token) - let projects = await result.json() - let projectsArray = [] - if (projects && projects.length > 0) { - for (let project of projects) { - //TODO Figure out a way to see avatars of private repositories - /*if(project.visibility == 'public') { + let result = await fetch( + store.host + + '/api/v4/users/' + + store.user_id + + '/starred_projects?min_access_level=30&per_page=' + + numberOfFavoriteProjects + + '&order_by=updated_at&access_token=' + + store.access_token, + ); + let projects = await result.json(); + let projectsArray = []; + if (projects && projects.length > 0) { + for (let project of projects) { + //TODO Figure out a way to see avatars of private repositories + /*if(project.visibility == 'public') { favoriteProjectsString += '
  • ' }*/ - let projectObject = { - id: project.id, - visibility: project.visibility, - web_url: project.web_url, - name: project.name, - namespace: { - name: project.namespace.name - }, - added: Date.now(), - name_with_namespace: project.name_with_namespace, - open_issues_count: project.open_issues_count, - last_activity_at: project.last_activity_at, - avatar_url: project.avatar_url, - star_count: project.star_count, - forks_count: project.forks_count, - } - projectsArray.push(projectObject) - } + let projectObject = { + id: project.id, + visibility: project.visibility, + web_url: project.web_url, + name: project.name, + namespace: { + name: project.namespace.name, + }, + added: Date.now(), + name_with_namespace: project.name_with_namespace, + open_issues_count: project.open_issues_count, + last_activity_at: project.last_activity_at, + avatar_url: project.avatar_url, + star_count: project.star_count, + forks_count: project.forks_count, + }; + projectsArray.push(projectObject); } - return projectsArray + } + return projectsArray; } function displayUsersProjects() { - let favoriteProjectsString = '' - let projects = store['favorite-projects'] - if (projects && projects.length > 0) { - favoriteProjectsString += '' - } else { - let projectLink = "'project-overview-link'" - favoriteProjectsString = '
    Track projects you care about 🌟
    Add any project you want a directly accessible shortcut for.
    ' + let favoriteProjectsString = ''; + let projects = store['favorite-projects']; + if (projects && projects.length > 0) { + favoriteProjectsString += ''; + } else { + let projectLink = "'project-overview-link'"; + favoriteProjectsString = + '
    Track projects you care about 🌟
    Add any project you want a directly accessible shortcut for.
    '; + } + mb.window.webContents.executeJavaScript( + 'document.getElementById("projects").innerHTML = "' + favoriteProjectsString + '"', + ); } function getRecentComments() { - if (lastRecentCommentsExecutionFinished && lastRecentCommentsExecution + delay < Date.now()) { - lastRecentCommentsExecutionFinished = false - let recentCommentsString = '' - fetch(store.host + '/api/v4/events?action=commented&per_page=' + numberOfRecentComments + '&access_token=' + store.access_token).then(result => { - return result.json() - }).then(async comments => { - if (comments && comments.length > 0) { - recentCommentsString += '' - mb.window.webContents.executeJavaScript('document.getElementById("comments").innerHTML = "' + recentCommentsString + '"') - } else { - mb.window.webContents.executeJavaScript('document.getElementById("comments").innerHTML = "

    You haven't written any comments yet.

    "') - } - lastRecentCommentsExecution = Date.now() - lastRecentCommentsExecutionFinished = true - }) - } else { - console.log('Recent comments running or not out of delay') - } -} - -function getMoreRecentComments(url = store.host + '/api/v4/events?action=commented&per_page=' + numberOfComments + '&access_token=' + store.access_token) { - let recentCommentsString = '' + displayPagination(keysetLinks, type) - mb.window.webContents.executeJavaScript('document.getElementById("detail-content").innerHTML = "' + recentCommentsString + '"') - }) + lastRecentCommentsExecution = Date.now(); + lastRecentCommentsExecutionFinished = true; + }); + } else { + console.log('Recent comments running or not out of delay'); + } } -function getIssues(url = store.host + '/api/v4/issues?scope=assigned_to_me&state=opened&order_by=created_at&per_page=' + numberOfIssues + '&access_token=' + store.access_token, id = 'detail-content') { - let issuesString = '' - let type = "'Issues'" - let keysetLinks - fetch(url).then(result => { - keysetLinks = result.headers.get('Link') - return result.json() - }).then(issues => { - if (issues && issues.length > 0) { - issuesString += '' + displayPagination(keysetLinks, type) - } else { - let illustration = escapeQuotes('') - issuesString = '
    ' + illustration + '

    No issues with the specified criteria.

    ' - } - mb.window.webContents.executeJavaScript('document.getElementById("' + id + '").innerHTML = "' + issuesString + '"') +function getMoreRecentComments( + url = store.host + + '/api/v4/events?action=commented&per_page=' + + numberOfComments + + '&access_token=' + + store.access_token, +) { + let recentCommentsString = '' + displayPagination(keysetLinks, type); + mb.window.webContents.executeJavaScript( + 'document.getElementById("detail-content").innerHTML = "' + recentCommentsString + '"', + ); + }); } -function getMRs(url = store.host + '/api/v4/merge_requests?scope=assigned_to_me&state=opened&order_by=created_at&per_page=' + numberOfMRs + '&access_token=' + store.access_token, id = 'detail-content') { - let mrsString = '' - let type = "'MRs'" - let keysetLinks - fetch(url).then(result => { - keysetLinks = result.headers.get('Link') - return result.json() - }).then(mrs => { - if (mrs && mrs.length > 0) { - mrsString = '' + displayPagination(keysetLinks, type) - } else { - let illustration = escapeQuotes('') - mrsString = '
    ' + illustration + '

    No merge requests with the specified criteria.

    ' - } - mb.window.webContents.executeJavaScript('document.getElementById("' + id + '").innerHTML = "' + mrsString + '"') +function getIssues( + url = store.host + + '/api/v4/issues?scope=assigned_to_me&state=opened&order_by=created_at&per_page=' + + numberOfIssues + + '&access_token=' + + store.access_token, + id = 'detail-content', +) { + let issuesString = ''; + let type = "'Issues'"; + let keysetLinks; + fetch(url) + .then((result) => { + keysetLinks = result.headers.get('Link'); + return result.json(); }) + .then((issues) => { + if (issues && issues.length > 0) { + issuesString += '' + displayPagination(keysetLinks, type); + } else { + let illustration = escapeQuotes( + '', + ); + issuesString = + '
    ' + + illustration + + '

    No issues with the specified criteria.

    '; + } + mb.window.webContents.executeJavaScript( + 'document.getElementById("' + id + '").innerHTML = "' + issuesString + '"', + ); + }); } -function getTodos(url = store.host + '/api/v4/todos?per_page=' + numberOfTodos + '&access_token=' + store.access_token) { - let todosString = '' - let type = "'Todos'" - let keysetLinks - fetch(url).then(result => { - keysetLinks = result.headers.get('Link') - return result.json() - }).then(todos => { - if (todos && todos.length > 0) { - todosString = '' + displayPagination(keysetLinks, type) - } else { - let illustration = escapeQuotes('') - todosString = '
    ' + illustration + '

    Take the day off, you have no To-Dos!

    ' - } - mb.window.webContents.executeJavaScript('document.getElementById("detail-content").innerHTML = "' + todosString + '"') +function getMRs( + url = store.host + + '/api/v4/merge_requests?scope=assigned_to_me&state=opened&order_by=created_at&per_page=' + + numberOfMRs + + '&access_token=' + + store.access_token, + id = 'detail-content', +) { + let mrsString = ''; + let type = "'MRs'"; + let keysetLinks; + fetch(url) + .then((result) => { + keysetLinks = result.headers.get('Link'); + return result.json(); }) + .then((mrs) => { + if (mrs && mrs.length > 0) { + mrsString = '' + displayPagination(keysetLinks, type); + } else { + let illustration = escapeQuotes( + '', + ); + mrsString = + '
    ' + + illustration + + '

    No merge requests with the specified criteria.

    '; + } + mb.window.webContents.executeJavaScript( + 'document.getElementById("' + id + '").innerHTML = "' + mrsString + '"', + ); + }); +} + +function getTodos( + url = store.host + + '/api/v4/todos?per_page=' + + numberOfTodos + + '&access_token=' + + store.access_token, +) { + let todosString = ''; + let type = "'Todos'"; + let keysetLinks; + fetch(url) + .then((result) => { + keysetLinks = result.headers.get('Link'); + return result.json(); + }) + .then((todos) => { + if (todos && todos.length > 0) { + todosString = '' + displayPagination(keysetLinks, type); + } else { + let illustration = escapeQuotes( + '', + ); + todosString = + '
    ' + + illustration + + '

    Take the day off, you have no To-Dos!

    '; + } + mb.window.webContents.executeJavaScript( + 'document.getElementById("detail-content").innerHTML = "' + todosString + '"', + ); + }); } function getBookmarks() { - let bookmarks = store.bookmarks - let bookmarksString = '' - if (bookmarks && bookmarks.length > 0) { - bookmarksString = '' - mb.window.webContents.executeJavaScript('document.getElementById("bookmarks").innerHTML = "' + bookmarksString + '"') - } else { - let bookmarkLink = "'bookmark-link'" - bookmarksString = '
    Add a new GitLab bookmark 🔖
    Bookmarks are helpful when you have an issue/merge request you will have to come back to repeatedly.
    ' - mb.window.webContents.executeJavaScript('document.getElementById("bookmarks").innerHTML = "' + bookmarksString + '"') - } + let bookmarks = store.bookmarks; + let bookmarksString = ''; + if (bookmarks && bookmarks.length > 0) { + bookmarksString = ''; + mb.window.webContents.executeJavaScript( + 'document.getElementById("bookmarks").innerHTML = "' + bookmarksString + '"', + ); + } else { + let bookmarkLink = "'bookmark-link'"; + bookmarksString = + '
    Add a new GitLab bookmark 🔖
    Bookmarks are helpful when you have an issue/merge request you will have to come back to repeatedly.
    '; + mb.window.webContents.executeJavaScript( + 'document.getElementById("bookmarks").innerHTML = "' + bookmarksString + '"', + ); + } } function displayPagination(keysetLinks, type) { - let paginationString = '' - if (keysetLinks.indexOf('rel="next"') != -1 || keysetLinks.indexOf('rel="prev"') != -1) { - paginationString += '
    ' - if (keysetLinks.indexOf('rel="prev"') != -1) { - let prevLink = '' - let icon = '' - prevLink = escapeHtml('"' + keysetLinks.split('>; rel="prev"')[0].substring(1) + '"') - paginationString += '' - } else { - paginationString += '
    ' - } - if (keysetLinks.indexOf('rel="next"') != -1) { - let nextLink = '' - let icon = '' - if (keysetLinks.indexOf('rel="prev"') != -1) { - nextLink = escapeHtml('"' + keysetLinks.split('rel="prev", ')[1].split('>; rel="next"')[0].substring(1) + '"') - paginationString += '' - } else { - nextLink = escapeHtml('"' + keysetLinks.split('>; rel="next"')[0].substring(1) + '"') - paginationString += '' - } - } else { - paginationString += '
    ' - } - paginationString += '
    ' - return paginationString + let paginationString = ''; + if (keysetLinks.indexOf('rel="next"') != -1 || keysetLinks.indexOf('rel="prev"') != -1) { + paginationString += '
    '; + if (keysetLinks.indexOf('rel="prev"') != -1) { + let prevLink = ''; + let icon = + ''; + prevLink = escapeHtml('"' + keysetLinks.split('>; rel="prev"')[0].substring(1) + '"'); + paginationString += + ''; } else { - return '' + paginationString += '
    '; } + if (keysetLinks.indexOf('rel="next"') != -1) { + let nextLink = ''; + let icon = + ''; + if (keysetLinks.indexOf('rel="prev"') != -1) { + nextLink = escapeHtml( + '"' + keysetLinks.split('rel="prev", ')[1].split('>; rel="next"')[0].substring(1) + '"', + ); + paginationString += + ''; + } else { + nextLink = escapeHtml('"' + keysetLinks.split('>; rel="next"')[0].substring(1) + '"'); + paginationString += + ''; + } + } else { + paginationString += '
    '; + } + paginationString += '
    '; + return paginationString; + } else { + return ''; + } } function setupEmptyProjectPage() { - let emptyPage = '
    ' - emptyPage += '
    Issues
    ' - emptyPage += '
    ' - emptyPage += '
    Merge requests
    ' - emptyPage += '
    ' - mb.window.webContents.executeJavaScript('document.getElementById("detail-content").innerHTML = "' + emptyPage + '"') + let emptyPage = + '
    '; + emptyPage += '
    Issues
    '; + emptyPage += + '
    '; + emptyPage += '
    Merge requests
    '; + emptyPage += + '
    '; + mb.window.webContents.executeJavaScript( + 'document.getElementById("detail-content").innerHTML = "' + emptyPage + '"', + ); } function displayProjectPage(project) { - let logo - if (project.avatar_url && project.avatar_url != null && project.visibility == 'public') { - logo = '' - } else { - logo = '
    ' + project.name.charAt(0).toUpperCase() + '
    ' - } - mb.window.webContents.executeJavaScript('document.getElementById("detail-header-content").classList.remove("empty")') - mb.window.webContents.executeJavaScript('document.getElementById("detail-header-content").innerHTML = "
    ' + logo + '' + escapeHtml(project.name) + '' + escapeHtml(project.namespace.name) + '
    "') + let logo; + if (project.avatar_url && project.avatar_url != null && project.visibility == 'public') { + logo = ''; + } else { + logo = + '
    ' + project.name.charAt(0).toUpperCase() + '
    '; + } + mb.window.webContents.executeJavaScript( + 'document.getElementById("detail-header-content").classList.remove("empty")', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("detail-header-content").innerHTML = "
    ' + + logo + + '' + + escapeHtml(project.name) + + '' + + escapeHtml(project.namespace.name) + + '
    "', + ); } function getProjectIssues(project) { - let projectIssuesString = '' - let jsonProjectObject = JSON.parse(JSON.stringify(project)) - jsonProjectObject.name_with_namespace = escapeQuotes(project.name_with_namespace) - jsonProjectObject.namespace.name = escapeQuotes(project.namespace.name) - jsonProjectObject.name = escapeQuotes(project.name) - let projectString = "'" + escapeHtml(JSON.stringify(jsonProjectObject)) + "'" - let issuesString = "'Issues'" - fetch(store.host + '/api/v4/projects/' + project.id + '/issues?state=opened&order_by=created_at&per_page=3&access_token=' + store.access_token).then(result => { - return result.json() - }).then(issues => { - if (issues.length > 0) { - projectIssuesString = '' - } else { - projectIssuesString = '

    No open issues.

    ' - projectIssuesString += '
    View all
    ' - } - mb.window.webContents.executeJavaScript('document.getElementById("project-recent-issues").innerHTML = "' + projectIssuesString + '"') + let projectIssuesString = ''; + let jsonProjectObject = JSON.parse(JSON.stringify(project)); + jsonProjectObject.name_with_namespace = escapeQuotes(project.name_with_namespace); + jsonProjectObject.namespace.name = escapeQuotes(project.namespace.name); + jsonProjectObject.name = escapeQuotes(project.name); + let projectString = "'" + escapeHtml(JSON.stringify(jsonProjectObject)) + "'"; + let issuesString = "'Issues'"; + fetch( + store.host + + '/api/v4/projects/' + + project.id + + '/issues?state=opened&order_by=created_at&per_page=3&access_token=' + + store.access_token, + ) + .then((result) => { + return result.json(); }) + .then((issues) => { + if (issues.length > 0) { + projectIssuesString = ''; + } else { + projectIssuesString = '

    No open issues.

    '; + projectIssuesString += + '
    View all
    '; + } + mb.window.webContents.executeJavaScript( + 'document.getElementById("project-recent-issues").innerHTML = "' + + projectIssuesString + + '"', + ); + }); } function getProjectMRs(project) { - let projectMRsString = '' - let jsonProjectObject = JSON.parse(JSON.stringify(project)) - jsonProjectObject.name_with_namespace = escapeQuotes(project.name_with_namespace) - jsonProjectObject.namespace.name = escapeQuotes(project.namespace.name) - jsonProjectObject.name = escapeQuotes(project.name) - let projectString = "'" + escapeHtml(JSON.stringify(jsonProjectObject)) + "'" - let mrsString = "'Merge Requests'" - fetch(store.host + '/api/v4/projects/' + project.id + '/merge_requests?state=opened&order_by=created_at&per_page=3&access_token=' + store.access_token).then(result => { - return result.json() - }).then(mrs => { - if (mrs.length > 0) { - projectMRsString += '' - } else { - projectMRsString = '

    No open merge requests.

    ' - projectMRsString += '
    View all
    ' - } - mb.window.webContents.executeJavaScript('document.getElementById("project-recent-mrs").innerHTML = "' + projectMRsString + '"') + let projectMRsString = ''; + let jsonProjectObject = JSON.parse(JSON.stringify(project)); + jsonProjectObject.name_with_namespace = escapeQuotes(project.name_with_namespace); + jsonProjectObject.namespace.name = escapeQuotes(project.namespace.name); + jsonProjectObject.name = escapeQuotes(project.name); + let projectString = "'" + escapeHtml(JSON.stringify(jsonProjectObject)) + "'"; + let mrsString = "'Merge Requests'"; + fetch( + store.host + + '/api/v4/projects/' + + project.id + + '/merge_requests?state=opened&order_by=created_at&per_page=3&access_token=' + + store.access_token, + ) + .then((result) => { + return result.json(); }) + .then((mrs) => { + if (mrs.length > 0) { + projectMRsString += ''; + } else { + projectMRsString = '

    No open merge requests.

    '; + projectMRsString += + '
    View all
    '; + } + mb.window.webContents.executeJavaScript( + 'document.getElementById("project-recent-mrs").innerHTML = "' + projectMRsString + '"', + ); + }); } function displayCommit(commit, project, focus = 'project') { - let logo = '' - if (commit.last_pipeline) { - logo += '' - if (commit.last_pipeline.status == 'scheduled') { - logo += '' - } else { - logo += '' - if (commit.last_pipeline.status == 'running') { - logo += '' - } else if (commit.last_pipeline.status == 'failed') { - logo += '' - } else if (commit.last_pipeline.status == 'success') { - logo += '' - } else if (commit.last_pipeline.status == 'pending') { - logo += '' - } else if (commit.last_pipeline.status == 'canceled') { - logo += '' - } else if (commit.last_pipeline.status == 'skipped') { - logo += '' - } else if (commit.last_pipeline.status == 'created') { - logo += '' - } else if (commit.last_pipeline.status == 'preparing') { - logo += '' - } else if (commit.last_pipeline.status == 'manual') { - logo += '' - } - } - } - logo += '' - let subline - if (focus == 'project') { - subline = '' + escapeHtml(project.name_with_namespace) + '' + let logo = ''; + if (commit.last_pipeline) { + logo += + ''; + if (commit.last_pipeline.status == 'scheduled') { + logo += + ''; } else { - subline = escapeHtml(commit.author_name) + logo += + ''; + if (commit.last_pipeline.status == 'running') { + logo += + ''; + } else if (commit.last_pipeline.status == 'failed') { + logo += + ''; + } else if (commit.last_pipeline.status == 'success') { + logo += + ''; + } else if (commit.last_pipeline.status == 'pending') { + logo += + ''; + } else if (commit.last_pipeline.status == 'canceled') { + logo += + ''; + } else if (commit.last_pipeline.status == 'skipped') { + logo += + ''; + } else if (commit.last_pipeline.status == 'created') { + logo += ''; + } else if (commit.last_pipeline.status == 'preparing') { + logo += + ''; + } else if (commit.last_pipeline.status == 'manual') { + logo += + ''; + } } - return '
    ' + escapeHtml(commit.title) + '' + timeSince(new Date(commit.committed_date)) + ' ago · ' + subline + '
    ' + logo + '
    ' + } + logo += ''; + let subline; + if (focus == 'project') { + subline = + '' + + escapeHtml(project.name_with_namespace) + + ''; + } else { + subline = escapeHtml(commit.author_name); + } + return ( + '
    ' + + escapeHtml(commit.title) + + '' + + timeSince(new Date(commit.committed_date)) + + ' ago · ' + + subline + + '
    ' + + logo + + '
    ' + ); } function addBookmark(link) { - let spinner = '' - mb.window.webContents.executeJavaScript('document.getElementById("bookmark-add-button").disabled = "disabled"') - mb.window.webContents.executeJavaScript('document.getElementById("bookmark-link").disabled = "disabled"') - mb.window.webContents.executeJavaScript('document.getElementById("bookmark-add-button").innerHTML = "' + spinner + ' Add"') - if (link.indexOf(store.host + '') == 0 || link.indexOf('gitlab.com') == 0 || link.indexOf('http://gitlab.com') == 0) { - parseGitLabUrl(link).then(bookmark => { - if (!bookmark.type || (bookmark.type != 'issues' && bookmark.type != 'merge_requests' && bookmark.type != 'epics' && bookmark.type != 'projects' && bookmark.type != 'groups' && bookmark.type != 'boards' && bookmark.type != 'users' && bookmark.type != 'unknown')) { - displayAddError('bookmark', '-') - } else { - let bookmarks = store.bookmarks || [] - bookmarks.push(bookmark) - store.bookmarks = bookmarks - getBookmarks() - } - }).catch(error => { - displayAddError('bookmark', '-') - }) - } else { - displayAddError('bookmark', '-') - } + let spinner = + ''; + mb.window.webContents.executeJavaScript( + 'document.getElementById("bookmark-add-button").disabled = "disabled"', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("bookmark-link").disabled = "disabled"', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("bookmark-add-button").innerHTML = "' + spinner + ' Add"', + ); + if ( + link.indexOf(store.host + '') == 0 || + link.indexOf('gitlab.com') == 0 || + link.indexOf('http://gitlab.com') == 0 + ) { + parseGitLabUrl(link) + .then((bookmark) => { + if ( + !bookmark.type || + (bookmark.type != 'issues' && + bookmark.type != 'merge_requests' && + bookmark.type != 'epics' && + bookmark.type != 'projects' && + bookmark.type != 'groups' && + bookmark.type != 'boards' && + bookmark.type != 'users' && + bookmark.type != 'unknown') + ) { + displayAddError('bookmark', '-'); + } else { + let bookmarks = store.bookmarks || []; + bookmarks.push(bookmark); + store.bookmarks = bookmarks; + getBookmarks(); + } + }) + .catch((error) => { + displayAddError('bookmark', '-'); + }); + } else { + displayAddError('bookmark', '-'); + } } function addProject(link, target) { - if (target == 'project-settings-link') { - target = '-settings-' - } else if (target == 'project-overview-link') { - target = '-overview-' - } - let spinner = '' - mb.window.webContents.executeJavaScript('document.getElementById("project' + target + 'add-button").disabled = "disabled"') - mb.window.webContents.executeJavaScript('document.getElementById("project' + target + 'link").disabled = "disabled"') - mb.window.webContents.executeJavaScript('document.getElementById("project' + target + 'add-button").innerHTML = "' + spinner + ' Add"') - if (link.indexOf(store.host + '') == 0 || link.indexOf('gitlab.com') == 0 || link.indexOf('http://gitlab.com') == 0) { - parseGitLabUrl(link).then(project => { - if (project.type && project.type != 'projects') { - displayAddError('project', target) - } else { - let projects = store['favorite-projects'] || [] - projects.push(project) - store['favorite-projects'] = projects - if (target == '-settings-') { - openSettingsPage() - } - displayUsersProjects(projects) - } - }).catch(error => { - displayAddError('project', target) - }) - } else { - displayAddError('project', target) - } + if (target == 'project-settings-link') { + target = '-settings-'; + } else if (target == 'project-overview-link') { + target = '-overview-'; + } + let spinner = + ''; + mb.window.webContents.executeJavaScript( + 'document.getElementById("project' + target + 'add-button").disabled = "disabled"', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("project' + target + 'link").disabled = "disabled"', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("project' + target + 'add-button").innerHTML = "' + spinner + ' Add"', + ); + if ( + link.indexOf(store.host + '') == 0 || + link.indexOf('gitlab.com') == 0 || + link.indexOf('http://gitlab.com') == 0 + ) { + parseGitLabUrl(link) + .then((project) => { + if (project.type && project.type != 'projects') { + displayAddError('project', target); + } else { + let projects = store['favorite-projects'] || []; + projects.push(project); + store['favorite-projects'] = projects; + if (target == '-settings-') { + openSettingsPage(); + } + displayUsersProjects(projects); + } + }) + .catch((error) => { + displayAddError('project', target); + }); + } else { + displayAddError('project', target); + } } function displayAddError(type, target) { - mb.window.webContents.executeJavaScript('document.getElementById("add-' + type + target + 'error").style.display = "block"') - mb.window.webContents.executeJavaScript('document.getElementById("add-' + type + target + 'error").innerHTML = "This is not a valid GitLab ' + type + ' URL."') - mb.window.webContents.executeJavaScript('document.getElementById("' + type + target + 'add-button").disabled = false') - mb.window.webContents.executeJavaScript('document.getElementById("' + type + target + 'link").disabled = false') - mb.window.webContents.executeJavaScript('document.getElementById("' + type + target + 'add-button").innerHTML = "Add"') + mb.window.webContents.executeJavaScript( + 'document.getElementById("add-' + type + target + 'error").style.display = "block"', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("add-' + + type + + target + + 'error").innerHTML = "This is not a valid GitLab ' + + type + + ' URL."', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("' + type + target + 'add-button").disabled = false', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("' + type + target + 'link").disabled = false', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("' + type + target + 'add-button").innerHTML = "Add"', + ); } function startBookmarkDialog() { - let bookmarkLink = "'bookmark-link'" - let bookmarkInput = '
    ' - mb.window.webContents.executeJavaScript('document.getElementById("add-bookmark-dialog").classList.add("opened")') - mb.window.webContents.executeJavaScript('document.getElementById("add-bookmark-dialog").innerHTML = "' + bookmarkInput + '"') - mb.window.webContents.executeJavaScript('window.scrollBy(0, 14)') - mb.window.webContents.executeJavaScript('document.getElementById("bookmark-link").focus()') + let bookmarkLink = "'bookmark-link'"; + let bookmarkInput = + '
    '; + mb.window.webContents.executeJavaScript( + 'document.getElementById("add-bookmark-dialog").classList.add("opened")', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("add-bookmark-dialog").innerHTML = "' + bookmarkInput + '"', + ); + mb.window.webContents.executeJavaScript('window.scrollBy(0, 14)'); + mb.window.webContents.executeJavaScript('document.getElementById("bookmark-link").focus()'); } function startProjectDialog() { - let projectLink = "'project-settings-link'" - let projectInput = '
    ' - mb.window.webContents.executeJavaScript('document.getElementById("add-project-dialog").classList.add("opened")') - mb.window.webContents.executeJavaScript('document.getElementById("add-project-dialog").innerHTML = "' + projectInput + '"') - mb.window.webContents.executeJavaScript('window.scrollBy(0, 14)') - mb.window.webContents.executeJavaScript('document.getElementById("project-settings-link").focus()') + let projectLink = "'project-settings-link'"; + let projectInput = + '
    '; + mb.window.webContents.executeJavaScript( + 'document.getElementById("add-project-dialog").classList.add("opened")', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("add-project-dialog").innerHTML = "' + projectInput + '"', + ); + mb.window.webContents.executeJavaScript('window.scrollBy(0, 14)'); + mb.window.webContents.executeJavaScript( + 'document.getElementById("project-settings-link").focus()', + ); } async function parseGitLabUrl(link) { - if (!/^(?:f|ht)tps?\:\/\//.test(link)) { - link = "https://" + link; + if (!/^(?:f|ht)tps?\:\/\//.test(link)) { + link = 'https://' + link; + } + let object = await parse(link); + let issuable; + if (object.type == 'issues' || object.type == 'merge_requests') { + let result = await fetch( + store.host + + '/api/v4/projects/' + + encodeURIComponent(object.namespaceWithProject) + + '/' + + object.type + + '/' + + object[object.type] + + '?access_token=' + + store.access_token, + ); + issuable = await result.json(); + let result2 = await fetch( + store.host + + '/api/v4/projects/' + + issuable.project_id + + '?access_token=' + + store.access_token, + ); + let project = await result2.json(); + return { + web_url: link, + parent_name: project.name_with_namespace, + project: project.name, + title: issuable.title, + added: Date.now(), + type: object.type, + parent_url: project.web_url, + }; + } else if (object.type == 'epics') { + let result = await fetch( + store.host + + '/api/v4/groups/' + + encodeURIComponent(object.namespaceWithProject.replace('groups/', '')) + + '/' + + object.type + + '/' + + object[object.type] + + '?access_token=' + + store.access_token, + ); + issuable = await result.json(); + let result2 = await fetch( + store.host + '/api/v4/groups/' + issuable.group_id + '?access_token=' + store.access_token, + ); + let group = await result2.json(); + return { + web_url: link, + parent_name: group.full_name, + title: issuable.title, + added: Date.now(), + type: object.type, + parent_url: group.web_url, + }; + } else if (object.type == 'boards') { + let result = await fetch( + store.host + + '/api/v4/projects/' + + encodeURIComponent(object.namespaceWithProject) + + '/' + + object.type + + '/' + + object[object.type] + + '?access_token=' + + store.access_token, + ); + board = await result.json(); + return { + web_url: link, + parent_name: board.project.name_with_namespace, + title: board.name, + added: Date.now(), + type: object.type, + parent_url: board.project.web_url, + }; + } else if (object.type == 'projects') { + let result = await fetch( + store.host + + '/api/v4/projects/' + + encodeURIComponent(object.namespaceWithProject) + + '?access_token=' + + store.access_token, + ); + let project = await result.json(); + return { + id: project.id, + visibility: project.visibility, + web_url: project.web_url, + name: project.name, + title: project.name, + namespace: { + name: project.namespace.name, + }, + parent_name: project.name_with_namespace, + parent_url: project.namespace.web_url, + added: Date.now(), + name_with_namespace: project.name_with_namespace, + open_issues_count: project.open_issues_count, + last_activity_at: project.last_activity_at, + avatar_url: project.avatar_url, + star_count: project.star_count, + forks_count: project.forks_count, + type: 'projects', + }; + } else if (object.type == 'groups') { + let result = await fetch( + store.host + + '/api/v4/groups/' + + encodeURIComponent(object.namespaceWithProject) + + '?access_token=' + + store.access_token, + ); + let group = await result.json(); + let groupObject = { + id: group.id, + visibility: group.visibility, + web_url: group.web_url, + title: group.name, + name: group.name, + namespace: { + name: group.name, + }, + added: Date.now(), + name_with_namespace: group.name_with_namespace, + avatar_url: group.avatar_url, + type: 'groups', + }; + if (group.full_name.indexOf(' / ' + group.name) != -1) { + groupObject.parent_name = group.full_name.replace(' / ' + group.name, ''); + groupObject.parent_url = group.web_url.replace('/' + group.path, ''); } - let object = await parse(link) - let issuable - if (object.type == 'issues' || object.type == 'merge_requests') { - let result = await fetch(store.host + '/api/v4/projects/' + encodeURIComponent(object.namespaceWithProject) + '/' + object.type + '/' + object[object.type] + '?access_token=' + store.access_token) - issuable = await result.json() - let result2 = await fetch(store.host + '/api/v4/projects/' + issuable.project_id + '?access_token=' + store.access_token) - let project = await result2.json() - return { - web_url: link, - parent_name: project.name_with_namespace, - project: project.name, - title: issuable.title, - added: Date.now(), - type: object.type, - parent_url: project.web_url - } - } else if (object.type == 'epics') { - let result = await fetch(store.host + '/api/v4/groups/' + encodeURIComponent(object.namespaceWithProject.replace('groups/', '')) + '/' + object.type + '/' + object[object.type] + '?access_token=' + store.access_token) - issuable = await result.json() - let result2 = await fetch(store.host + '/api/v4/groups/' + issuable.group_id + '?access_token=' + store.access_token) - let group = await result2.json() - return { - web_url: link, - parent_name: group.full_name, - title: issuable.title, - added: Date.now(), - type: object.type, - parent_url: group.web_url - } - } else if (object.type == 'boards') { - let result = await fetch(store.host + '/api/v4/projects/' + encodeURIComponent(object.namespaceWithProject) + '/' + object.type + '/' + object[object.type] + '?access_token=' + store.access_token) - board = await result.json() - return { - web_url: link, - parent_name: board.project.name_with_namespace, - title: board.name, - added: Date.now(), - type: object.type, - parent_url: board.project.web_url - } - } else if (object.type == 'projects') { - let result = await fetch(store.host + '/api/v4/projects/' + encodeURIComponent(object.namespaceWithProject) + '?access_token=' + store.access_token) - let project = await result.json() - return { - id: project.id, - visibility: project.visibility, - web_url: project.web_url, - name: project.name, - title: project.name, - namespace: { - name: project.namespace.name - }, - parent_name: project.name_with_namespace, - parent_url: project.namespace.web_url, - added: Date.now(), - name_with_namespace: project.name_with_namespace, - open_issues_count: project.open_issues_count, - last_activity_at: project.last_activity_at, - avatar_url: project.avatar_url, - star_count: project.star_count, - forks_count: project.forks_count, - type: 'projects' - } - } else if (object.type == 'groups') { - let result = await fetch(store.host + '/api/v4/groups/' + encodeURIComponent(object.namespaceWithProject) + '?access_token=' + store.access_token) - let group = await result.json() - let groupObject = { - id: group.id, - visibility: group.visibility, - web_url: group.web_url, - title: group.name, - name: group.name, - namespace: { - name: group.name - }, - added: Date.now(), - name_with_namespace: group.name_with_namespace, - avatar_url: group.avatar_url, - type: 'groups' - } - if (group.full_name.indexOf(' / ' + group.name) != -1) { - groupObject.parent_name = group.full_name.replace(' / ' + group.name, '') - groupObject.parent_url = group.web_url.replace('/' + group.path, '') - } - return groupObject - } else if (object.type == 'users') { - let result = await fetch(store.host + '/api/v4/users?username=' + encodeURIComponent(object.namespaceWithProject)) - let user = await result.json() - user = user[0] - return { - title: user.name, - type: object.type, - web_url: user.web_url, - added: Date.now() - } - } else if (object.type == 'unknown') { - let titleArray = object.doc.querySelector('title').text.split(' · ') - let unknownObject = { - title: titleArray[0], - type: object.type, - web_url: link, - added: Date.now() - } - if (object.doc.querySelector('.context-header a')) { - unknownObject.parent_url = store.host + object.doc.querySelector('.context-header a').getAttribute('href') - console.log(object.doc.querySelector('.context-header a').getAttribute('href')) - if (titleArray.length == 3) { - unknownObject.parent_name = titleArray[1] - } else if (titleArray.length == 4) { - unknownObject.parent_name = titleArray[2] - } - } - return unknownObject + return groupObject; + } else if (object.type == 'users') { + let result = await fetch( + store.host + '/api/v4/users?username=' + encodeURIComponent(object.namespaceWithProject), + ); + let user = await result.json(); + user = user[0]; + return { + title: user.name, + type: object.type, + web_url: user.web_url, + added: Date.now(), + }; + } else if (object.type == 'unknown') { + let titleArray = object.doc.querySelector('title').text.split(' · '); + let unknownObject = { + title: titleArray[0], + type: object.type, + web_url: link, + added: Date.now(), + }; + if (object.doc.querySelector('.context-header a')) { + unknownObject.parent_url = + store.host + object.doc.querySelector('.context-header a').getAttribute('href'); + console.log(object.doc.querySelector('.context-header a').getAttribute('href')); + if (titleArray.length == 3) { + unknownObject.parent_name = titleArray[1]; + } else if (titleArray.length == 4) { + unknownObject.parent_name = titleArray[2]; + } } + return unknownObject; + } } async function parse(gitlabUrl) { - if (typeof gitlabUrl !== 'string') { - throw new Error('Expected gitLabUrl of type string') - } - const url = new URL(gitlabUrl) - let path = url.pathname - path = path.replace(/^\/|\/$/g, '') - path = path.replace(/\+$/, '') - if (path.indexOf('/-/') != -1) { - let pathArray = path.split('/-/') - let object = { - namespaceWithProject: pathArray[0], - type: pathArray[1].split('/')[0] - - } - if (pathArray[1].split('/')[1] == 'issues' || pathArray[1].split('/')[1] == 'merge_requests' || pathArray[1].split('/')[1] == 'epics' || pathArray[1].split('/')[1] == 'boards') { - object[object.type] = pathArray[1].split('/')[1].split('#')[0] - return object - } else { - let result = await fetch(gitlabUrl) - let body = await result.text() - let doc = new DOMParser().parseFromString(body, 'text/html'); - return { - namespaceWithProject: path, - type: 'unknown', - doc: doc - } - } + if (typeof gitlabUrl !== 'string') { + throw new Error('Expected gitLabUrl of type string'); + } + const url = new URL(gitlabUrl); + let path = url.pathname; + path = path.replace(/^\/|\/$/g, ''); + path = path.replace(/\+$/, ''); + if (path.indexOf('/-/') != -1) { + let pathArray = path.split('/-/'); + let object = { + namespaceWithProject: pathArray[0], + type: pathArray[1].split('/')[0], + }; + if ( + pathArray[1].split('/')[1] == 'issues' || + pathArray[1].split('/')[1] == 'merge_requests' || + pathArray[1].split('/')[1] == 'epics' || + pathArray[1].split('/')[1] == 'boards' + ) { + object[object.type] = pathArray[1].split('/')[1].split('#')[0]; + return object; } else { - let result = await fetch(gitlabUrl) - let body = await result.text() - let doc = new DOMParser().parseFromString(body, 'text/html'); - if (doc.querySelector('.group-home-panel')) { - return { - namespaceWithProject: path, - type: 'groups' - } - } else if (doc.querySelector('.project-home-panel')) { - return { - namespaceWithProject: path, - type: 'projects' - } - } else if (doc.querySelector('.user-profile')) { - return { - namespaceWithProject: path, - type: 'users' - } - } else { - return { - namespaceWithProject: path, - type: 'unknown', - doc: doc - } - } + let result = await fetch(gitlabUrl); + let body = await result.text(); + let doc = new DOMParser().parseFromString(body, 'text/html'); + return { + namespaceWithProject: path, + type: 'unknown', + doc: doc, + }; } + } else { + let result = await fetch(gitlabUrl); + let body = await result.text(); + let doc = new DOMParser().parseFromString(body, 'text/html'); + if (doc.querySelector('.group-home-panel')) { + return { + namespaceWithProject: path, + type: 'groups', + }; + } else if (doc.querySelector('.project-home-panel')) { + return { + namespaceWithProject: path, + type: 'projects', + }; + } else if (doc.querySelector('.user-profile')) { + return { + namespaceWithProject: path, + type: 'users', + }; + } else { + return { + namespaceWithProject: path, + type: 'unknown', + doc: doc, + }; + } + } } function escapeHtml(unsafe) { - return unsafe - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/`/g, "'") - .replace(/'/g, "'") - .replace(/@/g, "@") - .replace(/[\\]/g, '\\\\') - .replace(/[\"]/g, '\\\"') - .replace(/[\/]/g, '\\/') - .replace(/[\b]/g, '\\b') - .replace(/[\f]/g, '\\f') - .replace(/[\n]/g, '\\n') - .replace(/[\r]/g, '\\r') - .replace(/[\t]/g, '\\t') + return unsafe + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/`/g, ''') + .replace(/'/g, ''') + .replace(/@/g, '@') + .replace(/[\\]/g, '\\\\') + .replace(/[\"]/g, '\\"') + .replace(/[\/]/g, '\\/') + .replace(/[\b]/g, '\\b') + .replace(/[\f]/g, '\\f') + .replace(/[\n]/g, '\\n') + .replace(/[\r]/g, '\\r') + .replace(/[\t]/g, '\\t'); } function escapeQuotes(unsafe) { - return unsafe.replace(/"/g, '\\"') + return unsafe.replace(/"/g, '\\"'); } function timeSince(date, direction = 'since') { - var seconds - if (direction == 'since') { - seconds = Math.floor((new Date() - date) / 1000); - } else if (direction == 'to') { - seconds = Math.floor((date - new Date()) / 1000); - } - var interval = seconds / 31536000; - if (interval >= 2) { - return Math.floor(interval) + " years"; - } else if (interval > 1 && interval < 2) { - return Math.floor(interval) + " year"; - } - interval = seconds / 2592000; - if (interval > 2) { - return Math.floor(interval) + " months"; - } else if (interval > 1 && interval < 2) { - return Math.floor(interval) + " month"; - } - interval = seconds / 604800; - if (interval > 2) { - return Math.floor(interval) + " weeks"; - } else if (interval > 1 && interval < 2) { - return Math.floor(interval) + " week"; - } - interval = seconds / 86400; - if (interval > 2) { - return Math.floor(interval) + " days"; - } else if (interval > 1 && interval < 2) { - return Math.floor(interval) + " day"; - } - interval = seconds / 3600; - if (interval >= 2) { - return Math.floor(interval) + " hours"; - } else if (interval > 1 && interval < 2) { - return Math.floor(interval) + " hour"; - } - interval = seconds / 60; - if (interval > 2) { - return Math.floor(interval) + " minutes"; - } else if (interval > 1 && interval < 2) { - return Math.floor(interval) + " minute"; - } - return Math.floor(seconds) + " seconds"; + var seconds; + if (direction == 'since') { + seconds = Math.floor((new Date() - date) / 1000); + } else if (direction == 'to') { + seconds = Math.floor((date - new Date()) / 1000); + } + var interval = seconds / 31536000; + if (interval >= 2) { + return Math.floor(interval) + ' years'; + } else if (interval > 1 && interval < 2) { + return Math.floor(interval) + ' year'; + } + interval = seconds / 2592000; + if (interval > 2) { + return Math.floor(interval) + ' months'; + } else if (interval > 1 && interval < 2) { + return Math.floor(interval) + ' month'; + } + interval = seconds / 604800; + if (interval > 2) { + return Math.floor(interval) + ' weeks'; + } else if (interval > 1 && interval < 2) { + return Math.floor(interval) + ' week'; + } + interval = seconds / 86400; + if (interval > 2) { + return Math.floor(interval) + ' days'; + } else if (interval > 1 && interval < 2) { + return Math.floor(interval) + ' day'; + } + interval = seconds / 3600; + if (interval >= 2) { + return Math.floor(interval) + ' hours'; + } else if (interval > 1 && interval < 2) { + return Math.floor(interval) + ' hour'; + } + interval = seconds / 60; + if (interval > 2) { + return Math.floor(interval) + ' minutes'; + } else if (interval > 1 && interval < 2) { + return Math.floor(interval) + ' minute'; + } + return Math.floor(seconds) + ' seconds'; } function displaySkeleton(count, pagination = false, id = 'detail-content') { - let skeletonString = ''; + mb.window.webContents.executeJavaScript( + 'document.getElementById("' + id + '").innerHTML = "' + skeletonString + '"', + ); } function changeTheme(option = 'light', manual = false) { - store.theme = option - if (option == 'light') { - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--background-color", "#fff")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--text-color", "#24292f")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--muted-text-color", "#57606a")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--placeholder-text-color", "#6e7781")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--panel-background-color", "#fff")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--hover-color", "#f6f8fa")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--dropdown-hover-color", "#f0f2f4")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--border-color", "#d0d7de")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--lighter-background-color", "#d8dee4")'); - } else if (option == 'dark') { - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--background-color", "#090c10")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--text-color", "#c9d1d9")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--muted-text-color", "#aaa")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--placeholder-text-color", "rgba(255, 255, 255, .7)")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--panel-background-color", "#0d1117")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--hover-color", "#161b22")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--dropdown-hover-color", "#1f242c")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--border-color", "#30363d")'); - mb.window.webContents.executeJavaScript('document.documentElement.style.setProperty("--lighter-background-color", "#21262d")'); - } - if (manual) { - mb.window.webContents.executeJavaScript('document.getElementById("light-mode").classList.remove("active")') - mb.window.webContents.executeJavaScript('document.getElementById("dark-mode").classList.remove("active")') - mb.window.webContents.executeJavaScript('document.getElementById("' + option + '-mode").classList.add("active")') - } + store.theme = option; + if (option == 'light') { + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--background-color", "#fff")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--text-color", "#24292f")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--muted-text-color", "#57606a")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--placeholder-text-color", "#6e7781")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--panel-background-color", "#fff")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--hover-color", "#f6f8fa")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--dropdown-hover-color", "#f0f2f4")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--border-color", "#d0d7de")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--lighter-background-color", "#d8dee4")', + ); + } else if (option == 'dark') { + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--background-color", "#090c10")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--text-color", "#c9d1d9")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--muted-text-color", "#aaa")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--placeholder-text-color", "rgba(255, 255, 255, .7)")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--panel-background-color", "#0d1117")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--hover-color", "#161b22")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--dropdown-hover-color", "#1f242c")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--border-color", "#30363d")', + ); + mb.window.webContents.executeJavaScript( + 'document.documentElement.style.setProperty("--lighter-background-color", "#21262d")', + ); + } + if (manual) { + mb.window.webContents.executeJavaScript( + 'document.getElementById("light-mode").classList.remove("active")', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("dark-mode").classList.remove("active")', + ); + mb.window.webContents.executeJavaScript( + 'document.getElementById("' + option + '-mode").classList.add("active")', + ); + } } function logout() { - deleteFromStore('user_id') - deleteFromStore('username') - deleteFromStore('access_token') - deleteFromStore('favorite-projects') - deleteFromStore('bookmarks') - deleteFromStore('host') - deleteFromStore('plan') - deleteFromStore('analytics') - deleteFromStore('analytics_id') - mb.window.webContents.session.clearCache() - mb.window.webContents.session.clearStorageData() - app.quit() - app.relaunch() + deleteFromStore('user_id'); + deleteFromStore('username'); + deleteFromStore('access_token'); + deleteFromStore('favorite-projects'); + deleteFromStore('bookmarks'); + deleteFromStore('host'); + deleteFromStore('plan'); + deleteFromStore('analytics'); + deleteFromStore('analytics_id'); + mb.window.webContents.session.clearCache(); + mb.window.webContents.session.clearStorageData(); + app.quit(); + app.relaunch(); } diff --git a/package-lock.json b/package-lock.json index d2e6054..25da186 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "@electron-forge/publisher-github": "^6.0.0-beta.59", "electron": "^13.1.7", "mocha": "^9.1.2", + "prettier": "2.4.1", "spectron": "^15.0.0" } }, @@ -7426,6 +7427,18 @@ "node": ">=4" } }, + "node_modules/prettier": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/pretty-bytes": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", @@ -15733,6 +15746,12 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" }, + "prettier": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", + "dev": true + }, "pretty-bytes": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", diff --git a/package.json b/package.json index d9e20c9..a28c2f1 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ "start": "electron-forge start", "package": "electron-forge package", "make": "electron-forge make", - "publish": "electron-forge publish" + "publish": "electron-forge publish", + "prettier:check": "prettier --check .", + "pretier:fix": "prettier --write ." }, "repository": "https://github.com/mvremmerden/gitdock", "keywords": [ @@ -30,6 +32,7 @@ "@electron-forge/publisher-github": "^6.0.0-beta.59", "electron": "^13.1.7", "mocha": "^9.1.2", + "prettier": "2.4.1", "spectron": "^15.0.0" }, "dependencies": { diff --git a/preload.js b/preload.js index e28ae16..662fcdc 100644 --- a/preload.js +++ b/preload.js @@ -1,4 +1,4 @@ -const { contextBridge, ipcRenderer } = require('electron') +const { contextBridge, ipcRenderer } = require('electron'); const api = { goToDetail: (value) => ipcRenderer.send('detail-page', value), @@ -21,39 +21,41 @@ const api = { changeAnalytics: (value) => ipcRenderer.send('change-analytics', value), startLogin: () => ipcRenderer.send('start-login'), startManualLogin: (value) => ipcRenderer.send('start-manual-login', value), - logout: () => ipcRenderer.send('logout') -} + logout: () => ipcRenderer.send('logout'), +}; if (process.contextIsolated) { - contextBridge.exposeInMainWorld('electron', api) + contextBridge.exposeInMainWorld('electron', api); } else { function deepFreeze(o) { - Object.freeze(o) + Object.freeze(o); - Object.getOwnPropertyNames(o).forEach(prop => { - if (o.hasOwnProperty(prop) - && o[prop] !== null - && (typeof o[prop] === 'object' || typeof o[prop] === 'function') - && !Object.isFrozen(o[prop])) { - deepFreeze(o[prop]) + Object.getOwnPropertyNames(o).forEach((prop) => { + if ( + o.hasOwnProperty(prop) && + o[prop] !== null && + (typeof o[prop] === 'object' || typeof o[prop] === 'function') && + !Object.isFrozen(o[prop]) + ) { + deepFreeze(o[prop]); } - }) - return o + }); + return o; } - deepFreeze(api) + deepFreeze(api); // @ts-expect-error https://github.com/electron-userland/spectron#node-integration - window.electronRequire = require + window.electronRequire = require; // @ts-expect-error https://github.com/electron-userland/spectron/issues/693#issuecomment-747872160 - window.electron = api + window.electron = api; } window.addEventListener('DOMContentLoaded', () => { const replaceText = (selector, text) => { - const element = document.getElementById(selector) - if (element) element.innerText = text - } + const element = document.getElementById(selector); + if (element) element.innerText = text; + }; for (const type of ['chrome', 'node', 'electron']) { - replaceText(`${type}-version`, process.versions[type]) + replaceText(`${type}-version`, process.versions[type]); } -}) +}); diff --git a/renderer.js b/renderer.js index 0389f5a..0b85073 100644 --- a/renderer.js +++ b/renderer.js @@ -1,122 +1,122 @@ function goToDetail(page, object) { - let value = { - page: page, - object: object - } - document.getElementById('detail-view').style.left = 0 - document.body.style.overflow = 'hidden' - window.electron.goToDetail(value) + let value = { + page: page, + object: object, + }; + document.getElementById('detail-view').style.left = 0; + document.body.style.overflow = 'hidden'; + window.electron.goToDetail(value); } function goBackToDetail() { - document.getElementById('sub-detail-view').style.left = '100vw' - window.electron.goBackToDetail() + document.getElementById('sub-detail-view').style.left = '100vw'; + window.electron.goBackToDetail(); } function goToSubDetail(page, project, all = false) { - let value = { - page: page, - project: project, - all: all - } - document.getElementById('sub-detail-view').style.left = 0 - window.electron.goToSubDetail(value) + let value = { + page: page, + project: project, + all: all, + }; + document.getElementById('sub-detail-view').style.left = 0; + window.electron.goToSubDetail(value); } function goToOverview() { - window.electron.goToOverview() - document.getElementById('detail-view').style.left = '100vw' - document.getElementById('detail-content').innerHTML = '' - document.getElementById('detail-headline').innerHTML = '' - document.body.style.overflow = 'auto' + window.electron.goToOverview(); + document.getElementById('detail-view').style.left = '100vw'; + document.getElementById('detail-content').innerHTML = ''; + document.getElementById('detail-headline').innerHTML = ''; + document.body.style.overflow = 'auto'; } function switchIssues(value, type, text) { - let object = { - label: value, - type: type, - text: text - } - window.electron.switchIssues(object) + let object = { + label: value, + type: type, + text: text, + }; + window.electron.switchIssues(object); } function switchMRs(value, type, text) { - let object = { - label: value, - type: type, - text: text - } - window.electron.switchMRs(object) + let object = { + label: value, + type: type, + text: text, + }; + window.electron.switchMRs(object); } function switchPage(url, type) { - let value = { - url: url, - type: type - } - window.electron.switchPage(value) + let value = { + url: url, + type: type, + }; + window.electron.switchPage(value); } function searchRecent(input) { - window.electron.searchRecent(input.value) + window.electron.searchRecent(input.value); } function changeCommit(value) { - window.electron.changeCommit(value) + window.electron.changeCommit(value); } function changeProjectCommit(value) { - window.electron.changeProjectCommit(value) + window.electron.changeProjectCommit(value); } function addBookmark(value) { - window.electron.addBookmark(value) + window.electron.addBookmark(value); } function addProject(input, target) { - let value = { - input: input, - target: target - } - window.electron.addProject(value) + let value = { + input: input, + target: target, + }; + window.electron.addProject(value); } function startBookmarkDialog() { - window.electron.startBookmarkDialog() + window.electron.startBookmarkDialog(); } function startProjectDialog() { - window.electron.startProjectDialog() + window.electron.startProjectDialog(); } function deleteBookmark(value) { - window.electron.deleteBookmark(value) + window.electron.deleteBookmark(value); } function deleteProject(value) { - window.electron.deleteProject(value) + window.electron.deleteProject(value); } function changeTheme(value) { - window.electron.changeTheme(value) + window.electron.changeTheme(value); } function changeAnalytics(value) { - window.electron.changeAnalytics(value) + window.electron.changeAnalytics(value); } function startLogin() { - window.electron.startLogin() + window.electron.startLogin(); } function startManualLogin(access_token, host) { - let value = { - access_token: access_token, - host: host - } - window.electron.startManualLogin(value) + let value = { + access_token: access_token, + host: host, + }; + window.electron.startManualLogin(value); } function logout() { - window.electron.logout() -} \ No newline at end of file + window.electron.logout(); +} diff --git a/src/filter-text.js b/src/filter-text.js index 86e2401..bc85690 100644 --- a/src/filter-text.js +++ b/src/filter-text.js @@ -1,29 +1,29 @@ module.exports = { - query: "'query'", - state: "'state'", - sort: "'sort'", - allLabel: "'all'", - allText: "'All'", - assignedLabel: "'assigned_to_me'", - assignedText: "'Assigned'", - createdLabel: "'created_by_me'", - createdText: "'Created'", - openedLabel: "'opened'", - openedText: "'Open'", - closedLabel: "'closed'", - closedText: "'Closed'", - recentlyUpdatedLabel: "'updated_at'", - recentlyUpdatedText: "'Sort by recently updated'", - recentlyCreatedLabel: "'created_at'", - recentlyCreatedText: "'Sort by recently created'", - dueDateLabel: "'due_date&sort=asc'", - dueDateText: "'Sort by due date'", - reviewedLabel: "'review_requests_for_me'", - reviewedText: "'Reviewed'", - approvedLabel: "'approved_by_me'", - approvedText: "'Approved'", - mergedLabel: "'merged'", - mergedText: "'Merged'", - approvalLabel: "'approval_rule_for_me'", - approvalText: "'Approval rules'", + query: "'query'", + state: "'state'", + sort: "'sort'", + allLabel: "'all'", + allText: "'All'", + assignedLabel: "'assigned_to_me'", + assignedText: "'Assigned'", + createdLabel: "'created_by_me'", + createdText: "'Created'", + openedLabel: "'opened'", + openedText: "'Open'", + closedLabel: "'closed'", + closedText: "'Closed'", + recentlyUpdatedLabel: "'updated_at'", + recentlyUpdatedText: "'Sort by recently updated'", + recentlyCreatedLabel: "'created_at'", + recentlyCreatedText: "'Sort by recently created'", + dueDateLabel: "'due_date&sort=asc'", + dueDateText: "'Sort by due date'", + reviewedLabel: "'review_requests_for_me'", + reviewedText: "'Reviewed'", + approvedLabel: "'approved_by_me'", + approvedText: "'Approved'", + mergedLabel: "'merged'", + mergedText: "'Merged'", + approvalLabel: "'approval_rule_for_me'", + approvalText: "'Approval rules'", }; diff --git a/style.css b/style.css index e8136a7..4453c53 100644 --- a/style.css +++ b/style.css @@ -1,240 +1,245 @@ :root { - --background-color: #090c10; - --text-color: #c9d1d9; - --muted-text-color: #aaa; - --placeholder-text-color: rgba(255, 255, 255, .7); - --panel-background-color: #0d1117; - --hover-color: #161b22; - --dropdown-hover-color: #1f242c; - --dropdown-active-color: #1f6feb; - --dropdown-active-text-color: #c9d1d9; - --border-color: #30363d; - --lighter-background-color: #21262d; - --disabled-background-color: #484f58; - } + --background-color: #090c10; + --text-color: #c9d1d9; + --muted-text-color: #aaa; + --placeholder-text-color: rgba(255, 255, 255, 0.7); + --panel-background-color: #0d1117; + --hover-color: #161b22; + --dropdown-hover-color: #1f242c; + --dropdown-active-color: #1f6feb; + --dropdown-active-text-color: #c9d1d9; + --border-color: #30363d; + --lighter-background-color: #21262d; + --disabled-background-color: #484f58; +} body { - background-color: var(--background-color); - color: var(--text-color); - padding: 1.5rem; - margin: 0; - font-family: 'Inter'; - font-size: 15px; - line-height: 1.25rem; + background-color: var(--background-color); + color: var(--text-color); + padding: 1.5rem; + margin: 0; + font-family: 'Inter'; + font-size: 15px; + line-height: 1.25rem; } :focus { - outline: 0; - outline-color: transparent; - outline-style: none; - } + outline: 0; + outline-color: transparent; + outline-style: none; +} a { - color: var(--text-color); - text-decoration: none; - font-weight: bold; + color: var(--text-color); + text-decoration: none; + font-weight: bold; } a:hover { - text-decoration: underline; + text-decoration: underline; } #login-page-wrapper { - display: flex; - justify-content: center; + display: flex; + justify-content: center; } #login-page { - display: flex; - flex-direction: column; - justify-content: center; - max-width: 400px; - margin-top: 1.5rem; + display: flex; + flex-direction: column; + justify-content: center; + max-width: 400px; + margin-top: 1.5rem; } #login-page .lead { - font-weight: bold; - font-size: 1.125rem; - margin: 0.5rem 0; + font-weight: bold; + font-size: 1.125rem; + margin: 0.5rem 0; } #login-page .description { - margin-bottom: 1.5rem; + margin-bottom: 1.5rem; } #login-page #hero-wrapper { - height: 100%; - width: 100%; - display: flex; - justify-content: center; - margin-bottom: 1.5rem; + height: 100%; + width: 100%; + display: flex; + justify-content: center; + margin-bottom: 1.5rem; } #login-page svg { - max-width: 250px; - margin-bottom: 1rem; + max-width: 250px; + margin-bottom: 1rem; } -#login-page #login-gitlab-button, #login-page #login-instance-button { - padding: 0.5rem 0.75rem; - background-color: #238636; - border-radius: 0.25rem; - color: white; - border: 1px solid rgba(240, 246, 252, 0.1); - cursor: pointer; - margin-bottom: 0.5rem; +#login-page #login-gitlab-button, +#login-page #login-instance-button { + padding: 0.5rem 0.75rem; + background-color: #238636; + border-radius: 0.25rem; + color: white; + border: 1px solid rgba(240, 246, 252, 0.1); + cursor: pointer; + margin-bottom: 0.5rem; } #login-page #instance-checkbox { - margin-left: 0; + margin-left: 0; } #login-page #instance-checkbox ~ #instance-details { - display: none; - margin-top: 0.5rem; + display: none; + margin-top: 0.5rem; } #login-page #instance-checkbox ~ #instance-details .instance-details-input input { - width: 100%; - margin-right: 0.5rem; - border: 1px solid var(--hover-color); - font-size: 0.875rem; - padding: 0.5rem; - background-color: var(--lighter-background-color); - border-radius: 0.375rem; - color: var(--text-color); - box-sizing: border-box; - outline: none; + width: 100%; + margin-right: 0.5rem; + border: 1px solid var(--hover-color); + font-size: 0.875rem; + padding: 0.5rem; + background-color: var(--lighter-background-color); + border-radius: 0.375rem; + color: var(--text-color); + box-sizing: border-box; + outline: none; } #login-page #instance-checkbox ~ #instance-details .instance-details-input label { - font-weight: bold; + font-weight: bold; } #login-page #instance-checkbox:checked ~ #instance-details { - display: flex; - flex-direction: column; + display: flex; + flex-direction: column; } #login-page #instance-checkbox:checked ~ #instance-details .instance-details-input { - display: flex; - flex-direction: column; - margin-bottom: 1rem; + display: flex; + flex-direction: column; + margin-bottom: 1rem; } .icon { - fill: var(--text-color) + fill: var(--text-color); } .icon-muted { - fill: var(--muted-text-color); + fill: var(--muted-text-color); } .icon-inverse { - fill: var(--background-color) + fill: var(--background-color); } #header { - display: flex; - justify-content: space-between; - align-items: center; - background-color: var(--hover-color); - border-bottom: 1px solid var(--border-color); - margin: -1.5rem -1.5rem -0.5rem -1.5rem; - padding: 1.5rem 1.5rem 1.5rem 1.5rem; + display: flex; + justify-content: space-between; + align-items: center; + background-color: var(--hover-color); + border-bottom: 1px solid var(--border-color); + margin: -1.5rem -1.5rem -0.5rem -1.5rem; + padding: 1.5rem 1.5rem 1.5rem 1.5rem; } #header #user { - flex-grow: 1; - overflow: hidden; + flex-grow: 1; + overflow: hidden; } #header #user a { - display: flex; - align-items: center; - width: fit-content; - max-width: 100%; + display: flex; + align-items: center; + width: fit-content; + max-width: 100%; } #header #user a img { - width: 2.5rem; - border-radius: 2.5rem; - margin-right: 0.5rem; + width: 2.5rem; + border-radius: 2.5rem; + margin-right: 0.5rem; } #header #user a .user-information { - display: flex; - flex-direction: column; - overflow: hidden; + display: flex; + flex-direction: column; + overflow: hidden; } #header #user a .user-name { - font-size: 1.125rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; + font-size: 1.125rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; } #header #user a .username { - font-weight: normal; - color: var(--muted-text-color); - font-size: 0.875rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; + font-weight: normal; + color: var(--muted-text-color); + font-size: 0.875rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; } #header #counts { - display: flex; - flex-grow: 1; - justify-content: flex-end; - margin: -0.375rem 0 -0.25rem; - margin-right: -0.5rem; + display: flex; + flex-grow: 1; + justify-content: flex-end; + margin: -0.375rem 0 -0.25rem; + margin-right: -0.5rem; } #header #counts .count { - padding: 0.5rem 0.25rem 0.25rem; - margin-left: 0.25rem; - border-radius: 0.375rem; - align-items: center; - display: flex; - flex-direction: column; - color: var(--muted-text-color); - font-size: 0.825rem; + padding: 0.5rem 0.25rem 0.25rem; + margin-left: 0.25rem; + border-radius: 0.375rem; + align-items: center; + display: flex; + flex-direction: column; + color: var(--muted-text-color); + font-size: 0.825rem; } #header #counts .count:hover { - background-color: var(--border-color); - cursor: pointer; + background-color: var(--border-color); + cursor: pointer; } #header #counts .count svg { - width: 1rem; + width: 1rem; } #header #counts .count span { - padding: 2px 0.375rem; - border-radius: 2.5rem; - margin-top: 2px; - line-height: 1rem; - white-space: nowrap; + padding: 2px 0.375rem; + border-radius: 2.5rem; + margin-top: 2px; + line-height: 1rem; + white-space: nowrap; } .headline { - display: flex; - align-items: center; - justify-content: space-between; - font-size: 1.25rem; - font-weight: bold; - margin: 2rem 0 1rem; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 1.25rem; + font-weight: bold; + margin: 2rem 0 1rem; } .headline:first-of-type { - margin-top: 0; + margin-top: 0; } .headline #commits-pagination { - display: flex; - align-items: center; + display: flex; + align-items: center; } .headline #project-commits-pagination { - display: flex; - justify-content: space-between; + display: flex; + justify-content: space-between; } -.headline #commits-pagination button, .headline #project-commits-pagination button { - border: 1px solid var(--border-color); - border-radius: 5rem; - width: 1.5rem; - height: 1.5rem; - display: flex; - align-items: center; - justify-content: center; - background-color: var(--background-color); - color: var(--text-color); - margin-left: 0.25rem; - cursor: pointer; +.headline #commits-pagination button, +.headline #project-commits-pagination button { + border: 1px solid var(--border-color); + border-radius: 5rem; + width: 1.5rem; + height: 1.5rem; + display: flex; + align-items: center; + justify-content: center; + background-color: var(--background-color); + color: var(--text-color); + margin-left: 0.25rem; + cursor: pointer; } -.headline #commits-pagination button:hover, .headline #project-commits-pagination button:hover { - background-color: var(--hover-color); +.headline #commits-pagination button:hover, +.headline #project-commits-pagination button:hover { + background-color: var(--hover-color); } -.headline #commits-pagination #commits-count, .headline #project-commits-pagination #project-commits-count { - font-size: 0.825rem; - color: var(--muted-text-color); - font-weight: normal; - margin: 0 0.25rem; +.headline #commits-pagination #commits-count, +.headline #project-commits-pagination #project-commits-count { + font-size: 0.825rem; + color: var(--muted-text-color); + font-weight: normal; + margin: 0 0.25rem; } -.headline #commits-pagination #commits-count.empty, .headline #project-commits-pagination #project-commits-count.empty { - width: 2rem; - height: 0.825rem; - background-color: var(--border-color); - margin-top: 2px; +.headline #commits-pagination #commits-count.empty, +.headline #project-commits-pagination #project-commits-count.empty { + width: 2rem; + height: 0.825rem; + background-color: var(--border-color); + margin-top: 2px; } /*.headline #edit-favorite-projects { font-size: 0.875rem; @@ -250,694 +255,748 @@ a:hover { background-color: var(--border-color); }*/ .headline.with-overflow { - overflow: visible!important; + overflow: visible !important; } -.headline .filter-sort { - display: flex; - padding: 0.5rem 0; +.headline .filter-sort { + display: flex; + padding: 0.5rem 0; } .headline .custom-select-active { - cursor: pointer; - background-color: var(--background-color); - border: 1px solid var(--border-color); - border-radius: 2rem; - padding: 0.25rem 2rem 0.25rem 0.75rem; - width: fit-content; - position: relative; - color: var(--text-color); + cursor: pointer; + background-color: var(--background-color); + border: 1px solid var(--border-color); + border-radius: 2rem; + padding: 0.25rem 2rem 0.25rem 0.75rem; + width: fit-content; + position: relative; + color: var(--text-color); } .headline .custom-select-active.changed { - background-color: var(--dropdown-active-color); - color: white + background-color: var(--dropdown-active-color); + color: white; } .headline .custom-select-active.changed:after { - border-top-color: white; + border-top-color: white; } .headline .custom-select-active:after { - content:''; - width: 0; - height: 0; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-top: 5px solid var(--text-color); - position:absolute; - right:0.75rem; - top:calc(50% - 2.5px); - pointer-events:none; - z-index:3; + content: ''; + width: 0; + height: 0; + border-left: 5px solid transparent; + border-right: 5px solid transparent; + border-top: 5px solid var(--text-color); + position: absolute; + right: 0.75rem; + top: calc(50% - 2.5px); + pointer-events: none; + z-index: 3; } .headline .custom-select { - display:flex; - flex-direction: column; - position:relative; - height: 1.75rem; - margin-right: 0.75rem; + display: flex; + flex-direction: column; + position: relative; + height: 1.75rem; + margin-right: 0.75rem; } .headline .custom-options-wrapper { - position: absolute; - top: 2rem; + position: absolute; + top: 2rem; } .headline .custom-select .custom-option-label { - padding: 0 1rem 0 0.75rem; - min-height: 2.5rem; - display: none; - align-items: center; - background-color: var(--hover-color); - border: 1px solid var(--border-color); - border-bottom: none; - color: var(--text-color); - position: absolute; - top: 0.5rem; - width: 115%; - pointer-events:none; - z-index:99; - box-sizing:border-box; - overflow:hidden; - white-space:nowrap; + padding: 0 1rem 0 0.75rem; + min-height: 2.5rem; + display: none; + align-items: center; + background-color: var(--hover-color); + border: 1px solid var(--border-color); + border-bottom: none; + color: var(--text-color); + position: absolute; + top: 0.5rem; + width: 115%; + pointer-events: none; + z-index: 99; + box-sizing: border-box; + overflow: hidden; + white-space: nowrap; } .headline .custom-select .custom-option-label:first-of-type { - border-top-left-radius: 0.75rem; - border-top-right-radius: 0.75rem; - border-top-color: var(--border-color); + border-top-left-radius: 0.75rem; + border-top-right-radius: 0.75rem; + border-top-color: var(--border-color); } .headline .custom-select .custom-option-label:last-of-type { - border-bottom-left-radius: 0.75rem; - border-bottom-right-radius: 0.75rem; - border-bottom: 1px solid var(--border-color);; + border-bottom-left-radius: 0.75rem; + border-bottom-right-radius: 0.75rem; + border-bottom: 1px solid var(--border-color); } .headline .custom-select .custom-option-label:hover { - cursor: pointer; + cursor: pointer; } .headline .custom-select:focus { - pointer-events: none; + pointer-events: none; } .headline .custom-select:focus .custom-option-label { - position:relative; - pointer-events:all; - display: flex; + position: relative; + pointer-events: all; + display: flex; } .headline .custom-select:focus .custom-option-label:hover { - background-color: var(--dropdown-hover-color); + background-color: var(--dropdown-hover-color); } -.headline .custom-select input[type=radio] { - opacity:0; - position:absolute; - left:-99999px; +.headline .custom-select input[type='radio'] { + opacity: 0; + position: absolute; + left: -99999px; } -.headline .custom-select input[type=radio]:checked + label:after { - content:'✓'; - position:absolute; - right: 0.625rem; - top: 0.625rem; - pointer-events:none; - z-index:3; - color: var(--text-color); +.headline .custom-select input[type='radio']:checked + label:after { + content: '✓'; + position: absolute; + right: 0.625rem; + top: 0.625rem; + pointer-events: none; + z-index: 3; + color: var(--text-color); } .namespace-with-time { - font-size: 0.825rem; - color: var(--muted-text-color); + font-size: 0.825rem; + color: var(--muted-text-color); } .namespace-with-time a { - font-weight: normal; - color: var(--muted-text-color); + font-weight: normal; + color: var(--muted-text-color); } -.commit svg, .commit img, .commit #project-name { - min-width: 1.5rem; - height: 1.5rem; - border-radius: 1.5rem; - border: 1px solid transparent; +.commit svg, +.commit img, +.commit #project-name { + min-width: 1.5rem; + height: 1.5rem; + border-radius: 1.5rem; + border: 1px solid transparent; } .commit img { - background-color: var(--border-color); + background-color: var(--border-color); } .commit #project-name { - display: flex; - align-items: center; - justify-content: center; - border: 1px solid var(--border-color); + display: flex; + align-items: center; + justify-content: center; + border: 1px solid var(--border-color); } .commit.empty #project-name { - background-color: var(--border-color); - border: 1px solid var(--border-color); + background-color: var(--border-color); + border: 1px solid var(--border-color); } .commit { - display: flex; - align-items: center; - padding: 0.5rem 0.75rem; - background-color: var(--panel-background-color); - border: 1px solid var(--border-color); - border-radius: 0.375rem; - min-height: 2.5rem; + display: flex; + align-items: center; + padding: 0.5rem 0.75rem; + background-color: var(--panel-background-color); + border: 1px solid var(--border-color); + border-radius: 0.375rem; + min-height: 2.5rem; } .commit:hover { - background-color: var(--hover-color); + background-color: var(--hover-color); } .commit:hover .icon-inverse { - fill: var(--lighter-background-color); + fill: var(--lighter-background-color); } .commit .pipeline-link { - margin-left: 0.75rem; + margin-left: 0.75rem; } .commit .pipeline-link:hover .icon-inverse { - fill: var(--border-color); + fill: var(--border-color); } -.commit.empty .commit-name, .history-entry.empty .history-link, .comment.empty .comment-link { - width: 80%; - background-color: var(--border-color); - height: 1rem; - margin-bottom: 0.5rem; +.commit.empty .commit-name, +.history-entry.empty .history-link, +.comment.empty .comment-link { + width: 80%; + background-color: var(--border-color); + height: 1rem; + margin-bottom: 0.5rem; } -.commit.empty .commit-details, .history-entry.empty .history-details, .comment.empty .comment-details { - width: 65%; - background-color: var(--border-color); - height: 0.875rem; +.commit.empty .commit-details, +.history-entry.empty .history-details, +.comment.empty .comment-details { + width: 65%; + background-color: var(--border-color); + height: 0.875rem; } -.history-entry.empty .history-details, .comment.empty .comment-details { - width: 45%; +.history-entry.empty .history-details, +.comment.empty .comment-details { + width: 45%; } -.commit-information, .todo-information, .history-entry { - display: flex; - flex-direction: column; - width: 100%; - overflow: hidden; +.commit-information, +.todo-information, +.history-entry { + display: flex; + flex-direction: column; + width: 100%; + overflow: hidden; } .commit-information a { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - width: fit-content; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + width: fit-content; } -.todo, .history-entry, .comment { - display: flex; - align-items: center; - width: calc(100% - 2rem); - box-sizing: border-box; +.todo, +.history-entry, +.comment { + display: flex; + align-items: center; + width: calc(100% - 2rem); + box-sizing: border-box; } -.todo.empty, .history-entry.empty, .comment.empty { - height: 65px; +.todo.empty, +.history-entry.empty, +.comment.empty { + height: 65px; } .bookmark-entry { - flex-direction: row!important; + flex-direction: row !important; } .bookmark-entry .bookmark-information { - display: flex; - flex-direction: column; - width: calc(100% - 4rem); + display: flex; + flex-direction: column; + width: calc(100% - 4rem); } .bookmark-delete-wrapper { - width: 3.5rem; - height: 2.5rem; - margin-left: auto; - margin-right: -0.75rem; - border-left: 1px solid var(--lighter-background-color); - display: flex; - align-items: center; - justify-content: center; + width: 3.5rem; + height: 2.5rem; + margin-left: auto; + margin-right: -0.75rem; + border-left: 1px solid var(--lighter-background-color); + display: flex; + align-items: center; + justify-content: center; } .bookmark-delete-wrapper .bookmark-delete svg { - width: 1rem; - margin: 0; - line-height: 1; + width: 1rem; + margin: 0; + line-height: 1; } .bookmark-delete-wrapper .bookmark-delete { - padding: 0.5rem 0.5rem 0.425rem; - border-radius: 0.375rem; - line-height: 1; + padding: 0.5rem 0.5rem 0.425rem; + border-radius: 0.375rem; + line-height: 1; } .bookmark-delete-wrapper .bookmark-delete:hover { - background-color: var(--border-color); - cursor: pointer; + background-color: var(--border-color); + cursor: pointer; } -.list-container li.history-entry, .list-container li.comment { - align-items: flex-start; - flex-direction: column; +.list-container li.history-entry, +.list-container li.comment { + align-items: flex-start; + flex-direction: column; } -.todo img, #history img { - width: 2rem; - border-radius: 2rem; - margin-right: 1rem; +.todo img, +#history img { + width: 2rem; + border-radius: 2rem; + margin-right: 1rem; } -.todo-information, .history-entry, .comment { - width: 100%; - box-sizing: border-box; +.todo-information, +.history-entry, +.comment { + width: 100%; + box-sizing: border-box; } -.todo-information a, .todo-information span, .history-entry a, .history-entry span, .comment a, .comment span, .commit-information span { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 100%; +.todo-information a, +.todo-information span, +.history-entry a, +.history-entry span, +.comment a, +.comment span, +.commit-information span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; } .list-container { - padding: 0; - background-color: var(--panel-background-color); - border: 1px solid var(--border-color); - border-radius: 0.375rem; - overflow: hidden; - box-sizing: border-box; + padding: 0; + background-color: var(--panel-background-color); + border: 1px solid var(--border-color); + border-radius: 0.375rem; + overflow: hidden; + box-sizing: border-box; } .list-container.empty.with-pagination { - margin-bottom: 73px; + margin-bottom: 73px; } .list-container li { - list-style-type: none; - padding: 0.75rem; - display: flex; - align-items: center; - border-bottom: 1px solid var(--lighter-background-color); - font-weight: bold; + list-style-type: none; + padding: 0.75rem; + display: flex; + align-items: center; + border-bottom: 1px solid var(--lighter-background-color); + font-weight: bold; } .list-container.clickable li { - cursor: pointer; + cursor: pointer; } .list-container#projects li { - padding: 0.5rem 0.75rem; + padding: 0.5rem 0.75rem; } .list-container li:hover { - background-color: var(--hover-color); + background-color: var(--hover-color); } .list-container li:last-of-type { - border-bottom: none; + border-bottom: none; } .list-container.empty li.empty:last-of-type:not(.more-link) { - height: 64px; + height: 64px; } .list-container li.more-link { - box-sizing: border-box; + box-sizing: border-box; } .list-container li.more-link.empty { - height: 44px; + height: 44px; } -.list-container li.more-link a { - display: flex; - cursor: pointer; - align-items: center; - font-weight: normal; - font-size: 0.825rem; - color: var(--muted-text-color); +.list-container li.more-link a { + display: flex; + cursor: pointer; + align-items: center; + font-weight: normal; + font-size: 0.825rem; + color: var(--muted-text-color); } .list-container li.more-link a svg { - margin: 2px 0 0 0; + margin: 2px 0 0 0; } .list-container li.more-link.empty .more-link-button { - width: 30%; - height: 0.875rem; - background-color: var(--border-color); + width: 30%; + height: 0.875rem; + background-color: var(--border-color); } -.list-container li svg, .list-container li img { - width: 1rem; - height: 1rem; - margin: 0 1rem 0 0.5rem; +.list-container li svg, +.list-container li img { + width: 1rem; + height: 1rem; + margin: 0 1rem 0 0.5rem; } .list-container li svg.chevron { - width: 1rem; - margin: 0; - margin-left: auto; + width: 1rem; + margin: 0; + margin-left: auto; } .list-container li .name-with-namespace { - display: flex; - flex-direction: column; + display: flex; + flex-direction: column; } -.list-container li .name-with-namespace .namespace, .list-container li .namespace-with-time { - font-weight: normal; - font-size: 0.825rem; - color: var(--muted-text-color); +.list-container li .name-with-namespace .namespace, +.list-container li .namespace-with-time { + font-weight: normal; + font-size: 0.825rem; + color: var(--muted-text-color); } .all-link { - margin-bottom: 1rem; - display: inline-block; + margin-bottom: 1rem; + display: inline-block; } .all-link a { - display: flex; - align-items: center; - cursor: pointer; + display: flex; + align-items: center; + cursor: pointer; } .all-link svg { - width: 1rem; - fill: var(--text-color); + width: 1rem; + fill: var(--text-color); } -#bookmarks #new-bookmark, #projects .new-project { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - border: 2px dashed var(--lighter-background-color); - border-radius: 0.375rem; - padding: 1rem; - background-color: var(--panel-background-color); +#bookmarks #new-bookmark, +#projects .new-project { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + border: 2px dashed var(--lighter-background-color); + border-radius: 0.375rem; + padding: 1rem; + background-color: var(--panel-background-color); } -#bookmarks .cta, .new-project .cta { - margin: 0 0.5rem 0.5rem 0; - font-weight: 1.125rem; - font-weight: bold; - display: inline-block; +#bookmarks .cta, +.new-project .cta { + margin: 0 0.5rem 0.5rem 0; + font-weight: 1.125rem; + font-weight: bold; + display: inline-block; } -#bookmarks .cta-description, .new-project .cta-description { - font-size: 0.825rem; - color: var(--muted-text-color); - width: 100%; - margin-bottom: 1rem; +#bookmarks .cta-description, +.new-project .cta-description { + font-size: 0.825rem; + color: var(--muted-text-color); + width: 100%; + margin-bottom: 1rem; } -#bookmarks #bookmark-input, .new-project .project-input { - display: flex; - align-items: center; - width: 100%; +#bookmarks #bookmark-input, +.new-project .project-input { + display: flex; + align-items: center; + width: 100%; } -#bookmarks #add-bookmark-error, .new-project .add-project-error, #favorite-projects .add-project-error { - margin: 0.5rem auto 0 0; - font-weight: normal; - color: #f85149; - font-size: 0.875rem; - display: none; +#bookmarks #add-bookmark-error, +.new-project .add-project-error, +#favorite-projects .add-project-error { + margin: 0.5rem auto 0 0; + font-weight: normal; + color: #f85149; + font-size: 0.875rem; + display: none; } -#bookmarks #add-bookmark-dialog.opened, #favorite-projects #add-project-dialog.opened { - background-color: var(--panel-background-color); - display: flex; - flex-direction: column; -} -#bookmarks #add-bookmark-dialog #bookmark-input, #favorite-projects #add-project-dialog .project-input { - display: flex; - align-items: center; - width: 100%; +#bookmarks #add-bookmark-dialog.opened, +#favorite-projects #add-project-dialog.opened { + background-color: var(--panel-background-color); + display: flex; + flex-direction: column; } -#bookmarks #bookmark-link, .project-input .project-link { - width: 100%; - margin-right: 0.5rem; - border: 1px solid var(--border-color); - font-size: 0.875rem; - padding: 0.5rem; - background-color: var(--lighter-background-color); - border-radius: 0.375rem; - color: var(--text-color); - box-sizing: border-box; - outline: none; +#bookmarks #add-bookmark-dialog #bookmark-input, +#favorite-projects #add-project-dialog .project-input { + display: flex; + align-items: center; + width: 100%; } -#bookmarks #bookmark-link::placeholder, .new-project .project-link::placeholder, #favorite-projects .project-link::placeholder { - color: var(--placeholder-text-color); +#bookmarks #bookmark-link, +.project-input .project-link { + width: 100%; + margin-right: 0.5rem; + border: 1px solid var(--border-color); + font-size: 0.875rem; + padding: 0.5rem; + background-color: var(--lighter-background-color); + border-radius: 0.375rem; + color: var(--text-color); + box-sizing: border-box; + outline: none; } -#bookmarks #bookmark-link:disabled, .new-project .project-link:disabled, #favorite-projects .project-link:disabled { - color: var(--disabled-background-color); - cursor: not-allowed; +#bookmarks #bookmark-link::placeholder, +.new-project .project-link::placeholder, +#favorite-projects .project-link::placeholder { + color: var(--placeholder-text-color); } -.add-button, #logout-button { - background-color: var(--lighter-background-color); - border: 1px solid var(--border-color); - color: var(--text-color); - font-size: 0.875rem; - border-radius: 0.375rem; - padding: 0.5rem 0.75rem; - display: flex; - align-items: center; - cursor: pointer; +#bookmarks #bookmark-link:disabled, +.new-project .project-link:disabled, +#favorite-projects .project-link:disabled { + color: var(--disabled-background-color); + cursor: not-allowed; +} +.add-button, +#logout-button { + background-color: var(--lighter-background-color); + border: 1px solid var(--border-color); + color: var(--text-color); + font-size: 0.875rem; + border-radius: 0.375rem; + padding: 0.5rem 0.75rem; + display: flex; + align-items: center; + cursor: pointer; } .add-button svg.button-spinner { - width: 1rem; - margin-right: 0.5rem; - margin-left: 0; - -webkit-animation:spin 2s linear infinite; - -moz-animation:spin 2s linear infinite; - animation:spin 2s linear infinite; + width: 1rem; + margin-right: 0.5rem; + margin-left: 0; + -webkit-animation: spin 2s linear infinite; + -moz-animation: spin 2s linear infinite; + animation: spin 2s linear infinite; } -.add-button:hover, #logout-button:hover { - background-color: var(--border-color); - border: 1px solid #8b949e; +.add-button:hover, +#logout-button:hover { + background-color: var(--border-color); + border: 1px solid #8b949e; } .add-button:disabled { - background-color: var(--lighter-background-color); - border: 1px solid var(--border-color); - color: var(--disabled-background-color); - cursor: not-allowed; + background-color: var(--lighter-background-color); + border: 1px solid var(--border-color); + color: var(--disabled-background-color); + cursor: not-allowed; } .detail-view { - position: fixed; - width: 100vw; - height: 100vh; - overflow: scroll; - left: 100vw; - top: 0; - padding: 0; - box-sizing: border-box; - background-color: var(--background-color); - transition: 250ms ease-in; + position: fixed; + width: 100vw; + height: 100vh; + overflow: scroll; + left: 100vw; + top: 0; + padding: 0; + box-sizing: border-box; + background-color: var(--background-color); + transition: 250ms ease-in; } .detail-view .detail-header { - display: flex; - position: sticky; - top: 0; - background-color: var(--hover-color); - align-items: center; - cursor: pointer; - padding: 1rem 1.5rem; - border-bottom: 1px solid var(--border-color); - z-index: 999; + display: flex; + position: sticky; + top: 0; + background-color: var(--hover-color); + align-items: center; + cursor: pointer; + padding: 1rem 1.5rem; + border-bottom: 1px solid var(--border-color); + z-index: 999; } .detail-view .detail-header svg { - width: 1rem; - margin-right: 0.125rem; + width: 1rem; + margin-right: 0.125rem; } .detail-view .detail-header .detail-header-content { - display: flex; - align-items: center; - line-height: 1; - width: 100%; - justify-content: space-between; + display: flex; + align-items: center; + line-height: 1; + width: 100%; + justify-content: space-between; } .detail-view .detail-header .detail-header-content.empty { - width: 5rem; - height: 1rem; - background-color: var(--border-color); + width: 5rem; + height: 1rem; + background-color: var(--border-color); } .detail-view .detail-header #project-detail-information { - display: flex; - align-items: center; - margin: 0 0.375rem; + display: flex; + align-items: center; + margin: 0 0.375rem; } .detail-view .detail-header #project-detail-information img { - width: 1.5rem; - height: 1.5rem; - background-color: var(--border-color); - border-radius: 1rem; - margin-right: 0.75rem; + width: 1.5rem; + height: 1.5rem; + background-color: var(--border-color); + border-radius: 1rem; + margin-right: 0.75rem; } .detail-view .detail-header #project-detail-information div { - display: flex; - flex-direction: column; - line-height: 1.5rem; + display: flex; + flex-direction: column; + line-height: 1.5rem; } .detail-view .detail-header #project-detail-name-avatar { - display: flex; - align-items: center; - justify-content: center; - border: 1px solid var(--border-color); - width: 1.5rem; - height: 1.5rem; - border-radius: 1.5rem; - margin-right: 0.75rem; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid var(--border-color); + width: 1.5rem; + height: 1.5rem; + border-radius: 1.5rem; + margin-right: 0.75rem; } .detail-view .detail-header .project-name { - margin-right: 0.5rem; - font-size: 1rem; - font-weight: bold; - color: var(--text-color); + margin-right: 0.5rem; + font-size: 1rem; + font-weight: bold; + color: var(--text-color); } .detail-view .detail-header .project-namespace { - font-size: 0.825rem; - color: var(--muted-text-color); - margin-top: 0.175rem; + font-size: 0.825rem; + color: var(--muted-text-color); + margin-top: 0.175rem; } .detail-view .detail-header .detail-external-link { - margin: -0.5rem; + margin: -0.5rem; } .detail-view .detail-header .detail-external-link a { - padding: 0.5rem; - display: flex; - align-items: center; - cursor: pointer; + padding: 0.5rem; + display: flex; + align-items: center; + cursor: pointer; } .detail-view .detail-header .detail-external-link a svg { - cursor: pointer; - fill: var(--text-color); + cursor: pointer; + fill: var(--text-color); } .detail-view .detail-header .detail-external-link a:hover { - background-color: var(--border-color); - border-radius: 0.375rem; + background-color: var(--border-color); + border-radius: 0.375rem; } -.detail-view .detail-headline, .detail-view .detail-content { - padding: 0 1.5rem; - width: 100%; - box-sizing: border-box; +.detail-view .detail-headline, +.detail-view .detail-content { + padding: 0 1.5rem; + width: 100%; + box-sizing: border-box; } .detail-view .headline { - margin: 1rem 0 0.5rem; - display: inline-block; - justify-content: flex-start; - align-items: baseline; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - max-width: 100%; - font-weight: normal; - font-size: 0.875rem; - color: var(--muted-text-color); + margin: 1rem 0 0.5rem; + display: inline-block; + justify-content: flex-start; + align-items: baseline; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 100%; + font-weight: normal; + font-size: 0.875rem; + color: var(--muted-text-color); } .detail-view .headline .name { - font-size: 1.25rem; - font-weight: bold; - color: var(--text-color); + font-size: 1.25rem; + font-weight: bold; + color: var(--text-color); } -.detail-view .detail-headline input[type=text] { - border: none; - font-size: 0.875rem; - padding: 0.5rem 0.75rem; - background-color: var(--lighter-background-color); - border-radius: 0.375rem; - color: var(--text-color); - width: 100%; - box-sizing: border-box; +.detail-view .detail-headline input[type='text'] { + border: none; + font-size: 0.875rem; + padding: 0.5rem 0.75rem; + background-color: var(--lighter-background-color); + border-radius: 0.375rem; + color: var(--text-color); + width: 100%; + box-sizing: border-box; } -.detail-view .detail-headline input[type=text]:focus { - border: none; - outline: none; +.detail-view .detail-headline input[type='text']:focus { + border: none; + outline: none; } -.detail-view .detail-headline input[type=text]::placeholder { - color: var(--placeholder-text-color); +.detail-view .detail-headline input[type='text']::placeholder { + color: var(--placeholder-text-color); } .detail-view .detail-content { - margin-bottom: 1.5rem; + margin-bottom: 1.5rem; } .detail-view .detail-content .date { - margin: 1.5rem 0 1rem; - font-size: 1.125rem; - font-weight: bold; + margin: 1.5rem 0 1rem; + font-size: 1.125rem; + font-weight: bold; } .detail-view .detail-content .date:first-of-type { - margin-top: 0.5rem; + margin-top: 0.5rem; } .detail-view .detail-content .list-container { - margin-top: 0; + margin-top: 0; } .detail-view .detail-content .list-container.history-list-container { - margin-top: 0; + margin-top: 0; } .detail-view .detail-content .zero { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - min-height: 3rem; - padding-top: 2rem; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 3rem; + padding-top: 2rem; } .detail-view .detail-content .zero svg { - margin-bottom: 1rem; + margin-bottom: 1rem; } .no-results { - margin-top: 0; + margin-top: 0; } .no-results.with-all-link { - margin-bottom: 0.5rem; + margin-bottom: 0.5rem; } .no-results .supported-browsers { - font-size: 0.825rem; - color: var(--muted-text-color); - margin-top: 0.25rem; - display: inline-block; + font-size: 0.825rem; + color: var(--muted-text-color); + margin-top: 0.25rem; + display: inline-block; } .detail-view .detail-content #pagination { - display: flex; - justify-content: space-between; + display: flex; + justify-content: space-between; } .detail-view .detail-content #pagination button { - background-color: var(--panel-background-color); - border: 1px solid var(--border-color); - color: var(--text-color); - font-size: 0.875rem; - border-radius: 0.375rem; - padding: 0.5rem 0.75rem 0.5rem 0.5rem; - display: flex; - align-items: center; + background-color: var(--panel-background-color); + border: 1px solid var(--border-color); + color: var(--text-color); + font-size: 0.875rem; + border-radius: 0.375rem; + padding: 0.5rem 0.75rem 0.5rem 0.5rem; + display: flex; + align-items: center; } .detail-view .detail-content #pagination button:hover { - cursor: pointer; - background-color: var(--hover-color); + cursor: pointer; + background-color: var(--hover-color); } .detail-view .detail-content #pagination button svg { - width: 0.875rem; - margin-right: 0.25rem; + width: 0.875rem; + margin-right: 0.25rem; } .detail-view .detail-content #pagination button.next { - padding: 0.5rem 0.5rem 0.5rem 0.75rem; + padding: 0.5rem 0.5rem 0.5rem 0.75rem; } .detail-view .detail-content #pagination button.next svg { - margin-right: 0; - margin-left: 0.25rem; + margin-right: 0; + margin-left: 0.25rem; } .detail-view .detail-content #project-pipeline .commit { - margin-bottom: 1rem; + margin-bottom: 1rem; } .detail-view .detail-content #theme-selection { - margin-bottom: 1rem; - display: flex; - align-items: center; + margin-bottom: 1rem; + display: flex; + align-items: center; } .detail-view .detail-content #theme-selection .theme-option { - padding: 0.75rem 1.5rem 0.75rem 1.25rem; - margin-right: 1rem; - border-radius: 0.375rem; - cursor: pointer; - display: flex; - align-items: center; - box-sizing: border-box; + padding: 0.75rem 1.5rem 0.75rem 1.25rem; + margin-right: 1rem; + border-radius: 0.375rem; + cursor: pointer; + display: flex; + align-items: center; + box-sizing: border-box; } .detail-view .detail-content #theme-selection .theme-option.active { - border: 2px solid #1f6feb!important; + border: 2px solid #1f6feb !important; } .detail-view .detail-content #theme-selection .theme-option .indicator { - width: 1rem; - height: 1rem; - border: 1px solid #30363d; - border-radius: 1rem; - margin-right: 0.5rem; - display: flex; - align-items: center; - background-position: center; - background-repeat: no-repeat; + width: 1rem; + height: 1rem; + border: 1px solid #30363d; + border-radius: 1rem; + margin-right: 0.5rem; + display: flex; + align-items: center; + background-position: center; + background-repeat: no-repeat; } .detail-view .detail-content #theme-selection .theme-option#light-mode { - background-color: #fff; - color: #24292f; - border: 1px solid #d0d7de; + background-color: #fff; + color: #24292f; + border: 1px solid #d0d7de; } .detail-view .detail-content #theme-selection .theme-option#light-mode .indicator { - border-color: #d0d7de; + border-color: #d0d7de; } .detail-view .detail-content #theme-selection .theme-option#dark-mode { - background-color: #090c10; - color: #c9d1d9; - border: 1px solid #30363d; + background-color: #090c10; + color: #c9d1d9; + border: 1px solid #30363d; } .detail-view .detail-content #theme-selection .theme-option#dark-mode .indicator { - border-color: #30363d; + border-color: #30363d; } .detail-view .detail-content #theme-selection .theme-option.active .indicator { - background-color: #1f6feb; - background-image: url('data:image/svg+xml;utf8,'); + background-color: #1f6feb; + background-image: url('data:image/svg+xml;utf8,'); } #analytics { - margin-top: -0.5rem; - font-size: 0.825rem; - color: var(--muted-text-color); + margin-top: -0.5rem; + font-size: 0.825rem; + color: var(--muted-text-color); } #analytics-form { - margin: 0.5rem 0; - display: flex; - flex-direction: column; + margin: 0.5rem 0; + display: flex; + flex-direction: column; } #analytics-form div { - margin-bottom: 0.5rem; + margin-bottom: 0.5rem; } #analytics-form input { - margin-left: 0; - margin-right: 0.5rem; + margin-left: 0; + margin-right: 0.5rem; +} +@-moz-keyframes spin { + 100% { + -moz-transform: rotate(360deg); + } +} +@-webkit-keyframes spin { + 100% { + -webkit-transform: rotate(360deg); + } +} +@keyframes spin { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } } -@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } } -@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } } -@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } } \ No newline at end of file diff --git a/test/spec.js b/test/spec.js index 42a502b..beaa67a 100644 --- a/test/spec.js +++ b/test/spec.js @@ -1,107 +1,125 @@ -const Application = require('spectron').Application -const assert = require('assert') -const electronPath = require('electron') -const path = require('path') +const Application = require('spectron').Application; +const assert = require('assert'); +const electronPath = require('electron'); +const path = require('path'); describe('Application launch', function () { - this.timeout(25000) + this.timeout(25000); beforeEach(function (done) { this.app = new Application({ path: electronPath, - args: ['--no-sandbox', '--ignore-certificate-error', '--disable-dev-shm-usage', '--whitelisted-ips=', path.join(__dirname, '..')], - env: { NODE_ENV: 'test' } - }) + args: [ + '--no-sandbox', + '--ignore-certificate-error', + '--disable-dev-shm-usage', + '--whitelisted-ips=', + path.join(__dirname, '..'), + ], + env: { NODE_ENV: 'test' }, + }); this.app.start().then(() => { - done() - }) - }) + done(); + }); + }); afterEach(function () { if (this.app && this.app.isRunning()) { - return this.app.stop() + return this.app.stop(); } - }) + }); it('shows an initial window', function () { return this.app.client.getWindowCount().then(function (count) { - assert.equal(count, 1) - }) - }) + assert.equal(count, 1); + }); + }); it('has the right size', function () { return this.app.client.browserWindow.getSize().then(function (sizes) { - assert.equal(sizes[0], 550) && assert.equal(sizes[1], 700) - }) - }) + assert.equal(sizes[0], 550) && assert.equal(sizes[1], 700); + }); + }); it('can log in', async function () { - let element = await this.app.client.$('#instance-checkbox') - return element.click().then(async () => { - let token = await this.app.client.$('#access-token-input') - let url = await this.app.client.$('#instance-url-input') - await token.setValue(process.env.ACCESS_TOKEN) - await url.setValue('https://gitlab.com') - let button = await this.app.client.$('#login-instance-button') - return button.click() - }).then(async () => { - let issues = await this.app.client.$('#issues-count') - let mrs = await this.app.client.$('#mrs-count') - let todos = await this.app.client.$('#todos-count') - await issues.waitForExist({ timeout: 5000 }) - let issuesExists = await issues.isExisting() - let mrsExists = await mrs.isExisting() - let todosExists = await todos.isExisting() - assert.equal(issuesExists, true) - assert.equal(mrsExists, true) - assert.equal(todosExists, true) - }) - }) -}) + let element = await this.app.client.$('#instance-checkbox'); + return element + .click() + .then(async () => { + let token = await this.app.client.$('#access-token-input'); + let url = await this.app.client.$('#instance-url-input'); + await token.setValue(process.env.ACCESS_TOKEN); + await url.setValue('https://gitlab.com'); + let button = await this.app.client.$('#login-instance-button'); + return button.click(); + }) + .then(async () => { + let issues = await this.app.client.$('#issues-count'); + let mrs = await this.app.client.$('#mrs-count'); + let todos = await this.app.client.$('#todos-count'); + await issues.waitForExist({ timeout: 5000 }); + let issuesExists = await issues.isExisting(); + let mrsExists = await mrs.isExisting(); + let todosExists = await todos.isExisting(); + assert.equal(issuesExists, true); + assert.equal(mrsExists, true); + assert.equal(todosExists, true); + }); + }); +}); describe('Feature tests', function () { - this.timeout(25000) + this.timeout(25000); beforeEach(function (done) { this.app = new Application({ path: electronPath, - args: ['--no-sandbox', '--ignore-certificate-error', '--disable-dev-shm-usage', '--whitelisted-ips=', path.join(__dirname, '..')], - env: { NODE_ENV: 'test', LOGGED_IN: 'true' } - }) + args: [ + '--no-sandbox', + '--ignore-certificate-error', + '--disable-dev-shm-usage', + '--whitelisted-ips=', + path.join(__dirname, '..'), + ], + env: { NODE_ENV: 'test', LOGGED_IN: 'true' }, + }); this.app.start().then(() => { - done() - }) - }) + done(); + }); + }); afterEach(function () { if (this.app && this.app.isRunning()) { - return this.app.stop() + return this.app.stop(); } - }) + }); it('shows overview page', async function () { - let issues = await this.app.client.$('#issues-count') - let mrs = await this.app.client.$('#mrs-count') - let todos = await this.app.client.$('#todos-count') - await issues.waitForExist({ timeout: 5000 }) - let issuesExists = await issues.isExisting() - let mrsExists = await mrs.isExisting() - let todosExists = await todos.isExisting() - assert.equal(issuesExists, true) - assert.equal(mrsExists, true) - assert.equal(todosExists, true) - }) + let issues = await this.app.client.$('#issues-count'); + let mrs = await this.app.client.$('#mrs-count'); + let todos = await this.app.client.$('#todos-count'); + await issues.waitForExist({ timeout: 5000 }); + let issuesExists = await issues.isExisting(); + let mrsExists = await mrs.isExisting(); + let todosExists = await todos.isExisting(); + assert.equal(issuesExists, true); + assert.equal(mrsExists, true); + assert.equal(todosExists, true); + }); it('adds and deletes bookmark', async function () { - let bookmark = await this.app.client.$('#bookmark-link') - await bookmark.setValue('https://gitlab.com/gitlab-org/gitlab/-/issues/1') - let button = await this.app.client.$('#bookmark-add-button') - return button.click().then(async () => { - }).then(async () => { - let title = await this.app.client.$('#bookmark-title') - await title.waitForExist({ timeout: 5000 }) - let text = await title.getText() - assert.equal(text, '500 error on MR approvers edit page (#1)') - let button = await this.app.client.$('.bookmark-delete') - return button.click() - }).then(async () => { - let bookmark = await this.app.client.$('#bookmark-link') - await bookmark.waitForExist({ timeout: 5000 }) - let bookmarkExists = await bookmark.isExisting() - assert.equal(bookmarkExists, true) - }) - }) -}) \ No newline at end of file + let bookmark = await this.app.client.$('#bookmark-link'); + await bookmark.setValue('https://gitlab.com/gitlab-org/gitlab/-/issues/1'); + let button = await this.app.client.$('#bookmark-add-button'); + return button + .click() + .then(async () => {}) + .then(async () => { + let title = await this.app.client.$('#bookmark-title'); + await title.waitForExist({ timeout: 5000 }); + let text = await title.getText(); + assert.equal(text, '500 error on MR approvers edit page (#1)'); + let button = await this.app.client.$('.bookmark-delete'); + return button.click(); + }) + .then(async () => { + let bookmark = await this.app.client.$('#bookmark-link'); + await bookmark.waitForExist({ timeout: 5000 }); + let bookmarkExists = await bookmark.isExisting(); + assert.equal(bookmarkExists, true); + }); + }); +});