mirror of
https://github.com/shumadrid/obsidian-git-changelog.git
synced 2026-07-22 05:42:16 +00:00
refactor: switch settings code template
This commit is contained in:
parent
790fc02936
commit
2628a4ffca
61 changed files with 1709 additions and 1754 deletions
861
package-lock.json
generated
861
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -38,11 +38,12 @@
|
|||
"eslint-plugin-unicorn": "^57.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"obsidian": "^1.8.7",
|
||||
"obsidian-dev-utils": "^21.0.0",
|
||||
"obsidian-dev-utils": "latest",
|
||||
"obsidian-typings": "^2.35.0",
|
||||
"prettier": "3.5.3",
|
||||
"prettier-plugin-svelte": "^3.3.3",
|
||||
"sass": "^1.83.4",
|
||||
"simple-git": "^3.27.0",
|
||||
"spacetime": "^7.8.0",
|
||||
"svelte": "^5.23.1",
|
||||
"svelte-eslint-parser": "^0.43.0",
|
||||
|
|
@ -50,7 +51,7 @@
|
|||
"svelte-preprocess": "^6.0.3",
|
||||
"typescript": "^5.8.2",
|
||||
"typescript-eslint": "^8.25.0",
|
||||
"simple-git": "^3.27.0"
|
||||
"type-fest": "^4.39.1"
|
||||
},
|
||||
"overrides": {
|
||||
"boolean": "npm:dry-uninstall"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import type { BuildOptions } from 'esbuild';
|
||||
import type { CliTaskResult } from 'obsidian-dev-utils/ScriptUtils/CliUtils';
|
||||
|
||||
import {
|
||||
|
|
@ -9,9 +10,10 @@ export async function buildWithSvelte(
|
|||
developmentMode: boolean
|
||||
): Promise<CliTaskResult> {
|
||||
return await buildObsidianPlugin({
|
||||
customEsbuildOptions: {
|
||||
dropLabels: developmentMode ? undefined : ['DEV']
|
||||
customizeEsbuildOptions: (options: BuildOptions) => {
|
||||
options.dropLabels = developmentMode ? undefined : ['DEV'];
|
||||
},
|
||||
|
||||
customEsbuildPlugins: [
|
||||
{
|
||||
name: 'add-condition',
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { getDirname } from 'obsidian-dev-utils/Path';
|
||||
import { getFolderName } from 'obsidian-dev-utils/Path';
|
||||
import { existsSync } from 'obsidian-dev-utils/ScriptUtils/NodeModules';
|
||||
import {
|
||||
execFromRoot,
|
||||
getRootDir,
|
||||
getRootFolder,
|
||||
resolvePathFromRootSafe
|
||||
} from 'obsidian-dev-utils/ScriptUtils/Root';
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ export async function formatWithPrettier(rewrite: boolean): Promise<void> {
|
|||
|
||||
const prettierJsonPath = resolvePathFromRootSafe('.prettierrc.json');
|
||||
if (!existsSync(prettierJsonPath)) {
|
||||
const packageDirectory = getRootDir(getDirname(import.meta.url));
|
||||
const packageDirectory = getRootFolder(getFolderName(import.meta.url));
|
||||
if (!packageDirectory) {
|
||||
throw new Error('Could not find package directory.');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
import type { GitChangelogPluginTypes } from 'constants.ts';
|
||||
import type { ObsidianGitPlugin } from 'gitPluginTypes.ts';
|
||||
import type { Debouncer, PluginSettingTab } from 'obsidian';
|
||||
import type { ChangelogGenerationSettings } from 'settings/settings.ts';
|
||||
import type { Debouncer } from 'obsidian';
|
||||
import type { GitChangelogSettings } from 'settings/settings.ts';
|
||||
import type { SimpleGit } from 'simple-git';
|
||||
import type { ReadonlyDeep } from 'type-fest';
|
||||
|
||||
import { FileChangelogManager } from 'core/FileChangelogManager.ts';
|
||||
import { runHashObjectEmptyTree } from 'core/gitOperations/runHashObjectEmptyTree.ts';
|
||||
import { VaultChangelogManager } from 'core/VaultChangelogManager.ts';
|
||||
import { addContextMenuItems } from 'menu.ts';
|
||||
import { debounce, ItemView, Notice } from 'obsidian';
|
||||
import { PluginBase } from 'obsidian-dev-utils/obsidian/Plugin/PluginBase';
|
||||
import { changelogGenerationSettingsChanged } from 'settings/helper.ts';
|
||||
import { GitChangelogPluginSettings } from 'settings/settings.ts';
|
||||
import { GitChangelogSettingsManager } from 'settings/settingsManager.ts';
|
||||
import { getTimeZone } from 'settings/ui/CustomTimeZone.ts';
|
||||
import {
|
||||
gitPluginCompatibleVersion,
|
||||
|
|
@ -18,6 +20,7 @@ import {
|
|||
} from 'settings/ui/GitPluginWarning.ts';
|
||||
import spacetime from 'spacetime';
|
||||
import { TaskManager } from 'TaskManager.svelte.ts';
|
||||
import { applyDayStartHourSetting } from 'timeUtils.ts';
|
||||
import {
|
||||
FILE_CHANGELOG_VIEW_CONFIG,
|
||||
FileChangelogView
|
||||
|
|
@ -38,12 +41,12 @@ import {
|
|||
GitRepoMissingError
|
||||
} from './types.ts';
|
||||
|
||||
export class GitChangelogPlugin extends PluginBase<GitChangelogPluginSettings> {
|
||||
export class GitChangelogPlugin extends PluginBase<GitChangelogPluginTypes> {
|
||||
public debouncedChangelogSettingsChangedCheck:
|
||||
| Debouncer<
|
||||
[
|
||||
oldSettings: ReadonlyDeep<GitChangelogPluginSettings>,
|
||||
newSettings: ReadonlyDeep<GitChangelogPluginSettings>
|
||||
oldSettings: ReadonlyDeep<GitChangelogSettings>,
|
||||
newSettings: ReadonlyDeep<GitChangelogSettings>
|
||||
],
|
||||
void
|
||||
>
|
||||
|
|
@ -52,7 +55,7 @@ export class GitChangelogPlugin extends PluginBase<GitChangelogPluginSettings> {
|
|||
public gitPluginState = $state<GitPluginState>();
|
||||
public gitRepoReady = $state<boolean>();
|
||||
// Used for keeping relative interval labels like "today" and "yesterday" up to date
|
||||
public currentDay = $state<string>();
|
||||
public currentDay: string | undefined;
|
||||
/**
|
||||
* If we were to persist this, it would be less flexible if the user changes his repo or the hashing algorithm and we would need to either manually have a database of all possible empty tree hashes or validate it in runtime
|
||||
*/
|
||||
|
|
@ -65,10 +68,9 @@ export class GitChangelogPlugin extends PluginBase<GitChangelogPluginSettings> {
|
|||
);
|
||||
|
||||
public detectedTimeZone: string | undefined;
|
||||
public detectedLocale: string | undefined;
|
||||
public vaultChangelogManager = $state<VaultChangelogManager>();
|
||||
|
||||
public fileChangelogManager = $state<FileChangelogManager>();
|
||||
public settingsOfComputedCache?: ChangelogGenerationSettings;
|
||||
public statusBarStats?: StatusBarStats;
|
||||
|
||||
public cachedActiveGitFile: string | undefined;
|
||||
|
|
@ -150,40 +152,43 @@ export class GitChangelogPlugin extends PluginBase<GitChangelogPluginSettings> {
|
|||
}
|
||||
}
|
||||
|
||||
public override async saveSettings(
|
||||
newSettings: GitChangelogPluginSettings,
|
||||
debounceOnSettingsSave = true
|
||||
): Promise<void> {
|
||||
const oldSettings = this.settings;
|
||||
await super.saveSettings(newSettings);
|
||||
if (debounceOnSettingsSave) {
|
||||
this.debouncedChangelogSettingsChangedCheck?.(oldSettings, newSettings);
|
||||
} else {
|
||||
this.onSettingsSave(oldSettings, newSettings);
|
||||
public async getEmptyTreeHash(): Promise<string> {
|
||||
if (this.emptyTreeHash) {
|
||||
return this.emptyTreeHash;
|
||||
}
|
||||
const git = await this.getGit();
|
||||
const emptyTreeHash = await runHashObjectEmptyTree({ git });
|
||||
this.emptyTreeHash ??= emptyTreeHash;
|
||||
return this.emptyTreeHash;
|
||||
}
|
||||
|
||||
protected override createPluginSettings(
|
||||
data: unknown
|
||||
): GitChangelogPluginSettings {
|
||||
return new GitChangelogPluginSettings(data);
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
public override async onSaveSettings(
|
||||
_newSettings: GitChangelogSettings,
|
||||
_oldSettings: GitChangelogSettings
|
||||
): Promise<void> {
|
||||
this.debouncedChangelogSettingsChangedCheck?.(_oldSettings, _newSettings);
|
||||
}
|
||||
|
||||
protected override createPluginSettingsTab(): null | PluginSettingTab {
|
||||
protected override createPluginSettingsTab(): GitChangelogSettingsTab {
|
||||
return new GitChangelogSettingsTab(this);
|
||||
}
|
||||
|
||||
// Functions below are from obsidian-dev-utils (https://github.com/mnaoumov/obsidian-dev-utils/blob/main/src/obsidian/Plugin/PluginBase.ts)
|
||||
protected override createSettingsManager(): GitChangelogSettingsManager {
|
||||
return new GitChangelogSettingsManager(this);
|
||||
}
|
||||
|
||||
protected override onloadComplete(): void {
|
||||
// Runs when the plugin is unloaded.
|
||||
this.register(() => {
|
||||
this.debouncedChangelogSettingsChangedCheck?.cancel();
|
||||
this.fileChangelogManager?.taskManager.abort();
|
||||
this.vaultChangelogManager?.taskManager.abort();
|
||||
this.statusBarStats?.destroy();
|
||||
});
|
||||
// Runs when the plugin is unloaded.
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
protected override async onunloadImpl(): Promise<void> {
|
||||
this.debouncedChangelogSettingsChangedCheck?.cancel();
|
||||
this.fileChangelogManager?.taskManager.abort();
|
||||
this.vaultChangelogManager?.taskManager.abort();
|
||||
this.statusBarStats?.destroy();
|
||||
}
|
||||
|
||||
protected override async onloadImpl(): Promise<void> {
|
||||
await super.onloadImpl();
|
||||
this.registerView(VAULT_CHANGELOG_VIEW_CONFIG.type, (leaf) => {
|
||||
return new VaultChangelogView(leaf, this);
|
||||
});
|
||||
|
|
@ -198,10 +203,10 @@ export class GitChangelogPlugin extends PluginBase<GitChangelogPluginSettings> {
|
|||
|
||||
this.debouncedChangelogSettingsChangedCheck = debounce(
|
||||
(
|
||||
oldSettings: GitChangelogPluginSettings,
|
||||
newSettings: GitChangelogPluginSettings
|
||||
oldSettings: GitChangelogSettings,
|
||||
newSettings: GitChangelogSettings
|
||||
) => {
|
||||
this.onSettingsSave(oldSettings, newSettings);
|
||||
this.onSaveSettingsCheck(oldSettings, newSettings);
|
||||
},
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
700,
|
||||
|
|
@ -220,7 +225,7 @@ export class GitChangelogPlugin extends PluginBase<GitChangelogPluginSettings> {
|
|||
taskManager: new TaskManager(this)
|
||||
});
|
||||
|
||||
if (this.settings.statusBarStats) {
|
||||
if (this.settings.statusBarStatsEnabled) {
|
||||
this.initStatusBar();
|
||||
}
|
||||
|
||||
|
|
@ -241,11 +246,17 @@ export class GitChangelogPlugin extends PluginBase<GitChangelogPluginSettings> {
|
|||
this.registerInterval(
|
||||
window.setInterval(
|
||||
() => {
|
||||
const timezone = getTimeZone(
|
||||
this.settings.changelogGenerationSettings,
|
||||
this
|
||||
);
|
||||
this.currentDay = spacetime.now(timezone).format('day');
|
||||
const timeZone = getTimeZone(this);
|
||||
const fullyAdjustedNewDate = applyDayStartHourSetting({
|
||||
timeZoneAdjustedDate: spacetime.now(timeZone),
|
||||
dayStartHour: this.settings.dayStartHour
|
||||
});
|
||||
|
||||
const fullyAdjustedNewDayString = fullyAdjustedNewDate.format('day');
|
||||
if (fullyAdjustedNewDayString !== this.currentDay) {
|
||||
this.currentDay = fullyAdjustedNewDayString;
|
||||
this.app.workspace.trigger('git-changelog:day-changed');
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
5 * 60 * 1000
|
||||
|
|
@ -262,70 +273,17 @@ export class GitChangelogPlugin extends PluginBase<GitChangelogPluginSettings> {
|
|||
await this.addVaultChangelogView();
|
||||
await this.addFileChangelogView();
|
||||
|
||||
const newSettings = this.settingsClone;
|
||||
newSettings.firstStartup = false;
|
||||
await this.saveSettings(newSettings, false);
|
||||
await this.settingsManager.editAndSave(
|
||||
(settings: GitChangelogSettings): void => {
|
||||
settings.firstStartup = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Also checks the status of the Git plugin
|
||||
this.updateActiveGitFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers events for the views to listen to instead of updating the changelogs directly from the settings so that if the views aren't active we don't do unnecessary computation.
|
||||
* This allows us to check if relevant settings have changed and only then recompute changelogs, instead of recomputing after every single settings change.
|
||||
*/
|
||||
private onSettingsSave(
|
||||
oldSettings: ReadonlyDeep<GitChangelogPluginSettings>,
|
||||
newSettings: GitChangelogPluginSettings
|
||||
): void {
|
||||
try {
|
||||
if (
|
||||
changelogGenerationSettingsChanged({
|
||||
newChangelogSettings: newSettings.changelogGenerationSettings,
|
||||
oldChangelogSettings: oldSettings.changelogGenerationSettings,
|
||||
plugin: this
|
||||
})
|
||||
) {
|
||||
// The main settings, that trigger recalculation for all stats when they change.
|
||||
this.app.workspace.trigger('git-changelog:generation-settings-changed');
|
||||
} else {
|
||||
if (
|
||||
this.fileChangelogManager?.generationSettingsChanged(
|
||||
oldSettings,
|
||||
newSettings
|
||||
) &&
|
||||
this.cachedActiveGitFile
|
||||
) {
|
||||
this.app.workspace.trigger(
|
||||
'git-changelog:file-changelog-generation-settings-changed'
|
||||
);
|
||||
}
|
||||
if (
|
||||
this.statusBarStats &&
|
||||
StatusBarStats.generationSettingsChanged(oldSettings, newSettings) &&
|
||||
this.cachedActiveGitFile
|
||||
) {
|
||||
this.app.workspace.trigger(
|
||||
'git-changelog:status-bar-settings-changed'
|
||||
);
|
||||
}
|
||||
if (
|
||||
this.vaultChangelogManager?.generationSettingsChanged(
|
||||
oldSettings,
|
||||
newSettings
|
||||
)
|
||||
) {
|
||||
this.app.workspace.trigger(
|
||||
'git-changelog:vault-changelog-generation-settings-changed'
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
/* Empty */
|
||||
}
|
||||
}
|
||||
|
||||
private setNewActiveGitFile(activeGitFile: string | undefined): void {
|
||||
this.fileChangelogManager?.resetAndGetSignal(); // Does this belong inside the file changelog class?
|
||||
this.cachedActiveGitFile = activeGitFile;
|
||||
|
|
@ -359,4 +317,70 @@ export class GitChangelogPlugin extends PluginBase<GitChangelogPluginSettings> {
|
|||
/* Empty */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers events for the views to listen to instead of updating the changelogs directly from the settings so that if the views aren't active we don't do unnecessary computation.
|
||||
* This allows us to check if relevant settings have changed and only then recompute changelogs, instead of recomputing after every single settings change.
|
||||
*/
|
||||
private onSaveSettingsCheck(
|
||||
oldSettings: ReadonlyDeep<GitChangelogSettings>,
|
||||
newSettings: GitChangelogSettings
|
||||
): void {
|
||||
try {
|
||||
if (
|
||||
changelogGenerationSettingsChanged({
|
||||
newSettings,
|
||||
oldSettings
|
||||
})
|
||||
) {
|
||||
// The main settings, that trigger recalculation for all stats when they change.
|
||||
this.app.workspace.trigger('git-changelog:generation-settings-changed');
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.fileChangelogManager?.specificSettingsChanged(
|
||||
oldSettings,
|
||||
newSettings
|
||||
) &&
|
||||
this.cachedActiveGitFile
|
||||
) {
|
||||
this.app.workspace.trigger(
|
||||
'git-changelog:file-changelog-generation-settings-changed'
|
||||
);
|
||||
}
|
||||
|
||||
// Handle destroying and initializing the status bar stats
|
||||
if (this.settings.statusBarStatsEnabled !== !!this.statusBarStats) {
|
||||
const shouldEnableStatusBarStats = this.settings.statusBarStatsEnabled;
|
||||
if (shouldEnableStatusBarStats) {
|
||||
this.initStatusBar();
|
||||
} else {
|
||||
this.statusBarStats?.destroy?.();
|
||||
this.statusBarStats = undefined;
|
||||
}
|
||||
}
|
||||
// Handle status bar settings changes
|
||||
else if (
|
||||
this.statusBarStats &&
|
||||
StatusBarStats.generationSettingsChanged(oldSettings, newSettings) &&
|
||||
this.cachedActiveGitFile
|
||||
) {
|
||||
this.app.workspace.trigger('git-changelog:status-bar-settings-changed');
|
||||
}
|
||||
|
||||
if (
|
||||
this.vaultChangelogManager?.specificSettingsChanged(
|
||||
oldSettings,
|
||||
newSettings
|
||||
)
|
||||
) {
|
||||
this.app.workspace.trigger(
|
||||
'git-changelog:vault-changelog-generation-settings-changed'
|
||||
);
|
||||
}
|
||||
} catch {
|
||||
/* Empty */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
<script lang="ts">
|
||||
import type { FileChangelogEntry } from 'core/ChangelogEntry.svelte.ts';
|
||||
import type { GitChangelogPlugin } from 'GitChangelogPlugin.svelte.ts';
|
||||
import type { EventRef } from 'obsidian';
|
||||
|
||||
import { OPEN_FILE_ICON } from 'constants.ts';
|
||||
import { mayTriggerChangelogMenu } from 'menu.ts';
|
||||
import { setIcon } from 'obsidian';
|
||||
import { onDestroy } from 'svelte';
|
||||
import { DiffFileStatus } from 'types.ts';
|
||||
import { assertNotNull } from 'utils.ts';
|
||||
import DiffStatsComponent from 'Views/components/DiffStats.svelte';
|
||||
|
|
@ -26,6 +28,29 @@
|
|||
|
||||
let openFileButton = $state<HTMLElement>();
|
||||
|
||||
let dayChangedReference: EventRef;
|
||||
|
||||
dayChangedReference = plugin.app.workspace.on(
|
||||
'git-changelog:day-changed',
|
||||
() => {
|
||||
formattedVersionDateLabel = updateFormattedVersionDateLabel();
|
||||
}
|
||||
);
|
||||
|
||||
let formattedVersionDateLabel = $state(updateFormattedVersionDateLabel());
|
||||
|
||||
function updateFormattedVersionDateLabel(): string {
|
||||
return composeVersionTitle({
|
||||
interval: plugin.settings.fileChangelogInterval,
|
||||
plugin,
|
||||
timeZoneAdjustedEntryDate: entry.timeZoneAdjustedDate
|
||||
});
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
plugin.app.workspace.offref(dayChangedReference);
|
||||
});
|
||||
|
||||
function primaryClick(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
|
||||
|
|
@ -73,17 +98,6 @@
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
const formattedVersionDateLabel = $derived.by(() => {
|
||||
// CurrentDay just used to trigger updates
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const currentDay = plugin.currentDay;
|
||||
return composeVersionTitle({
|
||||
interval: plugin.settings.fileChangelogInterval,
|
||||
plugin,
|
||||
timezoneAdjustedEntryDate: entry.timezoneAdjustedDate
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Import { SimpleGit } from "src/gitManager/simpleGit";
|
||||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { EventRef } from 'obsidian';
|
||||
import type { GitChangelogSettings } from 'settings/settings.ts';
|
||||
|
||||
import { TOGGLE_FILES_SUMMARY_OPTION_ICON } from 'constants.ts';
|
||||
import { setIcon } from 'obsidian';
|
||||
|
|
@ -141,16 +142,17 @@
|
|||
collapseButton = undefined;
|
||||
});
|
||||
|
||||
function toggleFilesSummaryOption(): void {
|
||||
async function toggleFilesSummaryOption(): Promise<void> {
|
||||
showFilesCountSummariesMode =
|
||||
showFilesCountSummariesMode === FilesSummariesDisplayMode.Total
|
||||
? FilesSummariesDisplayMode.TextAndBinary
|
||||
: FilesSummariesDisplayMode.Total;
|
||||
|
||||
const newSettings = plugin.settingsClone;
|
||||
newSettings.fileSummariesDisplayMode = showFilesCountSummariesMode;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
plugin.saveSettings(newSettings);
|
||||
await plugin.settingsManager.editAndSave(
|
||||
(settings: GitChangelogSettings): void => {
|
||||
settings.fileSummariesDisplayMode = showFilesCountSummariesMode;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function toggleCollapsedState(): void {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
<script lang="ts">
|
||||
import type { VaultChangelogEntry } from 'core/ChangelogEntry.svelte.ts';
|
||||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { EventRef } from 'obsidian';
|
||||
|
||||
import { mayTriggerChangelogMenu } from 'menu.ts';
|
||||
// eslint-disable-next-line import-x/no-duplicates
|
||||
import { onDestroy } from 'svelte';
|
||||
// eslint-disable-next-line import-x/no-duplicates
|
||||
import { slide } from 'svelte/transition';
|
||||
import { FilesSummariesDisplayMode } from 'types.ts';
|
||||
import { composeVersionTitle } from 'Views/formatters.ts';
|
||||
|
|
@ -20,15 +24,27 @@
|
|||
|
||||
const { plugin, showFilesCountSummaries, version }: Properties = $props();
|
||||
|
||||
const formattedVersionDateLabel = $derived.by(() => {
|
||||
// CurrentDay just used to trigger updates
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const currentDay = plugin.currentDay;
|
||||
let dayChangedReference: EventRef;
|
||||
|
||||
dayChangedReference = plugin.app.workspace.on(
|
||||
'git-changelog:day-changed',
|
||||
() => {
|
||||
formattedVersionDateLabel = updateFormattedVersionDateLabel();
|
||||
}
|
||||
);
|
||||
|
||||
let formattedVersionDateLabel = $state(updateFormattedVersionDateLabel());
|
||||
|
||||
function updateFormattedVersionDateLabel(): string {
|
||||
return composeVersionTitle({
|
||||
interval: plugin.settings.vaultChangelogGenerationSettings.interval,
|
||||
interval: plugin.settings.vaultChangelogInterval,
|
||||
plugin,
|
||||
timezoneAdjustedEntryDate: version.timezoneAdjustedDate
|
||||
timeZoneAdjustedEntryDate: version.timeZoneAdjustedDate
|
||||
});
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
plugin.app.workspace.offref(dayChangedReference);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ import type { Spacetime } from 'spacetime';
|
|||
import type { DiffFile } from 'types.ts';
|
||||
|
||||
import { normalizePath } from 'obsidian';
|
||||
import { getUserLocale } from 'settings/ui/CustomLocale.ts';
|
||||
import { getLocale } from 'settings/ui/CustomLocale.ts';
|
||||
import { getTimeZone } from 'settings/ui/CustomTimeZone.ts';
|
||||
import { getDayStartTime } from 'settings/ui/DayStartTime.ts';
|
||||
import spacetime from 'spacetime';
|
||||
import { applyDayStartTimeSetting } from 'timeUtils.ts';
|
||||
import { applyDayStartHourSetting } from 'timeUtils.ts';
|
||||
import { ChangelogInterval } from 'types.ts';
|
||||
import {
|
||||
assertNotNull,
|
||||
|
|
@ -86,35 +85,35 @@ export function composeDailyVersionDisplayText({
|
|||
|
||||
return formatDate(
|
||||
fullyAdjustedEntryDate.toNativeDate(),
|
||||
getUserLocale(plugin),
|
||||
getTimeZone(plugin.settings.changelogGenerationSettings, plugin)
|
||||
getLocale(plugin),
|
||||
getTimeZone(plugin)
|
||||
);
|
||||
}
|
||||
|
||||
// Only for composing the UI string
|
||||
export function applyDayDisplayOffset({
|
||||
dayStartTime,
|
||||
timezoneAdjustedDate
|
||||
dayStartHour,
|
||||
timeZoneAdjustedDate
|
||||
}: {
|
||||
dayStartTime: number;
|
||||
timezoneAdjustedDate: Spacetime;
|
||||
dayStartHour: number;
|
||||
timeZoneAdjustedDate: Spacetime;
|
||||
}): Spacetime {
|
||||
const dayOffset = timezoneAdjustedDate.hour() < dayStartTime ? 1 : 0;
|
||||
return timezoneAdjustedDate.clone().subtract(dayOffset, 'day');
|
||||
const dayOffset = timeZoneAdjustedDate.hour() < dayStartHour ? 1 : 0;
|
||||
return timeZoneAdjustedDate.clone().subtract(dayOffset, 'day');
|
||||
}
|
||||
|
||||
export function composeHourlyVersionDisplayText({
|
||||
fullyAdjustedCurrentDate,
|
||||
fullyAdjustedEntryDate,
|
||||
timezoneAdjustedEntryDate,
|
||||
timeZoneAdjustedEntryDate,
|
||||
plugin
|
||||
}: {
|
||||
fullyAdjustedCurrentDate: Spacetime;
|
||||
fullyAdjustedEntryDate: Spacetime;
|
||||
timezoneAdjustedEntryDate: Spacetime;
|
||||
timeZoneAdjustedEntryDate: Spacetime;
|
||||
plugin: GitChangelogPlugin;
|
||||
}): string {
|
||||
// Use the fullyAdjusted dates only to check if the dates belong to the same day after the dayStartTime setting is applied.
|
||||
// Use the fullyAdjusted dates only to check if the dates belong to the same day after the dayStartHour setting is applied.
|
||||
const isToday = fullyAdjustedEntryDate.isSame(
|
||||
fullyAdjustedCurrentDate,
|
||||
'day'
|
||||
|
|
@ -124,12 +123,9 @@ export function composeHourlyVersionDisplayText({
|
|||
'day'
|
||||
);
|
||||
|
||||
const userLocale = getUserLocale(plugin);
|
||||
const userLocale = getLocale(plugin);
|
||||
|
||||
const timeZone = getTimeZone(
|
||||
plugin.settings.changelogGenerationSettings,
|
||||
plugin
|
||||
);
|
||||
const timeZone = getTimeZone(plugin);
|
||||
|
||||
// Replaces the day part of the date time string with today or yesterday labels.
|
||||
if (isToday || isYesterday) {
|
||||
|
|
@ -138,7 +134,7 @@ export function composeHourlyVersionDisplayText({
|
|||
timeZone
|
||||
});
|
||||
const timeString = timeFormatter.format(
|
||||
timezoneAdjustedEntryDate.startOf('hour').toNativeDate()
|
||||
timeZoneAdjustedEntryDate.startOf('hour').toNativeDate()
|
||||
);
|
||||
return `${isToday ? 'Today' : 'Yesterday'}, ${timeString}`;
|
||||
}
|
||||
|
|
@ -149,14 +145,14 @@ export function composeHourlyVersionDisplayText({
|
|||
timeZone
|
||||
});
|
||||
|
||||
// Use the timezoneAdjustedEntryDate in the UI and just potentially subtract a day if it crosses the dayStartTime boundary. Don't show the fake fullyAdjustedEntryDate that has the dayStartTime offset applied to hours.
|
||||
const timezoneAdjustedEntryDateWithDayOffset = applyDayDisplayOffset({
|
||||
dayStartTime: getDayStartTime(plugin.settings.changelogGenerationSettings),
|
||||
timezoneAdjustedDate: timezoneAdjustedEntryDate
|
||||
// Use the timeZoneAdjustedEntryDate in the UI and just potentially subtract a day if it crosses the dayStartHour boundary. Don't show the fake fullyAdjustedEntryDate that has the dayStartHour offset applied to hours.
|
||||
const timeZoneAdjustedEntryDateWithDayOffset = applyDayDisplayOffset({
|
||||
dayStartHour: plugin.settings.dayStartHour,
|
||||
timeZoneAdjustedDate: timeZoneAdjustedEntryDate
|
||||
});
|
||||
|
||||
return formatter.format(
|
||||
timezoneAdjustedEntryDateWithDayOffset.startOf('hour').toNativeDate()
|
||||
timeZoneAdjustedEntryDateWithDayOffset.startOf('hour').toNativeDate()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -169,30 +165,28 @@ export function composeMonthlyVersionDisplayText({
|
|||
}): string {
|
||||
return formatMonthYear(
|
||||
fullyAdjustedEntryDate.toNativeDate(),
|
||||
getUserLocale(plugin),
|
||||
getTimeZone(plugin.settings.changelogGenerationSettings, plugin)
|
||||
getLocale(plugin),
|
||||
getTimeZone(plugin)
|
||||
);
|
||||
}
|
||||
|
||||
export function composeVersionTitle({
|
||||
interval,
|
||||
plugin,
|
||||
timezoneAdjustedEntryDate
|
||||
timeZoneAdjustedEntryDate
|
||||
}: {
|
||||
interval: ChangelogInterval;
|
||||
plugin: GitChangelogPlugin;
|
||||
timezoneAdjustedEntryDate: Spacetime;
|
||||
timeZoneAdjustedEntryDate: Spacetime;
|
||||
}): string {
|
||||
const timezoneAdjustedCurrentDate = spacetime.now(
|
||||
getTimeZone(plugin.settings.changelogGenerationSettings, plugin)
|
||||
);
|
||||
const fullyAdjustedCurrentDate = applyDayStartTimeSetting({
|
||||
dayStartTime: getDayStartTime(plugin.settings.changelogGenerationSettings),
|
||||
timezoneAdjustedDate: timezoneAdjustedCurrentDate
|
||||
const timeZoneAdjustedCurrentDate = spacetime.now(getTimeZone(plugin));
|
||||
const fullyAdjustedCurrentDate = applyDayStartHourSetting({
|
||||
dayStartHour: plugin.settings.dayStartHour,
|
||||
timeZoneAdjustedDate: timeZoneAdjustedCurrentDate
|
||||
});
|
||||
const fullyAdjustedEntryDate = applyDayStartTimeSetting({
|
||||
dayStartTime: getDayStartTime(plugin.settings.changelogGenerationSettings),
|
||||
timezoneAdjustedDate: timezoneAdjustedEntryDate
|
||||
const fullyAdjustedEntryDate = applyDayStartHourSetting({
|
||||
dayStartHour: plugin.settings.dayStartHour,
|
||||
timeZoneAdjustedDate: timeZoneAdjustedEntryDate
|
||||
});
|
||||
|
||||
switch (interval) {
|
||||
|
|
@ -200,7 +194,7 @@ export function composeVersionTitle({
|
|||
return composeHourlyVersionDisplayText({
|
||||
fullyAdjustedCurrentDate,
|
||||
fullyAdjustedEntryDate,
|
||||
timezoneAdjustedEntryDate,
|
||||
timeZoneAdjustedEntryDate,
|
||||
plugin
|
||||
});
|
||||
}
|
||||
|
|
@ -251,7 +245,7 @@ export function composeWeeklyVersionDisplayText({
|
|||
return 'Last week';
|
||||
}
|
||||
|
||||
const userLocale = getUserLocale(plugin);
|
||||
const userLocale = getLocale(plugin);
|
||||
|
||||
const weekNumber = fullyAdjustedEntryDate.week();
|
||||
|
||||
|
|
@ -261,10 +255,7 @@ export function composeWeeklyVersionDisplayText({
|
|||
);
|
||||
|
||||
const nativeFullyAdjustedEntryWeek = fullyAdjustedEntryWeek.toNativeDate();
|
||||
const timeZone = getTimeZone(
|
||||
plugin.settings.changelogGenerationSettings,
|
||||
plugin
|
||||
);
|
||||
const timeZone = getTimeZone(plugin);
|
||||
|
||||
if (isCurrentYear) {
|
||||
const monthString = new Intl.DateTimeFormat(userLocale, {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,21 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { PluginTypesBase } from 'obsidian-dev-utils/obsidian/Plugin/PluginTypesBase';
|
||||
import type { GitChangelogSettings } from 'settings/settings.ts';
|
||||
import type { GitChangelogSettingsManager } from 'settings/settingsManager.ts';
|
||||
import type { GitChangelogSettingsTab } from 'settings/settingsTab.ts';
|
||||
|
||||
export const PLUGIN_NAME = 'Git Changelog';
|
||||
export const PLUGIN_NAME_SENTENCE_CASE = 'Git changelog';
|
||||
export const MIN_COMPATIBLE_GIT_PLUGIN_VERSION = '2.31.1';
|
||||
export const MAX_TESTED_GIT_PLUGIN_VERSION = '2.32.1';
|
||||
|
||||
export interface GitChangelogPluginTypes extends PluginTypesBase {
|
||||
plugin: GitChangelogPlugin;
|
||||
pluginSettings: GitChangelogSettings;
|
||||
pluginSettingsManager: GitChangelogSettingsManager;
|
||||
pluginSettingsTab: GitChangelogSettingsTab;
|
||||
}
|
||||
|
||||
// Strings
|
||||
export const FEEDBACK_URL =
|
||||
'https://github.com/shumadrid/obsidian-git-changelog/issues';
|
||||
|
|
@ -29,3 +42,7 @@ export const CHANGELOG_LOAD_AMOUNT_BASE_MULTIPLIER = 35;
|
|||
export const CHANGELOG_LOAD_AMOUNT_VERSIONS = 10;
|
||||
export const FILE_VIEW_VERSIONS_MULTIPLIER = 2.4;
|
||||
export const VAULT_MAX_COUNT_MULTIPLIER = 6;
|
||||
|
||||
// Settings
|
||||
export const MIN_RENAME_DETECTION_STRICTNESS = 1;
|
||||
export const MAX_RENAME_DETECTION_STRICTNESS = 100;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import type {
|
|||
|
||||
export abstract class ChangelogEntry {
|
||||
public constructor(
|
||||
public timezoneAdjustedDate: Spacetime,
|
||||
public timeZoneAdjustedDate: Spacetime,
|
||||
|
||||
public commitHash: string // Represents a single commit that's just the latest commit of a certain interval (day,week...).
|
||||
) {}
|
||||
|
|
@ -33,16 +33,16 @@ export class FileChangelogEntry extends ChangelogEntry implements DiffFile {
|
|||
pathGitRelative,
|
||||
status,
|
||||
textDiffStats,
|
||||
timezoneAdjustedDate
|
||||
timeZoneAdjustedDate
|
||||
}: {
|
||||
commitHash: string;
|
||||
fromPathGitRelative?: string;
|
||||
pathGitRelative: string;
|
||||
status: DiffFileStatus;
|
||||
textDiffStats?: TextDiffStats;
|
||||
timezoneAdjustedDate: Spacetime;
|
||||
timeZoneAdjustedDate: Spacetime;
|
||||
}) {
|
||||
super(timezoneAdjustedDate, commitHash);
|
||||
super(timeZoneAdjustedDate, commitHash);
|
||||
this.pathGitRelative = pathGitRelative;
|
||||
this.status = status;
|
||||
this.fromPathGitRelative = fromPathGitRelative;
|
||||
|
|
@ -78,7 +78,7 @@ export class VaultChangelogEntry extends ChangelogEntry {
|
|||
previousDayLastCommitHash,
|
||||
textFiles,
|
||||
textFilesSummaryCached,
|
||||
timezoneAdjustedDate
|
||||
timeZoneAdjustedDate
|
||||
}: {
|
||||
binaryFiles: DiffFile[];
|
||||
binaryFilesSummaryCached: FilesSummary;
|
||||
|
|
@ -86,9 +86,9 @@ export class VaultChangelogEntry extends ChangelogEntry {
|
|||
previousDayLastCommitHash?: string;
|
||||
textFiles: DiffFile[];
|
||||
textFilesSummaryCached: FilesSummary;
|
||||
timezoneAdjustedDate: Spacetime;
|
||||
timeZoneAdjustedDate: Spacetime;
|
||||
}) {
|
||||
super(timezoneAdjustedDate, commitHash);
|
||||
super(timeZoneAdjustedDate, commitHash);
|
||||
this.textFiles = textFiles;
|
||||
this.binaryFiles = binaryFiles;
|
||||
this.textFilesSummaryCached = textFilesSummaryCached;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { ChangelogEntry } from 'core/ChangelogEntry.svelte.ts';
|
||||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { GitChangelogPluginSettings } from 'settings/settings.ts';
|
||||
import type { GitChangelogSettings } from 'settings/settings.ts';
|
||||
import type { Spacetime } from 'spacetime';
|
||||
import type { TaskManager } from 'TaskManager.svelte.ts';
|
||||
import type { ReadonlyDeep } from 'type-fest';
|
||||
|
|
@ -12,6 +12,7 @@ import {
|
|||
extractLastCommitsForInterval,
|
||||
GIT_MAX_CONCURRENT_PROCESSES
|
||||
} from 'core/helper.ts';
|
||||
import { getTimeZone } from 'settings/ui/CustomTimeZone.ts';
|
||||
import { AbortError, ChangelogInterval } from 'types.ts';
|
||||
import { assertNotNull } from 'utils.ts';
|
||||
|
||||
|
|
@ -121,12 +122,10 @@ export abstract class ChangelogManager<T extends ChangelogEntry> {
|
|||
});
|
||||
}
|
||||
|
||||
public generationSettingsChanged(
|
||||
oldSettings: ReadonlyDeep<GitChangelogPluginSettings>,
|
||||
newSettings: GitChangelogPluginSettings
|
||||
): boolean {
|
||||
return this.getInterval(oldSettings) !== this.getInterval(newSettings);
|
||||
}
|
||||
public abstract specificSettingsChanged(
|
||||
oldSettings: ReadonlyDeep<GitChangelogSettings>,
|
||||
newSettings: GitChangelogSettings
|
||||
): boolean;
|
||||
|
||||
public resetAndGetSignal(): AbortSignal {
|
||||
// Reset `visibleEntries` to undefined each time when you schedule a recompute so that the UI correctly updates to "loading" state while it waits for the stats to compute.
|
||||
|
|
@ -143,7 +142,7 @@ export abstract class ChangelogManager<T extends ChangelogEntry> {
|
|||
public abstract setNextInterval(): Promise<void>;
|
||||
|
||||
public abstract getInterval(
|
||||
settings?: ReadonlyDeep<GitChangelogPluginSettings>
|
||||
settings?: ReadonlyDeep<GitChangelogSettings>
|
||||
): ChangelogInterval;
|
||||
|
||||
protected abstract updateEntries({
|
||||
|
|
@ -168,21 +167,23 @@ export abstract class ChangelogManager<T extends ChangelogEntry> {
|
|||
// ActiveGitFile: the current file path of some live file version.
|
||||
// FilePath: the path of some file in history.
|
||||
|
||||
const git = await this.plugin.getGit();
|
||||
// Gets all commits newer (>=) than the commit of the latest cached version.
|
||||
const timezoneAdjustedLogs = await runLog({
|
||||
const timeZoneAdjustedLogs = await runLog({
|
||||
abortSignal,
|
||||
filePath: activeGitFile,
|
||||
lowerBoundaryCommit: this.latestCachedVersion?.commitHash,
|
||||
maxCount: undefined,
|
||||
plugin: this.plugin,
|
||||
upperBoundaryCommit: undefined
|
||||
upperBoundaryCommit: undefined,
|
||||
git,
|
||||
renameDetectionStrictness: this.plugin.settings.renameDetectionStrictness,
|
||||
timeZone: getTimeZone(this.plugin)
|
||||
});
|
||||
|
||||
const extractedVersions = await extractLastCommitsForInterval({
|
||||
changelogGenerationSettings:
|
||||
this.plugin.settings.changelogGenerationSettings,
|
||||
dayStartHour: this.plugin.settings.dayStartHour,
|
||||
interval: this.getInterval(),
|
||||
timezoneAdjustedLogs
|
||||
timeZoneAdjustedLogs
|
||||
});
|
||||
|
||||
// Always recalculate the latest version in cached changelog (because it likely has outdated stats), but only if there are any versions to recalculate.
|
||||
|
|
@ -194,7 +195,7 @@ export abstract class ChangelogManager<T extends ChangelogEntry> {
|
|||
extractedVersions.push({
|
||||
filePath: versionBeforeLatestCached.getPotentialGitFilePath(),
|
||||
hash: versionBeforeLatestCached.commitHash,
|
||||
timezoneAdjustedDate: versionBeforeLatestCached.timezoneAdjustedDate
|
||||
timeZoneAdjustedDate: versionBeforeLatestCached.timeZoneAdjustedDate
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -392,31 +393,34 @@ export abstract class ChangelogManager<T extends ChangelogEntry> {
|
|||
) {
|
||||
logCycles++;
|
||||
|
||||
const timezoneAdjustedLogs = await runLog({
|
||||
const git = await this.plugin.getGit();
|
||||
const timeZoneAdjustedLogs = await runLog({
|
||||
abortSignal,
|
||||
filePath: startingFilePath,
|
||||
lowerBoundaryCommit: undefined,
|
||||
maxCount: logMaxCount,
|
||||
plugin: this.plugin,
|
||||
git,
|
||||
renameDetectionStrictness:
|
||||
this.plugin.settings.renameDetectionStrictness,
|
||||
timeZone: getTimeZone(this.plugin),
|
||||
upperBoundaryCommit: startingCommit
|
||||
});
|
||||
|
||||
// All we need from a version is its latest commit, not all commits included in that interval
|
||||
const extractedVersions = await extractLastCommitsForInterval({
|
||||
changelogGenerationSettings:
|
||||
this.plugin.settings.changelogGenerationSettings,
|
||||
dayStartHour: this.plugin.settings.dayStartHour,
|
||||
interval,
|
||||
previouslySeenFullyAdjustedDates: fullyAdjustedSeenDates,
|
||||
timezoneAdjustedLogs
|
||||
timeZoneAdjustedLogs
|
||||
});
|
||||
|
||||
if (timezoneAdjustedLogs.length < logMaxCount) {
|
||||
if (timeZoneAdjustedLogs.length < logMaxCount) {
|
||||
reachedInitialCommit = true;
|
||||
}
|
||||
// If getting file changelog versions and need to loop many times, we need to track the file path across renames so that we can follow the target file across its whole history.
|
||||
startingFilePath = timezoneAdjustedLogs.at(-1)?.filePath;
|
||||
startingFilePath = timeZoneAdjustedLogs.at(-1)?.filePath;
|
||||
|
||||
startingCommit = timezoneAdjustedLogs.at(-1)?.hash;
|
||||
startingCommit = timeZoneAdjustedLogs.at(-1)?.hash;
|
||||
|
||||
lastCommitsInEachVersion.push(...extractedVersions);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { FileChangelogEntry } from 'core/ChangelogEntry.svelte.ts';
|
||||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { GitChangelogPluginSettings } from 'settings/settings.ts';
|
||||
import type { GitChangelogSettings } from 'settings/settings.ts';
|
||||
import type { TaskManager } from 'TaskManager.svelte.ts';
|
||||
import type { ReadonlyDeep } from 'type-fest';
|
||||
import type { ChangelogInterval, FileLogEntry } from 'types.ts';
|
||||
|
|
@ -12,8 +12,8 @@ import {
|
|||
} from 'constants.ts';
|
||||
import { ChangelogManager } from 'core/ChangelogManager.svelte.ts';
|
||||
import { runFileDiff } from 'core/gitOperations/runFileDiff.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { validateChangelogInterval } from 'settings/validation/changelogInterval.ts';
|
||||
import { deepEqual } from 'obsidian-dev-utils/Object';
|
||||
import { pickFileChangelogSettings } from 'settings/settings.ts';
|
||||
|
||||
export class FileChangelogManager extends ChangelogManager<FileChangelogEntry> {
|
||||
public constructor({
|
||||
|
|
@ -47,23 +47,30 @@ export class FileChangelogManager extends ChangelogManager<FileChangelogEntry> {
|
|||
}
|
||||
|
||||
public override async setNextInterval(): Promise<void> {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
await this.plugin.settingsManager.editAndSave(
|
||||
(settings: GitChangelogSettings): void => {
|
||||
settings.fileChangelogInterval = this.getNextInterval();
|
||||
}
|
||||
);
|
||||
this.plugin.app.workspace.trigger(
|
||||
'git-changelog:file-changelog-generation-settings-changed'
|
||||
);
|
||||
}
|
||||
|
||||
newSettings.fileChangelogInterval = this.getNextInterval();
|
||||
public override specificSettingsChanged(
|
||||
oldSettings: ReadonlyDeep<GitChangelogSettings>,
|
||||
newSettings: GitChangelogSettings
|
||||
): boolean {
|
||||
const oldVaultGenerationSettings = pickFileChangelogSettings(oldSettings);
|
||||
const newVaultGenerationSettings = pickFileChangelogSettings(newSettings);
|
||||
|
||||
await this.plugin.saveSettings(newSettings, false);
|
||||
return !deepEqual(oldVaultGenerationSettings, newVaultGenerationSettings);
|
||||
}
|
||||
|
||||
public override getInterval(
|
||||
settings: ReadonlyDeep<GitChangelogPluginSettings> = this.plugin.settings
|
||||
settings: ReadonlyDeep<GitChangelogSettings> = this.plugin.settings
|
||||
): ChangelogInterval {
|
||||
const interval = settings.fileChangelogInterval;
|
||||
|
||||
if (!validateChangelogInterval(interval)) {
|
||||
return DEFAULT_SETTINGS.fileChangelogInterval;
|
||||
}
|
||||
|
||||
return interval;
|
||||
return settings.fileChangelogInterval;
|
||||
}
|
||||
|
||||
protected override async loadEntries({
|
||||
|
|
@ -124,11 +131,17 @@ export class FileChangelogManager extends ChangelogManager<FileChangelogEntry> {
|
|||
newCommit: FileLogEntry;
|
||||
oldCommit?: FileLogEntry;
|
||||
}): Promise<FileChangelogEntry | undefined> {
|
||||
const git = await this.plugin.getGit();
|
||||
return await runFileDiff({
|
||||
abortSignal,
|
||||
newCommit,
|
||||
oldCommit,
|
||||
plugin: this.plugin
|
||||
plugin: this.plugin,
|
||||
diffAlgorithm: this.plugin.settings.diffAlgorithm,
|
||||
whitespaceIgnoreMode: this.plugin.settings.whitespaceIgnoreMode,
|
||||
ignoreBlankLines: this.plugin.settings.ignoreBlankLines,
|
||||
emptyTreeHash: await this.plugin.getEmptyTreeHash(),
|
||||
git
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { VaultChangelogEntry } from 'core/ChangelogEntry.svelte.ts';
|
||||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { GitChangelogPluginSettings } from 'settings/settings.ts';
|
||||
import type { GitChangelogSettings } from 'settings/settings.ts';
|
||||
import type { TaskManager } from 'TaskManager.svelte.ts';
|
||||
import type { ReadonlyDeep } from 'type-fest';
|
||||
import type { ChangelogInterval, LogEntry } from 'types.ts';
|
||||
|
|
@ -13,8 +13,7 @@ import {
|
|||
import { ChangelogManager } from 'core/ChangelogManager.svelte.ts';
|
||||
import { runRepoDiff } from 'core/gitOperations/runRepoDiff.ts';
|
||||
import { deepEqual } from 'obsidian-dev-utils/Object';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { validateChangelogInterval } from 'settings/validation/changelogInterval.ts';
|
||||
import { pickVaultChangelogSettings } from 'settings/settings.ts';
|
||||
|
||||
export class VaultChangelogManager extends ChangelogManager<VaultChangelogEntry> {
|
||||
private collapseFirstVersion: boolean | undefined;
|
||||
|
|
@ -48,46 +47,30 @@ export class VaultChangelogManager extends ChangelogManager<VaultChangelogEntry>
|
|||
}
|
||||
|
||||
public override async setNextInterval(): Promise<void> {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
|
||||
newSettings.vaultChangelogGenerationSettings.interval =
|
||||
this.getNextInterval();
|
||||
|
||||
await this.plugin.saveSettings(newSettings, false);
|
||||
await this.plugin.settingsManager.editAndSave(
|
||||
(settings: GitChangelogSettings): void => {
|
||||
settings.vaultChangelogInterval = this.getNextInterval();
|
||||
}
|
||||
);
|
||||
this.plugin.app.workspace.trigger(
|
||||
'git-changelog:vault-changelog-generation-settings-changed'
|
||||
);
|
||||
}
|
||||
|
||||
public override generationSettingsChanged(
|
||||
oldSettings: ReadonlyDeep<GitChangelogPluginSettings>,
|
||||
newSettings: GitChangelogPluginSettings
|
||||
public override specificSettingsChanged(
|
||||
oldSettings: ReadonlyDeep<GitChangelogSettings>,
|
||||
newSettings: GitChangelogSettings
|
||||
): boolean {
|
||||
if (
|
||||
!deepEqual(
|
||||
oldSettings.vaultChangelogGenerationSettings
|
||||
.excludeFilesAndFoldersLines,
|
||||
newSettings.vaultChangelogGenerationSettings.excludeFilesAndFoldersLines
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
oldSettings.vaultChangelogGenerationSettings.convertToIncludeList !==
|
||||
newSettings.vaultChangelogGenerationSettings.convertToIncludeList
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return super.generationSettingsChanged(oldSettings, newSettings);
|
||||
const oldVaultGenerationSettings = pickVaultChangelogSettings(oldSettings);
|
||||
const newVaultGenerationSettings = pickVaultChangelogSettings(newSettings);
|
||||
|
||||
return !deepEqual(oldVaultGenerationSettings, newVaultGenerationSettings);
|
||||
}
|
||||
|
||||
public override getInterval(
|
||||
settings: ReadonlyDeep<GitChangelogPluginSettings> = this.plugin.settings
|
||||
settings: ReadonlyDeep<GitChangelogSettings> = this.plugin.settings
|
||||
): ChangelogInterval {
|
||||
const interval = settings.vaultChangelogGenerationSettings.interval;
|
||||
|
||||
if (!validateChangelogInterval(interval)) {
|
||||
return DEFAULT_SETTINGS.vaultChangelogGenerationSettings.interval;
|
||||
}
|
||||
|
||||
return interval;
|
||||
return settings.vaultChangelogInterval;
|
||||
}
|
||||
|
||||
protected override calculateVersionsToAppend(resetCache: boolean): number {
|
||||
|
|
@ -105,11 +88,22 @@ export class VaultChangelogManager extends ChangelogManager<VaultChangelogEntry>
|
|||
newCommit: LogEntry;
|
||||
oldCommit?: LogEntry;
|
||||
}): Promise<undefined | VaultChangelogEntry> {
|
||||
const git = await this.plugin.getGit();
|
||||
return await runRepoDiff({
|
||||
abortSignal,
|
||||
newCommit,
|
||||
oldCommit,
|
||||
plugin: this.plugin
|
||||
plugin: this.plugin,
|
||||
git,
|
||||
diffAlgorithm: this.plugin.settings.diffAlgorithm,
|
||||
renameLimit: this.plugin.settings.renameLimit,
|
||||
renameDetectionStrictness: this.plugin.settings.renameDetectionStrictness,
|
||||
emptyTreeHash: await this.plugin.getEmptyTreeHash(),
|
||||
excludeFilesAndFoldersLines:
|
||||
this.plugin.settings.excludeFilesAndFoldersLines,
|
||||
convertToIncludeList: this.plugin.settings.convertToIncludeList,
|
||||
whitespaceIgnoreMode: this.plugin.settings.whitespaceIgnoreMode,
|
||||
ignoreBlankLines: this.plugin.settings.ignoreBlankLines
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { SimpleGit } from 'simple-git';
|
||||
import type { LogEntry } from 'types.ts';
|
||||
|
||||
import { runLog } from 'core/gitOperations/runLog.ts';
|
||||
import { getTimeZone } from 'settings/ui/CustomTimeZone.ts';
|
||||
import spacetime from 'spacetime';
|
||||
import { AbortError } from 'types.ts';
|
||||
import { assertNotNull } from 'utils.ts';
|
||||
|
|
@ -14,21 +13,23 @@ export async function findFirstFileCommitBefore({
|
|||
abortSignal,
|
||||
filePath,
|
||||
minutes,
|
||||
plugin
|
||||
timeZone,
|
||||
git,
|
||||
renameDetectionStrictness
|
||||
}: {
|
||||
abortSignal: AbortSignal;
|
||||
filePath: string;
|
||||
minutes: number;
|
||||
plugin: GitChangelogPlugin;
|
||||
timeZone: string;
|
||||
git: SimpleGit;
|
||||
renameDetectionStrictness: number;
|
||||
}): Promise<LogEntry | undefined> {
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
const maxCount = Math.ceil(minutes / AVERAGE_COMMIT_FREQUENCY_MINUTES) + 20;
|
||||
|
||||
let firstEntriesOutsideInterval: LogEntry[] = [];
|
||||
let startingFilePath = filePath;
|
||||
const currentTime = spacetime.now(
|
||||
getTimeZone(plugin.settings.changelogGenerationSettings, plugin)
|
||||
);
|
||||
const currentTime = spacetime.now(timeZone);
|
||||
let startingCommit: string | undefined;
|
||||
|
||||
while (
|
||||
|
|
@ -36,7 +37,7 @@ export async function findFirstFileCommitBefore({
|
|||
!firstEntriesOutsideInterval.at(-1) ||
|
||||
// Only continue if commit(s) that happened before the specified interval aren't reached yet.
|
||||
|
||||
assertNotNull(firstEntriesOutsideInterval.at(-1)).timezoneAdjustedDate.diff(
|
||||
assertNotNull(firstEntriesOutsideInterval.at(-1)).timeZoneAdjustedDate.diff(
|
||||
currentTime,
|
||||
|
||||
'minutes'
|
||||
|
|
@ -49,8 +50,10 @@ export async function findFirstFileCommitBefore({
|
|||
filePath: startingFilePath,
|
||||
lowerBoundaryCommit: undefined,
|
||||
maxCount,
|
||||
plugin,
|
||||
upperBoundaryCommit: startingCommit
|
||||
upperBoundaryCommit: startingCommit,
|
||||
git,
|
||||
renameDetectionStrictness,
|
||||
timeZone
|
||||
});
|
||||
|
||||
if (firstEntriesOutsideInterval.length < maxCount) {
|
||||
|
|
@ -73,7 +76,7 @@ export async function findFirstFileCommitBefore({
|
|||
|
||||
// We just need to get the most recent commit that's still outside the interval.
|
||||
for (const entry of firstEntriesOutsideInterval) {
|
||||
if (entry.timezoneAdjustedDate.diff(currentTime, 'minutes') >= minutes) {
|
||||
if (entry.timeZoneAdjustedDate.diff(currentTime, 'minutes') >= minutes) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,24 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { SimpleGit } from 'simple-git';
|
||||
import type { LogEntry } from 'types.ts';
|
||||
|
||||
import { getTimeZone } from 'settings/ui/CustomTimeZone.ts';
|
||||
import spacetime from 'spacetime';
|
||||
import { AbortError } from 'types.ts';
|
||||
|
||||
export async function findFirstCommitBefore({
|
||||
abortSignal,
|
||||
minutes,
|
||||
plugin
|
||||
git,
|
||||
timeZone
|
||||
}: {
|
||||
abortSignal: AbortSignal;
|
||||
minutes: number;
|
||||
plugin: GitChangelogPlugin;
|
||||
git: SimpleGit;
|
||||
timeZone: string;
|
||||
}): Promise<LogEntry | undefined> {
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
|
||||
const options: Record<string, unknown> = {
|
||||
// "--no-patch": null,
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
|
|
@ -28,15 +33,7 @@ export async function findFirstCommitBefore({
|
|||
strictDate: true
|
||||
};
|
||||
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
const git = await plugin.getGit();
|
||||
const result = await git.log(options);
|
||||
const timezone = getTimeZone(
|
||||
plugin.settings.changelogGenerationSettings,
|
||||
plugin
|
||||
);
|
||||
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
|
|
@ -50,6 +47,6 @@ export async function findFirstCommitBefore({
|
|||
return result.all.map<LogEntry>((entry) => ({
|
||||
filePath: undefined,
|
||||
hash: entry.hash,
|
||||
timezoneAdjustedDate: spacetime(entry.date).goto(timezone)
|
||||
timeZoneAdjustedDate: spacetime(entry.date).goto(timeZone)
|
||||
}))[0];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
|
||||
async function runHashObjectEmptyTree({
|
||||
plugin
|
||||
}: {
|
||||
plugin: GitChangelogPlugin;
|
||||
}): Promise<string> {
|
||||
const git = await plugin.getGit();
|
||||
|
||||
const emptyTreeHash = await git.raw([
|
||||
'hash-object',
|
||||
'-t',
|
||||
'tree',
|
||||
'/dev/null'
|
||||
]);
|
||||
|
||||
return emptyTreeHash.trim();
|
||||
}
|
||||
|
||||
export async function getEmptyTreeHash({
|
||||
plugin
|
||||
}: {
|
||||
plugin: GitChangelogPlugin;
|
||||
}): Promise<string> {
|
||||
if (plugin.emptyTreeHash) {
|
||||
return plugin.emptyTreeHash;
|
||||
}
|
||||
|
||||
const emptyTreeHash = await runHashObjectEmptyTree({ plugin });
|
||||
plugin.emptyTreeHash ??= emptyTreeHash;
|
||||
return plugin.emptyTreeHash;
|
||||
}
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { DiffFile, FilesSummary } from 'types.ts';
|
||||
|
||||
import { normalizePath } from 'obsidian';
|
||||
import { getDiffAlgorithm } from 'settings/ui/DiffAlgorithmOptions.ts';
|
||||
import { getWhitespaceIgnoreMode } from 'settings/ui/WhitespaceIgnoreMode.ts';
|
||||
import { DiffAlgorithm, DiffFileStatus, WhitespaceIgnoreMode } from 'types.ts';
|
||||
import { getFileNameFromPath } from 'utils.ts';
|
||||
import { getDisplayExtensionFromPath } from 'Views/formatters.ts';
|
||||
|
|
@ -23,11 +20,14 @@ export function addFileStatusToSummary(
|
|||
}
|
||||
}
|
||||
|
||||
export function assignDiffAlgorithm(
|
||||
arguments_: string[],
|
||||
plugin: GitChangelogPlugin
|
||||
): void {
|
||||
switch (getDiffAlgorithm(plugin.settings.changelogGenerationSettings)) {
|
||||
export function assignDiffAlgorithm({
|
||||
arguments_,
|
||||
diffAlgorithm
|
||||
}: {
|
||||
arguments_: string[];
|
||||
diffAlgorithm: DiffAlgorithm;
|
||||
}): void {
|
||||
switch (diffAlgorithm) {
|
||||
case DiffAlgorithm.Default: {
|
||||
arguments_.push('--diff-algorithm=default');
|
||||
break;
|
||||
|
|
@ -44,13 +44,15 @@ export function assignDiffAlgorithm(
|
|||
}
|
||||
}
|
||||
|
||||
export function assignWhitespaceIgnoreSettings(
|
||||
arguments_: string[],
|
||||
plugin: GitChangelogPlugin
|
||||
): void {
|
||||
const whitespaceIgnoreMode = getWhitespaceIgnoreMode(
|
||||
plugin.settings.changelogGenerationSettings
|
||||
);
|
||||
export function assignWhitespaceIgnoreSettings({
|
||||
arguments_,
|
||||
whitespaceIgnoreMode,
|
||||
ignoreBlankLines
|
||||
}: {
|
||||
arguments_: string[];
|
||||
whitespaceIgnoreMode: WhitespaceIgnoreMode;
|
||||
ignoreBlankLines: boolean;
|
||||
}): void {
|
||||
switch (whitespaceIgnoreMode) {
|
||||
case WhitespaceIgnoreMode.None: {
|
||||
break;
|
||||
|
|
@ -69,7 +71,7 @@ export function assignWhitespaceIgnoreSettings(
|
|||
}
|
||||
}
|
||||
|
||||
if (plugin.settings.changelogGenerationSettings.ignoreBlankLines) {
|
||||
if (ignoreBlankLines) {
|
||||
arguments_.push('--ignore-blank-lines');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { SimpleGit } from 'simple-git';
|
||||
|
||||
/**
|
||||
* Doesn't work because of the way SimpleGit instance is set up in Git plugin.
|
||||
|
|
@ -6,16 +6,15 @@ import type GitChangelogPlugin from 'main.ts';
|
|||
export async function isAncestorOf({
|
||||
newCommit,
|
||||
oldCommit,
|
||||
plugin
|
||||
git
|
||||
}: {
|
||||
newCommit: string;
|
||||
oldCommit: string;
|
||||
plugin: GitChangelogPlugin;
|
||||
git: SimpleGit;
|
||||
}): Promise<boolean> {
|
||||
if (oldCommit === newCommit) {
|
||||
return true;
|
||||
}
|
||||
const git = await plugin.getGit();
|
||||
|
||||
const result = await git.raw([
|
||||
'merge-base',
|
||||
|
|
@ -23,7 +22,6 @@ export async function isAncestorOf({
|
|||
oldCommit,
|
||||
newCommit
|
||||
]);
|
||||
// Plugin.consoleDebug(result);
|
||||
|
||||
if (result === '1') {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,22 +1,20 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { SimpleGit } from 'simple-git';
|
||||
|
||||
import { AbortError } from 'types.ts';
|
||||
|
||||
export async function runCheckIgnore({
|
||||
abortSignal,
|
||||
activeGitFile,
|
||||
plugin
|
||||
git
|
||||
}: {
|
||||
abortSignal: AbortSignal;
|
||||
activeGitFile: string;
|
||||
plugin: GitChangelogPlugin;
|
||||
git: SimpleGit;
|
||||
}): Promise<boolean> {
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
const gitCheckIgnoreResult = await plugin
|
||||
.getGitPlugin()
|
||||
.gitManager.git.checkIgnore(activeGitFile);
|
||||
const gitCheckIgnoreResult = await git.checkIgnore(activeGitFile);
|
||||
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { FileLogEntry } from 'types.ts';
|
||||
import type { SimpleGit } from 'simple-git';
|
||||
import type {
|
||||
DiffAlgorithm,
|
||||
FileLogEntry,
|
||||
WhitespaceIgnoreMode
|
||||
} from 'types.ts';
|
||||
|
||||
import { FileChangelogEntry } from 'core/ChangelogEntry.svelte.ts';
|
||||
import { getEmptyTreeHash } from 'core/gitOperations/getEmptyTreeHash.ts';
|
||||
import {
|
||||
assignDiffAlgorithm,
|
||||
assignWhitespaceIgnoreSettings,
|
||||
|
|
@ -14,19 +18,33 @@ export async function runFileDiff({
|
|||
abortSignal,
|
||||
newCommit,
|
||||
oldCommit,
|
||||
plugin
|
||||
plugin,
|
||||
git,
|
||||
diffAlgorithm,
|
||||
whitespaceIgnoreMode,
|
||||
ignoreBlankLines,
|
||||
emptyTreeHash
|
||||
}: {
|
||||
abortSignal: AbortSignal;
|
||||
newCommit: FileLogEntry;
|
||||
oldCommit?: FileLogEntry;
|
||||
plugin: GitChangelogPlugin;
|
||||
plugin?: GitChangelogPlugin;
|
||||
git: SimpleGit;
|
||||
diffAlgorithm: DiffAlgorithm;
|
||||
whitespaceIgnoreMode: WhitespaceIgnoreMode;
|
||||
ignoreBlankLines: boolean;
|
||||
emptyTreeHash: string;
|
||||
}): Promise<FileChangelogEntry | undefined> {
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
|
||||
const oldVersionIsEmpty =
|
||||
oldCommit === undefined || oldCommit.fileDeleted === true;
|
||||
|
||||
if (oldVersionIsEmpty && newCommit.fileDeleted) {
|
||||
// I assumed that the other should always be defined if one is undefined, since newCommit.hash is only undefined for commits where the file was deleted, and it can't get deleted if it didn't exist before, but these are statuses calculated from comparing neighboring commits, but we are diffing selected commits only, so maybe it's possible that we get in a situation where we compare some initial version commit (that isn't the actual initial commit, so that commit could be a deletion of that file, if a file was newly added and then deleted in the same interval) with an empty state
|
||||
plugin.consoleDebug(
|
||||
plugin?.consoleDebug(
|
||||
'oldCommit and newCommit are both undefined, assumption is wrong'
|
||||
);
|
||||
|
||||
|
|
@ -39,13 +57,15 @@ export async function runFileDiff({
|
|||
'--no-renames'
|
||||
// `--exit-code`,
|
||||
];
|
||||
assignDiffAlgorithm(numstatArguments, plugin);
|
||||
assignWhitespaceIgnoreSettings(numstatArguments, plugin);
|
||||
assignDiffAlgorithm({ arguments_: numstatArguments, diffAlgorithm });
|
||||
assignWhitespaceIgnoreSettings({
|
||||
arguments_: numstatArguments,
|
||||
whitespaceIgnoreMode,
|
||||
ignoreBlankLines
|
||||
});
|
||||
|
||||
// Only one of these can be true at the same time since we are returning early if they are both true.
|
||||
if (oldVersionIsEmpty || newCommit.fileDeleted) {
|
||||
const emptyTreeHash = await getEmptyTreeHash({ plugin });
|
||||
|
||||
numstatArguments.push(
|
||||
emptyTreeHash,
|
||||
oldVersionIsEmpty ? newCommit.hash : oldCommit.hash,
|
||||
|
|
@ -77,11 +97,6 @@ export async function runFileDiff({
|
|||
);
|
||||
}
|
||||
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
|
||||
const git = await plugin.getGit();
|
||||
const diffNumstatResult = await git.diffSummary(numstatArguments);
|
||||
|
||||
if (
|
||||
|
|
@ -113,7 +128,7 @@ export async function runFileDiff({
|
|||
pathGitRelative: newCommit.filePath, // Passing oldCommit.filePath or undefined for fileDeleted case could be more logical, but not compatible with use in git commands.
|
||||
status: fileStatus,
|
||||
textDiffStats,
|
||||
timezoneAdjustedDate: newCommit.timezoneAdjustedDate
|
||||
timeZoneAdjustedDate: newCommit.timeZoneAdjustedDate
|
||||
});
|
||||
return fileEntry;
|
||||
}
|
||||
|
|
|
|||
17
src/core/gitOperations/runHashObjectEmptyTree.ts
Normal file
17
src/core/gitOperations/runHashObjectEmptyTree.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { SimpleGit } from 'simple-git';
|
||||
|
||||
export async function runHashObjectEmptyTree({
|
||||
git
|
||||
}: {
|
||||
git: SimpleGit;
|
||||
}): Promise<string> {
|
||||
const emptyTreeHash = await git.raw([
|
||||
'hash-object',
|
||||
'-t',
|
||||
'tree',
|
||||
'/dev/null'
|
||||
]);
|
||||
|
||||
// Trimming is required.
|
||||
return emptyTreeHash.trim();
|
||||
}
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { SimpleGit } from 'simple-git';
|
||||
import type { LogEntry } from 'types.ts';
|
||||
|
||||
import { unescapeGitFileOutput } from 'core/gitOperations/helper.ts';
|
||||
import { getTimeZone } from 'settings/ui/CustomTimeZone.ts';
|
||||
import { getRenameDetectionStrictness } from 'settings/ui/RenameDetectionStrictnessSlider.ts';
|
||||
import spacetime from 'spacetime';
|
||||
import { AbortError } from 'types.ts';
|
||||
import { assertNotNull } from 'utils.ts';
|
||||
|
|
@ -18,16 +16,23 @@ export async function runLog({
|
|||
filePath,
|
||||
lowerBoundaryCommit,
|
||||
maxCount,
|
||||
plugin,
|
||||
upperBoundaryCommit
|
||||
upperBoundaryCommit,
|
||||
timeZone,
|
||||
git,
|
||||
renameDetectionStrictness
|
||||
}: {
|
||||
abortSignal: AbortSignal;
|
||||
filePath: string | undefined;
|
||||
lowerBoundaryCommit: string | undefined;
|
||||
maxCount?: number;
|
||||
plugin: GitChangelogPlugin;
|
||||
upperBoundaryCommit: string | undefined;
|
||||
git: SimpleGit;
|
||||
timeZone: string;
|
||||
renameDetectionStrictness: number;
|
||||
}): Promise<LogEntry[]> {
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
// This is confusing, and could be accidentally broken in the future
|
||||
const retrievingNewLogs = lowerBoundaryCommit !== undefined;
|
||||
const options: Record<string, unknown> = {
|
||||
|
|
@ -50,8 +55,7 @@ export async function runLog({
|
|||
// `--follow` does not work well on non-linear history. It does not work for files that were just renamed in the working directory but haven't been committed yet. It needs commit information to track renames.
|
||||
// This problem can be solved by running a separate git diff name-status command before running git log, to detect potential renames and get the last committed filename of the current file, but the performance impact is not worth it.
|
||||
options['--follow'] = null;
|
||||
options['--find-renames'] =
|
||||
`${getRenameDetectionStrictness(plugin.settings.changelogGenerationSettings)}%`;
|
||||
options['--find-renames'] = `${renameDetectionStrictness}%`;
|
||||
}
|
||||
|
||||
if (upperBoundaryCommit) {
|
||||
|
|
@ -60,15 +64,8 @@ export async function runLog({
|
|||
options['--boundary'] = null;
|
||||
options[`${lowerBoundaryCommit}..HEAD`] = null;
|
||||
}
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
const git = await plugin.getGit();
|
||||
|
||||
const result = await git.log(options);
|
||||
const timezone = getTimeZone(
|
||||
plugin.settings.changelogGenerationSettings,
|
||||
plugin
|
||||
);
|
||||
|
||||
const logs: LogEntry[] = [];
|
||||
for (const entry of result.all) {
|
||||
|
|
@ -109,7 +106,7 @@ export async function runLog({
|
|||
: undefined,
|
||||
hash: entry.hash,
|
||||
fileDeleted,
|
||||
timezoneAdjustedDate: spacetime(entry.date).goto(timezone)
|
||||
timeZoneAdjustedDate: spacetime(entry.date).goto(timeZone)
|
||||
});
|
||||
}
|
||||
return logs;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,16 @@
|
|||
/* eslint-disable no-magic-numbers */
|
||||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { DiffFile, FilesSummary, LogEntry, TextDiffFile } from 'types.ts';
|
||||
import type { SimpleGit } from 'simple-git';
|
||||
import type {
|
||||
DiffAlgorithm,
|
||||
DiffFile,
|
||||
FilesSummary,
|
||||
LogEntry,
|
||||
TextDiffFile,
|
||||
WhitespaceIgnoreMode
|
||||
} from 'types.ts';
|
||||
|
||||
import { VaultChangelogEntry } from 'core/ChangelogEntry.svelte.ts';
|
||||
import { getEmptyTreeHash } from 'core/gitOperations/getEmptyTreeHash.ts';
|
||||
import {
|
||||
addFileStatusToSummary,
|
||||
assignDiffAlgorithm,
|
||||
|
|
@ -11,8 +18,6 @@ import {
|
|||
calculateFileStatusRenamedOrMoved
|
||||
} from 'core/gitOperations/helper.ts';
|
||||
import { convertGitIgnoreToPathspec } from 'settings/ui/ExcludeFilesAndFolders.ts';
|
||||
import { getRenameLimit } from 'settings/ui/RenameDetectionFileLimit.ts';
|
||||
import { getRenameDetectionStrictness } from 'settings/ui/RenameDetectionStrictnessSlider.ts';
|
||||
import { AbortError, DiffFileStatus } from 'types.ts';
|
||||
import { assertNotNull, insertSorted, parseContentChange } from 'utils.ts';
|
||||
|
||||
|
|
@ -54,19 +59,38 @@ export function compareTextFiles(
|
|||
return leftFile.pathGitRelative.localeCompare(rightFile.pathGitRelative);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
export async function runRepoDiff({
|
||||
abortSignal,
|
||||
newCommit,
|
||||
oldCommit,
|
||||
plugin
|
||||
git,
|
||||
plugin,
|
||||
excludeFilesAndFoldersLines,
|
||||
convertToIncludeList,
|
||||
renameLimit,
|
||||
renameDetectionStrictness,
|
||||
diffAlgorithm,
|
||||
whitespaceIgnoreMode,
|
||||
ignoreBlankLines,
|
||||
emptyTreeHash
|
||||
}: {
|
||||
abortSignal: AbortSignal;
|
||||
newCommit: LogEntry;
|
||||
oldCommit?: LogEntry;
|
||||
plugin: GitChangelogPlugin;
|
||||
diffAlgorithm: DiffAlgorithm;
|
||||
git: SimpleGit;
|
||||
excludeFilesAndFoldersLines: readonly string[];
|
||||
plugin?: GitChangelogPlugin;
|
||||
convertToIncludeList: boolean;
|
||||
renameLimit: number;
|
||||
emptyTreeHash: string;
|
||||
renameDetectionStrictness: number;
|
||||
ignoreBlankLines: boolean;
|
||||
whitespaceIgnoreMode: WhitespaceIgnoreMode;
|
||||
}): Promise<undefined | VaultChangelogEntry> {
|
||||
if (newCommit === undefined) {
|
||||
plugin.consoleDebug('newCommit is undefined');
|
||||
plugin?.consoleDebug('newCommit is undefined');
|
||||
}
|
||||
|
||||
if (abortSignal.aborted) {
|
||||
|
|
@ -74,34 +98,38 @@ export async function runRepoDiff({
|
|||
}
|
||||
|
||||
const pathSpec = convertGitIgnoreToPathspec(
|
||||
plugin.settings.vaultChangelogGenerationSettings
|
||||
.excludeFilesAndFoldersLines,
|
||||
plugin.settings.vaultChangelogGenerationSettings.convertToIncludeList
|
||||
excludeFilesAndFoldersLines,
|
||||
convertToIncludeList
|
||||
);
|
||||
|
||||
const numstatArguments = [
|
||||
'--numstat',
|
||||
`-l${getRenameLimit(plugin.settings.changelogGenerationSettings)}`,
|
||||
`--find-renames=${getRenameDetectionStrictness(plugin.settings.changelogGenerationSettings)}%`,
|
||||
`-l${renameLimit}`,
|
||||
`--find-renames=${renameDetectionStrictness}%`,
|
||||
'--color-moved=no',
|
||||
// Don't use empty files as rename candidates. If you delete any empty file and add a new empty file, that file will be considered a rename unless this flag is used.
|
||||
'--no-rename-empty',
|
||||
'-z'
|
||||
];
|
||||
assignDiffAlgorithm(numstatArguments, plugin);
|
||||
assignWhitespaceIgnoreSettings(numstatArguments, plugin);
|
||||
assignDiffAlgorithm({ arguments_: numstatArguments, diffAlgorithm });
|
||||
assignWhitespaceIgnoreSettings({
|
||||
arguments_: numstatArguments,
|
||||
whitespaceIgnoreMode,
|
||||
ignoreBlankLines
|
||||
});
|
||||
|
||||
let statusResult: Record<string, DiffFileStatus> | undefined;
|
||||
|
||||
if (oldCommit === undefined) {
|
||||
const emptyTreeHash = await getEmptyTreeHash({ plugin });
|
||||
numstatArguments.push(emptyTreeHash, newCommit.hash);
|
||||
} else {
|
||||
statusResult = await runRepoDiffStatus({
|
||||
newCommit: newCommit.hash,
|
||||
oldCommit: oldCommit.hash,
|
||||
pathSpec,
|
||||
plugin
|
||||
plugin,
|
||||
abortSignal,
|
||||
git
|
||||
});
|
||||
numstatArguments.push(oldCommit.hash, newCommit.hash);
|
||||
}
|
||||
|
|
@ -110,11 +138,11 @@ export async function runRepoDiff({
|
|||
numstatArguments.push('--', ...pathSpec);
|
||||
}
|
||||
|
||||
const diffNumstatResult = await git.diff(numstatArguments);
|
||||
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
const git = await plugin.getGit();
|
||||
const diffNumstatResult = await git.diff(numstatArguments);
|
||||
|
||||
const records = diffNumstatResult.split('\0').filter((token) => token !== '');
|
||||
|
||||
|
|
@ -171,7 +199,7 @@ export async function runRepoDiff({
|
|||
status = DiffFileStatus.Added;
|
||||
} else if (oldPath) {
|
||||
if (typeof oldPath !== 'string') {
|
||||
plugin.consoleDebug('oldPath is not a string', oldPath);
|
||||
plugin?.consoleDebug('oldPath is not a string', oldPath);
|
||||
}
|
||||
status = calculateFileStatusRenamedOrMoved(oldPath, filePath);
|
||||
} else if (assertNotNull(statusResult)[filePath]) {
|
||||
|
|
@ -215,7 +243,7 @@ export async function runRepoDiff({
|
|||
previousDayLastCommitHash: oldCommit?.hash,
|
||||
textFiles,
|
||||
textFilesSummaryCached: textFilesSummary,
|
||||
timezoneAdjustedDate: newCommit.timezoneAdjustedDate
|
||||
timeZoneAdjustedDate: newCommit.timeZoneAdjustedDate
|
||||
});
|
||||
|
||||
return dayEntry;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { SimpleGit } from 'simple-git';
|
||||
|
||||
import { DiffFileStatus } from 'types.ts';
|
||||
import { AbortError, DiffFileStatus } from 'types.ts';
|
||||
|
||||
import type { DiffResultNameStatusFile } from './simpleGitTypes.ts';
|
||||
|
||||
|
|
@ -13,13 +14,21 @@ export async function runRepoDiffStatus({
|
|||
newCommit,
|
||||
oldCommit,
|
||||
pathSpec,
|
||||
plugin
|
||||
git,
|
||||
plugin,
|
||||
abortSignal
|
||||
}: {
|
||||
newCommit: string;
|
||||
oldCommit?: string;
|
||||
pathSpec: string[];
|
||||
plugin: GitChangelogPlugin;
|
||||
plugin?: GitChangelogPlugin;
|
||||
abortSignal: AbortSignal;
|
||||
git: SimpleGit;
|
||||
}): Promise<Record<string, DiffFileStatus> | undefined> {
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
|
||||
if (oldCommit === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
|
@ -38,7 +47,6 @@ export async function runRepoDiffStatus({
|
|||
if (pathSpec.length > 0) {
|
||||
diffStatusArguments.push('--', ...pathSpec);
|
||||
}
|
||||
const git = await plugin.getGit();
|
||||
const diffStatusResult = await git.diffSummary(diffStatusArguments);
|
||||
|
||||
const changedFilesMap: Record<string, DiffFileStatus> = {};
|
||||
|
|
@ -60,7 +68,7 @@ export async function runRepoDiffStatus({
|
|||
file.status ?? DiffNameStatus.MODIFIED
|
||||
)
|
||||
) {
|
||||
plugin.consoleDebug(
|
||||
plugin?.consoleDebug(
|
||||
`Unexpected file status of ${file.file}:`,
|
||||
file.status
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
/* eslint-disable unicorn/prevent-abbreviations */
|
||||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { LogEntry, TextDiffBaseStats } from 'types.ts';
|
||||
import type { SimpleGit } from 'simple-git';
|
||||
import type {
|
||||
DiffAlgorithm,
|
||||
LogEntry,
|
||||
TextDiffBaseStats,
|
||||
WhitespaceIgnoreMode
|
||||
} from 'types.ts';
|
||||
|
||||
import {
|
||||
assignDiffAlgorithm,
|
||||
|
|
@ -14,32 +19,41 @@ import { AbortError } from 'types.ts';
|
|||
export async function runWorkingDirFileDiff({
|
||||
abortSignal,
|
||||
oldCommit,
|
||||
plugin,
|
||||
activeGitFile
|
||||
activeGitFile,
|
||||
git,
|
||||
diffAlgorithm,
|
||||
whitespaceIgnoreMode,
|
||||
ignoreBlankLines
|
||||
}: {
|
||||
diffAlgorithm: DiffAlgorithm;
|
||||
abortSignal: AbortSignal;
|
||||
oldCommit: LogEntry;
|
||||
activeGitFile: string;
|
||||
plugin: GitChangelogPlugin;
|
||||
git: SimpleGit;
|
||||
whitespaceIgnoreMode: WhitespaceIgnoreMode;
|
||||
ignoreBlankLines: boolean;
|
||||
}): Promise<TextDiffBaseStats | undefined> {
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
|
||||
// Status bar calculations should handle cases of undefined oldCommit and oldCommit.fileDeleted === true before reaching this function
|
||||
|
||||
const numstatArguments = ['--numstat', '--color-moved=no', '--no-renames'];
|
||||
|
||||
// Must come before the commit hashes and file paths
|
||||
assignDiffAlgorithm(numstatArguments, plugin);
|
||||
assignWhitespaceIgnoreSettings(numstatArguments, plugin);
|
||||
assignDiffAlgorithm({ arguments_: numstatArguments, diffAlgorithm });
|
||||
assignWhitespaceIgnoreSettings({
|
||||
arguments_: numstatArguments,
|
||||
whitespaceIgnoreMode,
|
||||
ignoreBlankLines
|
||||
});
|
||||
|
||||
numstatArguments.push(
|
||||
`${oldCommit.hash}:${oldCommit.filePath}`,
|
||||
activeGitFile
|
||||
);
|
||||
|
||||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
|
||||
const git = await plugin.getGit();
|
||||
const diffNumstatResult = await git.diffSummary(numstatArguments);
|
||||
|
||||
const textDiffStats =
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import type { ChangelogGenerationSettings } from 'settings/settings.ts';
|
||||
import type { Spacetime, TimeUnit } from 'spacetime';
|
||||
import type { ChangelogInterval, FilesSummary, LogEntry } from 'types.ts';
|
||||
|
||||
import { getDayStartTime } from 'settings/ui/DayStartTime.ts';
|
||||
import { applyDayStartTimeSetting } from 'timeUtils.ts';
|
||||
import { applyDayStartHourSetting } from 'timeUtils.ts';
|
||||
|
||||
export const GIT_MAX_CONCURRENT_PROCESSES = 6;
|
||||
|
||||
|
|
@ -68,24 +66,24 @@ export async function isSameAsync({
|
|||
}
|
||||
|
||||
export async function extractLastCommitsForInterval({
|
||||
changelogGenerationSettings,
|
||||
interval,
|
||||
previouslySeenFullyAdjustedDates,
|
||||
timezoneAdjustedLogs
|
||||
timeZoneAdjustedLogs,
|
||||
dayStartHour
|
||||
}: {
|
||||
changelogGenerationSettings: ChangelogGenerationSettings;
|
||||
interval: ChangelogInterval;
|
||||
previouslySeenFullyAdjustedDates?: Set<Spacetime>;
|
||||
timezoneAdjustedLogs: LogEntry[];
|
||||
timeZoneAdjustedLogs: LogEntry[];
|
||||
dayStartHour: number;
|
||||
}): Promise<LogEntry[]> {
|
||||
const lastCommitsInEachInterval: LogEntry[] = [];
|
||||
const fullyAdjustedSeenDates =
|
||||
previouslySeenFullyAdjustedDates ?? new Set<Spacetime>();
|
||||
|
||||
for (const log of timezoneAdjustedLogs) {
|
||||
const fullyAdjustedLogDate = applyDayStartTimeSetting({
|
||||
dayStartTime: getDayStartTime(changelogGenerationSettings),
|
||||
timezoneAdjustedDate: log.timezoneAdjustedDate
|
||||
for (const log of timeZoneAdjustedLogs) {
|
||||
const fullyAdjustedLogDate = applyDayStartHourSetting({
|
||||
dayStartHour,
|
||||
timeZoneAdjustedDate: log.timeZoneAdjustedDate
|
||||
});
|
||||
|
||||
const logDateAlreadySeen = await dateAlreadySeen({
|
||||
|
|
|
|||
26
src/menu.ts
26
src/menu.ts
|
|
@ -1,5 +1,6 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { MenuItem, WorkspaceLeaf } from 'obsidian';
|
||||
import type { GitChangelogSettings } from 'settings/settings.ts';
|
||||
|
||||
import { COPY_COMMIT_HASH_ICON, PLUGIN_NAME_SENTENCE_CASE } from 'constants.ts';
|
||||
import { Menu, TFolder } from 'obsidian';
|
||||
|
|
@ -117,8 +118,7 @@ export function addExcludeMenuItem({
|
|||
plugin
|
||||
});
|
||||
const ruleAlreadyExists = lineNumber !== -1;
|
||||
const isIncludeList =
|
||||
plugin.settings.vaultChangelogGenerationSettings.convertToIncludeList;
|
||||
const isIncludeList = plugin.settings.convertToIncludeList;
|
||||
let actionTitle: string;
|
||||
if (isIncludeList) {
|
||||
actionTitle = ruleAlreadyExists ? 'Re-exclude' : 'Include';
|
||||
|
|
@ -225,9 +225,7 @@ export function isAbsolutePathInExcludeFilesAndFolders({
|
|||
isFolder,
|
||||
gitRelativePath
|
||||
});
|
||||
const existingLines =
|
||||
plugin.settingsClone.vaultChangelogGenerationSettings
|
||||
.excludeFilesAndFoldersLines;
|
||||
const existingLines = plugin.settings.excludeFilesAndFoldersLines;
|
||||
|
||||
// Trim unescaped trailing white space from existing lines, since it gets trimmed by git anyways.
|
||||
// By doing this we won't miss already existing lines that only differ in trailing white space.
|
||||
|
|
@ -239,12 +237,11 @@ export async function removeExcludeFilesAndFoldersItem(
|
|||
lineNumber: number,
|
||||
plugin: GitChangelogPlugin
|
||||
): Promise<void> {
|
||||
const newSettings = plugin.settingsClone;
|
||||
newSettings.vaultChangelogGenerationSettings.excludeFilesAndFoldersLines.splice(
|
||||
lineNumber,
|
||||
1
|
||||
await plugin.settingsManager.editAndSave(
|
||||
(settings: GitChangelogSettings): void => {
|
||||
settings.excludeFilesAndFoldersLines.splice(lineNumber, 1);
|
||||
}
|
||||
);
|
||||
await plugin.saveSettings(newSettings);
|
||||
}
|
||||
|
||||
export async function addExcludeFilesAndFoldersItem({
|
||||
|
|
@ -261,10 +258,9 @@ export async function addExcludeFilesAndFoldersItem({
|
|||
isFolder
|
||||
});
|
||||
|
||||
const newSettings = plugin.settingsClone;
|
||||
newSettings.vaultChangelogGenerationSettings.excludeFilesAndFoldersLines.push(
|
||||
gitIgnoreRule
|
||||
await plugin.settingsManager.editAndSave(
|
||||
(settings: GitChangelogSettings): void => {
|
||||
settings.excludeFilesAndFoldersLines.push(gitIgnoreRule);
|
||||
}
|
||||
);
|
||||
|
||||
await plugin.saveSettings(newSettings);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +1,25 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { TextComponent } from 'obsidian';
|
||||
import type {
|
||||
ChangelogGenerationSettings,
|
||||
IGitChangelogSettings
|
||||
} from 'settings/settings.ts';
|
||||
import type { GitChangelogSettingsTab } from 'settings/settingsTab.ts';
|
||||
|
||||
import { moment } from 'obsidian';
|
||||
import { NumberComponent } from 'obsidian-dev-utils/obsidian/Components/NumberComponent';
|
||||
import { TimeComponent } from 'obsidian-dev-utils/obsidian/Components/TimeComponent';
|
||||
import { SettingEx } from 'obsidian-dev-utils/obsidian/SettingEx';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
|
||||
export abstract class GitChangelogSetting {
|
||||
export abstract class SettingComponent {
|
||||
protected containerEl: HTMLElement;
|
||||
protected disabled: boolean;
|
||||
protected plugin: GitChangelogPlugin;
|
||||
protected settingTab?: GitChangelogSettingsTab;
|
||||
protected settingTab: GitChangelogSettingsTab;
|
||||
|
||||
public constructor({
|
||||
containerEl,
|
||||
disabled = false,
|
||||
plugin,
|
||||
settingTab
|
||||
plugin
|
||||
}: {
|
||||
containerEl: HTMLElement;
|
||||
disabled?: boolean;
|
||||
plugin: GitChangelogPlugin;
|
||||
settingTab?: GitChangelogSettingsTab;
|
||||
}) {
|
||||
this.plugin = plugin;
|
||||
this.containerEl = containerEl;
|
||||
this.disabled = disabled;
|
||||
this.settingTab = settingTab;
|
||||
this.settingTab = this.plugin.settingsTab;
|
||||
this.containerEl = this.settingTab.containerEl;
|
||||
}
|
||||
|
||||
public abstract display(): void;
|
||||
|
|
@ -53,46 +40,9 @@ export abstract class GitChangelogSetting {
|
|||
*/
|
||||
protected refreshDisplayWithDelay(timeout = 80): void {
|
||||
if (this.settingTab) {
|
||||
setTimeout(() => this.settingTab?.display(), timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value in the textbox for a given setting only if the saved value differs from the default value.
|
||||
* If the saved value is the default value, it probably wasn't defined by the user, so it's better to display it as a placeholder.
|
||||
*/
|
||||
protected setNonDefaultValue({
|
||||
diffSettingsProperty,
|
||||
settingsProperty,
|
||||
text
|
||||
}: {
|
||||
diffSettingsProperty?: keyof ChangelogGenerationSettings;
|
||||
settingsProperty: keyof IGitChangelogSettings;
|
||||
text: NumberComponent | TextComponent | TimeComponent;
|
||||
}): void {
|
||||
const storedValue = diffSettingsProperty
|
||||
? (this.plugin.settings[settingsProperty] as ChangelogGenerationSettings)[
|
||||
diffSettingsProperty
|
||||
]
|
||||
: this.plugin.settings[settingsProperty];
|
||||
const defaultValue = diffSettingsProperty
|
||||
? (DEFAULT_SETTINGS[settingsProperty] as ChangelogGenerationSettings)[
|
||||
diffSettingsProperty
|
||||
]
|
||||
: DEFAULT_SETTINGS[settingsProperty];
|
||||
|
||||
if (defaultValue !== storedValue) {
|
||||
if (text instanceof NumberComponent) {
|
||||
text.setValue(Number(storedValue));
|
||||
} else if (text instanceof TimeComponent) {
|
||||
text.setValue(moment.duration({ hours: Number(storedValue) }));
|
||||
} else {
|
||||
text.setValue(
|
||||
typeof storedValue === 'object'
|
||||
? JSON.stringify(storedValue)
|
||||
: String(storedValue)
|
||||
);
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.settingTab?.display();
|
||||
}, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,23 +13,23 @@ export class TimeZoneSuggest extends AbstractInputSuggest<string> {
|
|||
|
||||
public getSuggestions(inputString: string): string[] {
|
||||
const lowerCaseInputString = inputString.toLowerCase();
|
||||
const timezones: string[] = [];
|
||||
const timeZones: string[] = [];
|
||||
|
||||
for (const timezone of TIME_ZONES_LIST) {
|
||||
if (timezone.toLowerCase().contains(lowerCaseInputString)) {
|
||||
timezones.push(timezone);
|
||||
for (const timeZone of TIME_ZONES_LIST) {
|
||||
if (timeZone.toLowerCase().contains(lowerCaseInputString)) {
|
||||
timeZones.push(timeZone);
|
||||
}
|
||||
}
|
||||
|
||||
return timezones;
|
||||
return timeZones;
|
||||
}
|
||||
|
||||
public renderSuggestion(timezone: string, element: HTMLElement): void {
|
||||
element.setText(timezone);
|
||||
public renderSuggestion(timeZone: string, element: HTMLElement): void {
|
||||
element.setText(timeZone);
|
||||
}
|
||||
|
||||
public override selectSuggestion(timezone: string): void {
|
||||
this.inputEl.value = timezone;
|
||||
public override selectSuggestion(timeZone: string): void {
|
||||
this.inputEl.value = timeZone;
|
||||
this.inputEl.trigger('input');
|
||||
this.close();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,22 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { ChangelogGenerationSettings } from 'settings/settings.ts';
|
||||
import type { GitChangelogSettings } from 'settings/settings.ts';
|
||||
import type { ReadonlyDeep } from 'type-fest';
|
||||
|
||||
import { deepEqual } from 'obsidian-dev-utils/Object';
|
||||
import {
|
||||
systemTimeZoneUnchanged,
|
||||
validateCustomTimeZone
|
||||
} from 'settings/ui/CustomTimeZone.ts';
|
||||
import { pickGeneralChangelogSettings } from 'settings/settings.ts';
|
||||
|
||||
export function changelogGenerationSettingsChanged({
|
||||
newChangelogSettings,
|
||||
oldChangelogSettings,
|
||||
plugin
|
||||
newSettings,
|
||||
oldSettings
|
||||
}: {
|
||||
newChangelogSettings: ChangelogGenerationSettings;
|
||||
oldChangelogSettings: ChangelogGenerationSettings;
|
||||
plugin: GitChangelogPlugin;
|
||||
newSettings: ReadonlyDeep<GitChangelogSettings>;
|
||||
oldSettings: ReadonlyDeep<GitChangelogSettings>;
|
||||
}): boolean {
|
||||
if (!oldChangelogSettings) {
|
||||
return true;
|
||||
}
|
||||
const oldVaultGenerationSettings = pickGeneralChangelogSettings(oldSettings);
|
||||
const newVaultGenerationSettings = pickGeneralChangelogSettings(newSettings);
|
||||
|
||||
// IsAncestor run
|
||||
|
||||
if (
|
||||
!validateCustomTimeZone(newChangelogSettings.timezone) &&
|
||||
!systemTimeZoneUnchanged(plugin)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
// Don't have to check if the detected system time zone or detected locale changed since they're only assigned once at startup.
|
||||
|
||||
if (deepEqual(oldChangelogSettings, newChangelogSettings)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return !deepEqual(oldVaultGenerationSettings, newVaultGenerationSettings);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { PluginSettingsBase } from 'obsidian-dev-utils/obsidian/Plugin/PluginSettingsBase';
|
||||
import type { Except, ReadonlyDeep } from 'type-fest';
|
||||
|
||||
import spacetime from 'spacetime';
|
||||
import {
|
||||
ChangelogInterval,
|
||||
|
|
@ -15,142 +16,172 @@ export const TIME_ZONES_LIST = new Set(Object.keys(spacetime().timezones));
|
|||
export const MAX_SUPPORTED_INTERVAL = 99_999; // ~69 days
|
||||
export const AUTO_DETECT_PLACEHOLDER = 'Auto-detect';
|
||||
|
||||
/**
|
||||
* Each change in these settings triggers a recalculation of the changelogs statistics.
|
||||
*/
|
||||
export interface ChangelogGenerationSettings {
|
||||
// Time settings
|
||||
dayStartHour: number;
|
||||
// Diff settings
|
||||
detectMovedContent: boolean;
|
||||
diffAlgorithm: DiffAlgorithm;
|
||||
measurementUnit: DiffMeasurementUnit;
|
||||
renameDetectionStrictness: number;
|
||||
renameLimit: string;
|
||||
timezone: string;
|
||||
locale: string;
|
||||
whitespaceIgnoreMode: WhitespaceIgnoreMode;
|
||||
ignoreBlankLines: boolean;
|
||||
}
|
||||
|
||||
export interface VaultChangelogGenerationSettings {
|
||||
excludeFilesAndFoldersLines: string[];
|
||||
convertToIncludeList: boolean;
|
||||
interval: ChangelogInterval;
|
||||
}
|
||||
|
||||
export interface IGitChangelogSettings {
|
||||
autoCommitDisabledWarningDismissed: boolean;
|
||||
changelogGenerationSettings: ChangelogGenerationSettings;
|
||||
contentDeletionsAndMovesWarningThreshold: string;
|
||||
dedicatedFileTypeSummaries: string[];
|
||||
fileChangelogInterval: ChangelogInterval;
|
||||
fileExplorerInterval: string;
|
||||
fileExplorerStats: FileExplorerStats;
|
||||
filesChangesWarningThreshold: string;
|
||||
fileSummariesDisplayMode: FilesSummariesDisplayMode;
|
||||
firstStartup: boolean;
|
||||
notifyOnContentDeletionsAndMovesThresholdReached: boolean;
|
||||
notifyOnFilesChangesThresholdReached: boolean;
|
||||
statusBarInterval: string;
|
||||
statusBarStats: boolean;
|
||||
vaultChangelogGenerationSettings: VaultChangelogGenerationSettings;
|
||||
}
|
||||
|
||||
export class GitChangelogPluginSettings
|
||||
extends PluginSettingsBase
|
||||
implements IGitChangelogSettings
|
||||
{
|
||||
export class GitChangelogSettings {
|
||||
// State
|
||||
public autoCommitDisabledWarningDismissed: boolean =
|
||||
DEFAULT_SETTINGS.autoCommitDisabledWarningDismissed;
|
||||
public autoCommitDisabledWarningDismissed = false;
|
||||
|
||||
public firstStartup: boolean = DEFAULT_SETTINGS.firstStartup;
|
||||
|
||||
public changelogGenerationSettings: ChangelogGenerationSettings =
|
||||
DEFAULT_CHANGELOG_GENERATION_SETTINGS;
|
||||
public firstStartup = true;
|
||||
|
||||
/**
|
||||
* The number refers to either words or lines depending on what the changelog is set up to count
|
||||
*/
|
||||
public contentDeletionsAndMovesWarningThreshold: string =
|
||||
DEFAULT_SETTINGS.contentDeletionsAndMovesWarningThreshold;
|
||||
public contentDeletionsAndMovesWarningThreshold = '2000';
|
||||
|
||||
// ShowFilesSummaryCountOptions[]; //Set<ShowFilesSummaryCountOptions>;
|
||||
// VaultChangelogFilesVisibility: VaultChangelogFilesVisibility;
|
||||
// NotifyOnLargeCommitAdditions: boolean;
|
||||
// NotifyOnLargeCommitAdditionsWarningThreshold: string;
|
||||
public dedicatedFileTypeSummaries: string[] = [
|
||||
...DEFAULT_SETTINGS.dedicatedFileTypeSummaries
|
||||
];
|
||||
public dedicatedFileTypeSummaries: string[] = [];
|
||||
|
||||
public fileChangelogInterval: ChangelogInterval =
|
||||
DEFAULT_SETTINGS.fileChangelogInterval;
|
||||
public fileExplorerInterval = '4320'; // In mins
|
||||
public fileExplorerStats: FileExplorerStats = FileExplorerStats.Disabled;
|
||||
|
||||
public fileExplorerInterval: string = DEFAULT_SETTINGS.fileExplorerInterval;
|
||||
public fileExplorerStats: FileExplorerStats =
|
||||
DEFAULT_SETTINGS.fileExplorerStats;
|
||||
|
||||
public filesChangesWarningThreshold: string =
|
||||
DEFAULT_SETTINGS.filesChangesWarningThreshold;
|
||||
public filesChangesWarningThreshold = '50';
|
||||
|
||||
public fileSummariesDisplayMode: FilesSummariesDisplayMode =
|
||||
DEFAULT_SETTINGS.fileSummariesDisplayMode;
|
||||
FilesSummariesDisplayMode.Total;
|
||||
|
||||
public notifyOnContentDeletionsAndMovesThresholdReached: boolean =
|
||||
DEFAULT_SETTINGS.notifyOnContentDeletionsAndMovesThresholdReached;
|
||||
public notifyOnContentDeletionsAndMovesThresholdReached = true;
|
||||
|
||||
public notifyOnFilesChangesThresholdReached: boolean =
|
||||
DEFAULT_SETTINGS.notifyOnFilesChangesThresholdReached;
|
||||
public notifyOnFilesChangesThresholdReached = false;
|
||||
|
||||
public statusBarInterval: string = DEFAULT_SETTINGS.statusBarInterval;
|
||||
public statusBarStats: boolean = DEFAULT_SETTINGS.statusBarStats;
|
||||
// Specific Changelog Generation Settings
|
||||
public vaultChangelogGenerationSettings: VaultChangelogGenerationSettings =
|
||||
DEFAULT_VAULT_CHANGELOG_GENERATION_SETTINGS;
|
||||
public statusBarInterval = 30; // In mins
|
||||
public statusBarStatsEnabled = false;
|
||||
|
||||
public constructor(data: unknown) {
|
||||
super();
|
||||
// Object.assign(this, DEFAULT_SETTINGS);
|
||||
this.init(data);
|
||||
this._shouldSaveAfterLoad = true;
|
||||
}
|
||||
// FileGenerationSettings
|
||||
public fileChangelogInterval: ChangelogInterval = ChangelogInterval.Daily;
|
||||
|
||||
// VaultGenerationSettings
|
||||
public excludeFilesAndFoldersLines: string[] = [];
|
||||
public convertToIncludeList = false;
|
||||
public vaultChangelogInterval = ChangelogInterval.Daily;
|
||||
|
||||
/**
|
||||
* Each change in these settings triggers a recalculation of all the changelogs statistics.
|
||||
*/
|
||||
// Time settings
|
||||
public dayStartHour = 0;
|
||||
// Diff settings
|
||||
public detectMovedContent = true;
|
||||
public diffAlgorithm = DiffAlgorithm.Inherit;
|
||||
public diffMeasurementUnit = DiffMeasurementUnit.Words;
|
||||
public renameDetectionStrictness = 50;
|
||||
public renameLimit = 1000;
|
||||
public timeZone = AUTO_DETECT_PLACEHOLDER;
|
||||
public locale = AUTO_DETECT_PLACEHOLDER;
|
||||
public whitespaceIgnoreMode = WhitespaceIgnoreMode.None;
|
||||
public ignoreBlankLines = false;
|
||||
}
|
||||
|
||||
export const DEFAULT_VAULT_CHANGELOG_GENERATION_SETTINGS: VaultChangelogGenerationSettings =
|
||||
{
|
||||
excludeFilesAndFoldersLines: [],
|
||||
convertToIncludeList: false,
|
||||
interval: ChangelogInterval.Daily
|
||||
} as const;
|
||||
// This is needed for checking if the generation settings have changed. And on each new added setting, the developer will have to explicitly include or exclude the added setting from all of these categories.
|
||||
|
||||
export const DEFAULT_CHANGELOG_GENERATION_SETTINGS: ChangelogGenerationSettings =
|
||||
{
|
||||
dayStartHour: 0,
|
||||
detectMovedContent: true,
|
||||
diffAlgorithm: DiffAlgorithm.Inherit,
|
||||
measurementUnit: DiffMeasurementUnit.Words,
|
||||
renameDetectionStrictness: 50,
|
||||
renameLimit: '1000',
|
||||
timezone: AUTO_DETECT_PLACEHOLDER,
|
||||
locale: AUTO_DETECT_PLACEHOLDER,
|
||||
whitespaceIgnoreMode: WhitespaceIgnoreMode.None,
|
||||
ignoreBlankLines: false
|
||||
} as const;
|
||||
export const DEFAULT_SETTINGS: IGitChangelogSettings = {
|
||||
autoCommitDisabledWarningDismissed: false,
|
||||
changelogGenerationSettings: DEFAULT_CHANGELOG_GENERATION_SETTINGS,
|
||||
vaultChangelogGenerationSettings: DEFAULT_VAULT_CHANGELOG_GENERATION_SETTINGS,
|
||||
contentDeletionsAndMovesWarningThreshold: '2000',
|
||||
dedicatedFileTypeSummaries: [] as const,
|
||||
fileChangelogInterval: ChangelogInterval.Daily,
|
||||
fileExplorerInterval: '4320', // In mins
|
||||
fileExplorerStats: FileExplorerStats.Disabled,
|
||||
filesChangesWarningThreshold: '50',
|
||||
fileSummariesDisplayMode: FilesSummariesDisplayMode.Total,
|
||||
firstStartup: true,
|
||||
notifyOnContentDeletionsAndMovesThresholdReached: true,
|
||||
notifyOnFilesChangesThresholdReached: false,
|
||||
statusBarInterval: '30', // In mins
|
||||
statusBarStats: false
|
||||
} as const;
|
||||
export function pickVaultChangelogSettings(
|
||||
settings: ReadonlyDeep<GitChangelogSettings>
|
||||
): ReadonlyDeep<VaultGenerationSettings> {
|
||||
return {
|
||||
excludeFilesAndFoldersLines: settings.excludeFilesAndFoldersLines,
|
||||
convertToIncludeList: settings.convertToIncludeList,
|
||||
vaultChangelogInterval: settings.vaultChangelogInterval
|
||||
};
|
||||
}
|
||||
|
||||
export function pickFileChangelogSettings(
|
||||
settings: ReadonlyDeep<GitChangelogSettings>
|
||||
): ReadonlyDeep<FileGenerationSettings> {
|
||||
return {
|
||||
fileChangelogInterval: settings.fileChangelogInterval
|
||||
};
|
||||
}
|
||||
|
||||
export function pickGeneralChangelogSettings(
|
||||
settings: ReadonlyDeep<GitChangelogSettings>
|
||||
): ReadonlyDeep<GenerationSettings> {
|
||||
return {
|
||||
dayStartHour: settings.dayStartHour,
|
||||
detectMovedContent: settings.detectMovedContent,
|
||||
diffAlgorithm: settings.diffAlgorithm,
|
||||
diffMeasurementUnit: settings.diffMeasurementUnit,
|
||||
renameDetectionStrictness: settings.renameDetectionStrictness,
|
||||
renameLimit: settings.renameLimit,
|
||||
timeZone: settings.timeZone,
|
||||
locale: settings.locale,
|
||||
whitespaceIgnoreMode: settings.whitespaceIgnoreMode,
|
||||
ignoreBlankLines: settings.ignoreBlankLines
|
||||
};
|
||||
}
|
||||
|
||||
type VaultGenerationSettings = Except<
|
||||
GitChangelogSettings,
|
||||
| 'autoCommitDisabledWarningDismissed'
|
||||
| 'contentDeletionsAndMovesWarningThreshold'
|
||||
| 'dayStartHour'
|
||||
| 'dedicatedFileTypeSummaries'
|
||||
| 'detectMovedContent'
|
||||
| 'diffAlgorithm'
|
||||
| 'diffMeasurementUnit'
|
||||
| 'fileChangelogInterval'
|
||||
| 'fileExplorerInterval'
|
||||
| 'fileExplorerStats'
|
||||
| 'filesChangesWarningThreshold'
|
||||
| 'fileSummariesDisplayMode'
|
||||
| 'firstStartup'
|
||||
| 'ignoreBlankLines'
|
||||
| 'locale'
|
||||
| 'notifyOnContentDeletionsAndMovesThresholdReached'
|
||||
| 'notifyOnFilesChangesThresholdReached'
|
||||
| 'renameDetectionStrictness'
|
||||
| 'renameLimit'
|
||||
| 'statusBarInterval'
|
||||
| 'statusBarStatsEnabled'
|
||||
| 'timeZone'
|
||||
| 'whitespaceIgnoreMode'
|
||||
>;
|
||||
|
||||
type FileGenerationSettings = Except<
|
||||
GitChangelogSettings,
|
||||
| 'autoCommitDisabledWarningDismissed'
|
||||
| 'contentDeletionsAndMovesWarningThreshold'
|
||||
| 'convertToIncludeList'
|
||||
| 'dayStartHour'
|
||||
| 'dedicatedFileTypeSummaries'
|
||||
| 'detectMovedContent'
|
||||
| 'diffAlgorithm'
|
||||
| 'diffMeasurementUnit'
|
||||
| 'excludeFilesAndFoldersLines'
|
||||
| 'fileExplorerInterval'
|
||||
| 'fileExplorerStats'
|
||||
| 'filesChangesWarningThreshold'
|
||||
| 'fileSummariesDisplayMode'
|
||||
| 'firstStartup'
|
||||
| 'ignoreBlankLines'
|
||||
| 'locale'
|
||||
| 'notifyOnContentDeletionsAndMovesThresholdReached'
|
||||
| 'notifyOnFilesChangesThresholdReached'
|
||||
| 'renameDetectionStrictness'
|
||||
| 'renameLimit'
|
||||
| 'statusBarInterval'
|
||||
| 'statusBarStatsEnabled'
|
||||
| 'timeZone'
|
||||
| 'vaultChangelogInterval'
|
||||
| 'whitespaceIgnoreMode'
|
||||
>;
|
||||
|
||||
type GenerationSettings = Except<
|
||||
GitChangelogSettings,
|
||||
| 'autoCommitDisabledWarningDismissed'
|
||||
| 'contentDeletionsAndMovesWarningThreshold'
|
||||
| 'convertToIncludeList'
|
||||
| 'dedicatedFileTypeSummaries'
|
||||
| 'excludeFilesAndFoldersLines'
|
||||
| 'fileChangelogInterval'
|
||||
| 'fileExplorerInterval'
|
||||
| 'fileExplorerStats'
|
||||
| 'filesChangesWarningThreshold'
|
||||
| 'fileSummariesDisplayMode'
|
||||
| 'firstStartup'
|
||||
| 'notifyOnContentDeletionsAndMovesThresholdReached'
|
||||
| 'notifyOnFilesChangesThresholdReached'
|
||||
| 'statusBarInterval'
|
||||
| 'statusBarStatsEnabled'
|
||||
| 'vaultChangelogInterval'
|
||||
>;
|
||||
|
|
|
|||
230
src/settings/settingsManager.ts
Normal file
230
src/settings/settingsManager.ts
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
import type { GitChangelogPluginTypes } from 'constants.ts';
|
||||
import type { MaybeReturn } from 'obsidian-dev-utils/Type';
|
||||
|
||||
import {
|
||||
MAX_RENAME_DETECTION_STRICTNESS,
|
||||
MIN_RENAME_DETECTION_STRICTNESS
|
||||
} from 'constants.ts';
|
||||
import { PluginSettingsManagerBase } from 'obsidian-dev-utils/obsidian/Plugin/PluginSettingsManagerBase';
|
||||
import {
|
||||
GitChangelogSettings,
|
||||
MAX_SUPPORTED_INTERVAL
|
||||
} from 'settings/settings.ts';
|
||||
import { validateLocale } from 'settings/ui/CustomLocale.ts';
|
||||
import { validateCustomTimeZone } from 'settings/ui/CustomTimeZone.ts';
|
||||
import {
|
||||
ChangelogInterval,
|
||||
DiffAlgorithm,
|
||||
DiffMeasurementUnit,
|
||||
FileExplorerStats,
|
||||
WhitespaceIgnoreMode
|
||||
} from 'types.ts';
|
||||
|
||||
export class GitChangelogSettingsManager extends PluginSettingsManagerBase<GitChangelogPluginTypes> {
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
protected override async onLoadRecord(
|
||||
record: Record<string, unknown>
|
||||
): Promise<void> {
|
||||
// Only migrate if this is legacy data - check for the existence of the old settings structure
|
||||
if ('vaultChangelogGenerationSettings' in record) {
|
||||
// Check if the legacy excludeFilesAndFoldersLines data exists
|
||||
const vaultSettings = record.vaultChangelogGenerationSettings as
|
||||
| Record<string, unknown>
|
||||
| undefined;
|
||||
const legacyExcludeLines = vaultSettings?.excludeFilesAndFoldersLines;
|
||||
|
||||
// Check if we need to migrate (legacy data exists)
|
||||
if (
|
||||
legacyExcludeLines &&
|
||||
Array.isArray(legacyExcludeLines) &&
|
||||
legacyExcludeLines.length > 0 &&
|
||||
(record.excludeFilesAndFoldersLines === undefined ||
|
||||
record.excludeFilesAndFoldersLines === null ||
|
||||
!Array.isArray(record.excludeFilesAndFoldersLines) ||
|
||||
record.excludeFilesAndFoldersLines.length === 0)
|
||||
) {
|
||||
// Migrate the data
|
||||
record.excludeFilesAndFoldersLines = legacyExcludeLines;
|
||||
// Remove the old settings structure to prevent future migrations
|
||||
delete record.vaultChangelogGenerationSettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override createDefaultSettings(): GitChangelogSettings {
|
||||
return new GitChangelogSettings();
|
||||
}
|
||||
|
||||
protected override registerValidators(): void {
|
||||
super.registerValidators();
|
||||
this.registerValidator(
|
||||
'diffMeasurementUnit',
|
||||
(measurementUnit): MaybeReturn<string> => {
|
||||
if (!Object.values(DiffMeasurementUnit).includes(measurementUnit)) {
|
||||
return 'Invalid measurement unit';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'contentDeletionsAndMovesWarningThreshold',
|
||||
(contentDeletionsAndMovesWarningThreshold): MaybeReturn<string> => {
|
||||
if (
|
||||
!Number.isInteger(Number(contentDeletionsAndMovesWarningThreshold)) ||
|
||||
Number(contentDeletionsAndMovesWarningThreshold) < 1
|
||||
) {
|
||||
return 'Invalid threshold value';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator('locale', (locale): MaybeReturn<string> => {
|
||||
if (
|
||||
!validateLocale(locale) &&
|
||||
locale !== this.getProperty('locale').defaultValue
|
||||
) {
|
||||
return 'Invalid locale';
|
||||
}
|
||||
});
|
||||
|
||||
this.registerValidator('timeZone', (timeZone): MaybeReturn<string> => {
|
||||
if (
|
||||
!validateCustomTimeZone(timeZone) &&
|
||||
timeZone !== this.getProperty('timeZone').defaultValue
|
||||
) {
|
||||
return 'Invalid timeZone';
|
||||
}
|
||||
});
|
||||
|
||||
const ONE_DAY_IN_HOURS = 24;
|
||||
|
||||
this.registerValidator(
|
||||
'dayStartHour',
|
||||
(dayStartHour): MaybeReturn<string> => {
|
||||
if (
|
||||
!Number.isInteger(dayStartHour) ||
|
||||
dayStartHour < 0 ||
|
||||
dayStartHour >= ONE_DAY_IN_HOURS
|
||||
) {
|
||||
return 'Invalid day start time';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'diffAlgorithm',
|
||||
(diffAlgorithm): MaybeReturn<string> => {
|
||||
if (!Object.values(DiffAlgorithm).includes(diffAlgorithm)) {
|
||||
return 'Invalid diff algorithm';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'filesChangesWarningThreshold',
|
||||
(filesChangesWarningThreshold): MaybeReturn<string> => {
|
||||
if (
|
||||
!Number.isInteger(Number(filesChangesWarningThreshold)) ||
|
||||
Number(filesChangesWarningThreshold) < 1
|
||||
) {
|
||||
return 'Invalid threshold value';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'fileExplorerStats',
|
||||
(fileExplorerStats): MaybeReturn<string> => {
|
||||
if (!Object.values(FileExplorerStats).includes(fileExplorerStats)) {
|
||||
return 'Invalid option';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'fileExplorerInterval',
|
||||
(fileExplorerInterval): MaybeReturn<string> => {
|
||||
if (
|
||||
!Number.isInteger(Number(fileExplorerInterval)) ||
|
||||
Number(fileExplorerInterval) < 1 ||
|
||||
Number(fileExplorerInterval) > MAX_SUPPORTED_INTERVAL
|
||||
) {
|
||||
return 'Invalid file explorer interval';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'renameLimit',
|
||||
(renameLimit): MaybeReturn<string> => {
|
||||
if (
|
||||
!(
|
||||
Number.isInteger(renameLimit) &&
|
||||
Number(renameLimit) >= 0 &&
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
Number(renameLimit) <= 99_999_999_999_999_999_999n
|
||||
)
|
||||
) {
|
||||
return 'Invalid rename limit';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'renameDetectionStrictness',
|
||||
(renameDetectionStrictness): MaybeReturn<string> => {
|
||||
if (
|
||||
!Number.isInteger(renameDetectionStrictness) ||
|
||||
renameDetectionStrictness < MIN_RENAME_DETECTION_STRICTNESS ||
|
||||
renameDetectionStrictness > MAX_RENAME_DETECTION_STRICTNESS
|
||||
) {
|
||||
return 'Invalid rename detection strictness';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'statusBarInterval',
|
||||
(statusBarInterval): MaybeReturn<string> => {
|
||||
if (
|
||||
!Number.isInteger(Number(statusBarInterval)) ||
|
||||
Number(statusBarInterval) < 1 ||
|
||||
Number(statusBarInterval) > MAX_SUPPORTED_INTERVAL
|
||||
) {
|
||||
return 'Invalid status bar interval';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'whitespaceIgnoreMode',
|
||||
(whitespaceIgnoreMode): MaybeReturn<string> => {
|
||||
if (
|
||||
!Object.values(WhitespaceIgnoreMode).includes(whitespaceIgnoreMode)
|
||||
) {
|
||||
return 'Invalid whitespace ignore mode';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'fileChangelogInterval',
|
||||
(fileChangelogInterval): MaybeReturn<string> => {
|
||||
if (!Object.values(ChangelogInterval).includes(fileChangelogInterval)) {
|
||||
return 'Invalid file changelog interval';
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.registerValidator(
|
||||
'vaultChangelogInterval',
|
||||
(vaultChangelogInterval): MaybeReturn<string> => {
|
||||
if (
|
||||
!Object.values(ChangelogInterval).includes(vaultChangelogInterval)
|
||||
) {
|
||||
return 'Invalid vault changelog interval';
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import type { GitChangelogPlugin } from 'GitChangelogPlugin.svelte.ts';
|
||||
import type { GitChangelogPluginTypes } from 'constants.ts';
|
||||
|
||||
import { PluginSettingsTabBase } from 'obsidian-dev-utils/obsidian/Plugin/PluginSettingsTabBase';
|
||||
import { CustomLocale } from 'settings/ui/CustomLocale.ts';
|
||||
import { DayStartHour } from 'settings/ui/DayStartTime.ts';
|
||||
import { DiffAlgorithmOptions } from 'settings/ui/DiffAlgorithmOptions.ts';
|
||||
import { IgnoreBlankLinesToggle } from 'settings/ui/IgnoreBlankLinesToggle.ts';
|
||||
import { IncludeItemsToggle } from 'settings/ui/IncludeItemsToggle.ts';
|
||||
|
|
@ -11,7 +12,6 @@ import { WhitespaceSettingsHeading } from 'settings/ui/WhitespaceSettingsHeading
|
|||
|
||||
import { AutoCommitDisabledWarning } from './ui/AutoCommitDisabledWarning.ts';
|
||||
import { CustomTimeZone } from './ui/CustomTimeZone.ts';
|
||||
import { DayStartTime } from './ui/DayStartTime.ts';
|
||||
import { ExcludeFilesAndFolders } from './ui/ExcludeFilesAndFolders.ts';
|
||||
import { GitPluginWarning } from './ui/GitPluginWarning.ts';
|
||||
import { RenameDetectionFileLimit } from './ui/RenameDetectionFileLimit.ts';
|
||||
|
|
@ -20,7 +20,7 @@ import { StatusBarInterval } from './ui/StatusBarInterval.ts';
|
|||
import { StatusBarStatsToggle } from './ui/StatusBarStatsToggle.ts';
|
||||
|
||||
// Commented-out settings are for features that will be implemented later
|
||||
export class GitChangelogSettingsTab extends PluginSettingsTabBase<GitChangelogPlugin> {
|
||||
export class GitChangelogSettingsTab extends PluginSettingsTabBase<GitChangelogPluginTypes> {
|
||||
public override display(): void {
|
||||
const { containerEl, plugin } = this;
|
||||
|
||||
|
|
@ -29,93 +29,60 @@ export class GitChangelogSettingsTab extends PluginSettingsTabBase<GitChangelogP
|
|||
// Plugin.settings.notifyIfContentDeletionsAndMovesThresholdReached ??
|
||||
// DEFAULT_SETTINGS.notifyIfContentDeletionsAndMovesThresholdReached;
|
||||
|
||||
new GitPluginWarning({ containerEl, plugin }).display();
|
||||
new GitPluginWarning({ plugin }).display();
|
||||
|
||||
new AutoCommitDisabledWarning({
|
||||
containerEl,
|
||||
plugin
|
||||
}).display();
|
||||
new AutoCommitDisabledWarning({ plugin }).display();
|
||||
|
||||
new DayStartTime({ containerEl, plugin }).display();
|
||||
new DayStartHour({ plugin }).display();
|
||||
|
||||
new CustomTimeZone({ containerEl, plugin }).display();
|
||||
new CustomTimeZone({ plugin }).display();
|
||||
|
||||
new CustomLocale({ containerEl, plugin }).display();
|
||||
new CustomLocale({ plugin }).display();
|
||||
|
||||
new DiffAlgorithmOptions({
|
||||
containerEl,
|
||||
plugin,
|
||||
settingTab: this
|
||||
}).display();
|
||||
new DiffAlgorithmOptions({ plugin }).display();
|
||||
|
||||
// New DeletionsNotificationThreshold(plugin, containerEl, false, this).display();
|
||||
// New DeletionsNotificationThreshold(plugin, false, this).display();
|
||||
// New configureDeletionsMovesAlert(
|
||||
// Plugin,
|
||||
// ContainerEl,
|
||||
//
|
||||
// !notifyOnLargeChanges
|
||||
// ).display();
|
||||
// New FileChangesNotificationThreshold(
|
||||
// Plugin,
|
||||
// ContainerEl,
|
||||
//
|
||||
// NotifyOnLargeChanges
|
||||
// ).display();
|
||||
// New ChangelogStatsInFileExplorerOptions(plugin, containerEl, false, this).display();
|
||||
// New ChangelogStatsInFileExplorerOptions(plugin, false, this).display();
|
||||
|
||||
// New FileExplorerStatsInterval(
|
||||
// Plugin,
|
||||
// ContainerEl,
|
||||
//
|
||||
// (plugin.settings?.fileExplorerChangelogStats ??
|
||||
// DEFAULT_SETTINGS.fileExplorerChangelogStats) ===
|
||||
// FileExplorerChangelogStats.Disabled
|
||||
// ).display();
|
||||
new ExcludeFilesAndFolders({ containerEl, plugin }).display();
|
||||
new ExcludeFilesAndFolders({ plugin }).display();
|
||||
|
||||
new IncludeItemsToggle({
|
||||
containerEl,
|
||||
plugin
|
||||
}).display();
|
||||
new IncludeItemsToggle({ plugin }).display();
|
||||
|
||||
new RenameDetectionStrictnessSlider({
|
||||
containerEl,
|
||||
plugin
|
||||
}).display();
|
||||
new RenameDetectionStrictnessSlider({ plugin }).display();
|
||||
|
||||
new RenameDetectionFileLimit({
|
||||
containerEl,
|
||||
plugin
|
||||
}).display();
|
||||
new RenameDetectionFileLimit({ plugin }).display();
|
||||
|
||||
new StatusBarStatsToggle({
|
||||
containerEl,
|
||||
plugin,
|
||||
settingTab: this
|
||||
}).display();
|
||||
new StatusBarStatsToggle({ plugin }).display();
|
||||
|
||||
new StatusBarInterval({
|
||||
containerEl,
|
||||
disabled: !plugin.settings.statusBarStats,
|
||||
disabled: !plugin.settings.statusBarStatsEnabled,
|
||||
plugin
|
||||
}).display();
|
||||
|
||||
new WhitespaceSettingsHeading({
|
||||
containerEl,
|
||||
plugin
|
||||
}).display();
|
||||
new WhitespaceSettingsHeading({ plugin }).display();
|
||||
|
||||
new WhitespaceIgnoreModeOptions({
|
||||
containerEl,
|
||||
plugin
|
||||
}).display();
|
||||
new WhitespaceIgnoreModeOptions({ plugin }).display();
|
||||
|
||||
new IgnoreBlankLinesToggle({
|
||||
containerEl,
|
||||
plugin
|
||||
}).display();
|
||||
new IgnoreBlankLinesToggle({ plugin }).display();
|
||||
|
||||
new MiscellaneousButtons({
|
||||
containerEl,
|
||||
plugin
|
||||
}).display();
|
||||
new MiscellaneousButtons({ plugin }).display();
|
||||
}
|
||||
// New DetectMovedContentToggle(plugin, containerEl).display();
|
||||
// New ChangelogMeasurementUnit(plugin, containerEl).display();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import type { GitChangelogSettings } from 'settings/settings.ts';
|
||||
|
||||
export class AutoCommitDisabledWarning extends GitChangelogSetting {
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class AutoCommitDisabledWarning extends SettingComponent {
|
||||
public display(): void {
|
||||
try {
|
||||
const gitPlugin = this.plugin.getGitPlugin();
|
||||
|
|
@ -19,10 +21,12 @@ export class AutoCommitDisabledWarning extends GitChangelogSetting {
|
|||
button.onClick(() => {
|
||||
warningSetting.settingEl.remove();
|
||||
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.autoCommitDisabledWarningDismissed = true;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
this.plugin.settingsManager.editAndSave(
|
||||
(settings: GitChangelogSettings): void => {
|
||||
settings.autoCommitDisabledWarningDismissed = true;
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,48 +1,16 @@
|
|||
import type { ChangelogGenerationSettings } from 'settings/settings.ts';
|
||||
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
import { DiffMeasurementUnit } from 'types.ts';
|
||||
|
||||
export class ChangelogMeasurementUnit extends GitChangelogSetting {
|
||||
export class ChangelogMeasurementUnit extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Changelog measurement unit')
|
||||
.addDropdown((dropdown) => {
|
||||
const options = {
|
||||
[DiffMeasurementUnit.Lines]: 'Lines',
|
||||
[DiffMeasurementUnit.Words]: 'Words'
|
||||
};
|
||||
dropdown.addOptions(options);
|
||||
dropdown.setValue(
|
||||
getMeasurementUnit(this.plugin.settings.changelogGenerationSettings)
|
||||
);
|
||||
|
||||
dropdown.onChange((value: DiffMeasurementUnit) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.changelogGenerationSettings.measurementUnit = value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
.addTypedDropdown((dropdown) => {
|
||||
dropdown.addOption(DiffMeasurementUnit.Lines, 'Lines');
|
||||
dropdown.addOption(DiffMeasurementUnit.Words, 'Words');
|
||||
this.settingTab.bind(dropdown, 'diffMeasurementUnit', {
|
||||
shouldShowValidationMessage: false
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
export function getMeasurementUnit(
|
||||
changelogGenerationSettings: ChangelogGenerationSettings
|
||||
): DiffMeasurementUnit {
|
||||
return DiffMeasurementUnit.Lines;
|
||||
if (!validateMeasurementUnit(changelogGenerationSettings.measurementUnit)) {
|
||||
return DEFAULT_SETTINGS.changelogGenerationSettings.measurementUnit;
|
||||
}
|
||||
|
||||
return changelogGenerationSettings.measurementUnit;
|
||||
}
|
||||
|
||||
export function validateMeasurementUnit(
|
||||
measurementUnit: DiffMeasurementUnit
|
||||
): boolean {
|
||||
if (Object.values(DiffMeasurementUnit).includes(measurementUnit)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,24 @@
|
|||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
import { FileExplorerStats } from 'types.ts';
|
||||
|
||||
export class ChangelogStatsInFileExplorerOptions extends GitChangelogSetting {
|
||||
export class ChangelogStatsInFileExplorerOptions extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Show changelog stats in file explorer')
|
||||
.addDropdown((dropdown) => {
|
||||
const options = {
|
||||
[FileExplorerStats.Disabled]: 'Disabled',
|
||||
[FileExplorerStats.Folders]: 'Folders',
|
||||
[FileExplorerStats.FoldersAndNotes]: 'Folders and notes'
|
||||
};
|
||||
dropdown.addOptions(options);
|
||||
dropdown.setValue(
|
||||
this.plugin.settings.fileExplorerStats ??
|
||||
DEFAULT_SETTINGS.fileExplorerStats
|
||||
.addTypedDropdown((dropdown) => {
|
||||
dropdown.addOption(FileExplorerStats.Disabled, 'Disabled');
|
||||
dropdown.addOption(FileExplorerStats.Folders, 'Folders');
|
||||
dropdown.addOption(
|
||||
FileExplorerStats.FoldersAndNotes,
|
||||
'Folders and notes'
|
||||
);
|
||||
dropdown.onChange((value: FileExplorerStats) => {
|
||||
this.refreshDisplayWithDelay(0);
|
||||
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.fileExplorerStats = value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
this.settingTab.bind(dropdown, 'fileExplorerStats', {
|
||||
shouldShowValidationMessage: false,
|
||||
onChanged: () => {
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
this.refreshDisplayWithDelay(30);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class ContentDeletionsMovesThreshold extends GitChangelogSetting {
|
||||
export class ContentDeletionsMovesThreshold extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Custom threshold for deletions/moves alert')
|
||||
|
|
@ -9,33 +8,12 @@ export class ContentDeletionsMovesThreshold extends GitChangelogSetting {
|
|||
"Acceptable amount of deletions and moves between commits. Represents either words or lines, depending on your setup. Note that this doesn't mean between each interval but between the actual commits, meaning if your auto-commit interval is five minutes, this will trigger only if you manage to delete that many files inside those five minutes, which usually signals corruption or data loss."
|
||||
)
|
||||
.addText((text) => {
|
||||
text.setDisabled(this.disabled).onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.contentDeletionsAndMovesWarningThreshold =
|
||||
validateContentDeletionsMovesThreshold(value)
|
||||
? value
|
||||
: DEFAULT_SETTINGS.contentDeletionsAndMovesWarningThreshold;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
});
|
||||
text.setDisabled(this.disabled);
|
||||
// This.restrictToPositiveIntegerInput(text);
|
||||
|
||||
this.setNonDefaultValue({
|
||||
settingsProperty: 'contentDeletionsAndMovesWarningThreshold',
|
||||
text
|
||||
this.settingTab.bind(text, 'contentDeletionsAndMovesWarningThreshold', {
|
||||
shouldShowValidationMessage: false
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function validateContentDeletionsMovesThreshold(
|
||||
contentDeletionsMovesThreshold: string
|
||||
): boolean {
|
||||
if (
|
||||
!Number.isInteger(Number(contentDeletionsMovesThreshold)) ||
|
||||
Number(contentDeletionsMovesThreshold) < 1
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,50 +1,58 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class CustomLocale extends GitChangelogSetting {
|
||||
export class CustomLocale extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Date format locale')
|
||||
.setDesc(`Accepts a locale code (e.g. "en-US").`)
|
||||
.addText((text) => {
|
||||
text.inputEl.maxLength = 30;
|
||||
text
|
||||
.setPlaceholder(DEFAULT_SETTINGS.changelogGenerationSettings.locale)
|
||||
.onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.changelogGenerationSettings.locale = value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
});
|
||||
|
||||
this.setNonDefaultValue({
|
||||
settingsProperty: 'changelogGenerationSettings',
|
||||
diffSettingsProperty: 'locale',
|
||||
text
|
||||
this.settingTab.bind(text, 'locale', {
|
||||
shouldShowValidationMessage: false
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getUserLocale(plugin: GitChangelogPlugin): string {
|
||||
const locale = plugin.settings.changelogGenerationSettings.locale;
|
||||
if (validateLocale(locale)) {
|
||||
return locale;
|
||||
function getSystemLocale(plugin: GitChangelogPlugin): string {
|
||||
if (plugin.detectedLocale === undefined) {
|
||||
// Detect the system locale using Intl API and save it for the current Obsidian session.
|
||||
const systemLocale = Intl.DateTimeFormat().resolvedOptions().locale;
|
||||
|
||||
if (validateLocale(systemLocale)) {
|
||||
plugin.detectedLocale = systemLocale;
|
||||
} else {
|
||||
new Notice(
|
||||
"Couldn't detect a valid system locale: Obsidian installer version might be too old.\nFallback to en-US."
|
||||
);
|
||||
plugin.detectedLocale = 'en-US';
|
||||
}
|
||||
}
|
||||
// Decided against using the new Obsidian language API so that the plugin is compatible with older versions of Obsidian (for now, will update later).
|
||||
return Intl.DateTimeFormat().resolvedOptions().locale;
|
||||
|
||||
return plugin.detectedLocale;
|
||||
}
|
||||
|
||||
export function validateLocale(locale?: string): boolean {
|
||||
export function getLocale(plugin: GitChangelogPlugin): string {
|
||||
return plugin.settings.locale ===
|
||||
plugin.settingsManager.getProperty('locale').defaultValue
|
||||
? getSystemLocale(plugin)
|
||||
: plugin.settings.locale;
|
||||
}
|
||||
|
||||
export function validateLocale(locale: string): boolean {
|
||||
try {
|
||||
if (!locale || typeof locale !== 'string') {
|
||||
return false;
|
||||
}
|
||||
new Intl.Locale(locale);
|
||||
return Intl.DateTimeFormat.supportedLocalesOf([locale]).length > 0;
|
||||
if (Intl.DateTimeFormat.supportedLocalesOf([locale]).length === 0) {
|
||||
return false;
|
||||
}
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,17 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { ChangelogGenerationSettings } from 'settings/settings.ts';
|
||||
|
||||
import { Notice } from 'obsidian';
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
import { TimeZoneSuggest } from 'settings/components/suggest.ts';
|
||||
import { DEFAULT_SETTINGS, TIME_ZONES_LIST } from 'settings/settings.ts';
|
||||
import { TIME_ZONES_LIST } from 'settings/settings.ts';
|
||||
|
||||
export class CustomTimeZone extends GitChangelogSetting {
|
||||
export class CustomTimeZone extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Timezone')
|
||||
.addText((text) => {
|
||||
text
|
||||
.setPlaceholder(DEFAULT_SETTINGS.changelogGenerationSettings.timezone)
|
||||
.onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.changelogGenerationSettings.timezone = value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
});
|
||||
|
||||
this.setNonDefaultValue({
|
||||
diffSettingsProperty: 'timezone',
|
||||
settingsProperty: 'changelogGenerationSettings',
|
||||
text
|
||||
this.settingTab.bind(text, 'timeZone', {
|
||||
shouldShowValidationMessage: false
|
||||
});
|
||||
|
||||
new TimeZoneSuggest(this.plugin.app, text.inputEl);
|
||||
|
|
@ -31,47 +19,33 @@ export class CustomTimeZone extends GitChangelogSetting {
|
|||
}
|
||||
}
|
||||
|
||||
export function detectSystemTimeZone(): string {
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone.toLowerCase();
|
||||
}
|
||||
function getSystemTimeZone(plugin: GitChangelogPlugin): string {
|
||||
if (plugin.detectedTimeZone === undefined) {
|
||||
// Detect the system time zone using Intl API and save it for the current Obsidian session.
|
||||
const systemTimeZone = Intl.DateTimeFormat()
|
||||
.resolvedOptions()
|
||||
.timeZone.toLowerCase();
|
||||
|
||||
export function getSystemTimeZone(plugin: GitChangelogPlugin): string {
|
||||
if (plugin.detectedTimeZone !== undefined) {
|
||||
return plugin.detectedTimeZone;
|
||||
if (validateCustomTimeZone(systemTimeZone)) {
|
||||
plugin.detectedTimeZone = systemTimeZone;
|
||||
} else {
|
||||
new Notice(
|
||||
"Couldn't detect a valid system time zone: Obsidian installer version might be too old.\nFallback to UTC."
|
||||
);
|
||||
plugin.detectedTimeZone = 'utc';
|
||||
}
|
||||
}
|
||||
|
||||
const systemTimeZone = detectSystemTimeZone();
|
||||
if (validateCustomTimeZone(systemTimeZone)) {
|
||||
plugin.detectedTimeZone = systemTimeZone;
|
||||
} else {
|
||||
new Notice(
|
||||
"Couldn't detect a valid system time zone: Obsidian installer version might be too old.\nFallback to UTC."
|
||||
);
|
||||
plugin.detectedTimeZone = 'utc';
|
||||
return 'utc';
|
||||
}
|
||||
return plugin.detectedTimeZone;
|
||||
}
|
||||
|
||||
export function getTimeZone(
|
||||
changelogGenerationSettings: ChangelogGenerationSettings,
|
||||
plugin: GitChangelogPlugin
|
||||
): string {
|
||||
return validateCustomTimeZone(changelogGenerationSettings.timezone)
|
||||
? changelogGenerationSettings.timezone
|
||||
: getSystemTimeZone(plugin);
|
||||
export function getTimeZone(plugin: GitChangelogPlugin): string {
|
||||
return plugin.settings.timeZone ===
|
||||
plugin.settingsManager.getProperty('timeZone').defaultValue
|
||||
? getSystemTimeZone(plugin)
|
||||
: plugin.settings.timeZone;
|
||||
}
|
||||
|
||||
export function systemTimeZoneUnchanged(plugin: GitChangelogPlugin): boolean {
|
||||
const systemTimeZone = detectSystemTimeZone();
|
||||
const cachedSystemTimeZone = plugin.detectedTimeZone;
|
||||
if (systemTimeZone !== cachedSystemTimeZone) {
|
||||
plugin.detectedTimeZone = systemTimeZone;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function validateCustomTimeZone(timezone: string): boolean {
|
||||
return TIME_ZONES_LIST.has(timezone.toLowerCase());
|
||||
export function validateCustomTimeZone(timeZone: string): boolean {
|
||||
return TIME_ZONES_LIST.has(timeZone.toLowerCase());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,60 +1,31 @@
|
|||
import type { ChangelogGenerationSettings } from 'settings/settings.ts';
|
||||
|
||||
import { moment } from 'obsidian';
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class DayStartTime extends GitChangelogSetting {
|
||||
export class DayStartHour extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Day start time')
|
||||
.setDesc('Adjust the day based on your schedule.')
|
||||
.addTime((text) => {
|
||||
text
|
||||
.setValue(
|
||||
moment.duration({
|
||||
hours:
|
||||
this.plugin.settings.changelogGenerationSettings.dayStartHour
|
||||
})
|
||||
)
|
||||
.onChange((value) => {
|
||||
this.settingTab.bind(text, 'dayStartHour', {
|
||||
componentToPluginSettingsValueConverter: (
|
||||
uiValue: moment.Duration
|
||||
) => {
|
||||
// Clip any minutes. The smallest possible interval is an hour and this value should be clipped to that.
|
||||
// Allowing the day start time to be specified in minutes doesn't make sense because then you would need to handle the half an hour that belongs to the previous day and the other half an hour that belongs to the next day separately.
|
||||
text.setValue(
|
||||
moment.duration({
|
||||
hours: value.hours()
|
||||
})
|
||||
);
|
||||
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.changelogGenerationSettings.dayStartHour =
|
||||
value.hours();
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
});
|
||||
|
||||
text.inputEl.step = '3600';
|
||||
// Allowing the day start time to be specified in minutes doesn't make sense because then e.g. you would need to handle the half an hour that belongs to the previous day and the other half an hour that belongs to the next day separately.
|
||||
return uiValue.hours();
|
||||
},
|
||||
onChanged: (value) => {
|
||||
text.setValue(moment.duration(value, 'hours'));
|
||||
},
|
||||
shouldShowValidationMessage: false,
|
||||
shouldResetSettingWhenComponentIsEmpty: false,
|
||||
pluginSettingsToComponentValueConverter: (
|
||||
pluginSettingsValue: number
|
||||
) => moment.duration(pluginSettingsValue, 'hours')
|
||||
});
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
text.setStep(3600);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getDayStartTime(
|
||||
changelogGenerationSettings: ChangelogGenerationSettings
|
||||
): number {
|
||||
return validateDayStartTime(changelogGenerationSettings.dayStartHour)
|
||||
? changelogGenerationSettings.dayStartHour
|
||||
: DEFAULT_SETTINGS.changelogGenerationSettings.dayStartHour;
|
||||
}
|
||||
|
||||
export const ONE_DAY_IN_HOURS = 24;
|
||||
|
||||
export function validateDayStartTime(dayStartTime: number): boolean {
|
||||
if (
|
||||
!Number.isInteger(dayStartTime) ||
|
||||
dayStartTime < 0 ||
|
||||
dayStartTime >= ONE_DAY_IN_HOURS
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,23 @@
|
|||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class DeletionsNotificationThreshold extends GitChangelogSetting {
|
||||
export class DeletionsNotificationThreshold extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Notify on large amount of changes.')
|
||||
.setDesc(
|
||||
'Notify if changes between neighboring commits exceed a threshold, which can be a sign of data loss or corruption.'
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(
|
||||
this.plugin.settings
|
||||
.notifyOnContentDeletionsAndMovesThresholdReached
|
||||
)
|
||||
.onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.notifyOnContentDeletionsAndMovesThresholdReached =
|
||||
value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
|
||||
this.refreshDisplayWithDelay();
|
||||
})
|
||||
);
|
||||
.addToggle((toggle) => {
|
||||
this.settingTab.bind(
|
||||
toggle,
|
||||
'notifyOnContentDeletionsAndMovesThresholdReached',
|
||||
{
|
||||
shouldShowValidationMessage: false,
|
||||
onChanged: () => {
|
||||
this.refreshDisplayWithDelay();
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class DetectMovedContentToggle extends GitChangelogSetting {
|
||||
export class DetectMovedContentToggle extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Detect moved lines/words')
|
||||
|
|
@ -8,16 +8,9 @@ export class DetectMovedContentToggle extends GitChangelogSetting {
|
|||
`If enabled, changelog will also track all moved words or lines between files or moved to another location in the same file. Adds significant computational overhead that increases with the number and size of changes.`
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(
|
||||
this.plugin.settings.changelogGenerationSettings.detectMovedContent
|
||||
)
|
||||
.onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.changelogGenerationSettings.detectMovedContent = value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
})
|
||||
this.settingTab.bind(toggle, 'detectMovedContent', {
|
||||
shouldShowValidationMessage: false
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
import type { ChangelogGenerationSettings } from 'settings/settings.ts';
|
||||
|
||||
import { appendCodeBlock } from 'obsidian-dev-utils/HTMLElement';
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
import { DiffAlgorithm } from 'types.ts';
|
||||
|
||||
const GIT_CONFIG_PATH = '.git/config';
|
||||
|
||||
export class DiffAlgorithmOptions extends GitChangelogSetting {
|
||||
export class DiffAlgorithmOptions extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Difference detection algorithm')
|
||||
|
|
@ -27,9 +25,7 @@ export class DiffAlgorithmOptions extends GitChangelogSetting {
|
|||
button.setButtonText('Apply');
|
||||
button.setDisabled(shouldDisableApplyButton(this.plugin));
|
||||
button.onClick(async () => {
|
||||
const diffAlgorithm = getDiffAlgorithm(
|
||||
this.plugin.settings.changelogGenerationSettings
|
||||
);
|
||||
const diffAlgorithm = this.plugin.settings.diffAlgorithm;
|
||||
if (diffAlgorithm !== DiffAlgorithm.Inherit) {
|
||||
try {
|
||||
const git = await this.plugin.getGit();
|
||||
|
|
@ -45,51 +41,25 @@ export class DiffAlgorithmOptions extends GitChangelogSetting {
|
|||
}
|
||||
});
|
||||
})
|
||||
.addDropdown((dropdown) => {
|
||||
const options = {
|
||||
[DiffAlgorithm.Inherit]: 'Inherit git config',
|
||||
[DiffAlgorithm.Default]: 'Default (Faster)',
|
||||
[DiffAlgorithm.Minimal]: 'Minimal (More precise)'
|
||||
} as const;
|
||||
dropdown.addOptions(options);
|
||||
|
||||
dropdown.setValue(
|
||||
getDiffAlgorithm(this.plugin.settings.changelogGenerationSettings)
|
||||
);
|
||||
|
||||
dropdown.onChange((value: DiffAlgorithm) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.changelogGenerationSettings.diffAlgorithm = value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings).then(() => {
|
||||
.addTypedDropdown((dropdown) => {
|
||||
dropdown.addOption(DiffAlgorithm.Inherit, 'Inherit git config');
|
||||
dropdown.addOption(DiffAlgorithm.Default, 'Default (Faster)');
|
||||
dropdown.addOption(DiffAlgorithm.Minimal, 'Minimal (More precise)');
|
||||
this.settingTab.bind(dropdown, 'diffAlgorithm', {
|
||||
shouldShowValidationMessage: false,
|
||||
onChanged: () => {
|
||||
// eslint-disable-next-line no-magic-numbers
|
||||
this.refreshDisplayWithDelay(30);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function shouldDisableApplyButton(plugin: GitChangelogPlugin): boolean {
|
||||
const diffAlgorithm = getDiffAlgorithm(
|
||||
plugin.settings.changelogGenerationSettings
|
||||
);
|
||||
const diffAlgorithm = plugin.settings.diffAlgorithm;
|
||||
if (diffAlgorithm === DiffAlgorithm.Inherit) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getDiffAlgorithm(
|
||||
changelogGenerationSettings: ChangelogGenerationSettings
|
||||
): DiffAlgorithm {
|
||||
if (
|
||||
!Object.values(DiffAlgorithm).includes(
|
||||
changelogGenerationSettings.diffAlgorithm
|
||||
)
|
||||
) {
|
||||
return DEFAULT_SETTINGS.changelogGenerationSettings.diffAlgorithm;
|
||||
}
|
||||
|
||||
return changelogGenerationSettings.diffAlgorithm;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@
|
|||
import type { ReadonlyDeep } from 'type-fest';
|
||||
|
||||
import { EXCLUDE_FILES_AND_FOLDERS } from 'constants.ts';
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class ExcludeFilesAndFolders extends GitChangelogSetting {
|
||||
export class ExcludeFilesAndFolders extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName(
|
||||
|
|
@ -40,22 +39,15 @@ export class ExcludeFilesAndFolders extends GitChangelogSetting {
|
|||
})
|
||||
)
|
||||
.addTextArea((text) => {
|
||||
text
|
||||
.setValue(
|
||||
joinExcludeItems(
|
||||
this.plugin.settingsClone.vaultChangelogGenerationSettings
|
||||
.excludeFilesAndFoldersLines ??
|
||||
DEFAULT_SETTINGS.vaultChangelogGenerationSettings
|
||||
.excludeFilesAndFoldersLines
|
||||
)
|
||||
)
|
||||
.onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.vaultChangelogGenerationSettings.excludeFilesAndFoldersLines =
|
||||
splitExcludeItems(value);
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
});
|
||||
this.settingTab.bind(text, 'excludeFilesAndFoldersLines', {
|
||||
componentToPluginSettingsValueConverter: (uiValue) =>
|
||||
splitExcludeItems(uiValue),
|
||||
|
||||
shouldShowValidationMessage: false,
|
||||
pluginSettingsToComponentValueConverter: (pluginSettingsValue) =>
|
||||
joinExcludeItems(pluginSettingsValue)
|
||||
});
|
||||
|
||||
text.inputEl.classList.add('git-changelog-text-area');
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,17 @@
|
|||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class FileChangesNotificationThreshold extends GitChangelogSetting {
|
||||
export class FileChangesNotificationThreshold extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Custom threshold for file changes alert')
|
||||
|
||||
.addText((text) => {
|
||||
text.setDisabled(this.disabled).onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.contentDeletionsAndMovesWarningThreshold =
|
||||
validateFileChangesNotificationThreshold(value)
|
||||
? value
|
||||
: DEFAULT_SETTINGS.contentDeletionsAndMovesWarningThreshold;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
this.settingTab.bind(text, 'filesChangesWarningThreshold', {
|
||||
shouldShowValidationMessage: false
|
||||
});
|
||||
// This.restrictToPositiveIntegerInput(text);
|
||||
|
||||
this.setNonDefaultValue({
|
||||
settingsProperty: 'filesChangesWarningThreshold',
|
||||
text
|
||||
});
|
||||
text.setDisabled(this.disabled);
|
||||
|
||||
// This.restrictToPositiveIntegerInput(text);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function validateFileChangesNotificationThreshold(
|
||||
fileChangesNotificationThreshold: string
|
||||
): boolean {
|
||||
if (
|
||||
!Number.isInteger(Number(fileChangesNotificationThreshold)) ||
|
||||
Number(fileChangesNotificationThreshold) < 1
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,15 @@
|
|||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS, MAX_SUPPORTED_INTERVAL } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class FileExplorerStatsInterval extends GitChangelogSetting {
|
||||
export class FileExplorerStatsInterval extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
|
||||
.setName('Interval for file explorer stats (minutes)')
|
||||
|
||||
.addText((text) => {
|
||||
text.setDisabled(this.disabled).onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.fileExplorerInterval = validateFileExplorerStatsInterval(
|
||||
value
|
||||
)
|
||||
? value
|
||||
: DEFAULT_SETTINGS.fileExplorerInterval;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
this.settingTab.bind(text, 'fileExplorerInterval', {
|
||||
shouldShowValidationMessage: false
|
||||
});
|
||||
|
||||
// This.restrictToPositiveIntegerInput(text, 5);
|
||||
this.setNonDefaultValue({
|
||||
settingsProperty: 'fileExplorerInterval',
|
||||
text
|
||||
});
|
||||
text.setDisabled(this.disabled);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function validateFileExplorerStatsInterval(
|
||||
fileExplorerStatsInterval: string
|
||||
): boolean {
|
||||
if (
|
||||
!Number.isInteger(Number(fileExplorerStatsInterval)) ||
|
||||
Number(fileExplorerStatsInterval) < 1 ||
|
||||
Number(fileExplorerStatsInterval) > MAX_SUPPORTED_INTERVAL
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import {
|
|||
MAX_TESTED_GIT_PLUGIN_VERSION,
|
||||
MIN_COMPATIBLE_GIT_PLUGIN_VERSION
|
||||
} from 'constants.ts';
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
import { GitPluginState } from 'types.ts';
|
||||
|
||||
export class GitPluginWarning extends GitChangelogSetting {
|
||||
export class GitPluginWarning extends SettingComponent {
|
||||
public display(): void {
|
||||
let desc: DocumentFragment | string;
|
||||
let setting: Setting;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class IgnoreBlankLinesToggle extends GitChangelogSetting {
|
||||
export class IgnoreBlankLinesToggle extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName(
|
||||
|
|
@ -13,16 +13,9 @@ export class IgnoreBlankLinesToggle extends GitChangelogSetting {
|
|||
)
|
||||
.setDesc('Ignore the additions and removals of completely empty lines.')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(
|
||||
this.plugin.settings.changelogGenerationSettings.ignoreBlankLines
|
||||
)
|
||||
.onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.changelogGenerationSettings.ignoreBlankLines = value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
})
|
||||
this.settingTab.bind(toggle, 'ignoreBlankLines', {
|
||||
shouldShowValidationMessage: false
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { EXCLUDE_FILES_AND_FOLDERS } from 'constants.ts';
|
||||
import { appendCodeBlock } from 'obsidian-dev-utils/HTMLElement';
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class IncludeItemsToggle extends GitChangelogSetting {
|
||||
export class IncludeItemsToggle extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName(
|
||||
|
|
@ -23,18 +23,9 @@ export class IncludeItemsToggle extends GitChangelogSetting {
|
|||
})
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(
|
||||
this.plugin.settings.vaultChangelogGenerationSettings
|
||||
.convertToIncludeList
|
||||
)
|
||||
.onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.vaultChangelogGenerationSettings.convertToInclude =
|
||||
value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
})
|
||||
this.settingTab.bind(toggle, 'convertToIncludeList', {
|
||||
shouldShowValidationMessage: false
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { FEEDBACK_URL } from 'constants.ts';
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class MiscellaneousButtons extends GitChangelogSetting {
|
||||
export class MiscellaneousButtons extends SettingComponent {
|
||||
public display(): void {
|
||||
const bugReportDiv = this.createSetting();
|
||||
bugReportDiv.addButton((button) => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
import type { ChangelogGenerationSettings } from 'settings/settings.ts';
|
||||
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
// https://github.com/git/git/blob/58b5801aa94ad5031978f8e42c1be1230b3d352f/diff.c#L58 - 1000 default
|
||||
export class RenameDetectionFileLimit extends GitChangelogSetting {
|
||||
export class RenameDetectionFileLimit extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
|
||||
|
|
@ -20,42 +17,10 @@ export class RenameDetectionFileLimit extends GitChangelogSetting {
|
|||
);
|
||||
})
|
||||
)
|
||||
.addText((text) => {
|
||||
text.inputEl.pattern = '[0-9]*';
|
||||
|
||||
text.inputEl.maxLength = 20;
|
||||
text.inputEl.inputMode = 'numeric';
|
||||
text
|
||||
.setPlaceholder(
|
||||
DEFAULT_SETTINGS.changelogGenerationSettings.renameLimit
|
||||
)
|
||||
.onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.changelogGenerationSettings.renameLimit = String(value);
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
});
|
||||
// This.restrictToPositiveIntegerInput(text);
|
||||
|
||||
this.setNonDefaultValue({
|
||||
diffSettingsProperty: 'renameLimit',
|
||||
settingsProperty: 'changelogGenerationSettings',
|
||||
text
|
||||
.addNumber((text) => {
|
||||
this.settingTab.bind(text, 'renameLimit', {
|
||||
shouldShowValidationMessage: false
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getRenameLimit(
|
||||
changelogGenerationSettings: ChangelogGenerationSettings
|
||||
): number {
|
||||
if (!validateRenameLimit(changelogGenerationSettings.renameLimit)) {
|
||||
return Number(DEFAULT_SETTINGS.changelogGenerationSettings.renameLimit);
|
||||
}
|
||||
|
||||
return Number(changelogGenerationSettings.renameLimit);
|
||||
}
|
||||
|
||||
export function validateRenameLimit(renameLimit: string): boolean {
|
||||
return Number(renameLimit) >= 0 && Number.isInteger(renameLimit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
import type { SliderComponent } from 'obsidian';
|
||||
import type { ChangelogGenerationSettings } from 'settings/settings.ts';
|
||||
|
||||
import {
|
||||
MAX_RENAME_DETECTION_STRICTNESS,
|
||||
MIN_RENAME_DETECTION_STRICTNESS
|
||||
} from 'constants.ts';
|
||||
import { ResetButton } from 'settings/components/resetButton.ts';
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
const MIN_RENAME_DETECTION_STRICTNESS = 1;
|
||||
const MAX_RENAME_DETECTION_STRICTNESS = 100;
|
||||
|
||||
export class RenameDetectionStrictnessSlider extends GitChangelogSetting {
|
||||
export class RenameDetectionStrictnessSlider extends SettingComponent {
|
||||
public display(): void {
|
||||
let slider: SliderComponent;
|
||||
const setting = this.createSetting()
|
||||
.setName('File move/rename detection strictness')
|
||||
.setDesc(
|
||||
|
|
@ -26,50 +22,25 @@ export class RenameDetectionStrictnessSlider extends GitChangelogSetting {
|
|||
);
|
||||
|
||||
new ResetButton(setting.controlEl).onClick(() => {
|
||||
slider.setValue(
|
||||
DEFAULT_SETTINGS.changelogGenerationSettings.renameDetectionStrictness
|
||||
const settingProperty = this.plugin.settingsManager.getProperty(
|
||||
'renameDetectionStrictness'
|
||||
);
|
||||
settingProperty.setValue(settingProperty.defaultValue);
|
||||
this.refreshDisplayWithDelay();
|
||||
});
|
||||
|
||||
setting.addSlider((percent) => {
|
||||
slider = percent;
|
||||
this.settingTab.bind(percent, 'renameDetectionStrictness', {
|
||||
shouldShowValidationMessage: false
|
||||
});
|
||||
|
||||
percent
|
||||
.setValue(
|
||||
getRenameDetectionStrictness(
|
||||
this.plugin.settings.changelogGenerationSettings
|
||||
)
|
||||
)
|
||||
.setLimits(
|
||||
MIN_RENAME_DETECTION_STRICTNESS,
|
||||
MAX_RENAME_DETECTION_STRICTNESS,
|
||||
1
|
||||
)
|
||||
.onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.changelogGenerationSettings.renameDetectionStrictness =
|
||||
value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
})
|
||||
.setDynamicTooltip();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getRenameDetectionStrictness(
|
||||
changelogGenerationSettings: ChangelogGenerationSettings
|
||||
): number {
|
||||
if (
|
||||
!Number.isInteger(changelogGenerationSettings.renameDetectionStrictness) ||
|
||||
changelogGenerationSettings.renameDetectionStrictness <
|
||||
MIN_RENAME_DETECTION_STRICTNESS ||
|
||||
changelogGenerationSettings.renameDetectionStrictness >
|
||||
MAX_RENAME_DETECTION_STRICTNESS
|
||||
) {
|
||||
return DEFAULT_SETTINGS.changelogGenerationSettings
|
||||
.renameDetectionStrictness;
|
||||
}
|
||||
|
||||
return changelogGenerationSettings.renameDetectionStrictness;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,60 +1,18 @@
|
|||
import type { GitChangelogPluginSettings } from 'settings/settings.ts';
|
||||
import type { ReadonlyDeep } from 'type-fest';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS, MAX_SUPPORTED_INTERVAL } from 'settings/settings.ts';
|
||||
|
||||
export class StatusBarInterval extends GitChangelogSetting {
|
||||
export class StatusBarInterval extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Interval for status bar stats (minutes)')
|
||||
.setDesc(
|
||||
'Works by comparing the live file version against the first commit before the interval.'
|
||||
)
|
||||
.addText((text) => {
|
||||
text.inputEl.pattern = '[1-9][0-9]*';
|
||||
text.inputEl.maxLength = MAX_SUPPORTED_INTERVAL.toString().length;
|
||||
text.inputEl.inputMode = 'numeric';
|
||||
text
|
||||
.setDisabled(this.disabled)
|
||||
.setPlaceholder(DEFAULT_SETTINGS.statusBarInterval)
|
||||
.onChange((value) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.statusBarInterval = validateStatusBarInterval(
|
||||
String(value)
|
||||
)
|
||||
? String(value)
|
||||
: DEFAULT_SETTINGS.statusBarInterval;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
});
|
||||
|
||||
this.setNonDefaultValue({
|
||||
settingsProperty: 'statusBarInterval',
|
||||
text
|
||||
.addNumber((text) => {
|
||||
this.settingTab.bind(text, 'statusBarInterval', {
|
||||
shouldShowValidationMessage: false
|
||||
});
|
||||
|
||||
text.setDisabled(this.disabled);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getStatusBarInterval(
|
||||
settings: ReadonlyDeep<GitChangelogPluginSettings>
|
||||
): number {
|
||||
if (!validateStatusBarInterval(settings.statusBarInterval)) {
|
||||
return Number(DEFAULT_SETTINGS.statusBarInterval);
|
||||
}
|
||||
return Number(settings.statusBarInterval);
|
||||
}
|
||||
|
||||
export function validateStatusBarInterval(
|
||||
statusBarAlternateInterval: string
|
||||
): boolean {
|
||||
if (
|
||||
!Number.isInteger(Number(statusBarAlternateInterval)) ||
|
||||
Number(statusBarAlternateInterval) < 1 ||
|
||||
Number(statusBarAlternateInterval) > MAX_SUPPORTED_INTERVAL
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,16 @@
|
|||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class StatusBarStatsToggle extends GitChangelogSetting {
|
||||
export class StatusBarStatsToggle extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName('Active note live status bar stats')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.statusBarStats)
|
||||
.onChange((value) => {
|
||||
.addToggle((toggle) => {
|
||||
this.settingTab.bind(toggle, 'statusBarStatsEnabled', {
|
||||
shouldShowValidationMessage: false,
|
||||
onChanged: () => {
|
||||
this.refreshDisplayWithDelay();
|
||||
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.statusBarStats = value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
|
||||
if (value) {
|
||||
this.plugin.initStatusBar();
|
||||
} else {
|
||||
this.plugin.statusBarStats?.destroy?.();
|
||||
this.plugin.statusBarStats = undefined;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
import type { ChangelogGenerationSettings } from 'settings/settings.ts';
|
||||
|
||||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
import { WhitespaceIgnoreMode } from 'types.ts';
|
||||
|
||||
export class WhitespaceIgnoreModeOptions extends GitChangelogSetting {
|
||||
export class WhitespaceIgnoreModeOptions extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setName(
|
||||
|
|
@ -15,43 +12,26 @@ export class WhitespaceIgnoreModeOptions extends GitChangelogSetting {
|
|||
.setText('NEW');
|
||||
})
|
||||
)
|
||||
.addDropdown((dropdown) => {
|
||||
const options = {
|
||||
[WhitespaceIgnoreMode.None]: 'Track all whitespace changes',
|
||||
[WhitespaceIgnoreMode.SpaceAtEol]:
|
||||
'Ignore whitespace changes at end of line',
|
||||
[WhitespaceIgnoreMode.SpaceChange]:
|
||||
'Ignore changes to pre-existing whitespace',
|
||||
[WhitespaceIgnoreMode.AllSpace]: 'Ignore all whitespace changes'
|
||||
} as const;
|
||||
dropdown.addOptions(options);
|
||||
|
||||
dropdown.setValue(
|
||||
getWhitespaceIgnoreMode(
|
||||
this.plugin.settings.changelogGenerationSettings
|
||||
)
|
||||
.addTypedDropdown((dropdown) => {
|
||||
dropdown.addOption(
|
||||
WhitespaceIgnoreMode.None,
|
||||
'Track all whitespace changes'
|
||||
);
|
||||
|
||||
dropdown.onChange((value: WhitespaceIgnoreMode) => {
|
||||
const newSettings = this.plugin.settingsClone;
|
||||
newSettings.changelogGenerationSettings.whitespaceIgnoreMode = value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.plugin.saveSettings(newSettings);
|
||||
dropdown.addOption(
|
||||
WhitespaceIgnoreMode.SpaceAtEol,
|
||||
'Ignore whitespace changes at end of line'
|
||||
);
|
||||
dropdown.addOption(
|
||||
WhitespaceIgnoreMode.SpaceChange,
|
||||
'Ignore changes to pre-existing whitespace'
|
||||
);
|
||||
dropdown.addOption(
|
||||
WhitespaceIgnoreMode.AllSpace,
|
||||
'Ignore all whitespace changes'
|
||||
);
|
||||
this.settingTab.bind(dropdown, 'whitespaceIgnoreMode', {
|
||||
shouldShowValidationMessage: false
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function getWhitespaceIgnoreMode(
|
||||
changelogGenerationSettings: ChangelogGenerationSettings
|
||||
): WhitespaceIgnoreMode {
|
||||
if (
|
||||
!Object.values(WhitespaceIgnoreMode).includes(
|
||||
changelogGenerationSettings.whitespaceIgnoreMode
|
||||
)
|
||||
) {
|
||||
return DEFAULT_SETTINGS.changelogGenerationSettings.whitespaceIgnoreMode;
|
||||
}
|
||||
|
||||
return changelogGenerationSettings.whitespaceIgnoreMode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { GitChangelogSetting } from 'settings/components/setting.ts';
|
||||
import { SettingComponent } from 'settings/components/setting.ts';
|
||||
|
||||
export class WhitespaceSettingsHeading extends GitChangelogSetting {
|
||||
export class WhitespaceSettingsHeading extends SettingComponent {
|
||||
public display(): void {
|
||||
this.createSetting()
|
||||
.setHeading()
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
import type GitChangelogPlugin from 'main.ts';
|
||||
|
||||
import { DEFAULT_SETTINGS } from 'settings/settings.ts';
|
||||
import { ChangelogInterval } from 'types.ts';
|
||||
|
||||
// Redundant currently
|
||||
export function getChangelogIntervalFromSettings(
|
||||
plugin: GitChangelogPlugin,
|
||||
fileOrVault: 'file' | 'vault'
|
||||
): ChangelogInterval {
|
||||
const interval =
|
||||
fileOrVault === 'file'
|
||||
? plugin.settings.fileChangelogInterval
|
||||
: plugin.settings.vaultChangelogGenerationSettings.interval;
|
||||
|
||||
if (!validateChangelogInterval(interval)) {
|
||||
return fileOrVault === 'file'
|
||||
? DEFAULT_SETTINGS.fileChangelogInterval
|
||||
: DEFAULT_SETTINGS.vaultChangelogGenerationSettings.interval;
|
||||
}
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
export function validateChangelogInterval(
|
||||
changelogInterval: ChangelogInterval
|
||||
): boolean {
|
||||
if (Object.values(ChangelogInterval).includes(changelogInterval)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import type { GitChangelogPluginSettings } from 'settings/settings.ts';
|
||||
import type { GitChangelogSettings } from 'settings/settings.ts';
|
||||
import type { TaskManager } from 'TaskManager.svelte.ts';
|
||||
import type { ReadonlyDeep } from 'type-fest';
|
||||
|
||||
|
|
@ -6,8 +6,6 @@ import { findFirstFileCommitBefore } from 'core/findFirstFileCommitBefore.ts';
|
|||
import { runCheckIgnore } from 'core/gitOperations/runCheckIgnore.ts';
|
||||
import { runWorkingDirFileDiff } from 'core/gitOperations/runWorkingDirFileDiff.ts';
|
||||
import { MarkdownView } from 'obsidian';
|
||||
import { getMeasurementUnit } from 'settings/ui/ChangelogMeasurementUnit.ts';
|
||||
import { getStatusBarInterval } from 'settings/ui/StatusBarInterval.ts';
|
||||
import { AbortError, DiffMeasurementUnit } from 'types.ts';
|
||||
import { getGitRelativeFilePath } from 'Views/helper.ts';
|
||||
|
||||
|
|
@ -68,12 +66,10 @@ export class StatusBarStats {
|
|||
}
|
||||
|
||||
public static generationSettingsChanged(
|
||||
oldSettings: ReadonlyDeep<GitChangelogPluginSettings>,
|
||||
newSettings: GitChangelogPluginSettings
|
||||
oldSettings: ReadonlyDeep<GitChangelogSettings>,
|
||||
newSettings: GitChangelogSettings
|
||||
): boolean {
|
||||
return (
|
||||
getStatusBarInterval(oldSettings) !== getStatusBarInterval(newSettings)
|
||||
);
|
||||
return oldSettings.statusBarInterval !== newSettings.statusBarInterval;
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
|
|
@ -90,7 +86,7 @@ export class StatusBarStats {
|
|||
if (abortSignal.aborted) {
|
||||
throw new AbortError();
|
||||
}
|
||||
if (this.plugin.settings.statusBarStats) {
|
||||
if (this.plugin.settings.statusBarStatsEnabled) {
|
||||
const result = await this.calculateStatsForActiveFile(
|
||||
this.plugin.app.workspace.getActiveViewOfType(MarkdownView),
|
||||
abortSignal
|
||||
|
|
@ -133,11 +129,15 @@ export class StatusBarStats {
|
|||
let additions = 0;
|
||||
let deletions = 0;
|
||||
|
||||
const git = await this.plugin.getGit();
|
||||
|
||||
const oldCommit = await findFirstFileCommitBefore({
|
||||
abortSignal,
|
||||
filePath: activeGitFile,
|
||||
minutes: getStatusBarInterval(this.plugin.settings),
|
||||
plugin: this.plugin
|
||||
minutes: this.plugin.settings.statusBarInterval,
|
||||
timeZone: await this.plugin.getEmptyTreeHash(),
|
||||
git,
|
||||
renameDetectionStrictness: this.plugin.settings.renameDetectionStrictness
|
||||
});
|
||||
|
||||
if (oldCommit && oldCommit.fileDeleted !== true) {
|
||||
|
|
@ -145,7 +145,10 @@ export class StatusBarStats {
|
|||
abortSignal,
|
||||
oldCommit,
|
||||
activeGitFile,
|
||||
plugin: this.plugin
|
||||
git,
|
||||
diffAlgorithm: this.plugin.settings.diffAlgorithm,
|
||||
whitespaceIgnoreMode: this.plugin.settings.whitespaceIgnoreMode,
|
||||
ignoreBlankLines: this.plugin.settings.ignoreBlankLines
|
||||
});
|
||||
if (baseStats) {
|
||||
additions = baseStats.additions;
|
||||
|
|
@ -160,15 +163,13 @@ export class StatusBarStats {
|
|||
const fileIsGitIgnored = await runCheckIgnore({
|
||||
abortSignal,
|
||||
activeGitFile,
|
||||
plugin: this.plugin
|
||||
git
|
||||
});
|
||||
|
||||
if (fileIsGitIgnored) {
|
||||
return 'In .gitignore';
|
||||
}
|
||||
const measurementUnit = getMeasurementUnit(
|
||||
this.plugin.settings.changelogGenerationSettings
|
||||
);
|
||||
const measurementUnit = this.plugin.settings.diffMeasurementUnit;
|
||||
|
||||
if (measurementUnit === DiffMeasurementUnit.Lines) {
|
||||
additions = activeFileView.editor.lineCount();
|
||||
|
|
|
|||
|
|
@ -3,31 +3,31 @@ import type { Spacetime } from 'spacetime';
|
|||
import type { LogEntry } from 'types.ts';
|
||||
|
||||
/**
|
||||
* This function produces "fullyAdjusted" dates, which are dates that have the "day start time" setting applied to a "timeAdjustedDate". timezoneAdjustedDate is a date adjusted with the timezone setting specified in the settings tab.
|
||||
* This function produces "fullyAdjusted" dates, which are dates that have the "day start time" setting applied to a "timeAdjustedDate". timeZoneAdjustedDate is a date adjusted with the timeZone setting specified in the settings tab.
|
||||
*/
|
||||
export function applyDayStartTimeSetting({
|
||||
dayStartTime,
|
||||
timezoneAdjustedDate
|
||||
export function applyDayStartHourSetting({
|
||||
dayStartHour,
|
||||
timeZoneAdjustedDate
|
||||
}: {
|
||||
dayStartTime: number;
|
||||
timezoneAdjustedDate: Spacetime;
|
||||
dayStartHour: number;
|
||||
timeZoneAdjustedDate: Spacetime;
|
||||
}): Spacetime {
|
||||
return timezoneAdjustedDate.subtract(dayStartTime, 'hours');
|
||||
return timeZoneAdjustedDate.subtract(dayStartHour, 'hours');
|
||||
}
|
||||
|
||||
export function getDayStartTimeAdjustedLogs(
|
||||
export function getDayStartHourAdjustedLogs(
|
||||
logEntries: LogEntry[],
|
||||
dayStartTime: number
|
||||
dayStartHour: number
|
||||
): LogEntry[] {
|
||||
if (dayStartTime === 0) {
|
||||
if (dayStartHour === 0) {
|
||||
return logEntries;
|
||||
}
|
||||
return logEntries.map((entry) => {
|
||||
return {
|
||||
...entry,
|
||||
fullyAdjustedDate: applyDayStartTimeSetting({
|
||||
dayStartTime,
|
||||
timezoneAdjustedDate: entry.timezoneAdjustedDate
|
||||
fullyAdjustedDate: applyDayStartHourSetting({
|
||||
dayStartHour,
|
||||
timeZoneAdjustedDate: entry.timeZoneAdjustedDate
|
||||
})
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare module 'obsidian' {
|
|||
on(
|
||||
name:
|
||||
| 'git-changelog:active-git-file-changed'
|
||||
| 'git-changelog:day-changed'
|
||||
| 'git-changelog:file-changelog-generation-settings-changed'
|
||||
| 'git-changelog:generation-settings-changed'
|
||||
| 'git-changelog:status-bar-settings-changed'
|
||||
|
|
@ -61,6 +62,7 @@ declare module 'obsidian' {
|
|||
trigger(
|
||||
name:
|
||||
| 'git-changelog:active-git-file-changed'
|
||||
| 'git-changelog:day-changed'
|
||||
| 'git-changelog:file-changelog-generation-settings-changed'
|
||||
| 'git-changelog:generation-settings-changed'
|
||||
| 'git-changelog:status-bar-settings-changed'
|
||||
|
|
@ -174,7 +176,7 @@ export interface FilesSummary {
|
|||
export interface LogEntry {
|
||||
// Can be null for file logs, if the file was deleted in some commit
|
||||
hash: string;
|
||||
timezoneAdjustedDate: Spacetime;
|
||||
timeZoneAdjustedDate: Spacetime;
|
||||
|
||||
// For file git logs only:
|
||||
// To track file renames through history
|
||||
|
|
|
|||
Loading…
Reference in a new issue