Skip to content

Commit

Permalink
feat: Rename card methods to refer to Card 'Instances' to be more exp…
Browse files Browse the repository at this point in the history
…licit about what's happening.
  • Loading branch information
adam-coster committed Aug 20, 2021
1 parent 248fd71 commit a5aa22e
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 29 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ Note that the card-search Favro API endpoint allows use of `sequentialId` as a q

Note that all of these also appear to work for the user-friendly Card URLs (e.g. where the default URL ends with `?card=BSC-123` you could instead use `?card=123`).

#### Widget-specific `cardId`s

Favro Cards are always return as an *instance* of that Card, each with its own `cardId`.

Despite this ID being Widget-specific, and the existence of global idtentifiers for Cards, most of the Favro API card endpoints use this Widget-scoped `cardId`. Presumably this is to prevent them having to have distinct endpoints for managing global vs. Widget-scoped properties.

### Creating Boards

> 💡 Create boards manually via the app to get all the features you expect from Favro.
Expand Down
1 change: 0 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

- Revisit "Columns" implementation to more intuitively reflect what it's *for*.
- Revisit "Custom Fields" implementation to make sure it reflects how Custom Fields are used.
- Revisit the class method and getter/setter names. Currently they are based directly on the field names from the Favro API, but many of those names are not easy to differentiate without referring to the docs (e.g. "cardId" vs "cardCommonId" vs "sequentialId"). Could keep the existing names but create more user-friendly aliases?

### Feature List

