1- import { getAllItems , IResult } from "@concord-consortium/codap-plugin-api" ;
2- import { makeAutoObservable } from "mobx" ;
1+ import { addDataContextChangeListener , getAllItems , getCaseByID , getCaseBySearch , getSelectionList , initializePlugin ,
2+ IResult , sendMessage } from "@concord-consortium/codap-plugin-api" ;
3+ import { makeAutoObservable , reaction } from "mobx" ;
34import {
4- kPinColorAttributeName , kPinDataContextName , kPinLatAttributeName , kPinLongAttributeName
5+ kDataContextName ,
6+ kInitialDimensions ,
7+ kMapPinsCollectionName ,
8+ kPinColorAttributeName , kPinDataContextName , kPinLatAttributeName , kPinLongAttributeName ,
9+ kPluginName ,
10+ kVersion
511} from "../data/constants" ;
12+ import { createOrUpdateMap , createSelectionList , deleteSelectionList , updateSelectionList } from "../utils/codap-utils" ;
613import { NeoDataset } from "./neo-types" ;
714
8- interface IMapPin {
15+ export interface IMapPin {
916 color : string ;
1017 id : string ;
1118 lat : number ;
1219 long : number ;
1320}
1421
22+ export interface ILocationCase {
23+ label : string ;
24+ pinColor : string ;
25+ }
26+
1527export function pinLabel ( pin : IMapPin ) {
1628 return `${ pin . lat . toFixed ( 2 ) } , ${ pin . long . toFixed ( 2 ) } ` ;
1729}
1830
31+
1932class PluginState {
2033 neoDataset : NeoDataset | undefined ;
2134 neoDatasetName = "" ;
2235 pins : IMapPin [ ] = [ ] ;
36+ selectedPins : IMapPin [ ] = [ ] ;
37+ selectedCases : any [ ] = [ ] ;
2338
2439 constructor ( ) {
2540 makeAutoObservable ( this ) ;
41+ // Reaction to changes in selectedPins from MapPinDataContext
42+ reaction (
43+ ( ) => this . selectedPins ,
44+ ( selectedPins ) => {
45+ this . handleSelectionChange (
46+ selectedPins ,
47+ kDataContextName ,
48+ kMapPinsCollectionName ,
49+ ( pin ) => `label == ${ pinLabel ( pin ) } `
50+ ) ;
51+ }
52+ ) ;
53+ // Reaction to changes in selectedCases NEOPluginDataContext
54+ reaction (
55+ ( ) => this . selectedCases ,
56+ ( selectedCases ) => {
57+ this . handleSelectionChange (
58+ selectedCases ,
59+ kPinDataContextName ,
60+ kMapPinsCollectionName ,
61+ ( sCase ) => `pinColor == ${ sCase . pinColor } `
62+ ) ;
63+ }
64+ ) ;
2665 }
2766
2867 setNeoDataset ( neoDataset : NeoDataset | undefined ) {
@@ -45,6 +84,124 @@ class PluginState {
4584 } ) ;
4685 }
4786 }
87+
88+ setSelectedPins ( selectedPins : IMapPin [ ] ) {
89+ this . selectedPins = selectedPins ;
90+ }
91+
92+ setSelectedCases ( selectedCases : any [ ] ) {
93+ this . selectedCases = selectedCases ;
94+ }
95+
96+ async handleSelectionChange < T > (
97+ selectedItems : T [ ] , dataContextName : string , collectionName : string , searchQueryFn : ( item : T ) => string
98+ ) : Promise < void > {
99+ if ( selectedItems . length === 0 ) {
100+ deleteSelectionList ( dataContextName ) ;
101+ return ;
102+ }
103+
104+ for ( const item of selectedItems ) {
105+ const searchQuery = searchQueryFn ( item ) ;
106+ const result = await getCaseBySearch ( dataContextName , collectionName , searchQuery ) ;
107+
108+ if ( result . success ) {
109+ const selectedItemIds = result . values . map ( ( val : any ) => val . id ) ;
110+ if ( selectedItems . length === 1 ) {
111+ createSelectionList ( dataContextName , selectedItemIds ) ;
112+ return ;
113+ } else {
114+ const updateSelection = await updateSelectionList ( dataContextName , selectedItemIds ) ;
115+ if ( ! updateSelection . success ) {
116+ createSelectionList ( dataContextName , selectedItemIds ) ;
117+ }
118+ }
119+ }
120+ }
121+ }
122+ }
123+
124+ export async function initializeNeoPlugin ( ) {
125+ await initializePlugin ( { pluginName : kPluginName , version : kVersion , dimensions : kInitialDimensions } ) ;
126+
127+ // Create the pin dataset
128+ await sendMessage ( "create" , `dataContext` , {
129+ name : kPinDataContextName ,
130+ collections : [
131+ {
132+ name : "Map Pins" ,
133+ attrs : [
134+ { name : kPinLatAttributeName , type : "numeric" } ,
135+ { name : kPinLongAttributeName , type : "numeric" } ,
136+ { name : kPinColorAttributeName , type : "color" }
137+ ]
138+ }
139+ ]
140+ } ) ;
141+
142+ // Create map if it doesn't exist
143+ await createOrUpdateMap ( "Map" ) ;
144+
145+ // See if there are any existing pins
146+ pluginState . updatePins ( ) ;
147+
148+ // Set up a listener for changes to the pin dataset
149+ addDataContextChangeListener ( kPinDataContextName , notification => {
150+ const { operation } = notification . values ;
151+
152+ if ( [ "createCases" , "deleteCases" , "updateCases" ] . includes ( operation ) ) {
153+ pluginState . updatePins ( ) ;
154+ }
155+ } ) ;
156+ // Set up a listener for pin selection
157+ addDataContextChangeListener ( kPinDataContextName , async notification => {
158+ const { operation, result } = notification . values ;
159+ if ( operation === "selectCases" && result . success ) {
160+ const selectedPins = await getSelectionList ( kPinDataContextName ) ;
161+ const selectedPinValues : IMapPin [ ] = await Promise . all (
162+ selectedPins . values . map ( async ( pin : any ) => {
163+ const pinItem = await getCaseByID ( kPinDataContextName , pin . caseID ) ;
164+ if ( pinItem . success ) {
165+ const pinValues = pinItem . values ;
166+ const pinCase = ( pinValues as any ) . case ;
167+ return {
168+ id : pinCase . id ,
169+ lat : pinCase . values . pinLat ,
170+ long : pinCase . values . pinLong ,
171+ color : pinCase . values . pinColor ,
172+ } ;
173+ }
174+ return null ;
175+ } )
176+ ) ;
177+ pluginState . setSelectedPins ( selectedPinValues ) ;
178+ }
179+ } ) ;
180+
181+ // Set up a listener for case selection
182+ addDataContextChangeListener ( kDataContextName , async notification => {
183+ const { operation, result } = notification . values ;
184+ if ( operation === "selectCases" && result . success ) {
185+ const selectedCases = await getSelectionList ( kDataContextName ) ;
186+ const selectedPinCases = selectedCases . values
187+ . filter ( ( sCase : any ) => sCase . collectionName === kMapPinsCollectionName ) ;
188+ const selectedCaseValues : any [ ] = await Promise . all (
189+ selectedPinCases . map ( async ( sCase : any ) => {
190+ const caseItem = await getCaseByID ( kDataContextName , sCase . caseID ) ;
191+ if ( caseItem . success ) {
192+ const caseValues = caseItem . values ;
193+ return {
194+ id : caseValues . id ,
195+ label : caseValues . case . values . label ,
196+ pinColor : caseValues . case . values . pinColor ,
197+ } ;
198+ }
199+ return null ;
200+ } )
201+ ) ;
202+ pluginState . setSelectedCases ( selectedCaseValues ) ;
203+ }
204+ } ) ;
48205}
49206
50207export const pluginState = new PluginState ( ) ;
0 commit comments