deicidus
2 years ago
12 changed files with 578 additions and 80 deletions
@ -0,0 +1,212 @@
|
||||
// Cards module - everything related to cards should go here (database install is automatic for AO server so no feature module)
|
||||
import inquirer from 'inquirer' |
||||
import { aoEnv } from './settings.js' |
||||
import { getCard, getCardByName, createCard, prioritizeCard, completeCard, uncheckCard, refocusCard } from './api.js' |
||||
import { headerStyle } from './styles.js' |
||||
|
||||
// The card menu is complex and so has been split into this separate file
|
||||
export async function cardMenu() { |
||||
console.log(`\n${headerStyle('My Deck')}`) |
||||
const cardChoices = [ |
||||
{ name: 'Top priorities', value: 'priorities', short: 'priorities' }, // hand? (7) (add #s in parens)
|
||||
{ name: 'Cards in hand', value: 'subcards', short: 'hand' }, // (current) deck? (60)
|
||||
{ name: 'Browse full deck', value: 'browse', short: 'browse' }, // archive? (10,000)
|
||||
'Back to AO Menu' |
||||
] |
||||
const answer = await inquirer.prompt({ |
||||
name: 'card_menu', |
||||
type: 'list', |
||||
message: 'Please choose:', |
||||
choices: cardChoices, |
||||
pageSize: cardChoices.length, |
||||
}) |
||||
switch(answer.card_menu) { |
||||
case 'priorities': |
||||
while(await prioritiesMenu()) {} |
||||
break |
||||
case 'subcards': |
||||
while(await subcardsMenu()) {} |
||||
break |
||||
case 'browse': |
||||
while(await browseMenu()) {} |
||||
break |
||||
default: |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
|
||||
// Displays the priorities of the given taskId in a menu. Selecting a card shows a menu for that card. If taskId is null, member card is used.
|
||||
async function prioritiesMenu(taskId = null) { |
||||
console.log(`\n${headerStyle('My Priorities')}`) |
||||
let prioritiesChoices = [] |
||||
|
||||
const memberId = aoEnv('AO_CLI_SESSION_MEMBERID') |
||||
if(!memberId) { |
||||
console.log('Not logged in.') |
||||
return false |
||||
} |
||||
if(!taskId) { |
||||
// Get the priorities of my member card
|
||||
taskId = memberId |
||||
} |
||||
const fetchedCards = await getCard(taskId, 'priorities') |
||||
if(!fetchedCards || fetchedCards.length < 1) { |
||||
console.log('Failed to fetch member card, this is bad.') |
||||
return false |
||||
} |
||||
const card = fetchedCards[0] |
||||
const priorityCards = fetchedCards.slice(1) // First card is member card itself
|
||||
let priorities = card.priorities.slice() |
||||
priorities.reverse() |
||||
console.log('You have', priorityCards.length, 'priorities:') |
||||
prioritiesChoices = priorities.map((priorityTaskId, i) => { |
||||
const priorityCard = priorityCards.find(p => p.taskId === priorityTaskId) |
||||
if(!priorityCard) { |
||||
return 'Missing card, repair your database' |
||||
} |
||||
return { |
||||
name: priorityCard.name, |
||||
value: { index: i, card: priorityCard }, |
||||
short: priorityCard.name.substring(0, 70) + priorityCard.name.length >= 70 ? '...' : '' |
||||
} |
||||
}) |
||||
prioritiesChoices.push( |
||||
{ name: 'Create priority', value: 'create_here', short: 'new priority' }, |
||||
{ name: 'Back to AO Menu', value: false, short: 'back' } |
||||
) |
||||
const answer = await inquirer.prompt({ |
||||
name: 'priorities_menu', |
||||
type: 'rawlist', |
||||
message: 'Please choose:', |
||||
choices: prioritiesChoices, |
||||
loop: false |
||||
}) |
||||
switch(answer.priorities_menu) { |
||||
case false: |
||||
return false |
||||
case 'create_here': |
||||
let previousCardCreatedText |
||||
do { |
||||
console.log('previousCardCreatedText is', previousCardCreatedText) |
||||
previousCardCreatedText = await createCardInteractive() |
||||
} while(previousCardCreatedText != '\n') |
||||
return true |
||||
case 'Missing card, repair your database': |
||||
console.log('Database repair yet implemented, sorry.') |
||||
return true |
||||
} |
||||
let chosenTask = answer.priorities_menu.card |
||||
const chosenTaskId = chosenTask.taskId |
||||
let previousAnswer |
||||
do { |
||||
previousAnswer = await priorityCardMenu(chosenTask, answer.priorities_menu.index) |
||||
if(previousAnswer) { |
||||
const fetchedCards = await getCard(chosenTaskId, false) |
||||
if(!fetchedCards || fetchedCards.length < 1) { |
||||
console.log('The card has disappeared. Maybe it was deleted, or cards held by no one are automatically cleaned up every five minutes.') |
||||
return false |
||||
} |
||||
chosenTask = fetchedCards[0] |
||||
} |
||||
} while(previousAnswer !== false) |
||||
console.log('Card menu not yet implemented.') |
||||
return true |
||||
} |
||||
|
||||
// Short action-oriented menu for cards in the priorities list
|
||||
// Index is the position of the card in the list that it is in, used for fencepost case to display upboat contextually
|
||||
async function priorityCardMenu(card, index) { |
||||
if(!card) { |
||||
console.log('priorityCardMenu: card is required.') |
||||
return false |
||||
} |
||||
const taskId = card.taskId |
||||
const memberId = aoEnv('AO_CLI_SESSION_MEMBERID') |
||||
if(!memberId) { |
||||
console.log('Not logged in.') |
||||
return false |
||||
} |
||||
const isChecked = card.claimed.includes(memberId) |
||||
console.log(`\n${headerStyle('Priority: ' + card.name)}`) |
||||
let priorityChoices = [] |
||||
if(index != 0) { |
||||
priorityChoices.push({ name: 'Upboat', value: 'upboat', short: 'upboat' }) |
||||
} |
||||
priorityChoices.push( |
||||
{ name: isChecked ? 'Uncheck' : 'Check off', value: 'check', short: 'check!' }, |
||||
{ name: 'Downboat', value: 'downboat', short: 'downboat' }, |
||||
//{ name: 'Browse within', value: 'browse', short: 'browse' }
|
||||
{ name: 'Back to Priorities', value: false, short: 'back' } |
||||
) |
||||
const answer = await inquirer.prompt({ |
||||
name: 'priority_card_menu', |
||||
type: 'list', |
||||
message: 'Please choose:', |
||||
choices: priorityChoices, |
||||
pageSize: priorityChoices.length, |
||||
}) |
||||
switch(answer.priority_card_menu) { |
||||
case 'check': |
||||
if(isChecked) { |
||||
await uncheckCard(taskId) |
||||
} else { |
||||
await completeCard(taskId) |
||||
} |
||||
break |
||||
case 'upboat': |
||||
await prioritizeCard(taskId, memberId) |
||||
return false |
||||
case 'downboat': |
||||
await refocusCard(taskId, memberId) |
||||
return false |
||||
case 'browse': |
||||
break |
||||
default: |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
|
||||
async function subcardsMenu() { |
||||
console.log('Not yet implemented')
|
||||
} |
||||
|
||||
async function browseMenu() { |
||||
console.log('Not yet implemented') |
||||
} |
||||
|
||||
// Ask the user to create a card, checks if it already exists, and then creates it if it doesn't
|
||||
async function createCardInteractive(prioritized = true) { |
||||
const memberId = aoEnv('AO_CLI_SESSION_MEMBERID') |
||||
if(!memberId) { |
||||
console.log('Not logged in.') |
||||
return false |
||||
} |
||||
const answer = await inquirer.prompt({ |
||||
name: 'new_card_text', |
||||
type: 'input', |
||||
message: 'New card or Enter to end:', |
||||
}) |
||||
if(answer.new_card_text.trim().length <= 0) { |
||||
return false |
||||
} |
||||
// Check if the card alerady exists
|
||||
const fetchedCards = await getCardByName(answer.new_card_text, false) |
||||
if(fetchedCards && fetchedCards.length >= 1) { |
||||
if(fetchedCards.length >= 2) { |
||||
console.log('More than one copy of this card was found. This should not happen.') |
||||
} |
||||
if(prioritized) { |
||||
console.log('Card already exists, prioritizing.') |
||||
const prioritizeResult = prioritizeCard(fetchedCards[0].taskId, memberId) |
||||
if(!prioritizeResult.ok) { |
||||
console.log('May have failed to prioritize card.') |
||||
} |
||||
} |
||||
return false |
||||
} |
||||
console.log('card does not exist yet. creating...', answer.new_card_text) |
||||
const result = await createCard(answer.new_card_text, false, true) |
||||
return answer.new_card_text |
||||
} |
@ -0,0 +1,43 @@
|
||||
import { execSync } from 'child_process' |
||||
import { lsFolder } from '../files.js'
|
||||
export const ALCHEMY_FOLDER = process.env.HOME + '/Alchemy' |
||||
|
||||
function statusAlchemy() { |
||||
return lsFolder(ALCHEMY_FOLDER).length >= 6 ? 'installed' : 'off' |
||||
} |
||||
|
||||
function downloadAlchemy() { |
||||
console.log('Beacon of Zen') |
||||
} |
||||
|
||||
function updateAlchemy() { |
||||
try { |
||||
const result = execSync('cd ~/Alchemy && git pull') |
||||
if(result.toString().includes('Already up to date.')) { |
||||
console.log('Alchemy is already up to date.') |
||||
} else { |
||||
console.log('Alchemy updated.') |
||||
return true |
||||
} |
||||
} catch(error) { |
||||
console.log('Failed to update Alchemy scripts: ', error) |
||||
} |
||||
return false |
||||
} |
||||
|
||||
function onMyCustomMenuItem() { |
||||
console.log("Not implemented.") |
||||
} |
||||
|
||||
export default { |
||||
name: 'Alchemy', |
||||
description: 'scripts that transmute your system into gold', |
||||
status: statusAlchemy, |
||||
install: downloadAlchemy, |
||||
update: updateAlchemy, |
||||
// These menu items will show up oin Features->Alchemy. The key/(menu:value:) is arbitrary but must be the same in both places.
|
||||
custom_script_1: onMyCustomMenuItem, |
||||
menu: [ |
||||
{ name: 'Menu item to trigger a very specific Alchemy script', value: 'custom_script_1' }
|
||||
] |
||||
} |
Loading…
Reference in new issue