Expand Down
18 changes: 10 additions & 8 deletions src/lib/BravoClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ export class BravoClient extends FavroClient {
*
* {@link https://favro.com/developer/#get-all-cards}
*/
async listCards(options?: FavroApiGetCardsParams) {
async listCardInstances(options?: FavroApiGetCardsParams) {
const res = (await this.requestWithReturnedEntities(
`cards`,
{
Expand All @@ -533,16 +533,15 @@ export class BravoClient extends FavroClient {
}

/**
* Fetch a card with a known `sequentialId`.
* Fetch instances of a card with a known `sequentialId`.
* The `sequentialId` is the numeric part of the incrementing
* ID shown in the card's UI and shareable URL.
*
* @param cardSequentialId The card's number as shown in the UI
* (can be just the number or include the prefix)
*/
async findCardBySequentialId(cardSequentialId: number | string) {
const cards = await this.listCards({ cardSequentialId });
return await cards.getFirstEntity();
async findCardInstancesBySequentialId(cardSequentialId: number | string) {
return await this.listCardInstances({ cardSequentialId });
}

/**
Expand Down Expand Up @@ -581,7 +580,10 @@ export class BravoClient extends FavroClient {
*
* {@link https://favro.com/developer/#update-a-card}
*/
async updateCardById(cardId: string, options: FavroApiParamsCardUpdate) {
async updateCardInstanceById(
cardId: string,
options: FavroApiParamsCardUpdate,
) {
const res = (await this.requestWithReturnedEntities(
`cards/${cardId}`,
{
Expand All @@ -601,7 +603,7 @@ export class BravoClient extends FavroClient {
* @param data If not provided, assumes `filename` exists and
* attempts to use its content.
*/
async addAttachmentToCard(
async addAttachmentToCardInstance(
cardId: string,
filename: string,
data?: string | Buffer,
Expand All @@ -625,7 +627,7 @@ export class BravoClient extends FavroClient {
*
* {@link https://favro.com/developer/#delete-a-card}
*/
async deleteCard(cardId: string, everywhere = false) {
async deleteCardInstance(cardId: string, everywhere = false) {
let url = `cards/${cardId}`;
if (everywhere) {
url += `?everywhere=true`;
Expand Down
13 changes: 6 additions & 7 deletions src/lib/entities/BravoCard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,6 @@ class BravoCardUpdateBuilder {
}
}

// TODO: Add a Favro-global-scope Card class as a base
// for specific Instances. (Still need to think through
// details of the data model...)

/**
* A Card "Instance" represents the combination of a Card's
* *global* data and its data associated with a specific Widget.
Expand Down Expand Up @@ -329,7 +325,10 @@ export class BravoCardInstance extends BravoEntity<DataFavroCard> {
// the the user might want to start building a new update
// before that returns.
this._updateBuilder = new BravoCardUpdateBuilder();
const updated = await this._client.updateCardById(this.cardId, data);
const updated = await this._client.updateCardInstanceById(
this.cardId,
data,
);
// Update this card!
this._data = updated._data;
return this;
Expand All @@ -341,7 +340,7 @@ export class BravoCardInstance extends BravoEntity<DataFavroCard> {
* attempts to use its content.
*/
async attach(filename: string, data?: string | Buffer) {
const attachment = await this._client.addAttachmentToCard(
const attachment = await this._client.addAttachmentToCardInstance(
this.cardId,
filename,
data,
Expand All @@ -367,7 +366,7 @@ export class BravoCardInstance extends BravoEntity<DataFavroCard> {
* delete it everywhere else, too!
*/
async delete(everywhere = false) {
return this._client.deleteCard(this.cardId, everywhere);
return this._client.deleteCardInstance(this.cardId, everywhere);
}

equals(org: BravoCardInstance) {
Expand Down
26 changes: 19 additions & 7 deletions src/lib/entities/BravoWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,35 +66,47 @@ export class BravoWidget extends BravoEntity<DataFavroWidget> {

/**
* Get all cards on this Widget, with optional
* additional filter parameters. **Note:** makes
* additional filter parameters. There is only
* one instance of a card per Widget.
*
* **Note:** makes
* an API request on *every call* (no caching),
* so prefer re-use of the results to re-fetching,
* and limit by `columnId` if possible.
*/
async listCards(options?: FavroApiGetCardsBase) {
return await this._client.listCards({
async listCardInstances(options?: FavroApiGetCardsBase) {
return await this._client.listCardInstances({
...options,
widgetCommonId: this.widgetCommonId,
});
}

async findCard(
async findCardInstance(
matchFunc: ArrayMatchFunction<BravoCardInstance>,
options?: FavroApiGetCardsBase,
) {
const cards = await this.listCards(options);
const cards = await this.listCardInstances(options);
return await cards.find(matchFunc);
}

async findCardByName(
async findCardInstanceByName(
name: string,
options?: FavroApiGetCardsBase & { ignoreCase?: boolean },
) {
return await this.findCard((card) => {
return await this.findCardInstance((card) => {
return stringsMatch(card.name, name, options);
}, options);
}

async findCardInstanceBySequentialId(sequentialId: string) {
return (
await this._client.listCardInstances({
cardSequentialId: sequentialId,
widgetCommonId: this.widgetCommonId,
})
).getFirstEntity();
}

async createCard(data: Omit<FavroApiParamsCardCreate, 'widgetCommonId'>) {
return await this._client.createCard({
...data,
Expand Down
14 changes: 8 additions & 6 deletions src/test/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,16 +230,18 @@ describe('BravoClient', function () {
it('can fetch a created card', async function () {
this.timeout(8000);

const foundCard = await testWidget.findCardByName(testCardName);
const foundCard = await testWidget.findCardInstanceByName(testCardName);
assertBravoTestClaim(foundCard);
expect(foundCard!.equals(testCard)).to.be.true;

// Fetch it again via sequentialId
const bySequentialId = await client.findCardBySequentialId(
const bySequentialId = await client.findCardInstancesBySequentialId(
foundCard.sequentialId,
);
expect(bySequentialId!.equals(foundCard), 'can fetch by sequentialId').to
.be.true;
expect(
(await bySequentialId.getFirstEntity())!.equals(foundCard),
'can fetch by sequentialId',
).to.be.true;

// Fetch it again via cardId
const byCardId = await client.findCardInstanceById(foundCard.cardId);
Expand Down Expand Up @@ -327,7 +329,7 @@ describe('BravoClient', function () {
it('can add attachment to a card (and remove it)', async function () {
const filename = 'hi.txt';
const attachedText = 'Hello World!';
const attachment = await client.addAttachmentToCard(
const attachment = await client.addAttachmentToCardInstance(
testCard.cardId,
filename,
attachedText,
Expand All @@ -350,7 +352,7 @@ describe('BravoClient', function () {
// Can't delete the last column, so we need to make another to delete!
await testCard.delete();
expect(
await testWidget.findCardByName(testCardName),
await testWidget.findCardInstanceByName(testCardName),
'Should not find deleted card',
).to.be.undefined;
});
Expand Down

0 comments on commit a5aa22e

Please sign in to comment.