Fix columns & cards
This commit is contained in:
parent
fb70658f23
commit
5fa653f401
|
@ -1,9 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import currentDraggedCard from '$lib/stores/currentDraggedCard';
|
import currentDraggedCard from '$lib/stores/currentDraggedCard';
|
||||||
import currentModalCard from '$lib/stores/currentModalCard';
|
import currentModalCard from '$lib/stores/currentModalCard';
|
||||||
import project_tags from '$lib/stores/projectTags';
|
|
||||||
import type Card from '$lib/types/Card';
|
import type Card from '$lib/types/Card';
|
||||||
import ModalCard from './ModalCard.svelte';
|
// import ModalCard from './ModalCard.svelte';
|
||||||
|
|
||||||
export let card: Card;
|
export let card: Card;
|
||||||
</script>
|
</script>
|
||||||
|
@ -21,25 +20,21 @@
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="title">{card.title}</div>
|
<div class="title">{card.id} - {card.title}</div>
|
||||||
{#if card.tags}
|
<div class="tags">
|
||||||
<div class="tags">
|
{#each card.cardTags as tag}
|
||||||
{#each card.tags as tag}
|
{#if tag.option}
|
||||||
{#if tag.option_id}
|
<span class="tag" style="border: 1px solid #333"
|
||||||
{#if $project_tags[tag.tag_id]}
|
>{tag.projectTag.id}: {tag.option.id} ({tag.option.value})</span
|
||||||
<span class="tag" style="border: 1px solid #333">
|
>
|
||||||
{$project_tags[tag.tag_id]?.options.find((o) => o.id == tag.option_id)?.value}</span
|
{:else if tag.value}
|
||||||
>
|
<span class="tag" style="border: 1px solid #333">{tag.value}</span>
|
||||||
{/if}
|
{/if}
|
||||||
{:else if tag.value}
|
{/each}
|
||||||
<span class="tag" style="border: 1px solid #333">{tag.value}</span>
|
</div>
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ModalCard bind:card />
|
<!-- <ModalCard bind:card /> -->
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.card {
|
.card {
|
||||||
|
|
|
@ -1,39 +1,43 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Card from '$lib/types/Card';
|
import Card, { cards } from '$lib/types/Card';
|
||||||
import CardComponent from '../card/Card.svelte';
|
import CardComponent from '../card/Card.svelte';
|
||||||
import AddIcon from '../icons/AddIcon.svelte';
|
import AddIcon from '../icons/AddIcon.svelte';
|
||||||
import type TagOption from '$lib/types/TagOption';
|
import type TagOption from '$lib/types/TagOption';
|
||||||
import type ProjectTag from '$lib/types/ProjectTag';
|
import type ProjectTag from '$lib/types/ProjectTag';
|
||||||
import type Project from '$lib/types/Project';
|
import type Project from '$lib/types/Project';
|
||||||
|
import currentDraggedCard from '$lib/stores/currentDraggedCard';
|
||||||
|
|
||||||
export let project: Project;
|
export let project: Project;
|
||||||
export let option: TagOption | null = null;
|
export let option: TagOption | null = null;
|
||||||
export let primaryTag: ProjectTag | null = null;
|
export let primaryTag: ProjectTag | null = null;
|
||||||
export let title: string;
|
|
||||||
export let columnCards: Card[] = [];
|
export let columnCards: Card[] = [];
|
||||||
|
|
||||||
let lastTitle = title;
|
let newOptionValue = option?.value || `No ${primaryTag?.title}`;
|
||||||
|
|
||||||
// async function onDrop(e: DragEvent) {
|
async function onDrop(e: DragEvent) {
|
||||||
// e.preventDefault();
|
e.preventDefault();
|
||||||
// if (!$currentDraggedCard || !$currentDraggedCard.cardTags) return;
|
if (!primaryTag || !$currentDraggedCard || !$currentDraggedCard.cardTags) return;
|
||||||
|
|
||||||
// $currentDraggedCard;
|
const currentCardTag =
|
||||||
|
$currentDraggedCard.cardTags.find((tag) => tag.projectTag === primaryTag) || null;
|
||||||
|
const currentOption = currentCardTag?.option || null;
|
||||||
|
|
||||||
// for (let tag of $currentDraggedCard.cardTags) {
|
if (currentOption === option) return;
|
||||||
// if (tag.projectTag !== primaryTag) continue;
|
|
||||||
// if (tag.option == option) return;
|
|
||||||
|
|
||||||
// if (!tag.option && !tag.value) await tag.delete();
|
if (!currentOption && option) {
|
||||||
// else if (tag.option && optionId)
|
await $currentDraggedCard.addTag(primaryTag, option, null);
|
||||||
// await createCardTagApi(tag.card_id, tag.tag_id, tag.option_id, tag.value);
|
} else if (currentOption && !option) {
|
||||||
// else await updateCardTagApi(tag.card_id, tag.tag_id, optionId, tag.value);
|
if (!currentCardTag) return;
|
||||||
|
await $currentDraggedCard.removeTag(currentCardTag);
|
||||||
|
} else if (currentOption && option) {
|
||||||
|
if (!currentCardTag) return;
|
||||||
|
await $currentDraggedCard.updateTag(currentCardTag, option, null);
|
||||||
|
}
|
||||||
|
|
||||||
// tag.option_id = optionId;
|
currentDraggedCard.set(null);
|
||||||
// cards.reload();
|
|
||||||
// }
|
cards.reload();
|
||||||
// currentDraggedCard.set(null);
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
async function addCard() {
|
async function addCard() {
|
||||||
const card = await Card.create(project);
|
const card = await Card.create(project);
|
||||||
|
@ -43,33 +47,30 @@
|
||||||
if (!option) return;
|
if (!option) return;
|
||||||
|
|
||||||
await card.addTag(primaryTag, option, null);
|
await card.addTag(primaryTag, option, null);
|
||||||
|
|
||||||
|
cards.reload();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- on:drop={onDrop} -->
|
|
||||||
<div
|
<div
|
||||||
class="column"
|
class="column"
|
||||||
role="listbox"
|
role="listbox"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
|
on:drop={onDrop}
|
||||||
on:dragover={(e) => {
|
on:dragover={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<header>
|
<header>
|
||||||
<input
|
<input
|
||||||
bind:value={title}
|
bind:value={newOptionValue}
|
||||||
type="text"
|
type="text"
|
||||||
on:blur={async () => {
|
on:blur={async () => {
|
||||||
if (lastTitle === title) return;
|
|
||||||
if (!option || !primaryTag) return;
|
if (!option || !primaryTag) return;
|
||||||
// option;
|
if (newOptionValue === option.value) return;
|
||||||
// await updateTagOptionAPI({
|
|
||||||
// id: optionId,
|
await option.setValue(newOptionValue);
|
||||||
// tag_id: primary_tag_id,
|
newOptionValue = option.value;
|
||||||
// value: title
|
|
||||||
// });
|
|
||||||
// lastTitle = title;
|
|
||||||
// cards.reload();
|
|
||||||
}}
|
}}
|
||||||
disabled={option === null}
|
disabled={option === null}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -6,21 +6,22 @@
|
||||||
import Header from './Header.svelte';
|
import Header from './Header.svelte';
|
||||||
|
|
||||||
export let project: Project;
|
export let project: Project;
|
||||||
|
|
||||||
|
$: allCards = $cards;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if project}
|
{#if project}
|
||||||
<section>
|
<section>
|
||||||
{#if $currentView}
|
{#if $currentView}
|
||||||
<Header {project} />
|
<Header {project} />
|
||||||
{#if $cards}
|
{#if $cards && allCards}
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
{#if $currentView.primaryTag}
|
{#if $currentView.primaryTag}
|
||||||
{#each $currentView.primaryTag.options as option}
|
{#each $currentView.primaryTag.options as option}
|
||||||
<Column
|
<Column
|
||||||
{option}
|
{option}
|
||||||
primaryTag={$currentView.primaryTag}
|
primaryTag={$currentView.primaryTag}
|
||||||
title={option.value}
|
columnCards={allCards
|
||||||
columnCards={$cards
|
|
||||||
.filter((c) => c.cardTags.map((t) => t.option).includes(option))
|
.filter((c) => c.cardTags.map((t) => t.option).includes(option))
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
if (!$currentView?.sortTag) return 0;
|
if (!$currentView?.sortTag) return 0;
|
||||||
|
@ -43,15 +44,14 @@
|
||||||
{/if}
|
{/if}
|
||||||
<Column
|
<Column
|
||||||
primaryTag={$currentView.primaryTag}
|
primaryTag={$currentView.primaryTag}
|
||||||
title={$currentView.primaryTag ? `No ${$currentView.title}` : 'No groups'}
|
|
||||||
columnCards={$currentView.primaryTag != null
|
columnCards={$currentView.primaryTag != null
|
||||||
? (() => {
|
? (() => {
|
||||||
const primaryTag = $currentView.primaryTag;
|
const primaryTag = $currentView.primaryTag;
|
||||||
return $cards.filter(
|
return allCards.filter(
|
||||||
(c) => !c.cardTags.map((t) => t.projectTag).includes(primaryTag)
|
(c) => !c.cardTags.map((t) => t.projectTag).includes(primaryTag)
|
||||||
);
|
);
|
||||||
})()
|
})()
|
||||||
: $cards}
|
: allCards}
|
||||||
{project}
|
{project}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,14 @@ import { toastAlert } from '$lib/utils/toasts';
|
||||||
import type TagOption from './TagOption';
|
import type TagOption from './TagOption';
|
||||||
import type ProjectTag from './ProjectTag';
|
import type ProjectTag from './ProjectTag';
|
||||||
|
|
||||||
export const cards = writable([] as Card[]);
|
const { subscribe, set, update } = writable([] as Card[]);
|
||||||
|
|
||||||
|
export const cards = {
|
||||||
|
subscribe,
|
||||||
|
set,
|
||||||
|
update,
|
||||||
|
reload: () => update((cards) => cards)
|
||||||
|
};
|
||||||
|
|
||||||
export default class Card {
|
export default class Card {
|
||||||
private _id: number;
|
private _id: number;
|
||||||
|
@ -90,16 +97,35 @@ export default class Card {
|
||||||
|
|
||||||
if (!cardTag) return false;
|
if (!cardTag) return false;
|
||||||
|
|
||||||
this._cardTags.push(cardTag);
|
this._cardTags = [...this._cardTags, cardTag];
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async removeTag(cardTag: CardTag): Promise<boolean> {
|
||||||
|
const res = await cardTag.delete();
|
||||||
|
|
||||||
|
if (!res) return false;
|
||||||
|
|
||||||
|
this._cardTags = this._cardTags.filter((ct) => ct !== cardTag);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateTag(
|
||||||
|
cardTag: CardTag,
|
||||||
|
tagOption: TagOption | null,
|
||||||
|
value: string | null
|
||||||
|
): Promise<boolean> {
|
||||||
|
return await cardTag.update(tagOption, value);
|
||||||
|
}
|
||||||
|
|
||||||
static parse(json: any): Card | null;
|
static parse(json: any): Card | null;
|
||||||
static parse(json: any, project: Project | null | undefined): Card | null;
|
static parse(json: any, project: Project | null | undefined): Card | null;
|
||||||
|
|
||||||
static parse(json: any, project?: Project | null | undefined): Card | null {
|
static parse(json: any, project?: Project | null | undefined): Card | null {
|
||||||
if (json === null) {
|
if (json === null) {
|
||||||
|
toastAlert('Failed to parse card: json is null');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import cardsTagsApi from '$lib/api/cardsTagsApi';
|
import cardsTagsApi from '$lib/api/cardsTagsApi';
|
||||||
|
import { toastAlert } from '$lib/utils/toasts';
|
||||||
import Card from './Card';
|
import Card from './Card';
|
||||||
import ProjectTag from './ProjectTag';
|
import ProjectTag from './ProjectTag';
|
||||||
import TagOption from './TagOption';
|
import TagOption from './TagOption';
|
||||||
|
@ -21,16 +22,16 @@ export default class CardTag {
|
||||||
this._value = value;
|
this._value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get card(): number {
|
get card(): Card {
|
||||||
return this.card;
|
return this._card;
|
||||||
}
|
}
|
||||||
|
|
||||||
get projectTag(): ProjectTag {
|
get projectTag(): ProjectTag {
|
||||||
return this.projectTag;
|
return this._projectTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
get option(): TagOption | null {
|
get option(): TagOption | null {
|
||||||
return this.option;
|
return this._option;
|
||||||
}
|
}
|
||||||
|
|
||||||
get value(): string | null {
|
get value(): string | null {
|
||||||
|
@ -43,31 +44,58 @@ export default class CardTag {
|
||||||
option: TagOption | null,
|
option: TagOption | null,
|
||||||
value: string | null
|
value: string | null
|
||||||
): Promise<CardTag | null> {
|
): Promise<CardTag | null> {
|
||||||
const id = await cardsTagsApi.create(card.id, tag.id, option ? option.id : null, value);
|
const res = await cardsTagsApi.create(card.id, tag.id, option ? option.id : null, value);
|
||||||
|
|
||||||
if (!id) return null;
|
if (!res) return null;
|
||||||
|
|
||||||
return new CardTag(card, tag, option, value);
|
return new CardTag(card, tag, option, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete() {
|
async delete(): Promise<boolean> {
|
||||||
return cardsTagsApi.delete(this._card.id, this._projectTag.id);
|
return cardsTagsApi.delete(this._card.id, this._projectTag.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async update(option: TagOption | null, value: string | null): Promise<boolean> {
|
||||||
|
const res = await cardsTagsApi.update(
|
||||||
|
this._card.id,
|
||||||
|
this._projectTag.id,
|
||||||
|
option ? option.id : null,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) return false;
|
||||||
|
|
||||||
|
this._option = option;
|
||||||
|
this._value = value;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static parse(json: any): CardTag | null;
|
static parse(json: any): CardTag | null;
|
||||||
static parse(json: any, card: Card | null | undefined): CardTag | null;
|
static parse(json: any, card: Card | null | undefined): CardTag | null;
|
||||||
|
|
||||||
static parse(json: any, card?: Card | null | undefined): CardTag | null {
|
static parse(json: any, card?: Card | null | undefined): CardTag | null {
|
||||||
if (!json) return null;
|
if (!json) {
|
||||||
|
toastAlert('Failed to parse card tag: json is null');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!card) card = Card.fromId(json.card_id);
|
if (!card) card = Card.fromId(json.card_id);
|
||||||
if (!card) return null;
|
if (!card) {
|
||||||
|
toastAlert('Failed to parse card tag: card is null');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const tag = ProjectTag.fromId(json.tag_id);
|
const tag = ProjectTag.fromId(json.tag_id);
|
||||||
if (!tag) return null;
|
if (!tag) {
|
||||||
|
toastAlert('Failed to parse card tag: tag is null');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const option = tag.options.find((option) => option.id === json.option_id);
|
const option = tag.options.find((option) => option.id === json.option_id);
|
||||||
if (!option) return null;
|
if (!option) {
|
||||||
|
toastAlert('Failed to parse card tag: option is null');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return new CardTag(card, tag, option, json.value);
|
return new CardTag(card, tag, option, json.value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import tagsOptions from '$lib/api/tagsOptions';
|
||||||
import ProjectTag from './ProjectTag';
|
import ProjectTag from './ProjectTag';
|
||||||
|
|
||||||
export default class TagOption {
|
export default class TagOption {
|
||||||
|
@ -23,6 +24,16 @@ export default class TagOption {
|
||||||
return this._value;
|
return this._value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async setValue(value: string): Promise<boolean> {
|
||||||
|
const res = await tagsOptions.update(this._id, this.projectTag.id, value);
|
||||||
|
|
||||||
|
if (!res) return false;
|
||||||
|
|
||||||
|
this._value = value;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static parse(json: any): TagOption | null;
|
static parse(json: any): TagOption | null;
|
||||||
static parse(json: any, projectTag: ProjectTag | null | undefined): TagOption | null;
|
static parse(json: any, projectTag: ProjectTag | null | undefined): TagOption | null;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue