forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			154 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
<script lang="ts">
 | 
						|
  import type { Feature } from "geojson"
 | 
						|
  import { Store, UIEventSource } from "../../Logic/UIEventSource"
 | 
						|
  import OsmObjectDownloader from "../../Logic/Osm/OsmObjectDownloader"
 | 
						|
  import { OsmObject } from "../../Logic/Osm/OsmObject"
 | 
						|
  import Loading from "../Base/Loading.svelte"
 | 
						|
  import { HistoryUtils } from "./HistoryUtils"
 | 
						|
  import * as favourite from "../../../public/assets/generated/layers/favourite.json"
 | 
						|
  import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
 | 
						|
  import Tr from "../Base/Tr.svelte"
 | 
						|
  import AccordionSingle from "../Flowbite/AccordionSingle.svelte"
 | 
						|
  import Translations from "../i18n/Translations"
 | 
						|
  import type { TagRenderingConfigJson } from "../../Models/ThemeConfig/Json/TagRenderingConfigJson"
 | 
						|
  import { Or } from "../../Logic/Tags/Or"
 | 
						|
  import { Utils } from "../../Utils"
 | 
						|
  import ChartJs from "../Base/ChartJs.svelte"
 | 
						|
  import { ChartJsUtils } from "../Base/ChartJsUtils"
 | 
						|
 | 
						|
  export let onlyShowUsername: string[]
 | 
						|
  export let features: Feature[]
 | 
						|
 | 
						|
  let usernames = new Set(onlyShowUsername)
 | 
						|
 | 
						|
  const downloader = new OsmObjectDownloader()
 | 
						|
  let allHistories: UIEventSource<OsmObject[][]> = UIEventSource.FromPromise(
 | 
						|
    Promise.all(features.map((f) => downloader.downloadHistory(f.properties.id)))
 | 
						|
  )
 | 
						|
  let allDiffs: Store<
 | 
						|
    {
 | 
						|
      key: string
 | 
						|
      value?: string
 | 
						|
      oldValue?: string
 | 
						|
      step: OsmObject
 | 
						|
    }[]
 | 
						|
  > = allHistories.mapD((histories) => HistoryUtils.fullHistoryDiff(histories, usernames))
 | 
						|
 | 
						|
  // We use the favourite-layer as it contains _all_ questions
 | 
						|
  const trs = favourite.tagRenderings.map(
 | 
						|
    (tr) => new TagRenderingConfig(<TagRenderingConfigJson>tr)
 | 
						|
  )
 | 
						|
 | 
						|
  function detectQuestion(key: string): TagRenderingConfig {
 | 
						|
    const byKey = trs.find((tr) => tr.freeform?.key === key)
 | 
						|
    if (byKey) {
 | 
						|
      return byKey
 | 
						|
    }
 | 
						|
    return trs.find((tr) =>
 | 
						|
      tr.mappings.some((mapping) => {
 | 
						|
        const ifTags = Or.construct(Utils.NoNull([mapping.if, mapping.alsoShowIf]))
 | 
						|
        const keys = ifTags.usedKeys()
 | 
						|
        return keys.some((k) => k == key)
 | 
						|
      })
 | 
						|
    )
 | 
						|
  }
 | 
						|
 | 
						|
  const mergedCount: Store<
 | 
						|
    {
 | 
						|
      key: string
 | 
						|
      tr: TagRenderingConfig
 | 
						|
      count: number
 | 
						|
      values: { value: string; count: number }[]
 | 
						|
      features: Feature[]
 | 
						|
    }[]
 | 
						|
  > = allDiffs.mapD((allDiffs) => {
 | 
						|
    const keyCounts = new Map<string, Map<string, OsmObject[]>>()
 | 
						|
    for (const diff of allDiffs) {
 | 
						|
      const k = diff.key
 | 
						|
      if (!keyCounts.has(k)) {
 | 
						|
        keyCounts.set(k, new Map<string, OsmObject[]>())
 | 
						|
      }
 | 
						|
      const valueCounts = keyCounts.get(k)
 | 
						|
      const v = diff.value ?? ""
 | 
						|
      const oldFeaturesList = valueCounts.get(v) ?? []
 | 
						|
      valueCounts.set(v, [...oldFeaturesList, diff.step])
 | 
						|
    }
 | 
						|
 | 
						|
    const perKey: {
 | 
						|
      key: string
 | 
						|
      tr: TagRenderingConfig
 | 
						|
      count: number
 | 
						|
      values: { value: string; count: number }[]
 | 
						|
      features: Feature[]
 | 
						|
    }[] = []
 | 
						|
    keyCounts.forEach((values: Map<string, OsmObject[]>, key: string) => {
 | 
						|
      const keyTotal: { value: string; features: Feature[] }[] = []
 | 
						|
      values.forEach((count, value) => {
 | 
						|
        keyTotal.push({ value, features: count.map((step) => step.asGeoJson()) })
 | 
						|
      })
 | 
						|
      let countForKey: Feature[] = []
 | 
						|
      for (const { features } of keyTotal) {
 | 
						|
        countForKey.push(...features)
 | 
						|
      }
 | 
						|
      keyTotal.sort((a, b) => b.features.length - a.features.length)
 | 
						|
      const tr = detectQuestion(key)
 | 
						|
      perKey.push({
 | 
						|
        count: countForKey.length,
 | 
						|
        tr,
 | 
						|
        key,
 | 
						|
        values: keyTotal.map(({ value, features }) => ({
 | 
						|
          value,
 | 
						|
          count: features.length,
 | 
						|
        })),
 | 
						|
        features: countForKey,
 | 
						|
      })
 | 
						|
    })
 | 
						|
    perKey.sort((a, b) => b.count - a.count)
 | 
						|
 | 
						|
    return perKey
 | 
						|
  })
 | 
						|
 | 
						|
  const t = Translations.t.inspector
 | 
						|
</script>
 | 
						|
 | 
						|
{#if allHistories === undefined}
 | 
						|
  <Loading />
 | 
						|
{:else if $allDiffs !== undefined}
 | 
						|
  {#each $mergedCount as diff}
 | 
						|
    <h3>
 | 
						|
      {#if diff.tr}
 | 
						|
        <Tr t={diff.tr.question} />
 | 
						|
      {:else}
 | 
						|
        {diff.key}
 | 
						|
      {/if}
 | 
						|
    </h3>
 | 
						|
    <AccordionSingle>
 | 
						|
      <span slot="header">
 | 
						|
        <Tr t={t.answeredCountTimes.Subs(diff)} />
 | 
						|
      </span>
 | 
						|
      <ul>
 | 
						|
        {#each diff.values as value}
 | 
						|
          <li>
 | 
						|
            <b>{value.value}</b>
 | 
						|
            {#if value.count > 1}
 | 
						|
              - {value.count}
 | 
						|
            {/if}
 | 
						|
          </li>
 | 
						|
        {/each}
 | 
						|
      </ul>
 | 
						|
      {#if diff.tr}
 | 
						|
        <div class="h-48 w-48">
 | 
						|
          <ChartJs config={ChartJsUtils.createConfigForTagRendering(
 | 
						|
            diff.tr, diff.features,{
 | 
						|
              groupToOtherCutoff: 0,
 | 
						|
              chartType: "pie",
 | 
						|
              sort: true,
 | 
						|
            }
 | 
						|
          )} />
 | 
						|
        </div>
 | 
						|
      {:else}
 | 
						|
        Could not create a graph - this item type has no associated question
 | 
						|
      {/if}
 | 
						|
    </AccordionSingle>
 | 
						|
  {/each}
 | 
						|
{/if}
 |