Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src-tauri/capabilities/desktop.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"fs:allow-app-read-recursive",
{
"identifier": "fs:scope",
"allow": ["*/**"]
"allow": [{ "path": "**" }]
},
"shell:allow-open",
"dialog:allow-open",
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/gen/schemas/capabilities.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"desktop-capability":{"identifier":"desktop-capability","description":"","local":true,"windows":["main"],"permissions":["core:default","fs:allow-read-file","fs:allow-read-dir","fs:allow-app-read-recursive",{"identifier":"fs:scope","allow":["*/**"]},"shell:allow-open","dialog:allow-open","notification:default","notification:default","updater:default"],"platforms":["macOS","windows","linux"]}}
{"desktop-capability":{"identifier":"desktop-capability","description":"","local":true,"windows":["main"],"permissions":["core:default","fs:allow-read-file","fs:allow-read-dir","fs:allow-app-read-recursive",{"identifier":"fs:scope","allow":[{"path":"**"}]},"shell:allow-open","dialog:allow-open","notification:default","notification:default","updater:default"],"platforms":["macOS","windows","linux"]}}
60 changes: 36 additions & 24 deletions src/components/FolderWatcher.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useStatusStore } from '../stores/status';
import { add_to_queue, fileList, isMultiGamePgn, lichessFetch, multiOrSingleFilter, openPath } from '../utils';
import { LichessRound } from '../types';
import { getIndividualGamePgns, getMultiGamePgns } from '../upload';
import { computed, ref } from 'vue';
import { computed } from 'vue';

const logs = useLogStore();
const status = useStatusStore();
Expand All @@ -17,11 +17,7 @@ const props = defineProps<{

const roundStatus = computed(() => status.getRound(props.round.round.id));

const error = ref<string | null>(null);

async function selectPgnFolder() {
error.value = null;

open({ directory: true }).then(async selected => {
if (selected === null) {
return;
Expand All @@ -31,20 +27,22 @@ async function selectPgnFolder() {
throw new Error('Expected a single folder to be selected');
}

if (await folderHasPgnFile(selected)) {
startWatchingFolder(selected);
} else {
const errorMsg = `No *.pgn file(s) found in the selected folder: ${selected}`;
error.value = errorMsg;
logs.error(errorMsg);
if (await multipleGamesPgnFiles(selected)) {
logs.error(
`Multiple games.pgn files were found within the selected folder (${selected}).
Make sure you select the Round folder and not the Tournament folder.`,
);
return;
}

startWatchingFolder(selected);
});
}

async function folderHasPgnFile(path: string): Promise<boolean> {
const files = await fileList(path);
console.log(path, files);
return files.some(file => file.endsWith('.pgn'));
async function multipleGamesPgnFiles(path: string) {
const files = await fileList(path, true);
console.log('multipleGamesPgnFiles', path, files);
return files.filter(file => file.endsWith('games.pgn')).length > 1;
}

async function startWatchingFolder(path: string) {
Expand All @@ -55,9 +53,17 @@ async function startWatchingFolder(path: string) {

status.startRound(props.round.tour.id, props.round.round.id, path, stopWatching);

await checkForExistingPgnFiles(path);
await uploadMultiGamePgn(path);
}

async function checkForExistingPgnFiles(path: string) {
const files = await fileList(path);
if (files.some(file => file.endsWith('.pgn'))) {
status.setRoundContainsAtLeastOnePgn(props.round.round.id);
}
}

async function uploadMultiGamePgn(path: string) {
const multiGamePgns = await getMultiGamePgns(path);
if (multiGamePgns.length > 0) {
Expand All @@ -84,6 +90,8 @@ function handleFolderChange(event: WatchEvent): void {
return;
}

status.setRoundContainsAtLeastOnePgn(props.round.round.id);

add_to_queue(props.round.round.id, toUpload);

const paths = toUpload.map(file => file.split('/').pop());
Expand Down Expand Up @@ -146,8 +154,19 @@ async function resetAndReupload() {
</div>
</div>
<div
v-if="!status.roundHasMultiGamePgn(round.round.id)"
class="bg-yellow-100 border-l-8 border-yellow-500 text-yellow-700 p-4 mb-4"
v-if="!status.roundContainsAtLeastOnePgn(round.round.id)"
class="bg-yellow-100 border-l-8 border-yellow-500 text-yellow-700 p-4 my-4"
>
<p>
No <code>*.pgn</code> file(s) found in the selected folder
<br />
Ensure you have selected the folder for the <strong>round</strong>'s PGN files and not the parent
<strong>tournament</strong> folder.
</p>
</div>
<div
v-else-if="!status.roundHasMultiGamePgn(round.round.id)"
class="bg-yellow-100 border-l-8 border-yellow-500 text-yellow-700 p-4 my-4"
>
<p>
There is no <code>games.pgn</code> file found in that folder. If you're using DGT LiveChess, it is recommended
Expand Down Expand Up @@ -203,12 +222,5 @@ async function resetAndReupload() {
Select Folder
</button>
</form>

<div v-if="error" class="bg-red-200 border-l-8 border-red-500 text-red-900 p-4 my-4">
<strong>Error:</strong> {{ error }}
<br />
Ensure you have selected the folder for the <strong>round</strong>'s PGN files and not the parent
<strong>tournament</strong> folder.
</div>
</div>
</template>
15 changes: 15 additions & 0 deletions src/stores/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const useStatusStore = defineStore('status', () => {
tourId: string;
roundId: string;
watchProcess: WatchProcess;
containsAtLeastOnePgn?: boolean;
hasMultiGamePgn?: boolean;
}[]
>([]);
Expand Down Expand Up @@ -70,6 +71,18 @@ export const useStatusStore = defineStore('status', () => {
return round?.hasMultiGamePgn ?? false;
};

const setRoundContainsAtLeastOnePgn = (roundId: string) => {
const round = getRound(roundId);
if (round) {
round.containsAtLeastOnePgn = true;
}
};

const roundContainsAtLeastOnePgn = (roundId: string): boolean => {
const round = getRound(roundId);
return round?.containsAtLeastOnePgn ?? false;
};

return {
activeCount,
friendly,
Expand All @@ -80,6 +93,8 @@ export const useStatusStore = defineStore('status', () => {
stopRound,
setRoundHasMultiGamePgn,
roundHasMultiGamePgn,
setRoundContainsAtLeastOnePgn,
roundContainsAtLeastOnePgn,
};
});

Expand Down
20 changes: 9 additions & 11 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { invoke } from '@tauri-apps/api/core';
import { DirEntry, readDir } from '@tauri-apps/plugin-fs';
import { join } from '@tauri-apps/api/path';
import { readDir } from '@tauri-apps/plugin-fs';
import { useLogStore } from './stores/logs';
import { useSettingsStore } from './stores/settings';
import { useUserStore } from './stores/user';
Expand Down Expand Up @@ -198,17 +199,14 @@ export async function fileList(folder: string, recursive: boolean = false): Prom
const files: string[] = [];
const entries = await readDir(folder);

const traverse = async (entries: DirEntry[]) => {
for (const entry of entries) {
if (entry.isDirectory && recursive) {
traverse(await readDir(entry.name));
} else {
files.push(entry.name);
}
for (const entry of entries) {
if (entry.isDirectory && recursive) {
const subfolder = await join(folder, entry.name);
files.push(...(await fileList(subfolder, recursive)));
} else {
files.push(await join(folder, entry.name));
}
};

traverse(entries);
}

return files.reverse();
}
Expand Down
Loading