1+ const base26 = require ( "./base26.js" ) ;
12const crypto = require ( "crypto" ) ;
23const sheets_lib = require ( "./sheets.js" ) ;
34const backend = require ( "./backend" ) ;
@@ -17,6 +18,13 @@ class Session {
1718 }
1819}
1920
21+ class Range {
22+ constructor ( start , end ) {
23+ this . start = start
24+ this . end = end
25+ }
26+ }
27+
2028exports . CreateSession = ( config , request ) => {
2129 const createResponse = {
2230 id : "" ,
@@ -67,3 +75,130 @@ var validateUpload = (file) => {
6775
6876 return undefined ;
6977} ;
78+
79+ /*
80+ * Returns a header row for display, based on the requested mode and the data
81+ * currently available in the state.
82+ *
83+ * The various display modes are:
84+ * - none - return nothing, no display required
85+ * - index - returns the index of the column in base26.
86+ * - source - returns the header names as they are defined in the source file
87+ * - target - returns the header names as they are in the domain object after mapping
88+ */
89+ exports . HeaderRowDisplay = ( session , displayMode ) => {
90+ var mode = displayMode . toLowerCase ( ) ;
91+
92+ // User has selected 'none' mode, which means we don't return any headers as
93+ // the user does not want to show them. No pre-requisites.
94+ // eslint-disable-next-line no-unused-vars
95+ const noneMode = ( _range ) => {
96+ return null
97+ }
98+
99+ // Index mode, shows the index as base26 where the values are taken from the range.
100+ // Requires a selected sheet
101+ const indexMode = ( range ) => {
102+ if ( ! session . sheet || session . sheet == "" ) {
103+ console . warn ( "HeaderRowDisplay: No sheet selected so header display mode is 'none'" )
104+ return null
105+ }
106+
107+ const headers = new Array ( ) ;
108+ for ( var i = range . start ; i <= range . end ; i ++ ) {
109+ headers . push ( base26 . toBase26 ( i + 1 ) )
110+ }
111+
112+ return headers
113+ }
114+
115+ // Using the header values selected by the user, use those instead of column indices.
116+ // Requires a selected sheet and a headerRange
117+ const sourceMode = ( range ) => {
118+ if ( ! session . sheet || session . sheet == "" || ! session . headerRange ) {
119+ console . warn ( "HeaderRowDisplay: No sheet selected so header display mode is 'none'" )
120+ return null
121+ }
122+
123+ if ( ! Object . prototype . hasOwnProperty . call ( session . headerRange , "start" ) ||
124+ ! Object . prototype . hasOwnProperty . call ( session . headerRange , "end" ) ) {
125+ console . warn ( "HeaderRowDisplay: No header range available for source headers" )
126+ return null
127+ }
128+
129+ const rows = sheets_lib . GetRows ( session , session . headerRange . start . row , session . headerRange . end . row + 1 ) [ 0 ] ;
130+ const headers = new Array ( ) ;
131+
132+ for ( var i = range . start ; i <= range . end ; i ++ ) {
133+ headers . push ( rows [ i ] ?. value ?? "" )
134+ }
135+
136+ return headers ;
137+ }
138+
139+ // Use the header values from the mapped domain object, so the target column headings and the user's data
140+ // for that column.
141+ // Requires a selected sheet and a mapping
142+ // eslint-disable-next-line no-unused-vars
143+ const targetMode = ( _range ) => {
144+ if ( ! session . sheet || session . sheet == "" ) {
145+ console . warn ( "HeaderRowDisplay: No sheet selected so header display mode is 'none'" )
146+ return null
147+ }
148+
149+ if ( ! session . mapping ) {
150+ console . warn ( "HeaderRowDisplay: No mapping available so header display mode is 'none'" )
151+ return null
152+ }
153+
154+ return noneMode ;
155+ }
156+
157+ var range = calculateHeaderRange ( session )
158+
159+ // Unless the mode is 'none' then a sheet is required to return headers for display
160+ if ( mode != "none" && ( ! session . sheet || session . sheet == "" ) ) {
161+ console . warn ( "HeaderRowDisplay: No sheet selected so header display mode is 'none'" )
162+ return null
163+ }
164+
165+ switch ( mode ) {
166+ // Index as base26 name
167+ case "index" :
168+ return indexMode ( range ) ;
169+ // Header names as selected by user
170+ case "source" :
171+ return sourceMode ( range ) ;
172+ // Header names as the fieldnames for the domain object
173+ case "target" :
174+ return targetMode ( range ) ;
175+ }
176+
177+ // If 'none' is specified, or the value provided isn't supported...
178+ return noneMode ( range ) ;
179+ }
180+
181+ // Calculate the range, either from the currently selected columns, or from the number
182+ // of items in a row (making the assumption that they're even).
183+ const calculateHeaderRange = ( session ) => {
184+ if ( Object . prototype . hasOwnProperty . call ( session , "headerRange" ) &&
185+ Object . prototype . hasOwnProperty . call ( session . headerRange , "start" ) &&
186+ Object . prototype . hasOwnProperty . call ( session . headerRange , "end" ) ) {
187+ return new Range ( session . headerRange . start . column , session . headerRange . end . column )
188+ }
189+
190+ if ( ! session . sheet || session . sheet == "" ) {
191+ console . warn ( "HeaderRowDisplay: No sheet selected so finding mode from rows is not possible" )
192+ return null
193+ }
194+
195+ // With no specified headers, try and default to the first row. This may already be set
196+ // earlier in the flow, but we add this defensively.
197+ const r = sheets_lib . GetRows ( session )
198+ if ( r ) {
199+ return new Range ( 0 , r [ 0 ] . length )
200+ }
201+
202+ console . warn ( "HeaderRowDisplay: No rows available when determining number of columns" )
203+ return null
204+ }
0 commit comments