Skip to content

Commit

Permalink
Smarter Requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
ltouroumov committed Aug 26, 2023
1 parent edb9a56 commit 3c6ffb3
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 59 deletions.
6 changes: 1 addition & 5 deletions components/viewer/ViewBackpack.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

<script setup lang="ts">
import * as R from 'ramda';
import { computed, watch } from 'vue';
import { computed } from 'vue';
import { ProjectObj, ProjectRow } from '~/composables/project';
import { useProjectRefs, useProjectStore } from '~/composables/store/project';
Expand Down Expand Up @@ -61,10 +61,6 @@ const packRows = computed(() => {
backpack.value,
);
});
watch(packRows, (newChoices) => {
console.log('choices', newChoices);
});
</script>

<style lang="scss">
Expand Down
12 changes: 4 additions & 8 deletions components/viewer/ViewProjectRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,18 @@
</template>

<script setup lang="ts">
import { buildConditions } from '~/composables/conditions';
import { computed } from 'vue';
import { ProjectRow } from '~/composables/project';
import { useProjectRefs } from '~/composables/store/project';
const { row } = defineProps<{
row: ProjectRow;
}>();
const { selected } = useProjectRefs();
const condition = buildConditions(row);
const isVisible = ref<boolean>(condition(selected.value));
const { rowStatus } = useProjectRefs();
watch(selected, (newSelection) => {
isVisible.value = condition(newSelection);
});
const isVisible = computed(() => rowStatus.value[row.id] ?? true);
</script>

<style lang="scss">
Expand Down
4 changes: 1 addition & 3 deletions components/viewer/ViewScore.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ if (score.requireds.length > 0) {
isEnabled.value = condition(selected.value);
watch(selected, (newSelection) => {
const value = condition(newSelection);
console.log('score enabled', score, value);
isEnabled.value = value;
isEnabled.value = condition(newSelection);
});
}
</script>
Expand Down
20 changes: 9 additions & 11 deletions composables/conditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,19 @@ import { P, match } from 'ts-pattern';

import { ConditionTerm, HasRequirements } from '~/composables/project';

type Term = (selected: string[]) => boolean;
type Condition = {
export type Term = (selected: string[]) => boolean;
export type Condition = {
exec: Term;
deps: string[];
};

export const buildConditions = (item: HasRequirements): Term =>
buildRootCondition(item.requireds);

const buildRootCondition = (terms: ConditionTerm[]): Term => {
if (terms.length === 0) return () => true;
else {
const { exec } = AND(R.map(buildCondition, terms));
return (selected) => exec(selected);
}
export const buildConditions = (item: HasRequirements): Term => {
const { exec } = buildRootCondition(item.requireds);
return exec;
};
export const buildRootCondition = (terms: ConditionTerm[]): Condition => {
if (terms.length === 0) return ALWAYS;
else return AND(R.map(buildCondition, terms));
};

const buildCondition = (term: ConditionTerm): Condition => {
Expand Down
44 changes: 24 additions & 20 deletions composables/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export type HasRequirements = {
requireds: ConditionTerm[];
};

export type HasId = {
id: string;
};

export type Score = HasRequirements & {
id: string;
value: string;
Expand All @@ -30,30 +34,30 @@ export type ObjAddon = HasRequirements & {
text: string;
};

export type ProjectObj = HasRequirements & {
id: string;
title: string;
text: string;
image: string;
imageIsLink: boolean;
objectWidth?: string;
scores: Score[];
addons: ObjAddon[];
};
export type ProjectObj = HasId &
HasRequirements & {
title: string;
text: string;
image: string;
imageIsLink: boolean;
objectWidth?: string;
scores: Score[];
addons: ObjAddon[];
};

export type ProjectRow = HasRequirements & {
id: string;
title: string;
titleText?: string;
export type ProjectRow = HasId &
HasRequirements & {
title: string;
titleText?: string;

image: string;
imageIsLink: boolean;
objectWidth: string;
image: string;
imageIsLink: boolean;
objectWidth: string;

resultGroupId: string;
resultGroupId: string;

objects: ProjectObj[];
};
objects: ProjectObj[];
};

export type PointType = {
id: string;
Expand Down
103 changes: 94 additions & 9 deletions composables/store/project.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { defineStore, storeToRefs } from 'pinia';
import * as R from 'ramda';
import { ComputedRef, computed } from 'vue';
import { ComputedRef, Ref, computed } from 'vue';

import { Condition, buildRootCondition } from '~/composables/conditions';
import {
HasId,
HasRequirements,
PointType,
Project,
ProjectFile,
ProjectObj,
ProjectRow,
} from '~/composables/project';

type Deps = Record<string, string[]>;

export const useProjectStore = defineStore('project', () => {
const project = ref<ProjectFile | null>(null);
const selected = ref<string[]>([]);
Expand All @@ -22,6 +27,13 @@ export const useProjectStore = defineStore('project', () => {
() => project.value?.data.pointTypes ?? [],
);

const projectRows: ComputedRef<ProjectRow[]> = computed(
() => project.value?.data.rows ?? [],
);
const projectObjs: ComputedRef<ProjectObj[]> = computed(() =>
R.chain(R.prop('objects'), projectRows.value),
);

const getRow = computed(() => {
const rows: Record<string, ProjectRow> = R.fromPairs(
R.map(
Expand Down Expand Up @@ -71,25 +83,95 @@ export const useProjectStore = defineStore('project', () => {
project.value = null;
};

const conditions = computed(() =>
R.pipe(
R.chain((row: ProjectRow) =>
R.map((obj: ProjectObj) => [row, obj], row.objects),
function _buildConditions(seq: (HasId & HasRequirements)[]) {
return R.pipe(
R.filter(({ requireds }: HasRequirements) => !R.isEmpty(requireds)),
R.map((item: HasRequirements & HasId): [string, Condition] => [
item.id,
buildRootCondition(item.requireds),
]),
R.fromPairs,
)(seq);
}

function _buildDeps(seq: Record<string, Condition>): Deps {
return R.pipe(
R.toPairs,
R.chain(([id, { deps }]: [string, Condition]) =>
R.map((dep: string): [string, string] => [dep, id], deps),
),
)(project.value?.data.rows ?? []),
);
R.reduceBy(
(acc: string[], [_, dep]) => R.append(dep, acc),
[],
([dep, _]) => dep,
),
)(seq);
}

const rowConditions = computed(() => {
console.log('rebuild rowConditions');
return _buildConditions(projectRows.value);
});
const rowDeps: ComputedRef<Deps> = computed(() => {
console.log('rebuild rowDeps');
return _buildDeps(rowConditions.value);
});
const rowStatus: Ref<Record<string, boolean>> = ref({});

// const objConditions = computed(() => _buildConditions(projectObjs.value));
// const objDeps = computed(() => _buildDeps(objConditions.value));

watch(projectRows, (newRows) => {
console.log('rebuild rowStatus defaults');

const _selected: string[] = selected.value;

rowStatus.value = R.pipe(
R.map((row: ProjectRow): [string, boolean] => {
if (row.id in rowConditions.value) {
const { exec } = rowConditions.value[row.id];
return [row.id, exec(_selected)];
} else {
return [row.id, true];
}
}),
R.fromPairs,
)(newRows);
});

watch(selected, (newValue, oldValue) => {
const _deps = rowDeps.value;
const _cond = rowConditions.value;
const updated = R.symmetricDifference(newValue, oldValue);

const _status: Record<string, boolean> = {};
R.pipe(
R.chain((id: string) => _deps[id] ?? []),
R.forEach((dep: string) => {
const { exec } = _cond[dep];
_status[dep] = exec(newValue);
}),
)(updated);

rowStatus.value = { ...rowStatus.value, ..._status };
});

const setSelected = (id: string, isSelected: boolean) => {
console.log(`setSelected(${id}, ${isSelected})`);
if (isSelected) {
selected.value = R.append(id, selected.value);
} else {
selected.value = R.without([id], selected.value);
}
};

const setRowStatus = (id: string, status: boolean) => {
rowStatus.value = { ...rowStatus.value, [id]: status };
};

return {
project,
projectRows,
projectObjs,
backpack,
selected,
pointTypes,
Expand All @@ -100,7 +182,10 @@ export const useProjectStore = defineStore('project', () => {
getObject,
getObjectRow,
setSelected,
conditions,
rowConditions,
rowDeps,
rowStatus,
setRowStatus,
};
});

Expand Down
2 changes: 1 addition & 1 deletion layouts/default.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div data-bs-theme="dark">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<nav class="navbar navbar-expand-lg bg-dark-subtle navbar-dark">
<div class="container-fluid">
<div class="navbar-nav">
<NuxtLink href="/editor" class="nav-link">Editor</NuxtLink>
Expand Down
4 changes: 2 additions & 2 deletions pages/viewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<ViewBackpack />
<ScoreBar />
</div>
<div v-else class="dialog-container bg-dark">
<div class="dialog bg-dark">
<div v-else class="dialog-container">
<div class="dialog bg-dark-subtle text-light">
<h5>Default Files</h5>
<ul class="list-group mb-3">
<li class="list-group-item">
Expand Down

0 comments on commit 3c6ffb3

Please sign in to comment.