Kanban Index for Typescript Helper

This commit is contained in:
Mike Phares 2024-05-01 17:08:21 -07:00
parent 4e3f06bb44
commit 299aa19d53
4 changed files with 159 additions and 148 deletions

6
.vscode/mklink.md vendored
View File

@ -15,7 +15,7 @@ mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.kanbn" "D:\5-Other-Small\Kanban
``` ```
```bash ```bash
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode" "C:\Users\phares\.vscode\extensions\ifx.type-script-helper-1.5.2" mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode" "C:\Users\phares\.vscode\extensions\ifx.type-script-helper-1.6.0"
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-oss" "C:\Users\phares\.vscode-oss\extensions\ifx.type-script-helper-1.5.2" mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-oss" "C:\Users\phares\.vscode-oss\extensions\ifx.type-script-helper-1.6.0"
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-insiders" "C:\Users\phares\.vscode-insiders\extensions\ifx.type-script-helper-1.5.2" mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-insiders" "C:\Users\phares\.vscode-insiders\extensions\ifx.type-script-helper-1.6.0"
``` ```

View File

@ -102,10 +102,10 @@ internal static partial class HelperKanbanMetadata
return results; return results;
} }
private static void WriteKanbanBoardFile(string fullPath, List<Record> records, string h1) private static void WriteKanbanBoardFile(string directory, List<Record> records, string h1)
{ {
string? last = null; string? last = null;
List<string> lines = [h1, string.Empty]; List<string> lines = [h1];
foreach (Record record in records) foreach (Record record in records)
{ {
if (last is null || record.Group != last) if (last is null || record.Group != last)
@ -117,31 +117,27 @@ internal static partial class HelperKanbanMetadata
lines.Add($"- [ ] {Path.GetFileNameWithoutExtension(record.FileInfo.Name)}"); lines.Add($"- [ ] {Path.GetFileNameWithoutExtension(record.FileInfo.Name)}");
last = record.Group; last = record.Group;
} }
File.WriteAllLines(Path.Combine(fullPath, "index.knb.md"), lines); File.WriteAllLines(Path.Combine(directory, "index.knb.md"), lines);
} }
internal static void SetMetadata(ILogger log, AppSettings appSettings, string sourceDirectory) internal static void SetMetadata(string sourceDirectory, string indexFile)
{ {
bool? match; bool? match;
string? paramCase; string? paramCase;
string statusLine; string statusLine;
List<string> lines; List<string> lines;
LineNumber lineNumber; LineNumber lineNumber;
if (log is null)
throw new NullReferenceException();
TestParamCases();
string fullPath = Path.GetFullPath(sourceDirectory);
if (!Directory.Exists(fullPath))
_ = Directory.CreateDirectory(fullPath);
string indexFile = Path.Combine(fullPath, "index.md");
if (File.Exists(indexFile))
{
FileInfo fileInfo = new(indexFile); FileInfo fileInfo = new(indexFile);
string? directory = Path.GetDirectoryName(sourceDirectory);
(lines, lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(fileInfo); (lines, lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(fileInfo);
ReadOnlyCollection<string> indexFileLines = new(lines); ReadOnlyCollection<string> indexFileLines = new(lines);
List<Record> records = GetCollectionFromIndex(sourceDirectory, indexFileLines); List<Record> records = GetCollectionFromIndex(sourceDirectory, indexFileLines);
if (lineNumber.H1 is not null) if (directory is not null && lineNumber.H1 is not null)
WriteKanbanBoardFile(fullPath, records, indexFileLines[lineNumber.H1.Value]); {
string checkDirectory = Path.Combine(directory, ".vscode", "helper");
if (Directory.Exists(checkDirectory))
WriteKanbanBoardFile(checkDirectory, records, indexFileLines[lineNumber.H1.Value]);
}
foreach (Record record in records) foreach (Record record in records)
{ {
if (record.ItemLineNumber == 0) if (record.ItemLineNumber == 0)
@ -167,6 +163,18 @@ internal static partial class HelperKanbanMetadata
File.WriteAllLines(record.FileInfo.FullName, lines); File.WriteAllLines(record.FileInfo.FullName, lines);
} }
} }
internal static void SetMetadata(ILogger logger, string sourceDirectory)
{
TestParamCases();
string fullPath = Path.GetFullPath(sourceDirectory);
if (!Directory.Exists(fullPath))
_ = Directory.CreateDirectory(fullPath);
string indexFile = Path.Combine(fullPath, "index.md");
if (File.Exists(indexFile))
SetMetadata(fullPath, indexFile);
else
logger.LogInformation("<{indexFile}> doesn't exist!", indexFile);
} }
} }

View File

@ -28,6 +28,7 @@ internal static partial class HelperMarkdown
string FileNameWithoutExtension, string FileNameWithoutExtension,
string H1, string H1,
bool IsKanbanIndex, bool IsKanbanIndex,
bool IsKanbanMarkdown,
DateTime LastWriteDateTime, DateTime LastWriteDateTime,
LineNumber LineNumber, LineNumber LineNumber,
string Type); string Type);
@ -243,11 +244,13 @@ internal static partial class HelperMarkdown
int? frontMatterYamlEndLineNumber = null; int? frontMatterYamlEndLineNumber = null;
Encoding? encoding = GetEncoding(fileInfo.FullName) ?? Encoding.Default; Encoding? encoding = GetEncoding(fileInfo.FullName) ?? Encoding.Default;
string[] lines = File.ReadAllLines(fileInfo.FullName, encoding); string[] lines = File.ReadAllLines(fileInfo.FullName, encoding);
for (int i = 1; i < lines.Length; i++) for (int i = 0; i < lines.Length; i++)
{ {
line = lines[i]; line = lines[i];
if (line.Length < 3) if (line.Length < 3)
continue; continue;
if (i == 0 && line[..3] == "---")
continue;
if (h1LineNumber is null && line[..3] == "---") if (h1LineNumber is null && line[..3] == "---")
{ {
frontMatterYamlEndLineNumber = i; frontMatterYamlEndLineNumber = i;
@ -594,6 +597,7 @@ internal static partial class HelperMarkdown
FileInfo fileInfo; FileInfo fileInfo;
bool isKanbanIndex; bool isKanbanIndex;
List<string> lines; List<string> lines;
bool isKanbanMarkdown;
LineNumber lineNumber; LineNumber lineNumber;
MarkdownFile markdownFile; MarkdownFile markdownFile;
string fileNameWithoutExtension; string fileNameWithoutExtension;
@ -614,7 +618,8 @@ internal static partial class HelperMarkdown
File.WriteAllLines(file, ["---", $"type: \"{type}\"", "---", string.Empty, $"# {h1}"]); File.WriteAllLines(file, ["---", $"type: \"{type}\"", "---", string.Empty, $"# {h1}"]);
lines = File.ReadAllLines(file).ToList(); lines = File.ReadAllLines(file).ToList();
} }
isKanbanIndex = fileNameWithoutExtension == "index" && type == "Kanban"; isKanbanMarkdown = fileInfo.Name.EndsWith(".knb.md");
isKanbanIndex = fileNameWithoutExtension == "index" && type.StartsWith("kanb", StringComparison.OrdinalIgnoreCase);
markdownFile = new(fileInfo.CreationTime, markdownFile = new(fileInfo.CreationTime,
fileInfo.DirectoryName, fileInfo.DirectoryName,
fileInfo.Extension, fileInfo.Extension,
@ -623,6 +628,7 @@ internal static partial class HelperMarkdown
fileNameWithoutExtension, fileNameWithoutExtension,
h1, h1,
isKanbanIndex, isKanbanIndex,
isKanbanMarkdown,
fileInfo.LastWriteTime, fileInfo.LastWriteTime,
lineNumber, lineNumber,
type); type);
@ -634,45 +640,47 @@ internal static partial class HelperMarkdown
return new(results); return new(results);
} }
private static ReadOnlyDictionary<string, List<Card>> GetColumnsToCards(Input input, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection) private static List<string> GetKeys(ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection)
{
List<string> results = [];
MarkdownFile markdownFile;
foreach (KeyValuePair<string, MarkdownFileAndLines> relativeTo in relativeToCollection)
{
markdownFile = relativeTo.Value.MarkdownFile;
if (markdownFile.IsKanbanMarkdown)
continue;
results.Add(relativeTo.Key);
}
return results;
}
private static MarkdownFileAndLines? GetKanbanIndexMarkdownFileAndLines(ReadOnlyDictionary<string, MarkdownFileAndLines> keyValuePairs)
{
MarkdownFile markdownFile;
MarkdownFileAndLines? result = null;
foreach (KeyValuePair<string, MarkdownFileAndLines> keyValuePair in keyValuePairs)
{
markdownFile = keyValuePair.Value.MarkdownFile;
if (markdownFile.IsKanbanIndex)
{
if (result is not null)
{
result = null;
break;
}
result = keyValuePair.Value;
}
}
return result;
}
private static void SetCards(Input input, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, List<Card> notLinkedKey, MarkdownFile markdownFile, string[] lines, List<Card> cards, List<string> allKeys, int i)
{ {
Dictionary<string, List<Card>> results = [];
Card card; Card card;
string key; string key;
string[] lines;
string[] segmentsA; string[] segmentsA;
string? column = null;
List<Card> cards = [];
List<string> allKeys = [];
MarkdownFile markdownFile;
MarkdownExtra markdownExtra; MarkdownExtra markdownExtra;
MarkdownFileAndLines? markdownFileAndLines; MarkdownFileAndLines? markdownFileAndLines;
foreach (KeyValuePair<string, MarkdownFileAndLines> relativeTo in relativeToCollection)
allKeys.Add(relativeTo.Key);
foreach (KeyValuePair<string, MarkdownFileAndLines> relativeTo in relativeToCollection)
{
if (relativeTo.Value.Lines.Length == 0)
continue;
lines = relativeTo.Value.Lines;
markdownFile = relativeTo.Value.MarkdownFile;
if (markdownFile.IsKanbanIndex)
continue;
if (!File.Exists(markdownFile.File))
continue;
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Length < 4 || lines[i][0] != '#' || lines[i][1] != '#' || lines[i][2] != ' ')
continue;
if (cards.Count > 1)
{
if (column is null)
throw new NullReferenceException(nameof(column));
results.Add(column, cards);
cards = [];
}
column = lines[i][3..].TrimEnd();
if (lines.Length == i + 1)
continue;
for (int j = i + 1; j < lines.Length; j++) for (int j = i + 1; j < lines.Length; j++)
{ {
if (lines[j].Length < 5) if (lines[j].Length < 5)
@ -683,8 +691,6 @@ internal static partial class HelperMarkdown
if (segmentsA.Length != 2 || segmentsA[1][^1] != ')') if (segmentsA.Length != 2 || segmentsA[1][^1] != ')')
continue; continue;
key = Path.GetRelativePath(input.Source, Path.Combine(markdownFile.Directory, segmentsA[1][..^1])); key = Path.GetRelativePath(input.Source, Path.Combine(markdownFile.Directory, segmentsA[1][..^1]));
if (!allKeys.Remove(key))
continue;
if (!relativeToCollection.TryGetValue(key, out markdownFileAndLines)) if (!relativeToCollection.TryGetValue(key, out markdownFileAndLines))
continue; continue;
markdownExtra = GetMarkdownExtra(markdownFileAndLines); markdownExtra = GetMarkdownExtra(markdownFileAndLines);
@ -704,42 +710,35 @@ internal static partial class HelperMarkdown
markdownFileAndLines.MarkdownFile.LineNumber, markdownFileAndLines.MarkdownFile.LineNumber,
markdownExtra.RequestedDateTime, markdownExtra.RequestedDateTime,
markdownFileAndLines.MarkdownFile.Type); markdownFileAndLines.MarkdownFile.Type);
if (allKeys.Remove(key))
cards.Add(card); cards.Add(card);
else
notLinkedKey.Add(card);
} }
} }
foreach (string notLinkedKey in allKeys)
private static ReadOnlyDictionary<string, List<Card>> GetColumnsToCards(Input input, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, MarkdownFileAndLines markdownFileAndLines)
{ {
key = notLinkedKey; Dictionary<string, List<Card>> results = [];
if (!relativeToCollection.TryGetValue(key, out markdownFileAndLines)) string? column;
continue; string[] lines;
if (markdownFileAndLines.MarkdownFile.LineNumber.FrontMatterYamlEnd is null) List<Card> cards = [];
continue; List<Card> notLinkedKey = [];
markdownExtra = GetMarkdownExtra(markdownFileAndLines); lines = markdownFileAndLines.Lines;
card = new(markdownExtra.Assignees, List<string> allKeys = GetKeys(relativeToCollection);
markdownFileAndLines.MarkdownFile.CreationDateTime, for (int i = 0; i < lines.Length; i++)
markdownFileAndLines.MarkdownFile.Directory,
markdownExtra.Effort,
markdownFileAndLines.MarkdownFile.Extension,
markdownFileAndLines.MarkdownFile.File,
markdownFileAndLines.MarkdownFile.FileName,
markdownFileAndLines.MarkdownFile.FileNameWithoutExtension,
markdownFileAndLines.MarkdownFile.H1,
markdownExtra.H2HexColorCollection,
markdownExtra.H2NoCheckboxesCollection,
markdownExtra.H2WithCheckboxesCollection,
markdownFileAndLines.MarkdownFile.LastWriteDateTime,
markdownFileAndLines.MarkdownFile.LineNumber,
markdownExtra.RequestedDateTime,
markdownFileAndLines.MarkdownFile.Type);
cards.Add(card);
}
if (cards.Count > 1)
{ {
column = "Not Linked"; if (lines[i].Length < 4 || lines[i][0] != '#' || lines[i][1] != '#' || lines[i][2] != ' ')
continue;
column = lines[i][3..].TrimEnd();
if (lines.Length == i + 1)
continue;
SetCards(input, relativeToCollection, notLinkedKey, markdownFileAndLines.MarkdownFile, lines, cards, allKeys, i);
results.Add(column, cards); results.Add(column, cards);
cards = []; cards = [];
} }
} if (notLinkedKey.Count > 1)
results.Add("Not Linked", notLinkedKey);
return new(results); return new(results);
} }
@ -1182,14 +1181,14 @@ internal static partial class HelperMarkdown
{ {
if (string.IsNullOrEmpty(input.StartAt) || string.IsNullOrEmpty(input.Destination)) if (string.IsNullOrEmpty(input.StartAt) || string.IsNullOrEmpty(input.Destination))
throw new NotSupportedException(); throw new NotSupportedException();
ReadOnlyDictionary<string, List<Card>> columnsToCards; MarkdownFileAndLines? markdownFileAndLines = GetKanbanIndexMarkdownFileAndLines(relativeToCollection);
int kanbanIndexFiles = (from l in relativeToCollection where l.Value.MarkdownFile.IsKanbanIndex select 1).Sum(); if (markdownFileAndLines is not null && File.Exists(markdownFileAndLines.MarkdownFile.File))
if (kanbanIndexFiles == 1)
{ {
ReadOnlyDictionary<string, List<Card>> columnsToCards;
string jsonFile = Path.Combine(input.Destination, $"{nameof(columnsToCards)}.json"); string jsonFile = Path.Combine(input.Destination, $"{nameof(columnsToCards)}.json");
if (File.Exists(jsonFile)) if (File.Exists(jsonFile))
File.Delete(jsonFile); File.Delete(jsonFile);
columnsToCards = GetColumnsToCards(input, relativeToCollection); columnsToCards = GetColumnsToCards(input, relativeToCollection, markdownFileAndLines);
if (columnsToCards.Count == 0) if (columnsToCards.Count == 0)
File.WriteAllText(jsonFile, "{}"); File.WriteAllText(jsonFile, "{}");
else else
@ -1207,7 +1206,7 @@ internal static partial class HelperMarkdown
return (type, h1FromFile); return (type, h1FromFile);
} }
private static int SetFrontMatterAndH1(AppSettings appSettings, Input input, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles) private static int SetFrontMatterAndH1(AppSettings appSettings, ILogger<Worker> logger, Input input, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
{ {
int result = 0; int result = 0;
List<string> results = []; List<string> results = [];
@ -1230,6 +1229,10 @@ internal static partial class HelperMarkdown
results.Clear(); results.Clear();
lines = relativeTo.Value.Lines; lines = relativeTo.Value.Lines;
markdownFile = relativeTo.Value.MarkdownFile; markdownFile = relativeTo.Value.MarkdownFile;
if (markdownFile.IsKanbanMarkdown)
continue;
if (markdownFile.IsKanbanIndex)
HelperKanbanMetadata.SetMetadata(markdownFile.Directory, markdownFile.File);
results.AddRange(lines); results.AddRange(lines);
typeLine = $"type: \"{appSettings.DefaultNoteType}\""; typeLine = $"type: \"{appSettings.DefaultNoteType}\"";
h1Line = $"# {markdownFile.FileNameWithoutExtension}"; h1Line = $"# {markdownFile.FileNameWithoutExtension}";
@ -1239,7 +1242,9 @@ internal static partial class HelperMarkdown
updatedLine = $"updated: \"{markdownFile.LastWriteDateTime.ToUniversalTime():yyyy-MM-ddTHH:mm:ss.fffZ}\""; updatedLine = $"updated: \"{markdownFile.LastWriteDateTime.ToUniversalTime():yyyy-MM-ddTHH:mm:ss.fffZ}\"";
if (markdownFile.LineNumber.FrontMatterYamlEnd is null) if (markdownFile.LineNumber.FrontMatterYamlEnd is null)
{ {
if (markdownFile.LineNumber.H1 is null) if (markdownFile.LineNumber.H1 is not null)
results.Insert(0, string.Empty);
else
{ {
results.Insert(0, string.Empty); results.Insert(0, string.Empty);
results.Insert(0, h1Line); results.Insert(0, h1Line);
@ -1320,7 +1325,7 @@ internal static partial class HelperMarkdown
Input input = GetInput(args); Input input = GetInput(args);
ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection = GetRelativeToCollection(appSettings, input); ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection = GetRelativeToCollection(appSettings, input);
ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles = HelperGit.GetOthersModifiedAndDeletedExcludingStandardFiles(input.Source, usePathCombine, cancellationToken); ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles = HelperGit.GetOthersModifiedAndDeletedExcludingStandardFiles(input.Source, usePathCombine, cancellationToken);
updated = SetFrontMatterAndH1(appSettings, input, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles); updated = SetFrontMatterAndH1(appSettings, logger, input, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles);
if (updated != 0) if (updated != 0)
{ {
relativeToCollection = GetRelativeToCollection(appSettings, input); relativeToCollection = GetRelativeToCollection(appSettings, input);

View File

@ -176,7 +176,7 @@ public class Worker : BackgroundService
Helpers.HelperPackageFilesByDate.SetDateFromJsonEntry(_Logger, _Args[0]); Helpers.HelperPackageFilesByDate.SetDateFromJsonEntry(_Logger, _Args[0]);
break; break;
case ConsoleKey.K: case ConsoleKey.K:
Helpers.HelperKanbanMetadata.SetMetadata(_Logger, _AppSettings, _Args[0]); Helpers.HelperKanbanMetadata.SetMetadata(_Logger, _Args[0]);
break; break;
case ConsoleKey.L: case ConsoleKey.L:
Helpers.HelperLogMerge.LogMerge(_Args[0]); Helpers.HelperLogMerge.LogMerge(_Args[0]);
@ -185,8 +185,6 @@ public class Worker : BackgroundService
Helpers.HelperCreateNoteFiles.CreateNoteFiles(_Logger, _Args[0]); Helpers.HelperCreateNoteFiles.CreateNoteFiles(_Logger, _Args[0]);
break; break;
case ConsoleKey.M: case ConsoleKey.M:
if (_Args[0].EndsWith(".kanbn") && Directory.Exists(_Args[0]))
Helpers.HelperKanbanMetadata.SetMetadata(_Logger, _AppSettings, _Args[0]);
Helpers.HelperMarkdown.MarkdownWikiLinkVerification(_AppSettings, _Logger, _Args, cancellationToken); Helpers.HelperMarkdown.MarkdownWikiLinkVerification(_AppSettings, _Logger, _Args, cancellationToken);
break; break;
case ConsoleKey.O: case ConsoleKey.O: