Ignored files
This commit is contained in:
parent
05b46a883f
commit
1f5bbae5ec
6 changed files with 3213 additions and 2985 deletions
6
.github/workflows/deploy-docs.yml
vendored
6
.github/workflows/deploy-docs.yml
vendored
|
|
@ -42,14 +42,10 @@ jobs:
|
|||
cd docs
|
||||
npm ci
|
||||
|
||||
- name: Check formatting
|
||||
- name: Check formatting & spelling
|
||||
run: |
|
||||
cd docs
|
||||
npm run format:check
|
||||
|
||||
- name: Check spelling
|
||||
run: |
|
||||
cd docs
|
||||
npm run spell:check
|
||||
|
||||
- name: Build documentation
|
||||
|
|
|
|||
5960
docs/package-lock.json
generated
5960
docs/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -58,6 +58,40 @@
|
|||
height: 75px;
|
||||
}
|
||||
|
||||
.ignored-files-container {
|
||||
margin-top: var(--size-4-3);
|
||||
padding: var(--size-4-3);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: var(--radius-s);
|
||||
background-color: var(--background-secondary);
|
||||
|
||||
h4 {
|
||||
margin-top: 0;
|
||||
margin-bottom: var(--size-4-2);
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.ignored-files-list {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
margin: 0;
|
||||
padding-left: var(--size-4-4);
|
||||
|
||||
li {
|
||||
font-family: var(--font-monospace);
|
||||
font-size: var(--font-ui-small);
|
||||
color: var(--text-muted);
|
||||
padding: var(--size-2-1) 0;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: var(--text-muted);
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.applying-changes-overlay {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import type { App } from "obsidian";
|
|||
import { Notice, PluginSettingTab, Setting } from "obsidian";
|
||||
import type VaultLinkPlugin from "src/vault-link-plugin";
|
||||
import type { SyncClient, SyncSettings } from "sync-client";
|
||||
import { globsToRegexes } from "sync-client";
|
||||
import { HistoryView } from "../history/history-view";
|
||||
import { LogsView } from "../logs/logs-view";
|
||||
import type { StatusDescription } from "../status-description/status-description";
|
||||
|
|
@ -351,6 +352,55 @@ export class SyncSettingsTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Update tracked files")
|
||||
.setDesc(
|
||||
"Apply current ignore patterns to already tracked files. Files that now match ignore patterns will be deleted from sync, and files that no longer match will be added to sync."
|
||||
)
|
||||
.addButton((button) =>
|
||||
button
|
||||
.setButtonText("Update tracked files")
|
||||
.setDisabled(this.isApplyingChanges)
|
||||
.setTooltip(
|
||||
this.isApplyingChanges
|
||||
? "Waiting for applying changes to finish..."
|
||||
: "Update tracked files based on current ignore patterns"
|
||||
)
|
||||
.onClick(() => {
|
||||
void (async (): Promise<void> => {
|
||||
await this.updateTrackedFilesBasedOnIgnorePatterns();
|
||||
})();
|
||||
})
|
||||
);
|
||||
|
||||
const ignoredFilesContainer = containerEl.createDiv({
|
||||
cls: "ignored-files-container"
|
||||
});
|
||||
let isIgnoredFilesVisible = false;
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Show ignored files")
|
||||
.setDesc(
|
||||
"Display a list of all files currently ignored by the patterns above."
|
||||
)
|
||||
.addButton((button) =>
|
||||
button.setButtonText("Show ignored files").onClick(() => {
|
||||
void (async (): Promise<void> => {
|
||||
if (isIgnoredFilesVisible) {
|
||||
ignoredFilesContainer.empty();
|
||||
isIgnoredFilesVisible = false;
|
||||
button.setButtonText("Show ignored files");
|
||||
} else {
|
||||
await this.displayIgnoredFiles(
|
||||
ignoredFilesContainer
|
||||
);
|
||||
isIgnoredFilesVisible = true;
|
||||
button.setButtonText("Hide ignored files");
|
||||
}
|
||||
})();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Sync concurrency")
|
||||
.setDesc(
|
||||
|
|
@ -562,4 +612,136 @@ export class SyncSettingsTab extends PluginSettingTab {
|
|||
|
||||
return [titleContainer, updateTitle];
|
||||
}
|
||||
|
||||
private async updateTrackedFilesBasedOnIgnorePatterns(): Promise<void> {
|
||||
this.isApplyingChanges = true;
|
||||
try {
|
||||
const ignorePatterns: RegExp[] = globsToRegexes(
|
||||
this.syncClient.getSettings().ignorePatterns,
|
||||
this.syncClient.logger
|
||||
);
|
||||
|
||||
const matchesIgnorePattern = (path: string): boolean => {
|
||||
return ignorePatterns.some((pattern) => pattern.test(path));
|
||||
};
|
||||
|
||||
const trackedFiles: string[] =
|
||||
this.syncClient.getTrackedFilePaths();
|
||||
const allVaultFiles: string[] =
|
||||
await this.syncClient.getAllVaultFiles();
|
||||
|
||||
const filesToDelete: string[] = trackedFiles.filter((path) =>
|
||||
matchesIgnorePattern(path)
|
||||
);
|
||||
const filesToCreate: string[] = allVaultFiles.filter(
|
||||
(path) =>
|
||||
!matchesIgnorePattern(path) && !trackedFiles.includes(path)
|
||||
);
|
||||
|
||||
if (filesToDelete.length === 0 && filesToCreate.length === 0) {
|
||||
new Notice("No files need to be updated");
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmMessageParts: string[] = [
|
||||
`This will update ${filesToDelete.length + filesToCreate.length} file(s):`
|
||||
];
|
||||
|
||||
if (filesToDelete.length > 0) {
|
||||
confirmMessageParts.push(
|
||||
`- Delete ${filesToDelete.length} file(s) from sync (now ignored)`
|
||||
);
|
||||
}
|
||||
|
||||
if (filesToCreate.length > 0) {
|
||||
confirmMessageParts.push(
|
||||
`- Add ${filesToCreate.length} file(s) to sync (no longer ignored)`
|
||||
);
|
||||
}
|
||||
|
||||
confirmMessageParts.push("", "Do you want to continue?");
|
||||
|
||||
const confirmMessage = confirmMessageParts.join("\n");
|
||||
|
||||
const confirmed = confirm(confirmMessage);
|
||||
if (!confirmed) {
|
||||
new Notice("Update cancelled");
|
||||
return;
|
||||
}
|
||||
|
||||
new Notice(
|
||||
`Updating ${filesToDelete.length + filesToCreate.length} file(s)...`
|
||||
);
|
||||
|
||||
for (const path of filesToDelete) {
|
||||
await this.syncClient.syncLocallyDeletedFile(path);
|
||||
}
|
||||
|
||||
for (const path of filesToCreate) {
|
||||
await this.syncClient.syncLocallyCreatedFile(path);
|
||||
}
|
||||
|
||||
new Notice(
|
||||
`Successfully updated ${filesToDelete.length + filesToCreate.length} file(s)`
|
||||
);
|
||||
} catch (error) {
|
||||
new Notice(`Error updating tracked files: ${String(error)}`);
|
||||
this.syncClient.logger.error(
|
||||
`Error updating tracked files: ${String(error)}`
|
||||
);
|
||||
} finally {
|
||||
this.isApplyingChanges = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async displayIgnoredFiles(container: HTMLElement): Promise<void> {
|
||||
container.empty();
|
||||
|
||||
try {
|
||||
const ignorePatterns: RegExp[] = globsToRegexes(
|
||||
this.syncClient.getSettings().ignorePatterns,
|
||||
this.syncClient.logger
|
||||
);
|
||||
|
||||
if (ignorePatterns.length === 0) {
|
||||
container.createEl("p", {
|
||||
text: "No ignore patterns configured"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const allVaultFiles: string[] =
|
||||
await this.syncClient.getAllVaultFiles();
|
||||
const ignoredFiles: string[] = allVaultFiles.filter((path) =>
|
||||
ignorePatterns.some((pattern) => pattern.test(path))
|
||||
);
|
||||
|
||||
if (ignoredFiles.length === 0) {
|
||||
container.createEl("p", {
|
||||
text: "No files are currently ignored"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
container.createEl("h4", {
|
||||
text: `Ignored files (${ignoredFiles.length})`
|
||||
});
|
||||
|
||||
const fileList = container.createEl("ul", {
|
||||
cls: "ignored-files-list"
|
||||
});
|
||||
|
||||
const sortedIgnoredFiles = [...ignoredFiles].sort();
|
||||
for (const path of sortedIgnoredFiles) {
|
||||
fileList.createEl("li", { text: path });
|
||||
}
|
||||
} catch (error) {
|
||||
container.createEl("p", {
|
||||
text: `Error loading ignored files: ${String(error)}`
|
||||
});
|
||||
this.syncClient.logger.error(
|
||||
`Error loading ignored files: ${String(error)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ export const debugging = {
|
|||
logToConsole
|
||||
};
|
||||
|
||||
export { globsToRegexes } from "./utils/globs-to-regexes";
|
||||
|
||||
export const utils = {
|
||||
getRandomColor,
|
||||
positionToLineAndColumn,
|
||||
|
|
|
|||
|
|
@ -417,6 +417,20 @@ export class SyncClient {
|
|||
await this.cursorTracker.sendLocalCursorsToServer(documentToCursors);
|
||||
}
|
||||
|
||||
public getTrackedFilePaths(): RelativePath[] {
|
||||
this.checkIfDestroyed("getTrackedFilePaths");
|
||||
|
||||
return this.database.resolvedDocuments
|
||||
.filter((doc) => !doc.isDeleted && doc.metadata !== undefined)
|
||||
.map((doc) => doc.relativePath);
|
||||
}
|
||||
|
||||
public async getAllVaultFiles(): Promise<RelativePath[]> {
|
||||
this.checkIfDestroyed("getAllVaultFiles");
|
||||
|
||||
return this.fileOperations.listFilesRecursively(undefined);
|
||||
}
|
||||
|
||||
public async waitUntilFinished(): Promise<void> {
|
||||
this.checkIfDestroyed("waitUntilIdle");
|
||||
await this.syncer.waitUntilFinished();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue