diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index e49d9314d..7cd980db1 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -4,7 +4,7 @@ ARG VARIANT="14-buster" FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-${VARIANT} -# same package list from github1s/scripts/pre-install.sh +# same package list from github1s/scripts/preinstall.sh RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ && apt-get -y install --no-install-recommends libx11-dev libxkbfile-dev libsecret-1-dev rsync diff --git a/extensions/github1s/package.json b/extensions/github1s/package.json index 73296a8e4..2baeae1d1 100644 --- a/extensions/github1s/package.json +++ b/extensions/github1s/package.json @@ -41,14 +41,19 @@ ], "scm": [ { - "id": "github1s.views.codeReviewList", - "name": "Code Reviews", - "when": "github1s:views:codeReviewList:visible == true" + "id": "github1s.views.fileHistory", + "name": "File History", + "when": "github1s:views:fileHistory:visible == true" }, { "id": "github1s.views.commitList", "name": "Commits", "when": "github1s:views:commitList:visible == true" + }, + { + "id": "github1s.views.codeReviewList", + "name": "Code Reviews", + "when": "github1s:views:codeReviewList:visible == true" } ] }, @@ -126,6 +131,12 @@ "icon": "$(globe)", "enablement": "github1s:adapters:default:platformName != 'GitHub' && github1s:adapters:default:platformName != 'GitLab' && github1s:adapters:default:platformName != 'Bitbucket'" }, + { + "command": "github1s.commands.refreshFileHistoryCommitList", + "title": "Refresh", + "category": "GitHub1s", + "icon": "$(refresh)" + }, { "command": "github1s.commands.refreshCommitList", "title": "Refresh", @@ -422,6 +433,16 @@ "when": "view == 'github1s.views.codeReviewList'", "group": "navigation@2" }, + { + "command": "github1s.commands.refreshFileHistoryCommitList", + "when": "view == 'github1s.views.fileHistory'", + "group": "navigation@1" + }, + { + "command": "github1s.commands.searchCommit", + "when": "view == 'github1s.views.fileHistory'", + "group": "navigation@2" + }, { "command": "github1s.commands.refreshCommitList", "when": "view == 'github1s.views.commitList'", diff --git a/extensions/github1s/src/adapters/bitbucket1s/index.ts b/extensions/github1s/src/adapters/bitbucket1s/index.ts index f5ff662e7..14cadfde8 100644 --- a/extensions/github1s/src/adapters/bitbucket1s/index.ts +++ b/extensions/github1s/src/adapters/bitbucket1s/index.ts @@ -23,9 +23,11 @@ export class BitbucketAdapter implements Adapter { activateAsDefault() { setVSCodeContext('github1s:views:commitList:visible', true); + setVSCodeContext('github1s:views:fileHistory:visible', true); } deactivateAsDefault() { setVSCodeContext('github1s:views:commitList:visible', false); + setVSCodeContext('github1s:views:fileHistory:visible', false); } } diff --git a/extensions/github1s/src/adapters/github1s/index.ts b/extensions/github1s/src/adapters/github1s/index.ts index 3a242183c..6bc25184d 100644 --- a/extensions/github1s/src/adapters/github1s/index.ts +++ b/extensions/github1s/src/adapters/github1s/index.ts @@ -29,6 +29,7 @@ export class GitHub1sAdapter implements Adapter { setVSCodeContext('github1s:views:settings:visible', true); setVSCodeContext('github1s:views:codeReviewList:visible', true); setVSCodeContext('github1s:views:commitList:visible', true); + setVSCodeContext('github1s:views:fileHistory:visible', true); vscode.window.registerWebviewViewProvider( GitHub1sSettingsViewProvider.viewType, @@ -43,5 +44,6 @@ export class GitHub1sAdapter implements Adapter { setVSCodeContext('github1s:views:settings:visible', false); setVSCodeContext('github1s:views:codeReviewList:visible', false); setVSCodeContext('github1s:views:commitList:visible', false); + setVSCodeContext('github1s:views:fileHistory:visible', false); } } diff --git a/extensions/github1s/src/adapters/gitlab1s/index.ts b/extensions/github1s/src/adapters/gitlab1s/index.ts index e28721d12..3da0450cd 100644 --- a/extensions/github1s/src/adapters/gitlab1s/index.ts +++ b/extensions/github1s/src/adapters/gitlab1s/index.ts @@ -23,9 +23,11 @@ export class GitLab1sAdapter implements Adapter { activateAsDefault() { setVSCodeContext('github1s:views:commitList:visible', true); + setVSCodeContext('github1s:views:fileHistory:visible', true); } deactivateAsDefault() { setVSCodeContext('github1s:views:commitList:visible', false); + setVSCodeContext('github1s:views:fileHistory:visible', false); } } diff --git a/extensions/github1s/src/adapters/sourcegraph/commit.ts b/extensions/github1s/src/adapters/sourcegraph/commit.ts index 3d1b0e33d..2d1f7285f 100644 --- a/extensions/github1s/src/adapters/sourcegraph/commit.ts +++ b/extensions/github1s/src/adapters/sourcegraph/commit.ts @@ -70,13 +70,16 @@ const formatCommit = (commit: any, isGitHub: boolean) => { export const getCommits = async (repository: string, ref: string, path?: string, limit?: number): Promise => { const repositoryData = await querySourcegraphRepository({ query: CommitsQuery, - variables: { repository, ref, path: path || '', first: limit ? limit - 1 : undefined }, + variables: { repository, ref, path: path || '', first: limit ? limit : undefined }, }); const firstCommit = repositoryData.commit; const isGitHub = repository.startsWith('github.com/'); const restCommits = firstCommit?.ancestors?.nodes?.map?.((item) => formatCommit(item, isGitHub)) || []; - return path ? restCommits : [formatCommit(firstCommit, isGitHub), ...restCommits].filter(Boolean); + if (firstCommit.oid === restCommits[0]?.sha) { + return restCommits.filter(Boolean); + } + return [formatCommit(firstCommit, isGitHub), ...restCommits].slice(0, limit).filter(Boolean); }; const CommitQuery = gql` diff --git a/extensions/github1s/src/commands/blame.ts b/extensions/github1s/src/commands/blame.ts index d333122b8..de8a673f3 100644 --- a/extensions/github1s/src/commands/blame.ts +++ b/extensions/github1s/src/commands/blame.ts @@ -10,7 +10,6 @@ import { setVSCodeContext } from '@/helpers/vscode'; import router from '@/router'; import { Repository } from '@/repository'; import { BlameRange, PlatformName } from '@/adapters/types'; -import { showFileBlameAuthorizedRequiredMessage } from '@/messages'; import { adapterManager } from '@/adapters'; const ageColors = [ diff --git a/extensions/github1s/src/commands/commit.ts b/extensions/github1s/src/commands/commit.ts index 757f9cba8..3c674b1bd 100644 --- a/extensions/github1s/src/commands/commit.ts +++ b/extensions/github1s/src/commands/commit.ts @@ -6,11 +6,11 @@ import * as vscode from 'vscode'; import router from '@/router'; import { CommitTreeItem, getCommitTreeItemDescription } from '@/views/commit-list'; -import { commitTreeDataProvider } from '@/views'; +import { commitTreeDataProvider, fileHistoryTreeDataProvider } from '@/views'; import { adapterManager } from '@/adapters'; import { Repository } from '@/repository'; -const checkCommitExists = async (repo: string, commitSha: string) => { +export const checkCommitExists = async (repo: string, commitSha: string) => { const adapter = adapterManager.getCurrentAdapter(); const dataSoruce = await adapter.resolveDataSource(); try { @@ -110,6 +110,18 @@ const commandLoadMoreCommitChangedFiles = async (commitSha: string) => { return commitTreeDataProvider.loadMoreChangedFiles(commitSha); }; +const commandRefreshFileHistoryCommitList = (forceUpdate = true) => { + return fileHistoryTreeDataProvider.updateTree(forceUpdate); +}; + +const commandLoadMoreFileHistoryCommits = async () => { + return fileHistoryTreeDataProvider.loadMoreCommits(); +}; + +const commandLoadMoreFileHistoryCommitChangedFiles = async (commitSha: string) => { + return fileHistoryTreeDataProvider.loadMoreChangedFiles(commitSha); +}; + export const registerCommitCommands = (context: vscode.ExtensionContext) => { return context.subscriptions.push( vscode.commands.registerCommand('github1s.commands.refreshCommitList', commandRefreshCommitList), @@ -119,10 +131,16 @@ export const registerCommitCommands = (context: vscode.ExtensionContext) => { vscode.commands.registerCommand('github1s.commands.openCommitOnGitLab', commandOpenCommitOnOfficialPage), vscode.commands.registerCommand('github1s.commands.openCommitOnBitbucket', commandOpenCommitOnOfficialPage), vscode.commands.registerCommand('github1s.commands.openCommitOnOfficialPage', commandOpenCommitOnOfficialPage), - vscode.commands.registerCommand('github1s.commands.load-more-commits', commandLoadMoreCommits), + vscode.commands.registerCommand('github1s.commands.loadMoreCommits', commandLoadMoreCommits), + vscode.commands.registerCommand('github1s.commands.loadMoreCommitChangedFiles', commandLoadMoreCommitChangedFiles), + vscode.commands.registerCommand('github1s.commands.loadMoreFileHistoryCommits', commandLoadMoreFileHistoryCommits), + vscode.commands.registerCommand( + 'github1s.commands.loadMoreFileHistoryCommitChangedFiles', + commandLoadMoreFileHistoryCommitChangedFiles + ), vscode.commands.registerCommand( - 'github1s.commands.load-more-commit-changed-files', - commandLoadMoreCommitChangedFiles + 'github1s.commands.refreshFileHistoryCommitList', + commandRefreshFileHistoryCommitList ) ); }; diff --git a/extensions/github1s/src/listeners/vscode.ts b/extensions/github1s/src/listeners/vscode.ts index 1757cbc4f..0a9978048 100644 --- a/extensions/github1s/src/listeners/vscode.ts +++ b/extensions/github1s/src/listeners/vscode.ts @@ -70,11 +70,17 @@ const handleRouterOnTextEditorSelectionChange = async (editor: vscode.TextEditor router.replace(browserPath); }; +// refresh file history view if active editor changed +const handleRefreshFileHistoryView = () => { + vscode.commands.executeCommand('github1s.commands.refreshFileHistoryCommitList', false); +}; + export const registerVSCodeEventListeners = () => { vscode.window.onDidChangeActiveTextEditor((editor) => { handleRouterOnActiveEditorChange(editor); handleOpenChangesContextOnActiveEditorChange(editor); handlegutterBlameOpenContextOnActiveEditorChange(); + handleRefreshFileHistoryView(); }); // debounce to update the browser url diff --git a/extensions/github1s/src/repository/commit-manager.ts b/extensions/github1s/src/repository/commit-manager.ts index f3b0b1438..2f50720d0 100644 --- a/extensions/github1s/src/repository/commit-manager.ts +++ b/extensions/github1s/src/repository/commit-manager.ts @@ -185,7 +185,7 @@ export class CommitManager { this.linkCommitShas(previousCommitSha, nextCommitSha); } // if has more commits - const hasMore = commits.length >= this._pageSize; + const hasMore = commits.length === this._pageSize; if (!hasMore) { const latestCommit = commits.length ? commits[commits.length - 1] : commitList[commitList.length - 1]; this.linkCommitShas(null, latestCommit.sha); diff --git a/extensions/github1s/src/views/commit-list.ts b/extensions/github1s/src/views/commit-list.ts index cc1ff83bf..80b098e38 100644 --- a/extensions/github1s/src/views/commit-list.ts +++ b/extensions/github1s/src/views/commit-list.ts @@ -22,35 +22,39 @@ export interface CommitTreeItem extends vscode.TreeItem { commit: adapterTypes.Commit; } -const loadMoreCommitItem: vscode.TreeItem = { - label: 'Load more', - tooltip: 'Load more commits', - command: { - title: 'Load more commits', - command: 'github1s.commands.load-more-commits', - tooltip: 'Load more commits', - }, -}; - -const createLoadMoreChangedFilesItem = (commitSha: string): vscode.TreeItem => ({ - label: 'Load more', - tooltip: 'Load more changed files', - command: { - title: 'Load more changed files', - command: 'github1s.commands.load-more-commit-changed-files', - tooltip: 'Load more changed files', - arguments: [commitSha], - }, -}); - export class CommitTreeDataProvider implements vscode.TreeDataProvider { public static viewType = 'github1s.views.commitList'; - private _forceUpdate = false; - private _loadingBarrier: Barrier | null = null; - private _onDidChangeTreeData = new vscode.EventEmitter(); + protected _forceUpdate = false; + protected _loadingBarrier: Barrier | null = null; + protected _onDidChangeTreeData = new vscode.EventEmitter(); readonly onDidChangeTreeData = this._onDidChangeTreeData.event; + protected loadMoreCommitItem: vscode.TreeItem = { + label: 'Load more', + tooltip: 'Load more commits', + command: { + title: 'Load more commits', + command: 'github1s.commands.loadMoreCommits', + tooltip: 'Load more commits', + }, + }; + + protected createLoadMoreChangedFilesItem = (commitSha: string): vscode.TreeItem => ({ + label: 'Load more', + tooltip: 'Load more changed files', + command: { + title: 'Load more changed files', + command: 'github1s.commands.loadMoreCommitChangedFiles', + tooltip: 'Load more changed files', + arguments: [commitSha], + }, + }); + + async resolveFilePath() { + return ''; + } + public updateTree(forceUpdate = true) { this._forceUpdate = forceUpdate; this._onDidChangeTreeData.fire(); @@ -62,7 +66,8 @@ export class CommitTreeDataProvider implements vscode.TreeDataProvider { this._loadingBarrier && (await this._loadingBarrier.wait()); + const filePath = await this.resolveFilePath(); const currentAdapter = adapterManager.getCurrentAdapter(); const { repo, ref } = await router.getState(); const repository = Repository.getInstance(currentAdapter.scheme, repo); - const repositoryCommits = await repository.getCommitList(ref, '', this._forceUpdate); + const repositoryCommits = await repository.getCommitList(ref, filePath, this._forceUpdate); const commitTreeItems = repositoryCommits.map((commit) => { const label = `${commit.message}`; const description = getCommitTreeItemDescription(commit); @@ -106,8 +112,8 @@ export class CommitTreeDataProvider implements vscode.TreeDataProvider { @@ -131,7 +137,7 @@ export class CommitTreeDataProvider implements vscode.TreeDataProvider ({ + label: 'Load more', + tooltip: 'Load more changed files', + command: { + title: 'Load more changed files', + command: 'github1s.commands.loadMoreFileHistoryCommitChangedFiles', + tooltip: 'Load more changed files', + arguments: [commitSha], + }, + }); + + async resolveFilePath() { + const activeDocumentUri = vscode.window.activeTextEditor?.document?.uri; + const currentScheme = adapterManager.getCurrentScheme(); + return activeDocumentUri?.scheme === currentScheme ? activeDocumentUri.path.slice(1) : ''; + } + + async getCommitItems() { + if (!(await this.resolveFilePath())) { + return []; + } + return super.getCommitItems(); + } +} diff --git a/extensions/github1s/src/views/index.ts b/extensions/github1s/src/views/index.ts index 509787644..481e5d786 100644 --- a/extensions/github1s/src/views/index.ts +++ b/extensions/github1s/src/views/index.ts @@ -3,12 +3,13 @@ */ import * as vscode from 'vscode'; -import { getExtensionContext } from '@/helpers/context'; -import { CodeReviewTreeDataProvider } from './code-review-list'; -import { CommitTreeDataProvider } from './commit-list'; import { adapterManager } from '@/adapters'; import { CodeReviewType } from '@/adapters/types'; +import { getExtensionContext } from '@/helpers/context'; +import { CodeReviewTreeDataProvider } from './code-review-list'; +import { CommitTreeDataProvider, FileHistoryTreeDataProvider } from './commit-list'; +export const fileHistoryTreeDataProvider = new FileHistoryTreeDataProvider(); export const commitTreeDataProvider = new CommitTreeDataProvider(); export const codeReviewRequestTreeDataProvider = new CodeReviewTreeDataProvider(); @@ -23,15 +24,16 @@ export const registerCustomViews = () => { const context = getExtensionContext(); // register code review view which is in source control panel - const treeView = vscode.window.createTreeView(CodeReviewTreeDataProvider.viewType, { + const codeReviewTreeView = vscode.window.createTreeView(CodeReviewTreeDataProvider.viewType, { treeDataProvider: codeReviewRequestTreeDataProvider, }); // set code view list view title according code review type const codeReviewType = adapterManager.getCurrentAdapter().codeReviewType || CodeReviewType.CodeReview; - treeView.title = codeReviewViewTitle[codeReviewType]; + codeReviewTreeView.title = codeReviewViewTitle[codeReviewType]; context.subscriptions.push( // register commit view which is in source control panel + vscode.window.registerTreeDataProvider(FileHistoryTreeDataProvider.viewType, fileHistoryTreeDataProvider), vscode.window.registerTreeDataProvider(CommitTreeDataProvider.viewType, commitTreeDataProvider) ); }; diff --git a/package.json b/package.json index c973bdd8f..be0b9fed2 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "yalc": "^1.0.0-pre.50" }, "scripts": { - "preinstall": "./scripts/pre-install.sh", + "preinstall": "./scripts/preinstall.sh", "postinstall": "husky install && ./scripts/postinstall.sh", "clean-build": "./scripts/clean-build.sh", "clean": "./scripts/clean.sh", diff --git a/resources/initialize.js b/resources/initialize.js index 2f8ceb599..0adb91e16 100644 --- a/resources/initialize.js +++ b/resources/initialize.js @@ -116,7 +116,7 @@ const renderNotification = () => { const NOTIFICATION_STORAGE_KEY = 'GITHUB1S_NOTIFICATION'; // Change this if a new notification should be shown - const NOTIFICATION_STORAGE_VALUE = '202102123'; + const NOTIFICATION_STORAGE_VALUE = '20210212'; // If user has confirmed the notification and checked `don't show me again`, ignore it if (window.localStorage.getItem(NOTIFICATION_STORAGE_KEY) === NOTIFICATION_STORAGE_VALUE) { return; diff --git a/scripts/package/copy-node_modules.sh b/scripts/package/copy-node_modules.sh index 69f0052eb..15ea0d469 100755 --- a/scripts/package/copy-node_modules.sh +++ b/scripts/package/copy-node_modules.sh @@ -11,7 +11,7 @@ function main() { for dependency in ${dependencies[@]}; do - rsync -a --del vscode-web/node_modules/${dependency} dist/static/node_modules + rsync -a --del vscode-web/node_modules/${dependency} dist/static/node_modules/$(dirname "${dependency}") done rsync -a node_modules/@github1s/vscode-web/dist/extensions/ dist/static/extensions diff --git a/scripts/pre-install.sh b/scripts/preinstall.sh similarity index 100% rename from scripts/pre-install.sh rename to scripts/preinstall.sh diff --git a/tests/__tests__/__image_snapshots__/index-test-ts-should-load-successfully-1-snap.png b/tests/__tests__/__image_snapshots__/index-test-ts-should-load-successfully-1-snap.png index a5ad7cf3d..115484404 100644 Binary files a/tests/__tests__/__image_snapshots__/index-test-ts-should-load-successfully-1-snap.png and b/tests/__tests__/__image_snapshots__/index-test-ts-should-load-successfully-1-snap.png differ diff --git a/tests/__tests__/__image_snapshots__/index-test-ts-should-open-file-correctly-1-snap.png b/tests/__tests__/__image_snapshots__/index-test-ts-should-open-file-correctly-1-snap.png index fd1c7e4be..c2535cee2 100644 Binary files a/tests/__tests__/__image_snapshots__/index-test-ts-should-open-file-correctly-1-snap.png and b/tests/__tests__/__image_snapshots__/index-test-ts-should-open-file-correctly-1-snap.png differ diff --git a/tests/__tests__/__image_snapshots__/index-test-ts-should-show-commit-files-1-snap.png b/tests/__tests__/__image_snapshots__/index-test-ts-should-show-commit-files-1-snap.png index 644e6087b..3f14fa8ad 100644 Binary files a/tests/__tests__/__image_snapshots__/index-test-ts-should-show-commit-files-1-snap.png and b/tests/__tests__/__image_snapshots__/index-test-ts-should-show-commit-files-1-snap.png differ diff --git a/vercel.json b/vercel.json index c7b547792..6265f023e 100644 --- a/vercel.json +++ b/vercel.json @@ -1,9 +1,5 @@ { "rewrites": [ - { - "source": "/api/sourcegraph", - "destination": "https://sourcegraph.com/.api/graphql" - }, { "source": "/api/github-auth-callback", "destination": "/api/github-auth-callback"